[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