20#include <com/sun/star/lang/IllegalArgumentException.hpp>
21#include <com/sun/star/mozilla/XMozillaBootstrap.hpp>
22#include <com/sun/star/xml/crypto/DigestID.hpp>
23#include <com/sun/star/xml/crypto/CipherID.hpp>
24#include <com/sun/star/xml/crypto/NSSInitializer.hpp>
25#include <com/sun/star/uno/XComponentContext.hpp>
27#include <officecfg/Office/Common.hxx>
29#include <rtl/bootstrap.hxx>
30#include <rtl/string.hxx>
31#include <osl/file.hxx>
32#include <osl/thread.h>
55namespace cssu = css::uno;
56namespace cssl = css::lang;
60#define ROOT_CERTS "Root Certs for OpenOffice.org"
74 std::optional<utl::TempFileNamed> m_oTempFileDatabaseDirectory;
77 OUString getTempDatabasePath()
79 if (!m_oTempFileDatabaseDirectory)
81 m_oTempFileDatabaseDirectory.emplace(
nullptr,
true);
82 m_oTempFileDatabaseDirectory->EnableKillingFile();
84 return m_oTempFileDatabaseDirectory->GetFileName();
89 if (m_oTempFileDatabaseDirectory)
91 m_oTempFileDatabaseDirectory.reset();
99 return &aInitNSSPrivate;
102bool nsscrypto_initialize(
const css::uno::Reference< css::uno::XComponentContext > &rxContext,
bool & out_nss_init );
104#ifdef XMLSEC_CRYPTO_NSS
106void deleteRootsModule()
108 SECMODModule *RootsModule =
nullptr;
109 SECMODModuleList *list = SECMOD_GetDefaultModuleList();
110 SECMODListLock *
lock = SECMOD_GetDefaultModuleListLock();
111 SECMOD_GetReadLock(lock);
113 while (!RootsModule && list)
115 SECMODModule *
module = list->module;
117 for (
int i=0;
i <
module->slotCount;
i++)
119 PK11SlotInfo *slot =
module->slots[
i];
120 if (PK11_IsPresent(slot))
122 if (PK11_HasRootCerts(slot))
124 SAL_INFO(
"xmlsecurity.xmlsec",
"The root certificates module \"" <<
module->commonName <<
"\" is already loaded: " <<
module->dllName);
126 RootsModule = SECMOD_ReferenceModule(module);
133 SECMOD_ReleaseReadLock(lock);
139 if (SECSuccess == SECMOD_DeleteModule(RootsModule->commonName, &modType))
141 SAL_INFO(
"xmlsecurity.xmlsec",
"Deleted module \"" << RootsModule->commonName <<
"\".");
145 SAL_INFO(
"xmlsecurity.xmlsec",
"Failed to delete \"" << RootsModule->commonName <<
"\": " << RootsModule->dllName);
147 SECMOD_DestroyModule(RootsModule);
148 RootsModule =
nullptr;
153bool lcl_pathExists(
const OUString& sPath)
158 ::osl::DirectoryItem aPathItem;
160 osl::FileBase::getFileURLFromSystemPath(sPath, sURL);
161 if (::osl::FileBase::E_None == ::osl::DirectoryItem::get(sURL, aPathItem))
163 ::osl::FileStatus aStatus = osl_FileStatus_Mask_Validate;
164 if (::osl::FileBase::E_None == aPathItem.getFileStatus(aStatus))
181 const char* pEnv = getenv(
"MOZILLA_CERTIFICATE_FOLDER");
185 "xmlsecurity.xmlsec",
186 "Using Mozilla profile from MOZILLA_CERTIFICATE_FOLDER=" << pEnv);
187 m_sNSSPath = OStringToOUString(pEnv, osl_getThreadTextEncoding());
195 OUString sUserSetCertPath =
196 officecfg::Office::Common::Security::Scripting::CertDir::get().value_or(OUString());
198 if (lcl_pathExists(sUserSetCertPath))
201 "xmlsecurity.xmlsec",
202 "Using Mozilla profile from /org.openoffice.Office.Common/"
203 "Security/Scripting/CertDir: " << sUserSetCertPath);
207 catch (
const uno::Exception &)
214 mozilla::MozillaProductType productTypes[3] = {
215 mozilla::MozillaProductType_Thunderbird,
216 mozilla::MozillaProductType_Firefox,
217 mozilla::MozillaProductType_Mozilla };
219 uno::Reference<uno::XInterface> xInstance = rxContext->getServiceManager()->createInstanceWithContext(
"com.sun.star.mozilla.MozillaBootstrap", rxContext);
220 OSL_ENSURE( xInstance.is(),
"failed to create instance" );
222 uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap(xInstance,uno::UNO_QUERY);
223 OSL_ENSURE( xMozillaBootstrap.is(),
"failed to create instance" );
225 if (xMozillaBootstrap.is())
227 for (
auto const productTypeIter : productTypes)
229 OUString profile = xMozillaBootstrap->getDefaultProfile(productTypeIter);
231 if (!profile.isEmpty())
233 OUString sProfilePath = xMozillaBootstrap->getProfilePath(productTypeIter, profile);
236 SAL_INFO(
"xmlsecurity.xmlsec",
"Using Mozilla profile " << sProfilePath);
252 std::vector<xml::crypto::NSSProfile> aProfileList;
253 aProfileList.reserve(10);
255 mozilla::MozillaProductType productTypes[3] = {
256 mozilla::MozillaProductType_Thunderbird,
257 mozilla::MozillaProductType_Firefox,
258 mozilla::MozillaProductType_Mozilla };
260 uno::Reference<uno::XInterface> xInstance =
m_xContext->getServiceManager()->createInstanceWithContext(
"com.sun.star.mozilla.MozillaBootstrap",
m_xContext);
261 OSL_ENSURE(xInstance.is(),
"failed to create instance" );
263 uno::Reference<mozilla::XMozillaBootstrap> xMozillaBootstrap(xInstance,uno::UNO_QUERY);
265 if (xMozillaBootstrap.is())
267 for (
auto const productTypeIter : productTypes)
269 uno::Sequence<OUString> aProductProfileList;
270 xMozillaBootstrap->getProfileList(productTypeIter, aProductProfileList);
271 for (
const auto& sProfile : std::as_const(aProductProfileList))
272 aProfileList.push_back({sProfile, xMozillaBootstrap->getProfilePath(productTypeIter, sProfile), productTypeIter});
276 OUString sUserSelect;
279 sUserSelect = officecfg::Office::Common::Security::Scripting::CertDir::get().value_or(OUString());;
280 if (!lcl_pathExists(sUserSelect))
281 sUserSelect = OUString();
283 catch (
const uno::Exception &)
287 aProfileList.push_back({
"MANUAL", sUserSelect, mozilla::MozillaProductType_Default});
289 const char* pEnv = getenv(
"MOZILLA_CERTIFICATE_FOLDER");
290 aProfileList.push_back({
"MOZILLA_CERTIFICATE_FOLDER",
291 pEnv ? OStringToOUString(pEnv, osl_getThreadTextEncoding()) : OUString(),
292 mozilla::MozillaProductType_Default});
344bool nsscrypto_initialize(css::uno::Reference<css::uno::XComponentContext>
const & rxContext,
bool & out_nss_init)
349#ifdef XMLSEC_CRYPTO_NSS
354 SAL_INFO(
"xmlsecurity.xmlsec",
"Using profile: " << sCertDir );
356 PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
358 bool bSuccess =
false;
360 if (!sCertDir.isEmpty())
362 if (sCertDir.indexOf(
':') == -1)
364 OUString sCertDirURL;
365 osl::FileBase::getFileURLFromSystemPath(
366 OStringToOUString(sCertDir, osl_getThreadTextEncoding()),
368 osl::DirectoryItem item;
369 if (osl::FileBase::E_NOENT != osl::DirectoryItem::get(sCertDirURL +
"/cert8.db", item) &&
370 osl::FileBase::E_NOENT == osl::DirectoryItem::get(sCertDirURL +
"/cert9.db", item))
372 SAL_INFO(
"xmlsecurity.xmlsec",
"nsscrypto_initialize: trying to avoid profile migration");
373 sCertDir =
"dbm:" + sCertDir;
376 if (NSS_InitReadWrite(sCertDir.getStr()) != SECSuccess)
378 SAL_INFO(
"xmlsecurity.xmlsec",
"Initializing NSS with profile failed.");
379 int errlen = PR_GetErrorTextLength();
382 std::unique_ptr<char[]>
const error(
new char[errlen + 1]);
383 PR_GetErrorText(error.get());
384 SAL_INFO(
"xmlsecurity.xmlsec", error.get());
395 SAL_INFO(
"xmlsecurity.xmlsec",
"Initializing NSS with a temporary profile.");
396 OUString rString = (*getInitNSSPrivate())->getTempDatabasePath();
398 if (NSS_InitReadWrite(rString.toUtf8().getStr()) != SECSuccess)
400 SAL_INFO(
"xmlsecurity.xmlsec",
"Initializing NSS with a temporary profile.");
401 int errlen = PR_GetErrorTextLength();
404 std::unique_ptr<char[]>
const error(
new char[errlen + 1]);
405 PR_GetErrorText(error.get());
406 SAL_INFO(
"xmlsecurity.xmlsec", error.get());
416 PK11SlotInfo* pSlot = PK11_GetInternalKeySlot();
419 if (PK11_NeedUserInit(pSlot))
420 PK11_InitPin(pSlot,
nullptr,
nullptr);
421 PK11_FreeSlot(pSlot);
426#ifdef XMLSEC_CRYPTO_NSS
427 bool return_value =
true;
429#if defined SYSTEM_NSS || defined IOS
430 if (!SECMOD_HasRootCerts())
436 OUString rootModulePath(
"NSSCKBI");
440#if defined SYSTEM_NSS || defined ANDROID
441 OUString rootModule(
"libnssckbi" SAL_DLLEXTENSION);
443 OUString rootModule(
"${LO_LIB_DIR}/libnssckbi" SAL_DLLEXTENSION);
445 ::rtl::Bootstrap::expandMacros(rootModule);
447 OUString rootModulePath;
448 if (::osl::File::E_None == ::osl::File::getSystemPathFromFileURL(rootModule, rootModulePath))
452 OString
aStr =
"name=\"" ROOT_CERTS "\" library=\"" + ospath +
"\"";
454 SECMODModule * RootsModule =
455 SECMOD_LoadUserModule(
456 const_cast<char*
>(
aStr.getStr()),
463 bool found = RootsModule->loaded;
465 SECMOD_DestroyModule(RootsModule);
466 RootsModule =
nullptr;
468 SAL_INFO(
"xmlsecurity.xmlsec",
"Added new root certificate module " ROOT_CERTS " contained in " << ospath);
471 SAL_INFO(
"xmlsecurity.xmlsec",
"FAILED to load the new root certificate module " ROOT_CERTS "contained in " << ospath);
472 return_value =
false;
477 SAL_INFO(
"xmlsecurity.xmlsec",
"FAILED to add new root certificate module " ROOT_CERTS " contained in " << ospath);
478 return_value =
false;
484 SAL_INFO(
"xmlsecurity.xmlsec",
"Adding new root certificate module failed.");
485 return_value =
false;
500 SECMODModule *RootsModule = SECMOD_FindModule(
ROOT_CERTS);
505 if (SECSuccess == SECMOD_UnloadUserModule(RootsModule))
513 SECMOD_DestroyModule(RootsModule);
517 SAL_INFO(
"xmlsecurity.xmlsec",
"Unloading module \"" ROOT_CERTS "\" failed because it was not found.");
520 (void)NSS_Shutdown();
522 (*getInitNSSPrivate())->reset();
532 static bool gbInitialized = [&rxContext]()
534 bool bNSSInit =
false;
535 bool bInitialized = nsscrypto_initialize( rxContext, bNSSInit );
540 return gbInitialized;
543css::uno::Reference< css::xml::crypto::XDigestContext > SAL_CALL
ONSSInitializer::getDigestContext( ::sal_Int32 nDigestID,
const css::uno::Sequence< css::beans::NamedValue >& aParams )
545 SECOidTag nNSSDigestID = SEC_OID_UNKNOWN;
546 sal_Int32 nDigestLength = 0;
547 bool b1KData =
false;
548 if ( nDigestID == css::xml::crypto::DigestID::SHA256
549 || nDigestID == css::xml::crypto::DigestID::SHA256_1K )
551 nNSSDigestID = SEC_OID_SHA256;
553 b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA256_1K );
555 else if ( nDigestID == css::xml::crypto::DigestID::SHA1
556 || nDigestID == css::xml::crypto::DigestID::SHA1_1K )
558 nNSSDigestID = SEC_OID_SHA1;
560 b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA1_1K );
562 else if ( nDigestID == css::xml::crypto::DigestID::SHA512
563 || nDigestID == css::xml::crypto::DigestID::SHA512_1K )
565 nNSSDigestID = SEC_OID_SHA512;
567 b1KData = ( nDigestID == css::xml::crypto::DigestID::SHA512_1K );
570 throw css::lang::IllegalArgumentException(
"Unexpected digest requested.", css::uno::Reference< css::uno::XInterface >(), 1 );
572 if ( aParams.hasElements() )
573 throw css::lang::IllegalArgumentException(
"Unexpected arguments provided for digest creation.", css::uno::Reference< css::uno::XInterface >(), 2 );
575 css::uno::Reference< css::xml::crypto::XDigestContext > xResult;
578 PK11Context* pContext = PK11_CreateDigestContext( nNSSDigestID );
579 if ( pContext && PK11_DigestBegin( pContext ) == SECSuccess )
586css::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 )
588 CK_MECHANISM_TYPE nNSSCipherID = 0;
589 bool bW3CPadding =
false;
590 if ( nCipherID != css::xml::crypto::CipherID::AES_CBC_W3C_PADDING )
591 throw css::lang::IllegalArgumentException(
"Unexpected cipher requested.", css::uno::Reference< css::uno::XInterface >(), 1 );
593 nNSSCipherID = CKM_AES_CBC;
596 if ( aKey.getLength() != 16 && aKey.getLength() != 24 && aKey.getLength() != 32 )
597 throw css::lang::IllegalArgumentException(
"Unexpected key length.", css::uno::Reference< css::uno::XInterface >(), 2 );
599 if ( aParams.hasElements() )
600 throw css::lang::IllegalArgumentException(
"Unexpected arguments provided for cipher creation.", css::uno::Reference< css::uno::XInterface >(), 5 );
602 css::uno::Reference< css::xml::crypto::XCipherContext > xResult;
605 if ( aInitializationVector.getLength() != PK11_GetIVLength( nNSSCipherID ) )
606 throw css::lang::IllegalArgumentException(
"Unexpected length of initialization vector.", css::uno::Reference< css::uno::XInterface >(), 3 );
617 return "com.sun.star.xml.crypto.NSSInitializer";
630#ifndef XMLSEC_CRYPTO_NSS
631extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
633 uno::XComponentContext* pCtx, uno::Sequence<uno::Any>
const& )
Reference< XComponentContext > m_xContext
static css::uno::Reference< css::xml::crypto::XCipherContext > Create(CK_MECHANISM_TYPE nNSSCipherID, const css::uno::Sequence< ::sal_Int8 > &aKey, const css::uno::Sequence< ::sal_Int8 > &aInitializationVector, bool bEncryption, bool bW3CPadding)
static bool initNSS(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
css::uno::Reference< css::uno::XComponentContext > m_xContext
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
virtual OUString SAL_CALL getImplementationName() override
virtual ~ONSSInitializer() override
static OUString m_sNSSPath
virtual css::uno::Reference< css::xml::crypto::XDigestContext > SAL_CALL getDigestContext(::sal_Int32 nDigestID, const css::uno::Sequence< css::beans::NamedValue > &aParams) override
static bool m_bIsNSSinitialized
virtual css::uno::Reference< css::xml::crypto::XCipherContext > SAL_CALL 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) override
virtual css::uno::Sequence< css::xml::crypto::NSSProfile > SAL_CALL getNSSProfiles() override
virtual sal_Bool SAL_CALL getIsNSSinitialized() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
static const OUString & getMozillaCurrentProfile(const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool bSetActive=false)
virtual OUString SAL_CALL getNSSPath() override
#define TOOLS_WARN_EXCEPTION(area, stream)
#define SAL_INFO_IF(condition, area, stream)
#define SAL_INFO(area, stream)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
std::shared_ptr< osl::Mutex > const & lock()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
SAL_DLLPUBLIC_EXPORT uno::XInterface * com_sun_star_xml_crypto_NSSInitializer_get_implementation(uno::XComponentContext *pCtx, uno::Sequence< uno::Any > const &)
static void nsscrypto_finalize()
constexpr OUStringLiteral NSS_SERVICE_NAME