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 OpenOffice.org" 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 104 InitNSSInitialize( const css::uno::Reference< css::lang::XMultiServiceFactory > &xMSF ) 105 : mxMSF( xMSF ) 106 { 107 } 108 109 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 { 122 ::osl::Mutex* operator()() 123 { 124 static ::osl::Mutex aNSSInitMutex; 125 return &aNSSInitMutex; 126 } 127 }; 128 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 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_MOZILLA 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. 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 char * error = NULL; 269 270 PR_GetErrorText(error); 271 if (error) 272 xmlsec_trace("%s",error); 273 return false ; 274 } 275 } 276 else 277 { 278 xmlsec_trace("Initializing NSS without profile."); 279 if ( NSS_NoDB_Init(NULL) != SECSuccess ) 280 { 281 xmlsec_trace("Initializing NSS without profile failed."); 282 char * error = NULL; 283 PR_GetErrorText(error); 284 if (error) 285 xmlsec_trace("%s",error); 286 return false ; 287 } 288 } 289 out_nss_init = true; 290 291 #ifdef XMLSEC_CRYPTO_NSS 292 #if defined SYSTEM_MOZILLA 293 if (!SECMOD_HasRootCerts()) 294 { 295 #endif 296 deleteRootsModule(); 297 298 #if defined SYSTEM_MOZILLA 299 OUString rootModule(RTL_CONSTASCII_USTRINGPARAM("libnssckbi"SAL_DLLEXTENSION)); 300 #else 301 OUString rootModule(RTL_CONSTASCII_USTRINGPARAM("${OOO_BASE_DIR}/program/libnssckbi"SAL_DLLEXTENSION)); 302 #endif 303 ::rtl::Bootstrap::expandMacros(rootModule); 304 305 OUString rootModulePath; 306 if (::osl::File::E_None == ::osl::File::getSystemPathFromFileURL(rootModule, rootModulePath)) 307 { 308 ::rtl::OString ospath = ::rtl::OUStringToOString(rootModulePath, osl_getThreadTextEncoding()); 309 ::rtl::OStringBuffer pkcs11moduleSpec; 310 pkcs11moduleSpec.append("name=\""); 311 pkcs11moduleSpec.append(ROOT_CERTS); 312 pkcs11moduleSpec.append("\" library=\""); 313 pkcs11moduleSpec.append(ospath.getStr()); 314 pkcs11moduleSpec.append("\""); 315 316 SECMODModule * RootsModule = 317 SECMOD_LoadUserModule( 318 const_cast<char*>(pkcs11moduleSpec.makeStringAndClear().getStr()), 319 0, // no parent 320 PR_FALSE); // do not recurse 321 322 if (RootsModule) 323 { 324 325 bool found = RootsModule->loaded; 326 327 SECMOD_DestroyModule(RootsModule); 328 RootsModule = 0; 329 if (found) 330 xmlsec_trace("Added new root certificate module " 331 "\""ROOT_CERTS"\" contained in \n%s", ospath.getStr()); 332 else 333 { 334 xmlsec_trace("FAILED to load the new root certificate module " 335 "\""ROOT_CERTS"\" contained in \n%s", ospath.getStr()); 336 return_value = false; 337 } 338 } 339 else 340 { 341 xmlsec_trace("FAILED to add new root certifice module: " 342 "\""ROOT_CERTS"\" contained in \n%s", ospath.getStr()); 343 return_value = false; 344 345 } 346 } 347 else 348 { 349 xmlsec_trace("Adding new root certificate module failed."); 350 return_value = false; 351 } 352 #if SYSTEM_MOZILLA 353 } 354 #endif 355 #endif 356 357 return return_value; 358 } 359 360 361 // must be extern "C" because we pass the function pointer to atexit 362 extern "C" void nsscrypto_finalize() 363 { 364 SECMODModule *RootsModule = SECMOD_FindModule(ROOT_CERTS); 365 366 if (RootsModule) 367 { 368 369 if (SECSuccess == SECMOD_UnloadUserModule(RootsModule)) 370 { 371 xmlsec_trace("Unloaded module \""ROOT_CERTS"\"."); 372 } 373 else 374 { 375 xmlsec_trace("Failed unloadeding module \""ROOT_CERTS"\"."); 376 } 377 SECMOD_DestroyModule(RootsModule); 378 } 379 else 380 { 381 xmlsec_trace("Unloading module \""ROOT_CERTS 382 "\" failed because it was not found."); 383 } 384 PK11_LogoutAll(); 385 NSS_Shutdown(); 386 } 387 } // namespace 388 389 ONSSInitializer::ONSSInitializer( 390 const css::uno::Reference< css::lang::XMultiServiceFactory > &rxMSF) 391 :mxMSF( rxMSF ) 392 { 393 } 394 395 ONSSInitializer::~ONSSInitializer() 396 { 397 } 398 399 bool ONSSInitializer::initNSS( const css::uno::Reference< css::lang::XMultiServiceFactory > &xMSF ) 400 { 401 return *rtl_Instance< bool, InitNSSInitialize, ::osl::MutexGuard, GetNSSInitStaticMutex > 402 ::create( InitNSSInitialize( xMSF ), GetNSSInitStaticMutex() ); 403 } 404 405 css::uno::Reference< css::xml::crypto::XDigestContext > SAL_CALL ONSSInitializer::getDigestContext( ::sal_Int32 nDigestID, const css::uno::Sequence< css::beans::NamedValue >& aParams ) 406 throw (css::lang::IllegalArgumentException, css::uno::RuntimeException) 407 { 408 SECOidTag nNSSDigestID = SEC_OID_UNKNOWN; 409 sal_Int32 nDigestLength = 0; 410 bool b1KData = false; 411 if ( nDigestID == css::xml::crypto::DigestID::SHA256 412 || nDigestID == css::xml::crypto::DigestID::SHA256_1K ) 413 { 414 nNSSDigestID = SEC_OID_SHA256; 415 nDigestLength = 32; 416 b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA256_1K ); 417 } 418 else if ( nDigestID == css::xml::crypto::DigestID::SHA1 419 || nDigestID == css::xml::crypto::DigestID::SHA1_1K ) 420 { 421 nNSSDigestID = SEC_OID_SHA1; 422 nDigestLength = 20; 423 b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA1_1K ); 424 } 425 else 426 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected digest requested." ) ), css::uno::Reference< css::uno::XInterface >(), 1 ); 427 428 if ( aParams.getLength() ) 429 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected arguments provided for digest creation." ) ), css::uno::Reference< css::uno::XInterface >(), 2 ); 430 431 css::uno::Reference< css::xml::crypto::XDigestContext > xResult; 432 if( initNSS( mxMSF ) ) 433 { 434 PK11Context* pContext = PK11_CreateDigestContext( nNSSDigestID ); 435 if ( pContext && PK11_DigestBegin( pContext ) == SECSuccess ) 436 xResult = new ODigestContext( pContext, nDigestLength, b1KData ); 437 } 438 439 return xResult; 440 } 441 442 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 ) 443 throw (css::lang::IllegalArgumentException, css::uno::RuntimeException) 444 { 445 CK_MECHANISM_TYPE nNSSCipherID = 0; 446 bool bW3CPadding = false; 447 if ( nCipherID == css::xml::crypto::CipherID::AES_CBC_W3C_PADDING ) 448 { 449 nNSSCipherID = CKM_AES_CBC; 450 bW3CPadding = true; 451 452 if ( aKey.getLength() != 16 && aKey.getLength() != 24 && aKey.getLength() != 32 ) 453 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected key length." ) ), css::uno::Reference< css::uno::XInterface >(), 2 ); 454 455 if ( aParams.getLength() ) 456 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected arguments provided for cipher creation." ) ), css::uno::Reference< css::uno::XInterface >(), 5 ); 457 } 458 else 459 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected cipher requested." ) ), css::uno::Reference< css::uno::XInterface >(), 1 ); 460 461 css::uno::Reference< css::xml::crypto::XCipherContext > xResult; 462 if( initNSS( mxMSF ) ) 463 { 464 if ( aInitializationVector.getLength() != PK11_GetIVLength( nNSSCipherID ) ) 465 throw css::lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Unexpected length of initialization vector." ) ), css::uno::Reference< css::uno::XInterface >(), 3 ); 466 467 xResult = OCipherContext::Create( nNSSCipherID, aKey, aInitializationVector, bEncryption, bW3CPadding ); 468 } 469 470 return xResult; 471 } 472 473 rtl::OUString ONSSInitializer_getImplementationName () 474 throw (cssu::RuntimeException) 475 { 476 477 return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( IMPLEMENTATION_NAME ) ); 478 } 479 480 sal_Bool SAL_CALL ONSSInitializer_supportsService( const rtl::OUString& ServiceName ) 481 throw (cssu::RuntimeException) 482 { 483 return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( NSS_SERVICE_NAME )); 484 } 485 486 cssu::Sequence< rtl::OUString > SAL_CALL ONSSInitializer_getSupportedServiceNames( ) 487 throw (cssu::RuntimeException) 488 { 489 cssu::Sequence < rtl::OUString > aRet(1); 490 rtl::OUString* pArray = aRet.getArray(); 491 pArray[0] = rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( NSS_SERVICE_NAME ) ); 492 return aRet; 493 } 494 495 cssu::Reference< cssu::XInterface > SAL_CALL ONSSInitializer_createInstance( const cssu::Reference< cssl::XMultiServiceFactory > & rSMgr) 496 throw( cssu::Exception ) 497 { 498 return (cppu::OWeakObject*) new ONSSInitializer( rSMgr ); 499 } 500 501 /* XServiceInfo */ 502 rtl::OUString SAL_CALL ONSSInitializer::getImplementationName() 503 throw (cssu::RuntimeException) 504 { 505 return ONSSInitializer_getImplementationName(); 506 } 507 sal_Bool SAL_CALL ONSSInitializer::supportsService( const rtl::OUString& rServiceName ) 508 throw (cssu::RuntimeException) 509 { 510 return ONSSInitializer_supportsService( rServiceName ); 511 } 512 cssu::Sequence< rtl::OUString > SAL_CALL ONSSInitializer::getSupportedServiceNames( ) 513 throw (cssu::RuntimeException) 514 { 515 return ONSSInitializer_getSupportedServiceNames(); 516 } 517 518