[Libreoffice-commits] core.git: vcl/source
Miklos Vajna
vmiklos at collabora.co.uk
Thu Nov 24 10:18:48 UTC 2016
vcl/source/gdi/pdfwriter_impl.cxx | 115 ++++++++++++++++++++++++++++++++++----
1 file changed, 105 insertions(+), 10 deletions(-)
New commits:
commit b12410f212658996fdb5fb291a06038e9ac39b2e
Author: Miklos Vajna <vmiklos at 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 <vmiklos at collabora.co.uk>
Tested-by: Jenkins <ci at 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));
More information about the Libreoffice-commits
mailing list