1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmlsecurity.hxx"
26
27 /*
28 * Turn off DEBUG Assertions
29 */
30 #ifdef _DEBUG
31 #define _DEBUG_WAS_DEFINED _DEBUG
32 #undef _DEBUG
33 #else
34 #undef _DEBUG_WAS_DEFINED
35 #endif
36
37 /*
38 * and turn off the additional virtual methods which are part of some interfaces when compiled
39 * with debug
40 */
41 #ifdef DEBUG
42 #define DEBUG_WAS_DEFINED DEBUG
43 #undef DEBUG
44 #else
45 #undef DEBUG_WAS_DEFINED
46 #endif
47
48
49 #include <com/sun/star/mozilla/XMozillaBootstrap.hpp>
50 #include <com/sun/star/xml/crypto/DigestID.hpp>
51 #include <com/sun/star/xml/crypto/CipherID.hpp>
52
53 #include <sal/types.h>
54 #include <rtl/instance.hxx>
55 #include <rtl/bootstrap.hxx>
56 #include <rtl/string.hxx>
57 #include <rtl/strbuf.hxx>
58 #include <osl/file.hxx>
59 #include <osl/thread.h>
60 #include <tools/debug.hxx>
61 #include <rtl/logfile.hxx>
62
63 #include "seinitializer_nssimpl.hxx"
64 #include "../diagnose.hxx"
65
66 #include "securityenvironment_nssimpl.hxx"
67 #include "digestcontext.hxx"
68 #include "ciphercontext.hxx"
69
70 #include <nspr.h>
71 #include <cert.h>
72 #include <nss.h>
73 #include <pk11pub.h>
74 #include <secmod.h>
75 #include <nssckbi.h>
76
77
78 namespace css = ::com::sun::star;
79 namespace cssu = css::uno;
80 namespace cssl = css::lang;
81 namespace cssxc = css::xml::crypto;
82
83 using namespace xmlsecurity;
84 using namespace com::sun::star;
85 using ::rtl::OUString;
86 using ::rtl::OString;
87
88 #define IMPLEMENTATION_NAME "com.sun.star.xml.security.bridge.xmlsec.NSSInitializer_NssImpl"
89
90 #define ROOT_CERTS "Root Certs for Apache OpenOffice"
91
92 extern "C" void nsscrypto_finalize();
93
94
95 namespace
96 {
97
98 bool nsscrypto_initialize( const css::uno::Reference< css::lang::XMultiServiceFactory > &xMSF, bool & out_nss_init );
99
100 struct InitNSSInitialize
101 {
102 css::uno::Reference< css::lang::XMultiServiceFactory > mxMSF;
103
InitNSSInitialize__anonc1099bfd0111::InitNSSInitialize104 InitNSSInitialize( const css::uno::Reference< css::lang::XMultiServiceFactory > &xMSF )
105 : mxMSF( xMSF )
106 {
107 }
108
operator ()__anonc1099bfd0111::InitNSSInitialize109 bool * operator()()
110 {
111 static bool bInitialized = false;
112 bool bNSSInit = false;
113 bInitialized = nsscrypto_initialize( mxMSF, bNSSInit );
114 if (bNSSInit)
115 atexit(nsscrypto_finalize );
116 return & bInitialized;
117 }
118 };
119
120 struct GetNSSInitStaticMutex
121 {
operator ()__anonc1099bfd0111::GetNSSInitStaticMutex122 ::osl::Mutex* operator()()
123 {
124 static ::osl::Mutex aNSSInitMutex;
125 return &aNSSInitMutex;
126 }
127 };
128
deleteRootsModule()129 void deleteRootsModule()
130 {
131 SECMODModule *RootsModule = 0;
132 SECMODModuleList *list = SECMOD_GetDefaultModuleList();
133 SECMODListLock *lock = SECMOD_GetDefaultModuleListLock();
134 SECMOD_GetReadLock(lock);
135
136 while (!RootsModule && list)
137 {
138 SECMODModule *module = list->module;
139
140 for (int i=0; i < module->slotCount; i++)
141 {
142 PK11SlotInfo *slot = module->slots[i];
143 if (PK11_IsPresent(slot))
144 {
145 if (PK11_HasRootCerts(slot))
146 {
147 xmlsec_trace("The root certifificates module \"%s"
148 "\" is already loaded: \n%s",
149 module->commonName, module->dllName);
150
151 RootsModule = SECMOD_ReferenceModule(module);
152 break;
153 }
154 }
155 }
156 list = list->next;
157 }
158 SECMOD_ReleaseReadLock(lock);
159
160 if (RootsModule)
161 {
162 PRInt32 modType;
163 if (SECSuccess == SECMOD_DeleteModule(RootsModule->commonName, &modType))
164 {
165 xmlsec_trace("Deleted module \"%s\".", RootsModule->commonName);
166 }
167 else
168 {
169 xmlsec_trace("Failed to delete \"%s\" : \n%s",
170 RootsModule->commonName, RootsModule->dllName);
171 }
172 SECMOD_DestroyModule(RootsModule);
173 RootsModule = 0;
174 }
175 }
176
getMozillaCurrentProfile(const css::uno::Reference<css::lang::XMultiServiceFactory> & rxMSF)177 ::rtl::OString getMozillaCurrentProfile( const css::uno::Reference< css::lang::XMultiServiceFactory > &rxMSF )
178 {
179 ::rtl::OString sResult;
180 // first, try to get the profile from "MOZILLA_CERTIFICATE_FOLDER"
181 char* pEnv = getenv( "MOZILLA_CERTIFICATE_FOLDER" );
182 if ( pEnv )
183 {
184 sResult = ::rtl::OString( pEnv );
185 RTL_LOGFILE_PRODUCT_TRACE1( "XMLSEC: Using env MOZILLA_CERTIFICATE_FOLDER: %s", sResult.getStr() );
186 }
187 else
188 {
189 mozilla::MozillaProductType productTypes[4] = {
190 mozilla::MozillaProductType_Thunderbird,
191 mozilla::MozillaProductType_Mozilla,
192 mozilla::MozillaProductType_Firefox,
193 mozilla::MozillaProductType_Default };
194 int nProduct = 4;
195
196 uno::Reference<uno::XInterface> xInstance = rxMSF->createInstance(
197 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.mozilla.MozillaBootstrap")) );
198 OSL_ENSURE( xInstance.is(), "failed to create instance" );
199
200 uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap
201 = uno::Reference<mozilla::XMozillaBootstrap>(xInstance,uno::UNO_QUERY);
202 OSL_ENSURE( xMozillaBootstrap.is(), "failed to create instance" );
203
204 if (xMozillaBootstrap.is())
205 {
206 for (int i=0; i<nProduct; i++)
207 {
208 ::rtl::OUString profile = xMozillaBootstrap->getDefaultProfile(productTypes[i]);
209
210 if (profile != NULL && profile.getLength()>0)
211 {
212 ::rtl::OUString sProfilePath = xMozillaBootstrap->getProfilePath( productTypes[i], profile );
213 sResult = ::rtl::OUStringToOString( sProfilePath, osl_getThreadTextEncoding() );
214 RTL_LOGFILE_PRODUCT_TRACE1( "XMLSEC: Using Mozilla Profile: %s", sResult.getStr() );
215 }
216 }
217 }
218
219 RTL_LOGFILE_PRODUCT_TRACE( "XMLSEC: No Mozilla Profile found!" );
220 }
221
222 return sResult;
223 }
224
225 //Older versions of Firefox (FF), for example FF2, and Thunderbird (TB) 2 write
226 //the roots certificate module (libnssckbi.so), which they use, into the
227 //profile. This module will then already be loaded during NSS_Init (and the
228 //other init functions). This fails in two cases. First, FF3 was used to create
229 //the profile, or possibly used that profile before, and second the profile was
230 //used on a different platform.
231 //
232 //Then one needs to add the roots module oneself. This should be done with
233 //SECMOD_LoadUserModule rather then SECMOD_AddNewModule. The latter would write
234 //the location of the roots module to the profile, which makes FF2 and TB2 use
235 //it instead of there own module.
236 //
237 //When using SYSTEM_NSS then the libnss3.so lib is typically found in
238 ///usr/lib. This folder may, however, NOT contain the roots certificate
239 //module. That is, just providing the library name in SECMOD_LoadUserModule or
240 //SECMOD_AddNewModule will FAIL to load the mozilla unless the LD_LIBRARY_PATH
241 //contains an FF or TB installation.
242 //ATTENTION: DO NOT call this function directly instead use initNSS
243 //return true - whole initialization was successful
244 //param out_nss_init = true: at least the NSS initialization (NSS_InitReadWrite
245 //was successful and therefor NSS_Shutdown should be called when terminating.
nsscrypto_initialize(const css::uno::Reference<css::lang::XMultiServiceFactory> & xMSF,bool & out_nss_init)246 bool nsscrypto_initialize( const css::uno::Reference< css::lang::XMultiServiceFactory > &xMSF, bool & out_nss_init )
247 {
248 bool return_value = true;
249
250 // this method must be called only once, no need for additional lock
251 rtl::OString sCertDir;
252
253 (void) xMSF;
254 #ifdef XMLSEC_CRYPTO_NSS
255 if ( xMSF.is() )
256 sCertDir = getMozillaCurrentProfile( xMSF );
257 #endif
258 xmlsec_trace( "Using profile: %s", sCertDir.getStr() );
259
260 PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
261
262 // there might be no profile
263 if ( sCertDir.getLength() > 0 )
264 {
265 if( NSS_InitReadWrite( sCertDir.getStr() ) != SECSuccess )
266 {
267 xmlsec_trace("Initializing NSS with profile failed.");
268 PRInt32 errorLength = PR_GetErrorTextLength();
269 char *error = new char[errorLength + 1];
270 error[0] = '\0'; // as per https://bugzilla.mozilla.org/show_bug.cgi?id=538940
271 PR_GetErrorText(error);
272 if (error[0])
273 xmlsec_trace("%s",error);
274 delete[] error;
275 return false ;
276 }
277 }
278 else
279 {
280 xmlsec_trace("Initializing NSS without profile.");
281 if ( NSS_NoDB_Init(NULL) != SECSuccess )
282 {
283 xmlsec_trace("Initializing NSS without profile failed.");
284 PRInt32 errorLength = PR_GetErrorTextLength();
285 char *error = new char[errorLength + 1];
286 error[0] = '\0';
287 PR_GetErrorText(error);
288 if (error[0])
289 xmlsec_trace("%s",error);
290 delete[] error;
291 return false ;
292 }
293 }
294 out_nss_init = true;
295
296 #ifdef XMLSEC_CRYPTO_NSS
297 #if defined SYSTEM_NSS
298 if (!SECMOD_HasRootCerts())
299 {
300 #endif
301 deleteRootsModule();
302
303 #if defined OS2
304 // YD the nss system dlls names are ending with 'k'
305 OUString rootModule(RTL_CONSTASCII_USTRINGPARAM( "nssckbik" SAL_DLLEXTENSION));
306 #elif defined SYSTEM_NSS
307 OUString rootModule(RTL_CONSTASCII_USTRINGPARAM( "libnssckbi" SAL_DLLEXTENSION));
308 #else
309 OUString rootModule(RTL_CONSTASCII_USTRINGPARAM( "${OOO_BASE_DIR}/program/libnssckbi" SAL_DLLEXTENSION));
310 #endif
311 ::rtl::Bootstrap::expandMacros(rootModule);
312
313 OUString rootModulePath;
314 if (::osl::File::E_None == ::osl::File::getSystemPathFromFileURL(rootModule, rootModulePath))
315 {
316 ::rtl::OString ospath = ::rtl::OUStringToOString(rootModulePath, osl_getThreadTextEncoding());
317 ::rtl::OStringBuffer pkcs11moduleSpec;
318 pkcs11moduleSpec.append("name=\"");
319 pkcs11moduleSpec.append(ROOT_CERTS);
320 pkcs11moduleSpec.append("\" library=\"");
321 pkcs11moduleSpec.append(ospath.getStr());
322 pkcs11moduleSpec.append("\"");
323
324 SECMODModule * RootsModule =
325 SECMOD_LoadUserModule(
326 const_cast<char*>(pkcs11moduleSpec.makeStringAndClear().getStr()),
327 0, // no parent
328 PR_FALSE); // do not recurse
329
330 if (RootsModule)
331 {
332
333 bool found = RootsModule->loaded;
334
335 SECMOD_DestroyModule(RootsModule);
336 RootsModule = 0;
337 if (found)
338 xmlsec_trace("Added new root certificate module "
339 "\"" ROOT_CERTS "\" contained in \n%s", ospath.getStr());
340 else
341 {
342 xmlsec_trace("FAILED to load the new root certificate module "
343 "\"" ROOT_CERTS "\" contained in \n%s", ospath.getStr());
344 return_value = false;
345 }
346 }
347 else
348 {
349 xmlsec_trace("FAILED to add new root certifice module: "
350 "\"" ROOT_CERTS "\" contained in \n%s", ospath.getStr());
351 return_value = false;
352
353 }
354 }
355 else
356 {
357 xmlsec_trace("Adding new root certificate module failed.");
358 return_value = false;
359 }
360 #if SYSTEM_NSS
361 }
362 #endif
363 #endif
364
365 return return_value;
366 }
367
368
369 // must be extern "C" because we pass the function pointer to atexit
nsscrypto_finalize()370 extern "C" void nsscrypto_finalize()
371 {
372 SECMODModule *RootsModule = SECMOD_FindModule(ROOT_CERTS);
373
374 if (RootsModule)
375 {
376
377 if (SECSuccess == SECMOD_UnloadUserModule(RootsModule))
378 {
379 xmlsec_trace( "Unloaded module \"" ROOT_CERTS "\".");
380 }
381 else
382 {
383 xmlsec_trace( "Failed unloadeding module \"" ROOT_CERTS "\".");
384 }
385 SECMOD_DestroyModule(RootsModule);
386 }
387 else
388 {
389 xmlsec_trace( "Unloading module \"" ROOT_CERTS
390 "\" failed because it was not found.");
391 }
392 PK11_LogoutAll();
393 NSS_Shutdown();
394 }
395 } // namespace
396
ONSSInitializer(const css::uno::Reference<css::lang::XMultiServiceFactory> & rxMSF)397 ONSSInitializer::ONSSInitializer(
398 const css::uno::Reference< css::lang::XMultiServiceFactory > &rxMSF)
399 :mxMSF( rxMSF )
400 {
401 }
402
~ONSSInitializer()403 ONSSInitializer::~ONSSInitializer()
404 {
405 }
406
initNSS(const css::uno::Reference<css::lang::XMultiServiceFactory> & xMSF)407 bool ONSSInitializer::initNSS( const css::uno::Reference< css::lang::XMultiServiceFactory > &xMSF )
408 {
409 return *rtl_Instance< bool, InitNSSInitialize, ::osl::MutexGuard, GetNSSInitStaticMutex >
410 ::create( InitNSSInitialize( xMSF ), GetNSSInitStaticMutex() );
411 }
412
getDigestContext(::sal_Int32 nDigestID,const css::uno::Sequence<css::beans::NamedValue> & aParams)413 css::uno::Reference< css::xml::crypto::XDigestContext > SAL_CALL ONSSInitializer::getDigestContext( ::sal_Int32 nDigestID, const css::uno::Sequence< css::beans::NamedValue >& aParams )
414 throw (css::lang::IllegalArgumentException, css::uno::RuntimeException)
415 {
416 SECOidTag nNSSDigestID = SEC_OID_UNKNOWN;
417 sal_Int32 nDigestLength = 0;
418 bool b1KData = false;
419 if ( nDigestID == css::xml::crypto::DigestID::SHA256
420 || nDigestID == css::xml::crypto::DigestID::SHA256_1K )
421 {
422 nNSSDigestID = SEC_OID_SHA256;
423 nDigestLength = 32;
424 b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA256_1K );
425 }
426 else if ( nDigestID == css::xml::crypto::DigestID::SHA1
427 || nDigestID == css::xml::crypto::DigestID::SHA1_1K )
428 {
429 nNSSDigestID = SEC_OID_SHA1;
430 nDigestLength = 20;
431 b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA1_1K );
432 }
433 else
434 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected digest requested." ) ), css::uno::Reference< css::uno::XInterface >(), 1 );
435
436 if ( aParams.getLength() )
437 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected arguments provided for digest creation." ) ), css::uno::Reference< css::uno::XInterface >(), 2 );
438
439 css::uno::Reference< css::xml::crypto::XDigestContext > xResult;
440 if( initNSS( mxMSF ) )
441 {
442 PK11Context* pContext = PK11_CreateDigestContext( nNSSDigestID );
443 if ( pContext && PK11_DigestBegin( pContext ) == SECSuccess )
444 xResult = new ODigestContext( pContext, nDigestLength, b1KData );
445 }
446
447 return xResult;
448 }
449
getCipherContext(::sal_Int32 nCipherID,const css::uno::Sequence<::sal_Int8> & aKey,const css::uno::Sequence<::sal_Int8> & aInitializationVector,::sal_Bool bEncryption,const css::uno::Sequence<css::beans::NamedValue> & aParams)450 css::uno::Reference< css::xml::crypto::XCipherContext > SAL_CALL ONSSInitializer::getCipherContext( ::sal_Int32 nCipherID, const css::uno::Sequence< ::sal_Int8 >& aKey, const css::uno::Sequence< ::sal_Int8 >& aInitializationVector, ::sal_Bool bEncryption, const css::uno::Sequence< css::beans::NamedValue >& aParams )
451 throw (css::lang::IllegalArgumentException, css::uno::RuntimeException)
452 {
453 CK_MECHANISM_TYPE nNSSCipherID = 0;
454 bool bW3CPadding = false;
455 if ( nCipherID == css::xml::crypto::CipherID::AES_CBC_W3C_PADDING )
456 {
457 nNSSCipherID = CKM_AES_CBC;
458 bW3CPadding = true;
459
460 if ( aKey.getLength() != 16 && aKey.getLength() != 24 && aKey.getLength() != 32 )
461 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected key length." ) ), css::uno::Reference< css::uno::XInterface >(), 2 );
462
463 if ( aParams.getLength() )
464 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected arguments provided for cipher creation." ) ), css::uno::Reference< css::uno::XInterface >(), 5 );
465 }
466 else
467 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected cipher requested." ) ), css::uno::Reference< css::uno::XInterface >(), 1 );
468
469 css::uno::Reference< css::xml::crypto::XCipherContext > xResult;
470 if( initNSS( mxMSF ) )
471 {
472 if ( aInitializationVector.getLength() != PK11_GetIVLength( nNSSCipherID ) )
473 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected length of initialization vector." ) ), css::uno::Reference< css::uno::XInterface >(), 3 );
474
475 xResult = OCipherContext::Create( nNSSCipherID, aKey, aInitializationVector, bEncryption, bW3CPadding );
476 }
477
478 return xResult;
479 }
480
ONSSInitializer_getImplementationName()481 rtl::OUString ONSSInitializer_getImplementationName ()
482 throw (cssu::RuntimeException)
483 {
484
485 return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( IMPLEMENTATION_NAME ) );
486 }
487
ONSSInitializer_supportsService(const rtl::OUString & ServiceName)488 sal_Bool SAL_CALL ONSSInitializer_supportsService( const rtl::OUString& ServiceName )
489 throw (cssu::RuntimeException)
490 {
491 return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( NSS_SERVICE_NAME ));
492 }
493
ONSSInitializer_getSupportedServiceNames()494 cssu::Sequence< rtl::OUString > SAL_CALL ONSSInitializer_getSupportedServiceNames( )
495 throw (cssu::RuntimeException)
496 {
497 cssu::Sequence < rtl::OUString > aRet(1);
498 rtl::OUString* pArray = aRet.getArray();
499 pArray[0] = rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( NSS_SERVICE_NAME ) );
500 return aRet;
501 }
502
ONSSInitializer_createInstance(const cssu::Reference<cssl::XMultiServiceFactory> & rSMgr)503 cssu::Reference< cssu::XInterface > SAL_CALL ONSSInitializer_createInstance( const cssu::Reference< cssl::XMultiServiceFactory > & rSMgr)
504 throw( cssu::Exception )
505 {
506 return (cppu::OWeakObject*) new ONSSInitializer( rSMgr );
507 }
508
509 /* XServiceInfo */
getImplementationName()510 rtl::OUString SAL_CALL ONSSInitializer::getImplementationName()
511 throw (cssu::RuntimeException)
512 {
513 return ONSSInitializer_getImplementationName();
514 }
supportsService(const rtl::OUString & rServiceName)515 sal_Bool SAL_CALL ONSSInitializer::supportsService( const rtl::OUString& rServiceName )
516 throw (cssu::RuntimeException)
517 {
518 return ONSSInitializer_supportsService( rServiceName );
519 }
getSupportedServiceNames()520 cssu::Sequence< rtl::OUString > SAL_CALL ONSSInitializer::getSupportedServiceNames( )
521 throw (cssu::RuntimeException)
522 {
523 return ONSSInitializer_getSupportedServiceNames();
524 }
525
526