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>
This commit is contained in:
committed by
Tomaž Vajngerl
parent
079977df3f
commit
87eec1b90b
@@ -40,6 +40,7 @@ $(eval $(call gb_Library_use_libraries,xsec_xmlsec,\
|
||||
svl \
|
||||
tl \
|
||||
xo \
|
||||
utl \
|
||||
))
|
||||
|
||||
ifeq ($(SYSTEM_XMLSEC),)
|
||||
|
@@ -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(
|
||||
|
@@ -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>
|
||||
@@ -440,15 +441,34 @@ X509Certificate_NssImpl* SecurityEnvironment_NssImpl::createAndAddCertificateFro
|
||||
if (!pCERTCertificate)
|
||||
return nullptr;
|
||||
|
||||
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;
|
||||
|
||||
if (CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), pCERTCertificate, &aTrust) != SECSuccess)
|
||||
PK11SlotInfo* pSlot = PK11_GetInternalKeySlot();
|
||||
|
||||
if (!pSlot)
|
||||
return nullptr;
|
||||
|
||||
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;
|
||||
@@ -838,12 +858,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);
|
||||
@@ -870,42 +888,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;
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
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)
|
||||
return pPrivateKey;
|
||||
}
|
||||
SECKEYPrivateKey* pPrivateKey = PK11_FindPrivateKeyFromCert(m_pCert->slot, m_pCert, nullptr);
|
||||
if (pPrivateKey)
|
||||
return pPrivateKey;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user