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