diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2018-05-29 20:54:52 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2018-05-30 09:04:28 +0200 |
commit | 93e33ba279e837356e157745177d7f6061d442b7 (patch) | |
tree | 34dcb184e79213d3fdd17df971139fe3a0ef906c | |
parent | 5f4d499493c68e52977543c3abc6713518e5e000 (diff) |
xmlsecurity windows: let cert picker and PDF sign find ECDSA keys
Need to incrementally migrate the remaining places (ODF, OOXML signing)
to CNG, then flip the default. SVL_CRYPTO_CNG=1 is needed till then.
(The testcase passes with and without the fix when SVL_CRYPTO_CNG is not
specified; it fails without the fix when SVL_CRYPTO_CNG is specified.)
Change-Id: Ide9d3b109bbd955a9cb83b18bba6aa72269f4d34
Reviewed-on: https://gerrit.libreoffice.org/55030
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
-rw-r--r-- | include/svl/cryptosign.hxx | 3 | ||||
-rw-r--r-- | svl/source/crypto/cryptosign.cxx | 25 | ||||
-rw-r--r-- | xmlsecurity/Library_xsec_xmlsec.mk | 1 | ||||
-rw-r--r-- | xmlsecurity/qa/unit/signing/signing.cxx | 45 | ||||
-rw-r--r-- | xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx | 27 | ||||
-rw-r--r-- | xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx | 12 |
6 files changed, 103 insertions, 10 deletions
diff --git a/include/svl/cryptosign.hxx b/include/svl/cryptosign.hxx index eacb4d78af25..b70b995b23b9 100644 --- a/include/svl/cryptosign.hxx +++ b/include/svl/cryptosign.hxx @@ -86,6 +86,9 @@ private: OUString m_aSignPassword; }; +/// Decides if SVL_CRYPTO_MSCRYPTO uses the new CNG API or not. +SVL_DLLPUBLIC bool isMSCng(); + } } diff --git a/svl/source/crypto/cryptosign.cxx b/svl/source/crypto/cryptosign.cxx index 96c349d68861..c7e62d58f836 100644 --- a/svl/source/crypto/cryptosign.cxx +++ b/svl/source/crypto/cryptosign.cxx @@ -1401,14 +1401,22 @@ bool Signing::Sign(OStringBuffer& rCMSHexBuffer) aPara.cMsgCert = 1; aPara.rgpMsgCert = &pCertContext; - HCRYPTPROV hCryptProv; + HCRYPTPROV hCryptProv = 0; + NCRYPT_KEY_HANDLE hCryptKey = 0; + DWORD dwFlags = CRYPT_ACQUIRE_CACHE_FLAG; + HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hCryptProv; + if (svl::crypto::isMSCng()) + { + dwFlags |= CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG; + phCryptProvOrNCryptKey = &hCryptKey; + } DWORD nKeySpec; BOOL bFreeNeeded; if (!CryptAcquireCertificatePrivateKey(pCertContext, - CRYPT_ACQUIRE_CACHE_FLAG, + dwFlags, nullptr, - &hCryptProv, + phCryptProvOrNCryptKey, &nKeySpec, &bFreeNeeded)) { @@ -1423,7 +1431,10 @@ bool Signing::Sign(OStringBuffer& rCMSHexBuffer) memset(&aSignerInfo, 0, sizeof(aSignerInfo)); aSignerInfo.cbSize = sizeof(aSignerInfo); aSignerInfo.pCertInfo = pCertContext->pCertInfo; - aSignerInfo.hCryptProv = hCryptProv; + if (!svl::crypto::isMSCng()) + aSignerInfo.hCryptProv = hCryptProv; + else + aSignerInfo.hNCryptKey = hCryptKey; aSignerInfo.dwKeySpec = nKeySpec; aSignerInfo.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256); aSignerInfo.HashAlgorithm.Parameters.cbData = 0; @@ -2409,6 +2420,12 @@ bool Signing::Verify(SvStream& rStream, #endif } +bool isMSCng() +{ + static bool bMSCng = getenv("SVL_CRYPTO_CNG"); + return bMSCng; +} + } } diff --git a/xmlsecurity/Library_xsec_xmlsec.mk b/xmlsecurity/Library_xsec_xmlsec.mk index ced31bc9c668..445d48e72a32 100644 --- a/xmlsecurity/Library_xsec_xmlsec.mk +++ b/xmlsecurity/Library_xsec_xmlsec.mk @@ -98,6 +98,7 @@ $(eval $(call gb_Library_add_libs,xsec_xmlsec,\ $(eval $(call gb_Library_use_system_win32_libs,xsec_xmlsec,\ crypt32 \ advapi32 \ + ncrypt \ )) $(eval $(call gb_Library_add_exception_objects,xsec_xmlsec,\ diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx index 7e326f2467bf..ece73c8dcdb2 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -37,6 +37,7 @@ #include <osl/file.hxx> #include <osl/process.h> #include <comphelper/ofopxmlhelper.hxx> +#include <unotools/streamwrap.hxx> #include <documentsignaturehelper.hxx> #include <xmlsignaturehelper.hxx> @@ -67,6 +68,7 @@ public: void testDescription(); void testECDSA(); void testECDSAOOXML(); + void testECDSAPDF(); /// Test a typical ODF where all streams are signed. void testODFGood(); /// Test a typical broken ODF signature where one stream is corrupted. @@ -118,6 +120,7 @@ public: CPPUNIT_TEST(testDescription); CPPUNIT_TEST(testECDSA); CPPUNIT_TEST(testECDSAOOXML); + CPPUNIT_TEST(testECDSAPDF); CPPUNIT_TEST(testODFGood); CPPUNIT_TEST(testODFBroken); CPPUNIT_TEST(testODFNo); @@ -321,7 +324,7 @@ void SigningTest::testECDSAOOXML() CPPUNIT_ASSERT(aManager.init()); uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL( - ZIP_STORAGE_FORMAT_STRING, aTempFile.GetURL(), embed::ElementModes::READWRITE); + ZIP_STORAGE_FORMAT_STRING, aTempFile.GetURL(), embed::ElementModes::READWRITE); CPPUNIT_ASSERT(xStorage.is()); aManager.mxStore = xStorage; aManager.maSignatureHelper.SetStorage(xStorage, "1.2"); @@ -346,6 +349,46 @@ void SigningTest::testECDSAOOXML() rInformations[0].nStatus); } +void SigningTest::testECDSAPDF() +{ + // Create an empty document and store it to a tempfile, finally load it as + // a stream. + createDoc(""); + + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content); + CPPUNIT_ASSERT(aManager.init()); + std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aTempFile.GetURL(), StreamMode::READ | StreamMode::WRITE)); + uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(*pStream)); + CPPUNIT_ASSERT(xStream.is()); + aManager.mxSignatureStream = xStream; + + // Then add a document signature. + uno::Reference<security::XCertificate> xCertificate + = getCertificate(aManager, svl::crypto::SignatureMethodAlgorithm::ECDSA); + if (!xCertificate.is()) + return; + OUString aDescription; + sal_Int32 nSecurityId; + aManager.add(xCertificate, mxSecurityContext, aDescription, nSecurityId, + /*bAdESCompliant=*/true); + + // Read back the signature and make sure that it's valid. + aManager.read(/*bUseTempStream=*/false); + std::vector<SignatureInformation>& rInformations = aManager.maCurrentSignatureInformations; + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations.size()); + // This was SecurityOperationStatus_UNKNOWN, signing with an ECDSA key was + // broken. + CPPUNIT_ASSERT_EQUAL(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED, + rInformations[0].nStatus); +} + void SigningTest::testOOXMLDescription() { // Create an empty document and store it to a tempfile, finally load it as a storage. diff --git a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx index ecfdd15d1895..4f1b7e81221f 100644 --- a/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx +++ b/xmlsecurity/source/xmlsec/mscrypt/securityenvironment_mscryptimpl.cxx @@ -45,6 +45,7 @@ #include <osl/nlsupport.h> #include <osl/process.h> #include <o3tl/char16_t2wchar_t.hxx> +#include <svl/cryptosign.hxx> using namespace ::com::sun::star; using namespace ::com::sun::star::lang ; @@ -344,6 +345,7 @@ uno::Sequence< uno::Reference < XCertificate > > SecurityEnvironment_MSCryptImpl HCERTSTORE hSystemKeyStore ; DWORD dwKeySpec; HCRYPTPROV hCryptProv; + NCRYPT_KEY_HANDLE hCryptKey; #ifdef SAL_LOG_INFO CertEnumSystemStore(CERT_SYSTEM_STORE_CURRENT_USER, nullptr, nullptr, cert_enum_system_store_callback); @@ -355,10 +357,17 @@ uno::Sequence< uno::Reference < XCertificate > > SecurityEnvironment_MSCryptImpl while (pCertContext) { // for checking whether the certificate is a personal certificate or not. + DWORD dwFlags = CRYPT_ACQUIRE_COMPARE_KEY_FLAG; + HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hCryptProv; + if (svl::crypto::isMSCng()) + { + dwFlags |= CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG; + phCryptProvOrNCryptKey = &hCryptKey; + } if(!(CryptAcquireCertificatePrivateKey(pCertContext, - CRYPT_ACQUIRE_COMPARE_KEY_FLAG, + dwFlags, nullptr, - &hCryptProv, + phCryptProvOrNCryptKey, &dwKeySpec, nullptr))) { @@ -969,10 +978,18 @@ sal_Int32 SecurityEnvironment_MSCryptImpl::getCertificateCharacters( const css:: BOOL fCallerFreeProv ; DWORD dwKeySpec ; HCRYPTPROV hProv ; + NCRYPT_KEY_HANDLE hKey = 0; + DWORD dwFlags = 0; + HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hProv; + if (svl::crypto::isMSCng()) + { + dwFlags |= CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG; + phCryptProvOrNCryptKey = &hKey; + } if( CryptAcquireCertificatePrivateKey( pCertContext , - 0 , + dwFlags, nullptr , - &hProv, + phCryptProvOrNCryptKey, &dwKeySpec, &fCallerFreeProv ) ) { @@ -980,6 +997,8 @@ sal_Int32 SecurityEnvironment_MSCryptImpl::getCertificateCharacters( const css:: if( hProv != NULL && fCallerFreeProv ) CryptReleaseContext( hProv, 0 ) ; + else if (hKey && fCallerFreeProv) + NCryptFreeObject(hKey); } else { characters &= ~ css::security::CertificateCharacters::HAS_PRIVATE_KEY ; } diff --git a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx index d213f21631f5..1e3bd93880f9 100644 --- a/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx +++ b/xmlsecurity/source/xmlsec/mscrypt/x509certificate_mscryptimpl.cxx @@ -573,7 +573,17 @@ uno::Sequence<sal_Int8> X509Certificate_MSCryptImpl::getSHA256Thumbprint() svl::crypto::SignatureMethodAlgorithm X509Certificate_MSCryptImpl::getSignatureMethodAlgorithm() { - return svl::crypto::SignatureMethodAlgorithm::RSA; + svl::crypto::SignatureMethodAlgorithm nRet = svl::crypto::SignatureMethodAlgorithm::RSA; + + if (!m_pCertContext || !m_pCertContext->pCertInfo) + return nRet; + + CRYPT_ALGORITHM_IDENTIFIER algorithm = m_pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm; + OString aObjId(algorithm.pszObjId); + if (aObjId == szOID_ECC_PUBLIC_KEY) + nRet = svl::crypto::SignatureMethodAlgorithm::ECDSA; + + return nRet; } css::uno::Sequence< sal_Int8 > SAL_CALL X509Certificate_MSCryptImpl::getSHA1Thumbprint() |