[Libreoffice-commits] core.git: include/svl svl/Library_svl.mk svl/source xmlsecurity/inc xmlsecurity/source xmlsecurity/workben

Ashod Nakashian ashod.nakashian at collabora.co.uk
Sun Jul 16 22:12:44 UTC 2017


 include/svl/cryptosign.hxx                      |   15 
 svl/Library_svl.mk                              |   19 
 svl/source/crypto/cryptosign.cxx                |  637 +++++++++++++++++++++++
 xmlsecurity/inc/certificatechooser.hxx          |    2 
 xmlsecurity/inc/documentsignaturehelper.hxx     |    2 
 xmlsecurity/inc/documentsignaturemanager.hxx    |    2 
 xmlsecurity/inc/pch/precompiled_xmlsecurity.hxx |    1 
 xmlsecurity/inc/pdfsignaturehelper.hxx          |    2 
 xmlsecurity/inc/xmlsignaturehelper.hxx          |    2 
 xmlsecurity/inc/xsecctl.hxx                     |    2 
 xmlsecurity/source/helper/ooxmlsecexporter.hxx  |    2 
 xmlsecurity/source/pdfio/pdfdocument.cxx        |  641 ------------------------
 xmlsecurity/workben/pdfverify.cxx               |    2 
 13 files changed, 680 insertions(+), 649 deletions(-)

New commits:
commit 4f17445c12dc26c4881c4e486215b58d26515f8d
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Sun Jul 9 09:42:01 2017 -0400

    svl: move byte-array verification from vcl
    
    Also use comphelper::Base64 and
    DateTime::CreateFromUnixTime to avoid depending on sax.
    
    Change-Id: If1853f8d9481c9caa0625a111707531bbc495f75
    Reviewed-on: https://gerrit.libreoffice.org/39993
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/include/svl/cryptosign.hxx b/include/svl/cryptosign.hxx
index db0abc9f1480..ae82a59b33a4 100644
--- a/include/svl/cryptosign.hxx
+++ b/include/svl/cryptosign.hxx
@@ -14,8 +14,12 @@
 #include <vector>
 
 #include <rtl/strbuf.hxx>
+#include <rtl/ustring.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+
 #include <svl/svldllapi.h>
-#include "com/sun/star/uno/Reference.hxx"
+#include <svl/sigstruct.hxx>
 
 namespace com {
 namespace sun {
@@ -24,6 +28,8 @@ namespace security {
     class XCertificate; }
 }}}
 
+class SvStream;
+
 namespace svl {
 
 namespace crypto {
@@ -54,6 +60,13 @@ public:
     /// Returns the signature (in PKCS#7 format) as string (hex).
     bool Sign(OStringBuffer& rCMSHexBuffer);
 
+    /// Verify and get Signature Information given a signature and stream.
+    static bool Verify(SvStream& rStream,
+                       const std::vector<std::pair<size_t, size_t>>& aByteRanges,
+                       const bool bNonDetached,
+                       const std::vector<unsigned char>& aSignature,
+                       SignatureInformation& rInformation);
+
 private:
     /// The certificate to use for signing.
     const css::uno::Reference<css::security::XCertificate> m_xCertificate;
diff --git a/xmlsecurity/inc/sigstruct.hxx b/include/svl/sigstruct.hxx
similarity index 100%
rename from xmlsecurity/inc/sigstruct.hxx
rename to include/svl/sigstruct.hxx
diff --git a/svl/Library_svl.mk b/svl/Library_svl.mk
index e3969b1d90a3..97fa4df3add9 100644
--- a/svl/Library_svl.mk
+++ b/svl/Library_svl.mk
@@ -95,6 +95,25 @@ $(eval $(call gb_Library_use_system_win32_libs,svl,\
     shlwapi \
 ))
 
+ifeq ($(OS),WNT)
+$(eval $(call gb_Library_add_defs,svl,\
+    -DSVL_CRYPTO_MSCRYPTO \
+))
+$(eval $(call gb_Library_use_system_win32_libs,svl,\
+    crypt32 \
+))
+else
+ifneq (,$(filter DESKTOP,$(BUILD_TYPE)))
+$(eval $(call gb_Library_add_defs,svl,\
+    -DSVL_CRYPTO_NSS \
+))
+$(eval $(call gb_Library_use_externals,svl,\
+    nss3 \
+    plc4 \
+))
+endif # BUILD_TYPE=DESKTOP
+endif
+
 $(eval $(call gb_Library_add_exception_objects,svl,\
     svl/source/config/asiancfg \
     svl/source/config/cjkoptions \
diff --git a/svl/source/crypto/cryptosign.cxx b/svl/source/crypto/cryptosign.cxx
index 0c16ba6fbd94..d5304e5e2d2a 100644
--- a/svl/source/crypto/cryptosign.cxx
+++ b/svl/source/crypto/cryptosign.cxx
@@ -12,12 +12,12 @@
 #include <rtl/character.hxx>
 #include <rtl/strbuf.hxx>
 #include <rtl/string.hxx>
+#include <tools/datetime.hxx>
 #include <tools/stream.hxx>
+#include <comphelper/base64.hxx>
 #include <comphelper/random.hxx>
 #include <comphelper/hash.hxx>
 #include <comphelper/processfactory.hxx>
-// #include <comphelper/scopeguard.hxx>
-// #include <comphelper/string.hxx>
 #include <com/sun/star/security/XCertificate.hpp>
 #include <com/sun/star/uno/Sequence.hxx>
 #include <filter/msfilter/mscodec.hxx>
@@ -1646,6 +1646,639 @@ bool Signing::Sign(OStringBuffer& rCMSHexBuffer)
 #endif
 }
 
+namespace
+{
+#ifdef SVL_CRYPTO_NSS
+/// Similar to NSS_CMSAttributeArray_FindAttrByOidTag(), but works directly with a SECOidData.
+NSSCMSAttribute* CMSAttributeArray_FindAttrByOidData(NSSCMSAttribute** attrs, SECOidData* oid, PRBool only)
+{
+    NSSCMSAttribute* attr1, *attr2;
+
+    if (attrs == nullptr)
+        return nullptr;
+
+    if (oid == nullptr)
+        return nullptr;
+
+    while ((attr1 = *attrs++) != nullptr)
+    {
+        if (attr1->type.len == oid->oid.len && PORT_Memcmp(attr1->type.data,
+                oid->oid.data,
+                oid->oid.len) == 0)
+            break;
+    }
+
+    if (attr1 == nullptr)
+        return nullptr;
+
+    if (!only)
+        return attr1;
+
+    while ((attr2 = *attrs++) != nullptr)
+    {
+        if (attr2->type.len == oid->oid.len && PORT_Memcmp(attr2->type.data,
+                oid->oid.data,
+                oid->oid.len) == 0)
+            break;
+    }
+
+    if (attr2 != nullptr)
+        return nullptr;
+
+    return attr1;
+}
+
+/// Same as SEC_StringToOID(), which is private to us.
+SECStatus StringToOID(SECItem* to, const char* from, PRUint32 len)
+{
+    PRUint32 decimal_numbers = 0;
+    PRUint32 result_bytes = 0;
+    SECStatus rv;
+    PRUint8 result[1024];
+
+    static const PRUint32 max_decimal = (0xffffffff / 10);
+    static const char OIDstring[] = {"OID."};
+
+    if (!from || !to)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    if (!len)
+    {
+        len = PL_strlen(from);
+    }
+    if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4))
+    {
+        from += 4; /* skip leading "OID." if present */
+        len  -= 4;
+    }
+    if (!len)
+    {
+bad_data:
+        PORT_SetError(SEC_ERROR_BAD_DATA);
+        return SECFailure;
+    }
+    do
+    {
+        PRUint32 decimal = 0;
+        while (len > 0 && rtl::isAsciiDigit(static_cast<unsigned char>(*from)))
+        {
+            PRUint32 addend = (*from++ - '0');
+            --len;
+            if (decimal > max_decimal)  /* overflow */
+                goto bad_data;
+            decimal = (decimal * 10) + addend;
+            if (decimal < addend)   /* overflow */
+                goto bad_data;
+        }
+        if (len != 0 && *from != '.')
+        {
+            goto bad_data;
+        }
+        if (decimal_numbers == 0)
+        {
+            if (decimal > 2)
+                goto bad_data;
+            result[0] = decimal * 40;
+            result_bytes = 1;
+        }
+        else if (decimal_numbers == 1)
+        {
+            if (decimal > 40)
+                goto bad_data;
+            result[0] += decimal;
+        }
+        else
+        {
+            /* encode the decimal number,  */
+            PRUint8* rp;
+            PRUint32 num_bytes = 0;
+            PRUint32 tmp = decimal;
+            while (tmp)
+            {
+                num_bytes++;
+                tmp >>= 7;
+            }
+            if (!num_bytes)
+                ++num_bytes;  /* use one byte for a zero value */
+            if (static_cast<size_t>(num_bytes) + result_bytes > sizeof result)
+                goto bad_data;
+            tmp = num_bytes;
+            rp = result + result_bytes - 1;
+            rp[tmp] = (PRUint8)(decimal & 0x7f);
+            decimal >>= 7;
+            while (--tmp > 0)
+            {
+                rp[tmp] = (PRUint8)(decimal | 0x80);
+                decimal >>= 7;
+            }
+            result_bytes += num_bytes;
+        }
+        ++decimal_numbers;
+        if (len > 0)   /* skip trailing '.' */
+        {
+            ++from;
+            --len;
+        }
+    }
+    while (len > 0);
+    /* now result contains result_bytes of data */
+    if (to->data && to->len >= result_bytes)
+    {
+        PORT_Memcpy(to->data, result, to->len = result_bytes);
+        rv = SECSuccess;
+    }
+    else
+    {
+        SECItem result_item = {siBuffer, nullptr, 0 };
+        result_item.data = result;
+        result_item.len  = result_bytes;
+        rv = SECITEM_CopyItem(nullptr, to, &result_item);
+    }
+    return rv;
+}
+#elif defined SVL_CRYPTO_MSCRYPTO
+/// Verifies a non-detached signature using CryptoAPI.
+bool VerifyNonDetachedSignature(SvStream& rStream, const std::vector<std::pair<size_t, size_t>>& rByteRanges, std::vector<BYTE>& rExpectedHash)
+{
+    HCRYPTPROV hProv = 0;
+    if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "CryptAcquireContext() failed");
+        return false;
+    }
+
+    HCRYPTHASH hHash = 0;
+    if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "CryptCreateHash() failed");
+        return false;
+    }
+
+    for (const auto& rByteRange : rByteRanges)
+    {
+        rStream.Seek(rByteRange.first);
+        const int nChunkLen = 4096;
+        std::vector<unsigned char> aBuffer(nChunkLen);
+        for (size_t nByte = 0; nByte < rByteRange.second;)
+        {
+            size_t nRemainingSize = rByteRange.second - nByte;
+            if (nRemainingSize < nChunkLen)
+            {
+                rStream.ReadBytes(aBuffer.data(), nRemainingSize);
+                if (!CryptHashData(hHash, aBuffer.data(), nRemainingSize, 0))
+                {
+                    SAL_WARN("xmlsecurity.pdfio", "CryptHashData() failed");
+                    return false;
+                }
+                nByte = rByteRange.second;
+            }
+            else
+            {
+                rStream.ReadBytes(aBuffer.data(), nChunkLen);
+                if (!CryptHashData(hHash, aBuffer.data(), nChunkLen, 0))
+                {
+                    SAL_WARN("xmlsecurity.pdfio", "CryptHashData() failed");
+                    return false;
+                }
+                nByte += nChunkLen;
+            }
+        }
+    }
+
+    DWORD nActualHash = 0;
+    if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nActualHash, 0))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "CryptGetHashParam() failed to provide the hash length");
+        return false;
+    }
+
+    std::vector<unsigned char> aActualHash(nActualHash);
+    if (!CryptGetHashParam(hHash, HP_HASHVAL, aActualHash.data(), &nActualHash, 0))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "CryptGetHashParam() failed to provide the hash");
+        return false;
+    }
+
+    CryptDestroyHash(hHash);
+    CryptReleaseContext(hProv, 0);
+
+    if (!std::memcmp(aActualHash.data(), rExpectedHash.data(), aActualHash.size()) && aActualHash.size() == rExpectedHash.size())
+        return true;
+
+    return false;
+}
+#endif
+}
+
+bool Signing::Verify(SvStream& rStream,
+                     const std::vector<std::pair<size_t, size_t>>& aByteRanges,
+                     const bool bNonDetached,
+                     const std::vector<unsigned char>& aSignature,
+                     SignatureInformation& rInformation)
+{
+
+#ifdef SVL_CRYPTO_NSS
+    // Validate the signature. No need to call NSS_Init() here, assume that the
+    // caller did that already.
+
+    SECItem aSignatureItem;
+    aSignatureItem.data = const_cast<unsigned char*>(aSignature.data());
+    aSignatureItem.len = aSignature.size();
+    NSSCMSMessage* pCMSMessage = NSS_CMSMessage_CreateFromDER(&aSignatureItem,
+                                 /*cb=*/nullptr,
+                                 /*cb_arg=*/nullptr,
+                                 /*pwfn=*/nullptr,
+                                 /*pwfn_arg=*/nullptr,
+                                 /*decrypt_key_cb=*/nullptr,
+                                 /*decrypt_key_cb_arg=*/nullptr);
+    if (!NSS_CMSMessage_IsSigned(pCMSMessage))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: message is not signed");
+        return false;
+    }
+
+    NSSCMSContentInfo* pCMSContentInfo = NSS_CMSMessage_ContentLevel(pCMSMessage, 0);
+    if (!pCMSContentInfo)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: NSS_CMSMessage_ContentLevel() failed");
+        return false;
+    }
+
+    auto pCMSSignedData = static_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(pCMSContentInfo));
+    if (!pCMSSignedData)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: NSS_CMSContentInfo_GetContent() failed");
+        return false;
+    }
+
+    // Import certificates from the signed data temporarily, so it'll be
+    // possible to verify the signature, even if we didn't have the certificate
+    // previously.
+    std::vector<CERTCertificate*> aDocumentCertificates;
+    for (size_t i = 0; pCMSSignedData->rawCerts[i]; ++i)
+        aDocumentCertificates.push_back(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), pCMSSignedData->rawCerts[i], nullptr, 0, 0));
+
+    NSSCMSSignerInfo* pCMSSignerInfo = NSS_CMSSignedData_GetSignerInfo(pCMSSignedData, 0);
+    if (!pCMSSignerInfo)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: NSS_CMSSignedData_GetSignerInfo() failed");
+        return false;
+    }
+
+    SECItem aAlgorithm = NSS_CMSSignedData_GetDigestAlgs(pCMSSignedData)[0]->algorithm;
+    SECOidTag eOidTag = SECOID_FindOIDTag(&aAlgorithm);
+
+    // Map a sign algorithm to a digest algorithm.
+    // See NSS_CMSUtil_MapSignAlgs(), which is private to us.
+    switch (eOidTag)
+    {
+    case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
+        eOidTag = SEC_OID_SHA1;
+        break;
+    case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
+        eOidTag = SEC_OID_SHA256;
+        break;
+    case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
+        eOidTag = SEC_OID_SHA512;
+        break;
+    default:
+        break;
+    }
+
+    HASH_HashType eHashType = HASH_GetHashTypeByOidTag(eOidTag);
+    HASHContext* pHASHContext = HASH_Create(eHashType);
+    if (!pHASHContext)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: HASH_Create() failed");
+        return false;
+    }
+
+    // We have a hash, update it with the byte ranges.
+    for (const auto& rByteRange : aByteRanges)
+    {
+        rStream.Seek(rByteRange.first);
+
+        // And now hash this byte range.
+        const int nChunkLen = 4096;
+        std::vector<unsigned char> aBuffer(nChunkLen);
+        for (size_t nByte = 0; nByte < rByteRange.second;)
+        {
+            size_t nRemainingSize = rByteRange.second - nByte;
+            if (nRemainingSize < nChunkLen)
+            {
+                rStream.ReadBytes(aBuffer.data(), nRemainingSize);
+                HASH_Update(pHASHContext, aBuffer.data(), nRemainingSize);
+                nByte = rByteRange.second;
+            }
+            else
+            {
+                rStream.ReadBytes(aBuffer.data(), nChunkLen);
+                HASH_Update(pHASHContext, aBuffer.data(), nChunkLen);
+                nByte += nChunkLen;
+            }
+        }
+    }
+
+    // Find out what is the expected length of the hash.
+    unsigned int nMaxResultLen = 0;
+    switch (eOidTag)
+    {
+    case SEC_OID_SHA1:
+        nMaxResultLen = msfilter::SHA1_HASH_LENGTH;
+        rInformation.nDigestID = xml::crypto::DigestID::SHA1;
+        break;
+    case SEC_OID_SHA256:
+        nMaxResultLen = msfilter::SHA256_HASH_LENGTH;
+        rInformation.nDigestID = xml::crypto::DigestID::SHA256;
+        break;
+    case SEC_OID_SHA512:
+        nMaxResultLen = msfilter::SHA512_HASH_LENGTH;
+        break;
+    default:
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: unrecognized algorithm");
+        return false;
+    }
+
+    auto pActualResultBuffer = static_cast<unsigned char*>(PORT_Alloc(nMaxResultLen));
+    unsigned int nActualResultLen;
+    HASH_End(pHASHContext, pActualResultBuffer, &nActualResultLen, nMaxResultLen);
+
+    CERTCertificate* pCertificate = NSS_CMSSignerInfo_GetSigningCertificate(pCMSSignerInfo, CERT_GetDefaultCertDB());
+    if (!pCertificate)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: NSS_CMSSignerInfo_GetSigningCertificate() failed");
+        return false;
+    }
+    else
+    {
+        uno::Sequence<sal_Int8> aDerCert(pCertificate->derCert.len);
+        for (size_t i = 0; i < pCertificate->derCert.len; ++i)
+            aDerCert[i] = pCertificate->derCert.data[i];
+        OUStringBuffer aBuffer;
+        comphelper::Base64::encode(aBuffer, aDerCert);
+        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
+    }
+
+    PRTime nSigningTime;
+    // This may fail, in which case the date should be taken from the dictionary's "M" key.
+    if (NSS_CMSSignerInfo_GetSigningTime(pCMSSignerInfo, &nSigningTime) == SECSuccess)
+    {
+        // First convert the UTC UNIX timestamp to a tools::DateTime.
+        // nSigningTime is in microseconds.
+        DateTime aDateTime = DateTime::CreateFromUnixTime(static_cast<double>(nSigningTime) / 1000000);
+
+        // Then convert to a local UNO DateTime.
+        aDateTime.ConvertToLocalTime();
+        rInformation.stDateTime = aDateTime.GetUNODateTime();
+    }
+
+    // Check if we have a signing certificate attribute.
+    SECOidData aOidData;
+    aOidData.oid.data = nullptr;
+    /*
+     * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
+     * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+     *   smime(16) id-aa(2) 47 }
+     */
+    if (StringToOID(&aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "StringToOID() failed");
+        return false;
+    }
+    aOidData.offset = SEC_OID_UNKNOWN;
+    aOidData.desc = "id-aa-signingCertificateV2";
+    aOidData.mechanism = CKM_SHA_1;
+    aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
+    NSSCMSAttribute* pAttribute = CMSAttributeArray_FindAttrByOidData(pCMSSignerInfo->authAttr, &aOidData, PR_TRUE);
+    if (pAttribute)
+        rInformation.bHasSigningCertificate = true;
+
+    SECItem* pContentInfoContentData = pCMSSignedData->contentInfo.content.data;
+    if (bNonDetached && pContentInfoContentData && pContentInfoContentData->data)
+    {
+        // Not a detached signature.
+        if (!std::memcmp(pActualResultBuffer, pContentInfoContentData->data, nMaxResultLen) && nActualResultLen == pContentInfoContentData->len)
+            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
+    }
+    else
+    {
+        // Detached, the usual case.
+        SECItem aActualResultItem;
+        aActualResultItem.data = pActualResultBuffer;
+        aActualResultItem.len = nActualResultLen;
+        if (NSS_CMSSignerInfo_Verify(pCMSSignerInfo, &aActualResultItem, nullptr) == SECSuccess)
+            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
+    }
+
+    // Everything went fine
+    PORT_Free(pActualResultBuffer);
+    HASH_Destroy(pHASHContext);
+    NSS_CMSSignerInfo_Destroy(pCMSSignerInfo);
+    for (auto pDocumentCertificate : aDocumentCertificates)
+        CERT_DestroyCertificate(pDocumentCertificate);
+
+    return true;
+#elif defined SVL_CRYPTO_MSCRYPTO
+    // Open a message for decoding.
+    HCRYPTMSG hMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+                                          CMSG_DETACHED_FLAG,
+                                          0,
+                                          NULL,
+                                          nullptr,
+                                          nullptr);
+    if (!hMsg)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgOpenToDecode() failed");
+        return false;
+    }
+
+    // Update the message with the encoded header blob.
+    if (!CryptMsgUpdate(hMsg, aSignature.data(), aSignature.size(), TRUE))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature, CryptMsgUpdate() for the header failed: " << WindowsErrorString(GetLastError()));
+        return false;
+    }
+
+    // Update the message with the content blob.
+    for (const auto& rByteRange : aByteRanges)
+    {
+        rStream.Seek(rByteRange.first);
+
+        const int nChunkLen = 4096;
+        std::vector<unsigned char> aBuffer(nChunkLen);
+        for (size_t nByte = 0; nByte < rByteRange.second;)
+        {
+            size_t nRemainingSize = rByteRange.second - nByte;
+            if (nRemainingSize < nChunkLen)
+            {
+                rStream.ReadBytes(aBuffer.data(), nRemainingSize);
+                if (!CryptMsgUpdate(hMsg, aBuffer.data(), nRemainingSize, FALSE))
+                {
+                    SAL_WARN("xmlsecurity.pdfio", "ValidateSignature, CryptMsgUpdate() for the content failed: " << WindowsErrorString(GetLastError()));
+                    return false;
+                }
+                nByte = rByteRange.second;
+            }
+            else
+            {
+                rStream.ReadBytes(aBuffer.data(), nChunkLen);
+                if (!CryptMsgUpdate(hMsg, aBuffer.data(), nChunkLen, FALSE))
+                {
+                    SAL_WARN("xmlsecurity.pdfio", "ValidateSignature, CryptMsgUpdate() for the content failed: " << WindowsErrorString(GetLastError()));
+                    return false;
+                }
+                nByte += nChunkLen;
+            }
+        }
+    }
+    if (!CryptMsgUpdate(hMsg, nullptr, 0, TRUE))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature, CryptMsgUpdate() for the last content failed: " << WindowsErrorString(GetLastError()));
+        return false;
+    }
+
+    // Get the CRYPT_ALGORITHM_IDENTIFIER from the message.
+    DWORD nDigestID = 0;
+    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, nullptr, &nDigestID))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed: " << WindowsErrorString(GetLastError()));
+        return false;
+    }
+    std::unique_ptr<BYTE[]> pDigestBytes(new BYTE[nDigestID]);
+    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, pDigestBytes.get(), &nDigestID))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed: " << WindowsErrorString(GetLastError()));
+        return false;
+    }
+    auto pDigestID = reinterpret_cast<CRYPT_ALGORITHM_IDENTIFIER*>(pDigestBytes.get());
+    if (OString(szOID_NIST_sha256) == pDigestID->pszObjId)
+        rInformation.nDigestID = xml::crypto::DigestID::SHA256;
+    else if (OString(szOID_RSA_SHA1RSA) == pDigestID->pszObjId || OString(szOID_OIWSEC_sha1) == pDigestID->pszObjId)
+        rInformation.nDigestID = xml::crypto::DigestID::SHA1;
+    else
+        // Don't error out here, we can still verify the message digest correctly, just the digest ID won't be set.
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: unhandled algorithm identifier '"<<pDigestID->pszObjId<<"'");
+
+    // Get the signer CERT_INFO from the message.
+    DWORD nSignerCertInfo = 0;
+    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, nullptr, &nSignerCertInfo))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
+        return false;
+    }
+    std::unique_ptr<BYTE[]> pSignerCertInfoBuf(new BYTE[nSignerCertInfo]);
+    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, pSignerCertInfoBuf.get(), &nSignerCertInfo))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
+        return false;
+    }
+    PCERT_INFO pSignerCertInfo = reinterpret_cast<PCERT_INFO>(pSignerCertInfoBuf.get());
+
+    // Open a certificate store in memory using CERT_STORE_PROV_MSG, which
+    // initializes it with the certificates from the message.
+    HCERTSTORE hStoreHandle = CertOpenStore(CERT_STORE_PROV_MSG,
+                                            PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+                                            NULL,
+                                            0,
+                                            hMsg);
+    if (!hStoreHandle)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CertOpenStore() failed");
+        return false;
+    }
+
+    // Find the signer's certificate in the store.
+    PCCERT_CONTEXT pSignerCertContext = CertGetSubjectCertificateFromStore(hStoreHandle,
+                                        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+                                        pSignerCertInfo);
+    if (!pSignerCertContext)
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CertGetSubjectCertificateFromStore() failed");
+        return false;
+    }
+    else
+    {
+        // Write rInformation.ouX509Certificate.
+        uno::Sequence<sal_Int8> aDerCert(pSignerCertContext->cbCertEncoded);
+        for (size_t i = 0; i < pSignerCertContext->cbCertEncoded; ++i)
+            aDerCert[i] = pSignerCertContext->pbCertEncoded[i];
+        OUStringBuffer aBuffer;
+        comphelper::Base64::encode(aBuffer, aDerCert);
+        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
+    }
+
+    if (bNonDetached)
+    {
+        // Not a detached signature.
+        DWORD nContentParam = 0;
+        if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, nullptr, &nContentParam))
+        {
+            SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
+            return false;
+        }
+
+        std::vector<BYTE> aContentParam(nContentParam);
+        if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, aContentParam.data(), &nContentParam))
+        {
+            SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
+            return false;
+        }
+
+        if (VerifyNonDetachedSignature(rStream, aByteRanges, aContentParam))
+            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
+    }
+    else
+    {
+        // Detached, the usual case.
+        // Use the CERT_INFO from the signer certificate to verify the signature.
+        if (CryptMsgControl(hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE, pSignerCertContext->pCertInfo))
+            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
+    }
+
+    // Check if we have a signing certificate attribute.
+    DWORD nSignedAttributes = 0;
+    if (CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, nullptr, &nSignedAttributes))
+    {
+        std::unique_ptr<BYTE[]> pSignedAttributesBuf(new BYTE[nSignedAttributes]);
+        if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, pSignedAttributesBuf.get(), &nSignedAttributes))
+        {
+            SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
+            return false;
+        }
+        auto pSignedAttributes = reinterpret_cast<PCRYPT_ATTRIBUTES>(pSignedAttributesBuf.get());
+        for (size_t nAttr = 0; nAttr < pSignedAttributes->cAttr; ++nAttr)
+        {
+            CRYPT_ATTRIBUTE& rAttr = pSignedAttributes->rgAttr[nAttr];
+            /*
+             * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
+             * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+             *   smime(16) id-aa(2) 47 }
+             */
+            if (OString("1.2.840.113549.1.9.16.2.47") == rAttr.pszObjId)
+            {
+                rInformation.bHasSigningCertificate = true;
+                break;
+            }
+        }
+    }
+
+    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
+    CryptMsgClose(hMsg);
+    return true;
+#else
+    // Not implemented.
+    (void)rStream;
+    (void)aByteRanges;
+    (void)bNonDetected;
+    (void)aSignature;
+    (void)rInformation;
+static_assert(false, "WHAT!!!");
+    return false;
+#endif
+}
+
 }
 
 }
diff --git a/xmlsecurity/inc/certificatechooser.hxx b/xmlsecurity/inc/certificatechooser.hxx
index 264b740dd448..009d20e4ea2f 100644
--- a/xmlsecurity/inc/certificatechooser.hxx
+++ b/xmlsecurity/inc/certificatechooser.hxx
@@ -28,7 +28,7 @@
 #include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
 #include <com/sun/star/uno/XComponentContext.hpp>
 #include <com/sun/star/uno/Sequence.hxx>
-#include <sigstruct.hxx>
+#include <svl/sigstruct.hxx>
 
 
 namespace com {
diff --git a/xmlsecurity/inc/documentsignaturehelper.hxx b/xmlsecurity/inc/documentsignaturehelper.hxx
index a8f3cb1f5d40..3997ae47260d 100644
--- a/xmlsecurity/inc/documentsignaturehelper.hxx
+++ b/xmlsecurity/inc/documentsignaturehelper.hxx
@@ -23,7 +23,7 @@
 #include <com/sun/star/uno/Reference.h>
 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
 #include <rtl/ustring.hxx>
-#include "sigstruct.hxx"
+#include <svl/sigstruct.hxx>
 #include "xmlsecurity/xmlsecuritydllapi.h"
 
 #include <vector>
diff --git a/xmlsecurity/inc/documentsignaturemanager.hxx b/xmlsecurity/inc/documentsignaturemanager.hxx
index f354ad8c8cbb..0ea708c5d241 100644
--- a/xmlsecurity/inc/documentsignaturemanager.hxx
+++ b/xmlsecurity/inc/documentsignaturemanager.hxx
@@ -24,7 +24,7 @@
 
 #include <memory>
 
-#include <sigstruct.hxx>
+#include <svl/sigstruct.hxx>
 #include <xmlsignaturehelper.hxx>
 #include <pdfsignaturehelper.hxx>
 #include <com/sun/star/uno/XComponentContext.hpp>
diff --git a/xmlsecurity/inc/pch/precompiled_xmlsecurity.hxx b/xmlsecurity/inc/pch/precompiled_xmlsecurity.hxx
index cfb26d8593ae..07008a0b5181 100644
--- a/xmlsecurity/inc/pch/precompiled_xmlsecurity.hxx
+++ b/xmlsecurity/inc/pch/precompiled_xmlsecurity.hxx
@@ -302,6 +302,5 @@
 #include <unotools/readwritemutexguard.hxx>
 #include <unotools/syslocale.hxx>
 #include <unotools/unotoolsdllapi.h>
-#include <sigstruct.hxx>
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmlsecurity/inc/pdfsignaturehelper.hxx b/xmlsecurity/inc/pdfsignaturehelper.hxx
index 74b89fe44e02..7da417c46e4f 100644
--- a/xmlsecurity/inc/pdfsignaturehelper.hxx
+++ b/xmlsecurity/inc/pdfsignaturehelper.hxx
@@ -19,7 +19,7 @@
 #include <com/sun/star/xml/crypto/XSEInitializer.hpp>
 #include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
 
-#include <sigstruct.hxx>
+#include <svl/sigstruct.hxx>
 
 /// Handles signatures of a PDF file.
 class XMLSECURITY_DLLPUBLIC PDFSignatureHelper
diff --git a/xmlsecurity/inc/xmlsignaturehelper.hxx b/xmlsecurity/inc/xmlsignaturehelper.hxx
index 209c93c15a09..d527942f50f2 100644
--- a/xmlsecurity/inc/xmlsignaturehelper.hxx
+++ b/xmlsecurity/inc/xmlsignaturehelper.hxx
@@ -25,7 +25,7 @@
 #include <tools/link.hxx>
 #include <rtl/ustring.hxx>
 #include <rtl/ref.hxx>
-#include <sigstruct.hxx>
+#include <svl/sigstruct.hxx>
 #include <xsecctl.hxx>
 #include <xmlsecurity/xmlsecuritydllapi.h>
 
diff --git a/xmlsecurity/inc/xsecctl.hxx b/xmlsecurity/inc/xsecctl.hxx
index 9ddc22affbae..27cb60e54dc0 100644
--- a/xmlsecurity/inc/xsecctl.hxx
+++ b/xmlsecurity/inc/xsecctl.hxx
@@ -20,7 +20,7 @@
 #ifndef INCLUDED_XMLSECURITY_SOURCE_HELPER_XSECCTL_HXX
 #define INCLUDED_XMLSECURITY_SOURCE_HELPER_XSECCTL_HXX
 
-#include <sigstruct.hxx>
+#include <svl/sigstruct.hxx>
 
 #include <com/sun/star/uno/XComponentContext.hpp>
 #include <com/sun/star/xml/sax/XParser.hpp>
diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.hxx b/xmlsecurity/source/helper/ooxmlsecexporter.hxx
index 1a96430bba9a..12c7c197047c 100644
--- a/xmlsecurity/source/helper/ooxmlsecexporter.hxx
+++ b/xmlsecurity/source/helper/ooxmlsecexporter.hxx
@@ -15,7 +15,7 @@
 #include <com/sun/star/uno/XComponentContext.hpp>
 #include <com/sun/star/embed/XStorage.hpp>
 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
-#include <sigstruct.hxx>
+#include <svl/sigstruct.hxx>
 
 /// Writes a single OOXML digital signature.
 class OOXMLSecExporter
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 6925b41a1960..d0d56f4bd409 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -32,7 +32,8 @@
 #include <xmloff/xmluconv.hxx>
 #include <o3tl/make_unique.hxx>
 
-#include <sigstruct.hxx>
+#include <svl/sigstruct.hxx>
+#include <svl/cryptosign.hxx>
 
 #ifdef XMLSEC_CRYPTO_NSS
 #include <cert.h>
@@ -56,232 +57,6 @@ namespace xmlsecurity
 namespace pdfio
 {
 
-namespace
-{
-#ifdef XMLSEC_CRYPTO_NSS
-/// Similar to NSS_CMSAttributeArray_FindAttrByOidTag(), but works directly with a SECOidData.
-NSSCMSAttribute* CMSAttributeArray_FindAttrByOidData(NSSCMSAttribute** attrs, SECOidData* oid, PRBool only)
-{
-    NSSCMSAttribute* attr1, *attr2;
-
-    if (attrs == nullptr)
-        return nullptr;
-
-    if (oid == nullptr)
-        return nullptr;
-
-    while ((attr1 = *attrs++) != nullptr)
-    {
-        if (attr1->type.len == oid->oid.len && PORT_Memcmp(attr1->type.data,
-                oid->oid.data,
-                oid->oid.len) == 0)
-            break;
-    }
-
-    if (attr1 == nullptr)
-        return nullptr;
-
-    if (!only)
-        return attr1;
-
-    while ((attr2 = *attrs++) != nullptr)
-    {
-        if (attr2->type.len == oid->oid.len && PORT_Memcmp(attr2->type.data,
-                oid->oid.data,
-                oid->oid.len) == 0)
-            break;
-    }
-
-    if (attr2 != nullptr)
-        return nullptr;
-
-    return attr1;
-}
-
-/// Same as SEC_StringToOID(), which is private to us.
-SECStatus StringToOID(SECItem* to, const char* from, PRUint32 len)
-{
-    PRUint32 decimal_numbers = 0;
-    PRUint32 result_bytes = 0;
-    SECStatus rv;
-    PRUint8 result[1024];
-
-    static const PRUint32 max_decimal = (0xffffffff / 10);
-    static const char OIDstring[] = {"OID."};
-
-    if (!from || !to)
-    {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return SECFailure;
-    }
-    if (!len)
-    {
-        len = PL_strlen(from);
-    }
-    if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4))
-    {
-        from += 4; /* skip leading "OID." if present */
-        len  -= 4;
-    }
-    if (!len)
-    {
-bad_data:
-        PORT_SetError(SEC_ERROR_BAD_DATA);
-        return SECFailure;
-    }
-    do
-    {
-        PRUint32 decimal = 0;
-        while (len > 0 && rtl::isAsciiDigit(static_cast<unsigned char>(*from)))
-        {
-            PRUint32 addend = (*from++ - '0');
-            --len;
-            if (decimal > max_decimal)  /* overflow */
-                goto bad_data;
-            decimal = (decimal * 10) + addend;
-            if (decimal < addend)   /* overflow */
-                goto bad_data;
-        }
-        if (len != 0 && *from != '.')
-        {
-            goto bad_data;
-        }
-        if (decimal_numbers == 0)
-        {
-            if (decimal > 2)
-                goto bad_data;
-            result[0] = decimal * 40;
-            result_bytes = 1;
-        }
-        else if (decimal_numbers == 1)
-        {
-            if (decimal > 40)
-                goto bad_data;
-            result[0] += decimal;
-        }
-        else
-        {
-            /* encode the decimal number,  */
-            PRUint8* rp;
-            PRUint32 num_bytes = 0;
-            PRUint32 tmp = decimal;
-            while (tmp)
-            {
-                num_bytes++;
-                tmp >>= 7;
-            }
-            if (!num_bytes)
-                ++num_bytes;  /* use one byte for a zero value */
-            if (static_cast<size_t>(num_bytes) + result_bytes > sizeof result)
-                goto bad_data;
-            tmp = num_bytes;
-            rp = result + result_bytes - 1;
-            rp[tmp] = (PRUint8)(decimal & 0x7f);
-            decimal >>= 7;
-            while (--tmp > 0)
-            {
-                rp[tmp] = (PRUint8)(decimal | 0x80);
-                decimal >>= 7;
-            }
-            result_bytes += num_bytes;
-        }
-        ++decimal_numbers;
-        if (len > 0)   /* skip trailing '.' */
-        {
-            ++from;
-            --len;
-        }
-    }
-    while (len > 0);
-    /* now result contains result_bytes of data */
-    if (to->data && to->len >= result_bytes)
-    {
-        PORT_Memcpy(to->data, result, to->len = result_bytes);
-        rv = SECSuccess;
-    }
-    else
-    {
-        SECItem result_item = {siBuffer, nullptr, 0 };
-        result_item.data = result;
-        result_item.len  = result_bytes;
-        rv = SECITEM_CopyItem(nullptr, to, &result_item);
-    }
-    return rv;
-}
-#elif defined XMLSEC_CRYPTO_MSCRYPTO
-/// Verifies a non-detached signature using CryptoAPI.
-bool VerifyNonDetachedSignature(SvStream& rStream, std::vector<std::pair<size_t, size_t>>& rByteRanges, std::vector<BYTE>& rExpectedHash)
-{
-    HCRYPTPROV hProv = 0;
-    if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "CryptAcquireContext() failed");
-        return false;
-    }
-
-    HCRYPTHASH hHash = 0;
-    if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "CryptCreateHash() failed");
-        return false;
-    }
-
-    for (const auto& rByteRange : rByteRanges)
-    {
-        rStream.Seek(rByteRange.first);
-        const int nChunkLen = 4096;
-        std::vector<unsigned char> aBuffer(nChunkLen);
-        for (size_t nByte = 0; nByte < rByteRange.second;)
-        {
-            size_t nRemainingSize = rByteRange.second - nByte;
-            if (nRemainingSize < nChunkLen)
-            {
-                rStream.ReadBytes(aBuffer.data(), nRemainingSize);
-                if (!CryptHashData(hHash, aBuffer.data(), nRemainingSize, 0))
-                {
-                    SAL_WARN("xmlsecurity.pdfio", "CryptHashData() failed");
-                    return false;
-                }
-                nByte = rByteRange.second;
-            }
-            else
-            {
-                rStream.ReadBytes(aBuffer.data(), nChunkLen);
-                if (!CryptHashData(hHash, aBuffer.data(), nChunkLen, 0))
-                {
-                    SAL_WARN("xmlsecurity.pdfio", "CryptHashData() failed");
-                    return false;
-                }
-                nByte += nChunkLen;
-            }
-        }
-    }
-
-    DWORD nActualHash = 0;
-    if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nActualHash, 0))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "CryptGetHashParam() failed to provide the hash length");
-        return false;
-    }
-
-    std::vector<unsigned char> aActualHash(nActualHash);
-    if (!CryptGetHashParam(hHash, HP_HASHVAL, aActualHash.data(), &nActualHash, 0))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "CryptGetHashParam() failed to provide the hash");
-        return false;
-    }
-
-    CryptDestroyHash(hHash);
-    CryptReleaseContext(hProv, 0);
-
-    if (!std::memcmp(aActualHash.data(), rExpectedHash.data(), aActualHash.size()) && aActualHash.size() == rExpectedHash.size())
-        return true;
-
-    return false;
-}
-#endif
-}
-
 bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignature, SignatureInformation& rInformation, bool bLast)
 {
     vcl::filter::PDFObjectElement* pValue = pSignature->LookupObject("V");
@@ -306,7 +81,7 @@ bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignat
     }
 
     auto pSubFilter = dynamic_cast<vcl::filter::PDFNameElement*>(pValue->Lookup("SubFilter"));
-    bool bNonDetached = pSubFilter && pSubFilter->GetValue() == "adbe.pkcs7.sha1";
+    const bool bNonDetached = pSubFilter && pSubFilter->GetValue() == "adbe.pkcs7.sha1";
     if (!pSubFilter || (pSubFilter->GetValue() != "adbe.pkcs7.detached" && !bNonDetached && pSubFilter->GetValue() != "ETSI.CAdES.detached"))
     {
         if (!pSubFilter)
@@ -414,415 +189,7 @@ bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignat
         return false;
     }
 
-#ifdef XMLSEC_CRYPTO_NSS
-    // Validate the signature. No need to call NSS_Init() here, assume that the
-    // caller did that already.
-
-    SECItem aSignatureItem;
-    aSignatureItem.data = aSignature.data();
-    aSignatureItem.len = aSignature.size();
-    NSSCMSMessage* pCMSMessage = NSS_CMSMessage_CreateFromDER(&aSignatureItem,
-                                 /*cb=*/nullptr,
-                                 /*cb_arg=*/nullptr,
-                                 /*pwfn=*/nullptr,
-                                 /*pwfn_arg=*/nullptr,
-                                 /*decrypt_key_cb=*/nullptr,
-                                 /*decrypt_key_cb_arg=*/nullptr);
-    if (!NSS_CMSMessage_IsSigned(pCMSMessage))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: message is not signed");
-        return false;
-    }
-
-    NSSCMSContentInfo* pCMSContentInfo = NSS_CMSMessage_ContentLevel(pCMSMessage, 0);
-    if (!pCMSContentInfo)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: NSS_CMSMessage_ContentLevel() failed");
-        return false;
-    }
-
-    auto pCMSSignedData = static_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(pCMSContentInfo));
-    if (!pCMSSignedData)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: NSS_CMSContentInfo_GetContent() failed");
-        return false;
-    }
-
-    // Import certificates from the signed data temporarily, so it'll be
-    // possible to verify the signature, even if we didn't have the certificate
-    // previously.
-    std::vector<CERTCertificate*> aDocumentCertificates;
-    for (size_t i = 0; pCMSSignedData->rawCerts[i]; ++i)
-        aDocumentCertificates.push_back(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), pCMSSignedData->rawCerts[i], nullptr, 0, 0));
-
-    NSSCMSSignerInfo* pCMSSignerInfo = NSS_CMSSignedData_GetSignerInfo(pCMSSignedData, 0);
-    if (!pCMSSignerInfo)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: NSS_CMSSignedData_GetSignerInfo() failed");
-        return false;
-    }
-
-    SECItem aAlgorithm = NSS_CMSSignedData_GetDigestAlgs(pCMSSignedData)[0]->algorithm;
-    SECOidTag eOidTag = SECOID_FindOIDTag(&aAlgorithm);
-
-    // Map a sign algorithm to a digest algorithm.
-    // See NSS_CMSUtil_MapSignAlgs(), which is private to us.
-    switch (eOidTag)
-    {
-    case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
-        eOidTag = SEC_OID_SHA1;
-        break;
-    case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
-        eOidTag = SEC_OID_SHA256;
-        break;
-    case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
-        eOidTag = SEC_OID_SHA512;
-        break;
-    default:
-        break;
-    }
-
-    HASH_HashType eHashType = HASH_GetHashTypeByOidTag(eOidTag);
-    HASHContext* pHASHContext = HASH_Create(eHashType);
-    if (!pHASHContext)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: HASH_Create() failed");
-        return false;
-    }
-
-    // We have a hash, update it with the byte ranges.
-    for (const auto& rByteRange : aByteRanges)
-    {
-        rStream.Seek(rByteRange.first);
-
-        // And now hash this byte range.
-        const int nChunkLen = 4096;
-        std::vector<unsigned char> aBuffer(nChunkLen);
-        for (size_t nByte = 0; nByte < rByteRange.second;)
-        {
-            size_t nRemainingSize = rByteRange.second - nByte;
-            if (nRemainingSize < nChunkLen)
-            {
-                rStream.ReadBytes(aBuffer.data(), nRemainingSize);
-                HASH_Update(pHASHContext, aBuffer.data(), nRemainingSize);
-                nByte = rByteRange.second;
-            }
-            else
-            {
-                rStream.ReadBytes(aBuffer.data(), nChunkLen);
-                HASH_Update(pHASHContext, aBuffer.data(), nChunkLen);
-                nByte += nChunkLen;
-            }
-        }
-    }
-
-    // Find out what is the expected length of the hash.
-    unsigned int nMaxResultLen = 0;
-    switch (eOidTag)
-    {
-    case SEC_OID_SHA1:
-        nMaxResultLen = msfilter::SHA1_HASH_LENGTH;
-        rInformation.nDigestID = xml::crypto::DigestID::SHA1;
-        break;
-    case SEC_OID_SHA256:
-        nMaxResultLen = msfilter::SHA256_HASH_LENGTH;
-        rInformation.nDigestID = xml::crypto::DigestID::SHA256;
-        break;
-    case SEC_OID_SHA512:
-        nMaxResultLen = msfilter::SHA512_HASH_LENGTH;
-        break;
-    default:
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: unrecognized algorithm");
-        return false;
-    }
-
-    auto pActualResultBuffer = static_cast<unsigned char*>(PORT_Alloc(nMaxResultLen));
-    unsigned int nActualResultLen;
-    HASH_End(pHASHContext, pActualResultBuffer, &nActualResultLen, nMaxResultLen);
-
-    CERTCertificate* pCertificate = NSS_CMSSignerInfo_GetSigningCertificate(pCMSSignerInfo, CERT_GetDefaultCertDB());
-    if (!pCertificate)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: NSS_CMSSignerInfo_GetSigningCertificate() failed");
-        return false;
-    }
-    else
-    {
-        uno::Sequence<sal_Int8> aDerCert(pCertificate->derCert.len);
-        for (size_t i = 0; i < pCertificate->derCert.len; ++i)
-            aDerCert[i] = pCertificate->derCert.data[i];
-        OUStringBuffer aBuffer;
-        sax::Converter::encodeBase64(aBuffer, aDerCert);
-        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
-    }
-
-    PRTime nSigningTime;
-    // This may fail, in which case the date should be taken from the dictionary's "M" key.
-    if (NSS_CMSSignerInfo_GetSigningTime(pCMSSignerInfo, &nSigningTime) == SECSuccess)
-    {
-        // First convert the UNIX timestamp to an ISO8601 string.
-        OUStringBuffer aBuffer;
-        uno::Reference<uno::XComponentContext> xComponentContext = comphelper::getProcessComponentContext();
-        CalendarWrapper aCalendarWrapper(xComponentContext);
-        // nSigningTime is in microseconds.
-        SvXMLUnitConverter::convertDateTime(aBuffer, static_cast<double>(nSigningTime) / 1000000 / tools::Time::secondPerDay, aCalendarWrapper.getEpochStart().GetUNODate());
-
-        // Then convert this string to a local UNO DateTime.
-        util::DateTime aUNODateTime;
-        try
-        {
-            utl::ISO8601parseDateTime(aBuffer.toString(), aUNODateTime);
-        }
-        catch (const std::length_error&)
-        {
-            SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: failed to parse signature date string");
-            return false;
-        }
-        DateTime aDateTime(aUNODateTime);
-        aDateTime.ConvertToLocalTime();
-        rInformation.stDateTime = aDateTime.GetUNODateTime();
-    }
-
-    // Check if we have a signing certificate attribute.
-    SECOidData aOidData;
-    aOidData.oid.data = nullptr;
-    /*
-     * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
-     * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
-     *   smime(16) id-aa(2) 47 }
-     */
-    if (StringToOID(&aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "StringToOID() failed");
-        return false;
-    }
-    aOidData.offset = SEC_OID_UNKNOWN;
-    aOidData.desc = "id-aa-signingCertificateV2";
-    aOidData.mechanism = CKM_SHA_1;
-    aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
-    NSSCMSAttribute* pAttribute = CMSAttributeArray_FindAttrByOidData(pCMSSignerInfo->authAttr, &aOidData, PR_TRUE);
-    if (pAttribute)
-        rInformation.bHasSigningCertificate = true;
-
-    SECItem* pContentInfoContentData = pCMSSignedData->contentInfo.content.data;
-    if (bNonDetached && pContentInfoContentData && pContentInfoContentData->data)
-    {
-        // Not a detached signature.
-        if (!std::memcmp(pActualResultBuffer, pContentInfoContentData->data, nMaxResultLen) && nActualResultLen == pContentInfoContentData->len)
-            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
-    }
-    else
-    {
-        // Detached, the usual case.
-        SECItem aActualResultItem;
-        aActualResultItem.data = pActualResultBuffer;
-        aActualResultItem.len = nActualResultLen;
-        if (NSS_CMSSignerInfo_Verify(pCMSSignerInfo, &aActualResultItem, nullptr) == SECSuccess)
-            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
-    }
-
-    // Everything went fine
-    PORT_Free(pActualResultBuffer);
-    HASH_Destroy(pHASHContext);
-    NSS_CMSSignerInfo_Destroy(pCMSSignerInfo);
-    for (auto pDocumentCertificate : aDocumentCertificates)
-        CERT_DestroyCertificate(pDocumentCertificate);
-
-    return true;
-#elif defined XMLSEC_CRYPTO_MSCRYPTO
-    // Open a message for decoding.
-    HCRYPTMSG hMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
-                                          CMSG_DETACHED_FLAG,
-                                          0,
-                                          NULL,
-                                          nullptr,
-                                          nullptr);
-    if (!hMsg)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgOpenToDecode() failed");
-        return false;
-    }
-
-    // Update the message with the encoded header blob.
-    if (!CryptMsgUpdate(hMsg, aSignature.data(), aSignature.size(), TRUE))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature, CryptMsgUpdate() for the header failed: " << WindowsErrorString(GetLastError()));
-        return false;
-    }
-
-    // Update the message with the content blob.
-    for (const auto& rByteRange : aByteRanges)
-    {
-        rStream.Seek(rByteRange.first);
-
-        const int nChunkLen = 4096;
-        std::vector<unsigned char> aBuffer(nChunkLen);
-        for (size_t nByte = 0; nByte < rByteRange.second;)
-        {
-            size_t nRemainingSize = rByteRange.second - nByte;
-            if (nRemainingSize < nChunkLen)
-            {
-                rStream.ReadBytes(aBuffer.data(), nRemainingSize);
-                if (!CryptMsgUpdate(hMsg, aBuffer.data(), nRemainingSize, FALSE))
-                {
-                    SAL_WARN("xmlsecurity.pdfio", "ValidateSignature, CryptMsgUpdate() for the content failed: " << WindowsErrorString(GetLastError()));
-                    return false;
-                }
-                nByte = rByteRange.second;
-            }
-            else
-            {
-                rStream.ReadBytes(aBuffer.data(), nChunkLen);
-                if (!CryptMsgUpdate(hMsg, aBuffer.data(), nChunkLen, FALSE))
-                {
-                    SAL_WARN("xmlsecurity.pdfio", "ValidateSignature, CryptMsgUpdate() for the content failed: " << WindowsErrorString(GetLastError()));
-                    return false;
-                }
-                nByte += nChunkLen;
-            }
-        }
-    }
-    if (!CryptMsgUpdate(hMsg, nullptr, 0, TRUE))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature, CryptMsgUpdate() for the last content failed: " << WindowsErrorString(GetLastError()));
-        return false;
-    }
-
-    // Get the CRYPT_ALGORITHM_IDENTIFIER from the message.
-    DWORD nDigestID = 0;
-    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, nullptr, &nDigestID))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed: " << WindowsErrorString(GetLastError()));
-        return false;
-    }
-    std::unique_ptr<BYTE[]> pDigestBytes(new BYTE[nDigestID]);
-    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, pDigestBytes.get(), &nDigestID))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed: " << WindowsErrorString(GetLastError()));
-        return false;
-    }
-    auto pDigestID = reinterpret_cast<CRYPT_ALGORITHM_IDENTIFIER*>(pDigestBytes.get());
-    if (OString(szOID_NIST_sha256) == pDigestID->pszObjId)
-        rInformation.nDigestID = xml::crypto::DigestID::SHA256;
-    else if (OString(szOID_RSA_SHA1RSA) == pDigestID->pszObjId || OString(szOID_OIWSEC_sha1) == pDigestID->pszObjId)
-        rInformation.nDigestID = xml::crypto::DigestID::SHA1;
-    else
-        // Don't error out here, we can still verify the message digest correctly, just the digest ID won't be set.
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: unhandled algorithm identifier '"<<pDigestID->pszObjId<<"'");
-
-    // Get the signer CERT_INFO from the message.
-    DWORD nSignerCertInfo = 0;
-    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, nullptr, &nSignerCertInfo))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
-        return false;
-    }
-    std::unique_ptr<BYTE[]> pSignerCertInfoBuf(new BYTE[nSignerCertInfo]);
-    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, pSignerCertInfoBuf.get(), &nSignerCertInfo))
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
-        return false;
-    }
-    PCERT_INFO pSignerCertInfo = reinterpret_cast<PCERT_INFO>(pSignerCertInfoBuf.get());
-
-    // Open a certificate store in memory using CERT_STORE_PROV_MSG, which
-    // initializes it with the certificates from the message.
-    HCERTSTORE hStoreHandle = CertOpenStore(CERT_STORE_PROV_MSG,
-                                            PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
-                                            NULL,
-                                            0,
-                                            hMsg);
-    if (!hStoreHandle)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CertOpenStore() failed");
-        return false;
-    }
-
-    // Find the signer's certificate in the store.
-    PCCERT_CONTEXT pSignerCertContext = CertGetSubjectCertificateFromStore(hStoreHandle,
-                                        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
-                                        pSignerCertInfo);
-    if (!pSignerCertContext)
-    {
-        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CertGetSubjectCertificateFromStore() failed");
-        return false;
-    }
-    else
-    {
-        // Write rInformation.ouX509Certificate.
-        uno::Sequence<sal_Int8> aDerCert(pSignerCertContext->cbCertEncoded);
-        for (size_t i = 0; i < pSignerCertContext->cbCertEncoded; ++i)
-            aDerCert[i] = pSignerCertContext->pbCertEncoded[i];
-        OUStringBuffer aBuffer;
-        sax::Converter::encodeBase64(aBuffer, aDerCert);
-        rInformation.ouX509Certificate = aBuffer.makeStringAndClear();
-    }
-
-    if (bNonDetached)
-    {
-        // Not a detached signature.
-        DWORD nContentParam = 0;
-        if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, nullptr, &nContentParam))
-        {
-            SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
-            return false;
-        }
-
-        std::vector<BYTE> aContentParam(nContentParam);
-        if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, aContentParam.data(), &nContentParam))
-        {
-            SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
-            return false;
-        }
-
-        if (VerifyNonDetachedSignature(rStream, aByteRanges, aContentParam))
-            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
-    }
-    else
-    {
-        // Detached, the usual case.
-        // Use the CERT_INFO from the signer certificate to verify the signature.
-        if (CryptMsgControl(hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE, pSignerCertContext->pCertInfo))
-            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
-    }
-
-    // Check if we have a signing certificate attribute.
-    DWORD nSignedAttributes = 0;
-    if (CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, nullptr, &nSignedAttributes))
-    {
-        std::unique_ptr<BYTE[]> pSignedAttributesBuf(new BYTE[nSignedAttributes]);
-        if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, pSignedAttributesBuf.get(), &nSignedAttributes))
-        {
-            SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: CryptMsgGetParam() failed");
-            return false;
-        }
-        auto pSignedAttributes = reinterpret_cast<PCRYPT_ATTRIBUTES>(pSignedAttributesBuf.get());
-        for (size_t nAttr = 0; nAttr < pSignedAttributes->cAttr; ++nAttr)
-        {
-            CRYPT_ATTRIBUTE& rAttr = pSignedAttributes->rgAttr[nAttr];
-            /*
-             * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
-             * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
-             *   smime(16) id-aa(2) 47 }
-             */
-            if (OString("1.2.840.113549.1.9.16.2.47") == rAttr.pszObjId)
-            {
-                rInformation.bHasSigningCertificate = true;
-                break;
-            }
-        }
-    }
-
-    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
-    CryptMsgClose(hMsg);
-    return true;
-#else
-    // Not implemented.
-    (void)rStream;
-    (void)rInformation;
-
-    return false;
-#endif
+    return svl::crypto::Signing::Verify(rStream, aByteRanges, bNonDetached, aSignature, rInformation);
 }
 
 } // namespace pdfio
diff --git a/xmlsecurity/workben/pdfverify.cxx b/xmlsecurity/workben/pdfverify.cxx
index 8a14f7bf3402..673eb0171050 100644
--- a/xmlsecurity/workben/pdfverify.cxx
+++ b/xmlsecurity/workben/pdfverify.cxx
@@ -23,7 +23,7 @@
 
 #include <xmlsecurity/pdfio/pdfdocument.hxx>
 
-#include <sigstruct.hxx>
+#include <svl/sigstruct.hxx>
 
 using namespace com::sun::star;
 


More information about the Libreoffice-commits mailing list