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