diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2018-12-31 12:14:19 +0100 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2019-09-22 19:00:58 +0200 |
commit | 3787e1b78299ee88a17c242d0b30181286a753c4 (patch) | |
tree | 6cfd8218b7e038fcef00da8e37f803383a641b51 /xmlsecurity | |
parent | 6fca83fab5a14745c3dc41eb8179d7ee0efd4e71 (diff) |
NSS: create a temporary database instead of in-memory
When initializing for the in-memory database (NSS_NoDB_Init) the
internal slot is read-only so a lot of actions (PK11_ImportCert)
fails. Instead of that we create a new cert/key database inside
the tmp directory and delete it on exit. This way there are no
limitations and all the actions perform as expected.
Change-Id: Iadec5dd8f3459be56ba57d077057eacf3e0797fc
Reviewed-on: https://gerrit.libreoffice.org/65765
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
(cherry picked from commit 87eec1b90b6ecd83455f09168430c23f73c25c86)
Diffstat (limited to 'xmlsecurity')
5 files changed, 162 insertions, 51 deletions
diff --git a/xmlsecurity/Library_xsec_xmlsec.mk b/xmlsecurity/Library_xsec_xmlsec.mk index 8efb4911fbbb..1ddbb712b957 100644 --- a/xmlsecurity/Library_xsec_xmlsec.mk +++ b/xmlsecurity/Library_xsec_xmlsec.mk @@ -41,6 +41,7 @@ $(eval $(call gb_Library_use_libraries,xsec_xmlsec,\ svl \ tl \ xo \ + utl \ )) ifeq ($(SYSTEM_XMLSEC),) diff --git a/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx b/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx index 5d33268f741d..534c5bd7fc5c 100644 --- a/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx +++ b/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx @@ -32,6 +32,8 @@ #include <osl/file.hxx> #include <osl/thread.h> #include <sal/log.hxx> +#include <unotools/tempfile.hxx> +#include <salhelper/singletonref.hxx> #include "seinitializer_nssimpl.hxx" @@ -40,6 +42,7 @@ #include "ciphercontext.hxx" #include <memory> +#include <vector> #include <nspr.h> #include <cert.h> @@ -64,6 +67,97 @@ static void nsscrypto_finalize(); namespace { +class InitNSSPrivate +{ +private: + std::unique_ptr<utl::TempFile> m_pTempFileDatabaseDirectory; + + static void scanDirsAndFiles(OUString const & rDirURL, std::vector<OUString> & rDirs, std::vector<OUString> & rFiles) + { + if (rDirURL.isEmpty()) + return; + osl::Directory aDirectory(rDirURL); + + if (osl::FileBase::E_None != aDirectory.open()) + return; + + osl::DirectoryItem aDirectoryItem; + + while (osl::FileBase::E_None == aDirectory.getNextItem(aDirectoryItem)) + { + osl::FileStatus aFileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName); + + if (osl::FileBase::E_None == aDirectoryItem.getFileStatus(aFileStatus)) + { + if (aFileStatus.isDirectory()) + { + const OUString aFileName(aFileStatus.getFileName()); + if (!aFileName.isEmpty()) + rDirs.push_back(aFileName); + } + else if (aFileStatus.isRegular()) + { + const OUString aFileName(aFileStatus.getFileName()); + if (!aFileName.isEmpty()) + rFiles.push_back(aFileName); + + } + } + } + } + + static bool deleteDirRecursively(OUString const & rDirURL) + { + std::vector<OUString> aDirs; + std::vector<OUString> aFiles; + bool bError(false); + + scanDirsAndFiles(rDirURL, aDirs, aFiles); + + for (const auto& sDir : aDirs) + { + const OUString aNewDirURL(rDirURL + "/" + sDir); + bError |= deleteDirRecursively(aNewDirURL); + } + + for (const auto& sFile : aFiles) + { + OUString aNewFileURL(rDirURL + "/" + sFile); + bError |= (osl::FileBase::E_None != osl::File::remove(aNewFileURL)); + } + + bError |= (osl::FileBase::E_None != osl::Directory::remove(rDirURL)); + + return bError; + } + +public: + OUString getTempDatabasePath() + { + if (!m_pTempFileDatabaseDirectory) + { + m_pTempFileDatabaseDirectory.reset(new utl::TempFile(nullptr, true)); + m_pTempFileDatabaseDirectory->EnableKillingFile(); + } + return m_pTempFileDatabaseDirectory->GetFileName(); + } + + void reset() + { + if (m_pTempFileDatabaseDirectory) + { + deleteDirRecursively(m_pTempFileDatabaseDirectory->GetURL()); + m_pTempFileDatabaseDirectory.reset(); + } + } +}; + +salhelper::SingletonRef<InitNSSPrivate>* getInitNSSPrivate() +{ + static salhelper::SingletonRef<InitNSSPrivate> aInitNSSPrivate; + return &aInitNSSPrivate; +} + bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool & out_nss_init ); struct InitNSSInitialize @@ -230,7 +324,7 @@ OString getMozillaCurrentProfile( const css::uno::Reference< css::uno::XComponen //return true - whole initialization was successful //param out_nss_init = true: at least the NSS initialization (NSS_InitReadWrite //was successful and therefore NSS_Shutdown should be called when terminating. -bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool & out_nss_init ) +bool nsscrypto_initialize(css::uno::Reference<css::uno::XComponentContext> const & rxContext, bool & out_nss_init) { // this method must be called only once, no need for additional lock OString sCertDir; @@ -244,9 +338,9 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ; - bool bSuccess = true; + bool bSuccess = false; // there might be no profile - if ( !sCertDir.isEmpty() ) + if (!sCertDir.isEmpty()) { if (sCertDir.indexOf(':') == -1) //might be env var with explicit prefix { @@ -262,26 +356,31 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex sCertDir = "dbm:" + sCertDir; } } - if( NSS_InitReadWrite( sCertDir.getStr() ) != SECSuccess ) + if (NSS_InitReadWrite(sCertDir.getStr()) != SECSuccess) { SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with profile failed."); int errlen = PR_GetErrorTextLength(); - if(errlen > 0) + if (errlen > 0) { std::unique_ptr<char[]> const error(new char[errlen + 1]); PR_GetErrorText(error.get()); SAL_INFO("xmlsecurity.xmlsec", error.get()); } - bSuccess = false; + } + else + { + bSuccess = true; } } - if( sCertDir.isEmpty() || !bSuccess ) + if (!bSuccess) // Try to create a database in temp dir { - SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS without profile."); - if ( NSS_NoDB_Init(nullptr) != SECSuccess ) + SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with a temporary profile."); + OUString rString = (*getInitNSSPrivate())->getTempDatabasePath(); + + if (NSS_InitReadWrite(rString.toUtf8().getStr()) != SECSuccess) { - SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS without profile failed."); + SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with a temporary profile."); int errlen = PR_GetErrorTextLength(); if(errlen > 0) { @@ -289,7 +388,15 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex PR_GetErrorText(error.get()); SAL_INFO("xmlsecurity.xmlsec", error.get()); } - return false ; + return false; + } + // Initialize and set empty password if needed + PK11SlotInfo* pSlot = PK11_GetInternalKeySlot(); + if (pSlot) + { + if (PK11_NeedUserInit(pSlot)) + PK11_InitPin(pSlot, nullptr, nullptr); + PK11_FreeSlot(pSlot); } } out_nss_init = true; @@ -383,6 +490,8 @@ extern "C" void nsscrypto_finalize() } PK11_LogoutAll(); (void)NSS_Shutdown(); + + (*getInitNSSPrivate())->reset(); } ONSSInitializer::ONSSInitializer( diff --git a/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx index 0da6276551af..b19ec766b5db 100644 --- a/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx +++ b/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx @@ -42,6 +42,7 @@ #include <comphelper/sequence.hxx> #include "secerror.hxx" +#include <prerror.h> // added for password exception #include <com/sun/star/security/NoPasswordException.hpp> @@ -442,15 +443,34 @@ X509Certificate_NssImpl* SecurityEnvironment_NssImpl::createAndAddCertificateFro if (!pCERTCertificate) return nullptr; - OString aTrustString = OUStringToOString(raString, RTL_TEXTENCODING_ASCII_US); + SECStatus aStatus; + OString aTrustString = OUStringToOString(raString, RTL_TEXTENCODING_ASCII_US); CERTCertTrust aTrust; - if (CERT_DecodeTrustString(&aTrust, aTrustString.getStr()) != SECSuccess) + + aStatus = CERT_DecodeTrustString(&aTrust, aTrustString.getStr()); + + if (aStatus != SECSuccess) + return nullptr; + + PK11SlotInfo* pSlot = PK11_GetInternalKeySlot(); + + if (!pSlot) return nullptr; - if (CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), pCERTCertificate, &aTrust) != SECSuccess) + aStatus = PK11_ImportCert(pSlot, pCERTCertificate, CK_INVALID_HANDLE, nullptr, PR_FALSE); + + if (aStatus != SECSuccess) return nullptr; + aStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), pCERTCertificate, &aTrust); + + if (aStatus != SECSuccess) + return nullptr; + + + PK11_FreeSlot(pSlot); + X509Certificate_NssImpl* pX509Certificate = new X509Certificate_NssImpl(); pX509Certificate->setCert(pCERTCertificate); return pX509Certificate; @@ -840,12 +860,10 @@ xmlSecKeysMngrPtr SecurityEnvironment_NssImpl::createKeysManager() { // Adopt the private key of the signing certificate, if it has any. if (auto pCertificate = dynamic_cast<X509Certificate_NssImpl*>(m_xSigningCertificate.get())) { - SECKEYPrivateKey* pPrivateKey = pCertificate->getPrivateKey(); - SECKEYPrivateKey* copy - = pPrivateKey == nullptr ? nullptr : SECKEY_CopyPrivateKey(pPrivateKey); - if (copy) + SECKEYPrivateKey* pPrivateKey = SECKEY_CopyPrivateKey(pCertificate->getPrivateKey()); + if (pPrivateKey) { - xmlSecKeyDataPtr pKeyData = xmlSecNssPKIAdoptKey(copy, nullptr); + xmlSecKeyDataPtr pKeyData = xmlSecNssPKIAdoptKey(pPrivateKey, nullptr); xmlSecKeyPtr pKey = xmlSecKeyCreate(); xmlSecKeySetValue(pKey, pKeyData); xmlSecNssAppDefaultKeysMngrAdoptKey(pKeysMngr, pKey); @@ -872,42 +890,40 @@ SECKEYPrivateKey* SecurityEnvironment_NssImpl::insertPrivateKey(css::uno::Sequen if (!pSlot) return nullptr; - SECItem pDerPrivateKeyInfo; - pDerPrivateKeyInfo.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(raPrivateKey.getConstArray())); - pDerPrivateKeyInfo.len = raPrivateKey.getLength(); + SECItem aDerPrivateKeyInfo; + aDerPrivateKeyInfo.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(raPrivateKey.getConstArray())); + aDerPrivateKeyInfo.len = raPrivateKey.getLength(); - const unsigned int aKeyUsage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE; + const unsigned int aKeyUsage = KU_ALL; SECKEYPrivateKey* pPrivateKey = nullptr; - bool bPermanent = false; - bool bSensitive = false; + bool bPermanent = PR_FALSE; + bool bPrivate = PR_TRUE; SECStatus nStatus = PK11_ImportDERPrivateKeyInfoAndReturnKey( - pSlot, &pDerPrivateKeyInfo, nullptr, nullptr, bPermanent, bSensitive, + pSlot, &aDerPrivateKeyInfo, nullptr, nullptr, bPermanent, bPrivate, aKeyUsage, &pPrivateKey, nullptr); if (nStatus != SECSuccess) return nullptr; + PK11_FreeSlot(pSlot); + return pPrivateKey; } uno::Reference<security::XCertificate> SecurityEnvironment_NssImpl::createDERCertificateWithPrivateKey( Sequence<sal_Int8> const & raDERCertificate, Sequence<sal_Int8> const & raPrivateKey) { - SECKEYPrivateKey* pPrivateKey = insertPrivateKey(raPrivateKey); if (!pPrivateKey) return uno::Reference<security::XCertificate>(); - X509Certificate_NssImpl* pX509Certificate = createAndAddCertificateFromPackage(raDERCertificate, "TCu,Cu,Tu"); - + X509Certificate_NssImpl* pX509Certificate = createAndAddCertificateFromPackage(raDERCertificate, "TCu,TCu,TCu"); if (!pX509Certificate) return uno::Reference<security::XCertificate>(); - pX509Certificate->setCustomPrivateKey(pPrivateKey); - return pX509Certificate; } diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx index 35a3e841e6f4..180ef6558d38 100644 --- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx +++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx @@ -46,8 +46,7 @@ using ::com::sun::star::security::XCertificate ; using ::com::sun::star::util::DateTime ; X509Certificate_NssImpl::X509Certificate_NssImpl() : - m_pCert(nullptr), - m_pPrivateKey(nullptr) + m_pCert(nullptr) { } @@ -332,25 +331,13 @@ void X509Certificate_NssImpl::setRawCert( const Sequence< sal_Int8 >& rawCert ) m_pCert = cert ; } -void X509Certificate_NssImpl::setCustomPrivateKey(SECKEYPrivateKey* pPrivateKey) -{ - m_pPrivateKey = pPrivateKey; -} - SECKEYPrivateKey* X509Certificate_NssImpl::getPrivateKey() { - if (m_pPrivateKey) - { - return m_pPrivateKey; - } - else + if (m_pCert && m_pCert->slot) { - if (m_pCert && m_pCert->slot) - { - SECKEYPrivateKey* pPrivateKey = PK11_FindPrivateKeyFromCert(m_pCert->slot, m_pCert, nullptr); - if (pPrivateKey) - return pPrivateKey; - } + SECKEYPrivateKey* pPrivateKey = PK11_FindPrivateKeyFromCert(m_pCert->slot, m_pCert, nullptr); + if (pPrivateKey) + return pPrivateKey; } return nullptr; } diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx index 64c76972bf83..cae1f7238739 100644 --- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx +++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx @@ -41,7 +41,6 @@ class X509Certificate_NssImpl : public ::cppu::WeakImplHelper< { private: CERTCertificate* m_pCert; - SECKEYPrivateKey* m_pPrivateKey; public: X509Certificate_NssImpl() ; @@ -97,7 +96,6 @@ class X509Certificate_NssImpl : public ::cppu::WeakImplHelper< /// @throws css::uno::RuntimeException void setRawCert( const css::uno::Sequence< sal_Int8 >& rawCert ) ; - void setCustomPrivateKey(SECKEYPrivateKey* pPrivateKey); SECKEYPrivateKey* getPrivateKey(); // XServiceInfo |