vcl/source/gdi/pdfwriter_impl.cxx | 115 ++++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 10 deletions(-)
New commits: commit b12410f212658996fdb5fb291a06038e9ac39b2e Author: Miklos Vajna <vmik...@collabora.co.uk> Date: Thu Nov 24 09:47:08 2016 +0100 vcl mscrypto PDF sign: write ESSCertIDv2 With this, the value of signing-certificate conforms to the RFC on Windows as well. Change-Id: I09d21026bfecd0453e194f3f4cd8bae9805a5d7a Reviewed-on: https://gerrit.libreoffice.org/31150 Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> Tested-by: Jenkins <c...@libreoffice.org> diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 03bf6f2..b81bb02 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6805,6 +6805,101 @@ typedef BOOL (WINAPI *PointerTo_CryptRetrieveTimeStamp)(LPCWSTR wszUrl, PCCERT_CONTEXT *ppTsSigner, HCERTSTORE phStore); +namespace +{ +/// Create payload for the 'signing-certificate' signed attribute. +bool CreateSigningCertificateAttribute(vcl::PDFWriter::PDFSignContext& rContext, SvStream& rEncodedCertificate) +{ + // CryptEncodeObjectEx() does not support encoding arbitrary ASN.1 + // structures, like SigningCertificateV2 from RFC 5035, so let's build it + // manually. + + // Count the certificate hash and put it to aHash. + // 2.16.840.1.101.3.4.2.1, i.e. sha256. + std::vector<unsigned char> aSHA256{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}; + + HCRYPTPROV hProv = 0; + if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) + { + SAL_WARN("vcl.pdfwriter", "CryptAcquireContext() failed"); + return false; + } + + HCRYPTHASH hHash = 0; + if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) + { + SAL_WARN("vcl.pdfwriter", "CryptCreateHash() failed"); + return false; + } + + if (!CryptHashData(hHash, reinterpret_cast<const BYTE*>(rContext.m_pDerEncoded), rContext.m_nDerEncoded, 0)) + { + SAL_WARN("vcl.pdfwriter", "CryptHashData() failed"); + return false; + } + + DWORD nHash = 0; + if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nHash, 0)) + { + SAL_WARN("vcl.pdfwriter", "CryptGetHashParam() failed to provide the hash length"); + return false; + } + + std::vector<unsigned char> aHash(nHash); + if (!CryptGetHashParam(hHash, HP_HASHVAL, aHash.data(), &nHash, 0)) + { + SAL_WARN("vcl.pdfwriter", "CryptGetHashParam() failed to provide the hash"); + return false; + } + + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, 0); + + // We now have all the info to count the lengths. + // The layout of the payload is: + // SEQUENCE: SigningCertificateV2 + // SEQUENCE: SEQUENCE OF ESSCertIDv2 + // SEQUENCE: ESSCertIDv2 + // SEQUENCE: AlgorithmIdentifier + // OBJECT: algorithm + // NULL: parameters + // OCTET STRING: certHash + + size_t nAlgorithm = aSHA256.size() + 2; + size_t nParameters = 2; + size_t nAlgorithmIdentifier = nAlgorithm + nParameters + 2; + size_t nCertHash = aHash.size() + 2; + size_t nESSCertIDv2 = nAlgorithmIdentifier + nCertHash + 2; + size_t nESSCertIDv2s = nESSCertIDv2 + 2; + + // Write SigningCertificateV2. + rEncodedCertificate.WriteUInt8(0x30); + rEncodedCertificate.WriteUInt8(nESSCertIDv2s); + // Write SEQUENCE OF ESSCertIDv2. + rEncodedCertificate.WriteUInt8(0x30); + rEncodedCertificate.WriteUInt8(nESSCertIDv2); + // Write ESSCertIDv2. + rEncodedCertificate.WriteUInt8(0x30); + rEncodedCertificate.WriteUInt8(nAlgorithmIdentifier + nCertHash); + // Write AlgorithmIdentifier. + rEncodedCertificate.WriteUInt8(0x30); + rEncodedCertificate.WriteUInt8(nAlgorithm + nParameters); + // Write algorithm. + rEncodedCertificate.WriteUInt8(0x06); + rEncodedCertificate.WriteUInt8(aSHA256.size()); + rEncodedCertificate.WriteBytes(aSHA256.data(), aSHA256.size()); + // Write parameters. + rEncodedCertificate.WriteUInt8(0x05); + rEncodedCertificate.WriteUInt8(0x00); + // Write certHash. + rEncodedCertificate.WriteUInt8(0x04); + rEncodedCertificate.WriteUInt8(aHash.size()); + rEncodedCertificate.WriteBytes(aHash.data(), aHash.size()); + + return true; +} +} // anonymous namespace + #endif bool PDFWriter::Sign(PDFSignContext& rContext) @@ -7340,10 +7435,14 @@ bool PDFWriter::Sign(PDFSignContext& rContext) // Add the signing certificate as a signed attribute. CRYPT_INTEGER_BLOB aCertificateBlob; - // Just en empty SEQUENCE stub for now. - std::vector<unsigned char> aEncodedCertificate{0x30, 0x00}; - aCertificateBlob.pbData = aEncodedCertificate.data(); - aCertificateBlob.cbData = aEncodedCertificate.size(); + SvMemoryStream aEncodedCertificate; + if (!CreateSigningCertificateAttribute(rContext, aEncodedCertificate)) + { + SAL_WARN("vcl.pdfwriter", "CreateSigningCertificateAttribute() failed"); + return false; + } + aCertificateBlob.pbData = const_cast<BYTE*>(static_cast<const BYTE*>(aEncodedCertificate.GetData())); + aCertificateBlob.cbData = aEncodedCertificate.GetSize(); CRYPT_ATTRIBUTE aCertificateAttribute; /* * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= @@ -7353,12 +7452,8 @@ bool PDFWriter::Sign(PDFSignContext& rContext) aCertificateAttribute.pszObjId = const_cast<LPSTR>("1.2.840.113549.1.9.16.2.47"); aCertificateAttribute.cValue = 1; aCertificateAttribute.rgValue = &aCertificateBlob; - // Don't write the signed attribute by default till the value is ready. - if (g_bDebugDisableCompression) - { - aSignerInfo.cAuthAttr = 1; - aSignerInfo.rgAuthAttr = &aCertificateAttribute; - } + aSignerInfo.cAuthAttr = 1; + aSignerInfo.rgAuthAttr = &aCertificateAttribute; CMSG_SIGNED_ENCODE_INFO aSignedInfo; memset(&aSignedInfo, 0, sizeof(aSignedInfo)); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits