diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-11-02 17:57:25 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-11-03 08:09:39 +0000 |
commit | 8d1fb35f5cd05fcbb2aae4d793b17ee4083c9b5e (patch) | |
tree | 4feee718d9707c66957dc40c100cbf54988bc74f /xmlsecurity/source | |
parent | 47521b5816c425497dd0fc5f91dc3e744abdecc1 (diff) |
xmlsecurity PDF verify: initial Windows support
The timestamp isn't extracted yet, but the digest match is already
checked correctly and the certificate is exposed.
Change-Id: Ieca002a5c4ca0b96f4dc397c460adb7f88f5ffc7
Reviewed-on: https://gerrit.libreoffice.org/30499
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Diffstat (limited to 'xmlsecurity/source')
-rw-r--r-- | xmlsecurity/source/pdfio/pdfdocument.cxx | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx index 894247f8f202..ac75059a5332 100644 --- a/xmlsecurity/source/pdfio/pdfdocument.cxx +++ b/xmlsecurity/source/pdfio/pdfdocument.cxx @@ -37,6 +37,13 @@ #include <sechash.h> #endif +#ifdef XMLSEC_CRYPTO_MSCRYPTO +#include <prewin.h> +#include <wincrypt.h> +#include <postwin.h> +#include <comphelper/windowserrorstring.hxx> +#endif + using namespace com::sun::star; namespace xmlsecurity @@ -1864,6 +1871,120 @@ bool PDFDocument::ValidateSignature(SvStream& rStream, PDFObjectElement* pSignat 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", "PDFDocument::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", "PDFDocument::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", "PDFDocument::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", "PDFDocument::ValidateSignature, CryptMsgUpdate() for the content failed: " << WindowsErrorString(GetLastError())); + return false; + } + nByte += nChunkLen; + } + } + } + if (!CryptMsgUpdate(hMsg, nullptr, 0, TRUE)) + { + SAL_WARN("xmlsecurity.pdfio", "PDFDocument::ValidateSignature, CryptMsgUpdate() for the last content failed: " << WindowsErrorString(GetLastError())); + return false; + } + + // 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", "PDFDocument::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", "PDFDocument::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", "PDFDocument::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", "PDFDocument::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(); + } + + // 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; + + CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG); + CryptMsgClose(hMsg); + return true; #else // Not implemented. (void)rStream; |