Kaydet (Commit) 87eec1b9 authored tarafından Tomaž Vajngerl's avatar Tomaž Vajngerl Kaydeden (comit) Tomaž Vajngerl

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: 's avatarTomaž Vajngerl <quikee@gmail.com>
üst 079977df
...@@ -40,6 +40,7 @@ $(eval $(call gb_Library_use_libraries,xsec_xmlsec,\ ...@@ -40,6 +40,7 @@ $(eval $(call gb_Library_use_libraries,xsec_xmlsec,\
svl \ svl \
tl \ tl \
xo \ xo \
utl \
)) ))
ifeq ($(SYSTEM_XMLSEC),) ifeq ($(SYSTEM_XMLSEC),)
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <osl/file.hxx> #include <osl/file.hxx>
#include <osl/thread.h> #include <osl/thread.h>
#include <sal/log.hxx> #include <sal/log.hxx>
#include <unotools/tempfile.hxx>
#include <salhelper/singletonref.hxx>
#include "seinitializer_nssimpl.hxx" #include "seinitializer_nssimpl.hxx"
...@@ -40,6 +42,7 @@ ...@@ -40,6 +42,7 @@
#include "ciphercontext.hxx" #include "ciphercontext.hxx"
#include <memory> #include <memory>
#include <vector>
#include <nspr.h> #include <nspr.h>
#include <cert.h> #include <cert.h>
...@@ -64,6 +67,97 @@ static void nsscrypto_finalize(); ...@@ -64,6 +67,97 @@ static void nsscrypto_finalize();
namespace 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 ); bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool & out_nss_init );
struct InitNSSInitialize struct InitNSSInitialize
...@@ -230,7 +324,7 @@ OString getMozillaCurrentProfile( const css::uno::Reference< css::uno::XComponen ...@@ -230,7 +324,7 @@ OString getMozillaCurrentProfile( const css::uno::Reference< css::uno::XComponen
//return true - whole initialization was successful //return true - whole initialization was successful
//param out_nss_init = true: at least the NSS initialization (NSS_InitReadWrite //param out_nss_init = true: at least the NSS initialization (NSS_InitReadWrite
//was successful and therefore NSS_Shutdown should be called when terminating. //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 // this method must be called only once, no need for additional lock
OString sCertDir; OString sCertDir;
...@@ -244,9 +338,9 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex ...@@ -244,9 +338,9 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex
PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ; PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ;
bool bSuccess = true; bool bSuccess = false;
// there might be no profile // there might be no profile
if ( !sCertDir.isEmpty() ) if (!sCertDir.isEmpty())
{ {
if (sCertDir.indexOf(':') == -1) //might be env var with explicit prefix 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 ...@@ -262,26 +356,31 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex
sCertDir = "dbm:" + sCertDir; sCertDir = "dbm:" + sCertDir;
} }
} }
if( NSS_InitReadWrite( sCertDir.getStr() ) != SECSuccess ) if (NSS_InitReadWrite(sCertDir.getStr()) != SECSuccess)
{ {
SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with profile failed."); SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with profile failed.");
int errlen = PR_GetErrorTextLength(); int errlen = PR_GetErrorTextLength();
if(errlen > 0) if (errlen > 0)
{ {
std::unique_ptr<char[]> const error(new char[errlen + 1]); std::unique_ptr<char[]> const error(new char[errlen + 1]);
PR_GetErrorText(error.get()); PR_GetErrorText(error.get());
SAL_INFO("xmlsecurity.xmlsec", 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."); SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with a temporary profile.");
if ( NSS_NoDB_Init(nullptr) != SECSuccess ) 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(); int errlen = PR_GetErrorTextLength();
if(errlen > 0) if(errlen > 0)
{ {
...@@ -289,7 +388,15 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex ...@@ -289,7 +388,15 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex
PR_GetErrorText(error.get()); PR_GetErrorText(error.get());
SAL_INFO("xmlsecurity.xmlsec", 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; out_nss_init = true;
...@@ -383,6 +490,8 @@ extern "C" void nsscrypto_finalize() ...@@ -383,6 +490,8 @@ extern "C" void nsscrypto_finalize()
} }
PK11_LogoutAll(); PK11_LogoutAll();
(void)NSS_Shutdown(); (void)NSS_Shutdown();
(*getInitNSSPrivate())->reset();
} }
ONSSInitializer::ONSSInitializer( ONSSInitializer::ONSSInitializer(
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <comphelper/sequence.hxx> #include <comphelper/sequence.hxx>
#include "secerror.hxx" #include "secerror.hxx"
#include <prerror.h>
// added for password exception // added for password exception
#include <com/sun/star/security/NoPasswordException.hpp> #include <com/sun/star/security/NoPasswordException.hpp>
...@@ -440,15 +441,34 @@ X509Certificate_NssImpl* SecurityEnvironment_NssImpl::createAndAddCertificateFro ...@@ -440,15 +441,34 @@ X509Certificate_NssImpl* SecurityEnvironment_NssImpl::createAndAddCertificateFro
if (!pCERTCertificate) if (!pCERTCertificate)
return nullptr; return nullptr;
OString aTrustString = OUStringToOString(raString, RTL_TEXTENCODING_ASCII_US); SECStatus aStatus;
OString aTrustString = OUStringToOString(raString, RTL_TEXTENCODING_ASCII_US);
CERTCertTrust aTrust; 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; 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; return nullptr;
aStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), pCERTCertificate, &aTrust);
if (aStatus != SECSuccess)
return nullptr;
PK11_FreeSlot(pSlot);
X509Certificate_NssImpl* pX509Certificate = new X509Certificate_NssImpl(); X509Certificate_NssImpl* pX509Certificate = new X509Certificate_NssImpl();
pX509Certificate->setCert(pCERTCertificate); pX509Certificate->setCert(pCERTCertificate);
return pX509Certificate; return pX509Certificate;
...@@ -838,12 +858,10 @@ xmlSecKeysMngrPtr SecurityEnvironment_NssImpl::createKeysManager() { ...@@ -838,12 +858,10 @@ xmlSecKeysMngrPtr SecurityEnvironment_NssImpl::createKeysManager() {
// Adopt the private key of the signing certificate, if it has any. // Adopt the private key of the signing certificate, if it has any.
if (auto pCertificate = dynamic_cast<X509Certificate_NssImpl*>(m_xSigningCertificate.get())) if (auto pCertificate = dynamic_cast<X509Certificate_NssImpl*>(m_xSigningCertificate.get()))
{ {
SECKEYPrivateKey* pPrivateKey = pCertificate->getPrivateKey(); SECKEYPrivateKey* pPrivateKey = SECKEY_CopyPrivateKey(pCertificate->getPrivateKey());
SECKEYPrivateKey* copy if (pPrivateKey)
= pPrivateKey == nullptr ? nullptr : SECKEY_CopyPrivateKey(pPrivateKey);
if (copy)
{ {
xmlSecKeyDataPtr pKeyData = xmlSecNssPKIAdoptKey(copy, nullptr); xmlSecKeyDataPtr pKeyData = xmlSecNssPKIAdoptKey(pPrivateKey, nullptr);
xmlSecKeyPtr pKey = xmlSecKeyCreate(); xmlSecKeyPtr pKey = xmlSecKeyCreate();
xmlSecKeySetValue(pKey, pKeyData); xmlSecKeySetValue(pKey, pKeyData);
xmlSecNssAppDefaultKeysMngrAdoptKey(pKeysMngr, pKey); xmlSecNssAppDefaultKeysMngrAdoptKey(pKeysMngr, pKey);
...@@ -870,42 +888,40 @@ SECKEYPrivateKey* SecurityEnvironment_NssImpl::insertPrivateKey(css::uno::Sequen ...@@ -870,42 +888,40 @@ SECKEYPrivateKey* SecurityEnvironment_NssImpl::insertPrivateKey(css::uno::Sequen
if (!pSlot) if (!pSlot)
return nullptr; return nullptr;
SECItem pDerPrivateKeyInfo; SECItem aDerPrivateKeyInfo;
pDerPrivateKeyInfo.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(raPrivateKey.getConstArray())); aDerPrivateKeyInfo.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(raPrivateKey.getConstArray()));
pDerPrivateKeyInfo.len = raPrivateKey.getLength(); 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; SECKEYPrivateKey* pPrivateKey = nullptr;
bool bPermanent = false; bool bPermanent = PR_FALSE;
bool bSensitive = false; bool bPrivate = PR_TRUE;
SECStatus nStatus = PK11_ImportDERPrivateKeyInfoAndReturnKey( SECStatus nStatus = PK11_ImportDERPrivateKeyInfoAndReturnKey(
pSlot, &pDerPrivateKeyInfo, nullptr, nullptr, bPermanent, bSensitive, pSlot, &aDerPrivateKeyInfo, nullptr, nullptr, bPermanent, bPrivate,
aKeyUsage, &pPrivateKey, nullptr); aKeyUsage, &pPrivateKey, nullptr);
if (nStatus != SECSuccess) if (nStatus != SECSuccess)
return nullptr; return nullptr;
PK11_FreeSlot(pSlot);
return pPrivateKey; return pPrivateKey;
} }
uno::Reference<security::XCertificate> SecurityEnvironment_NssImpl::createDERCertificateWithPrivateKey( uno::Reference<security::XCertificate> SecurityEnvironment_NssImpl::createDERCertificateWithPrivateKey(
Sequence<sal_Int8> const & raDERCertificate, Sequence<sal_Int8> const & raPrivateKey) Sequence<sal_Int8> const & raDERCertificate, Sequence<sal_Int8> const & raPrivateKey)
{ {
SECKEYPrivateKey* pPrivateKey = insertPrivateKey(raPrivateKey); SECKEYPrivateKey* pPrivateKey = insertPrivateKey(raPrivateKey);
if (!pPrivateKey) if (!pPrivateKey)
return uno::Reference<security::XCertificate>(); return uno::Reference<security::XCertificate>();
X509Certificate_NssImpl* pX509Certificate = createAndAddCertificateFromPackage(raDERCertificate, "TCu,Cu,Tu"); X509Certificate_NssImpl* pX509Certificate = createAndAddCertificateFromPackage(raDERCertificate, "TCu,TCu,TCu");
if (!pX509Certificate) if (!pX509Certificate)
return uno::Reference<security::XCertificate>(); return uno::Reference<security::XCertificate>();
pX509Certificate->setCustomPrivateKey(pPrivateKey);
return pX509Certificate; return pX509Certificate;
} }
......
...@@ -46,8 +46,7 @@ using ::com::sun::star::security::XCertificate ; ...@@ -46,8 +46,7 @@ using ::com::sun::star::security::XCertificate ;
using ::com::sun::star::util::DateTime ; using ::com::sun::star::util::DateTime ;
X509Certificate_NssImpl::X509Certificate_NssImpl() : X509Certificate_NssImpl::X509Certificate_NssImpl() :
m_pCert(nullptr), m_pCert(nullptr)
m_pPrivateKey(nullptr)
{ {
} }
...@@ -332,25 +331,13 @@ void X509Certificate_NssImpl::setRawCert( const Sequence< sal_Int8 >& rawCert ) ...@@ -332,25 +331,13 @@ void X509Certificate_NssImpl::setRawCert( const Sequence< sal_Int8 >& rawCert )
m_pCert = cert ; m_pCert = cert ;
} }
void X509Certificate_NssImpl::setCustomPrivateKey(SECKEYPrivateKey* pPrivateKey)
{
m_pPrivateKey = pPrivateKey;
}
SECKEYPrivateKey* X509Certificate_NssImpl::getPrivateKey() SECKEYPrivateKey* X509Certificate_NssImpl::getPrivateKey()
{ {
if (m_pPrivateKey) if (m_pCert && m_pCert->slot)
{
return m_pPrivateKey;
}
else
{ {
if (m_pCert && m_pCert->slot) SECKEYPrivateKey* pPrivateKey = PK11_FindPrivateKeyFromCert(m_pCert->slot, m_pCert, nullptr);
{ if (pPrivateKey)
SECKEYPrivateKey* pPrivateKey = PK11_FindPrivateKeyFromCert(m_pCert->slot, m_pCert, nullptr); return pPrivateKey;
if (pPrivateKey)
return pPrivateKey;
}
} }
return nullptr; return nullptr;
} }
......
...@@ -41,7 +41,6 @@ class X509Certificate_NssImpl : public ::cppu::WeakImplHelper< ...@@ -41,7 +41,6 @@ class X509Certificate_NssImpl : public ::cppu::WeakImplHelper<
{ {
private: private:
CERTCertificate* m_pCert; CERTCertificate* m_pCert;
SECKEYPrivateKey* m_pPrivateKey;
public: public:
X509Certificate_NssImpl() ; X509Certificate_NssImpl() ;
...@@ -97,7 +96,6 @@ class X509Certificate_NssImpl : public ::cppu::WeakImplHelper< ...@@ -97,7 +96,6 @@ class X509Certificate_NssImpl : public ::cppu::WeakImplHelper<
/// @throws css::uno::RuntimeException /// @throws css::uno::RuntimeException
void setRawCert( const css::uno::Sequence< sal_Int8 >& rawCert ) ; void setRawCert( const css::uno::Sequence< sal_Int8 >& rawCert ) ;
void setCustomPrivateKey(SECKEYPrivateKey* pPrivateKey);
SECKEYPrivateKey* getPrivateKey(); SECKEYPrivateKey* getPrivateKey();
// XServiceInfo // XServiceInfo
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment