diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-11-29 15:41:57 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-11-30 08:03:59 +0000 |
commit | e1446e9e25f784a730c0399ba64b52b36a01a91c (patch) | |
tree | 7616524ac0d248ed50201f5eb6b071e140ceed4c /vcl | |
parent | 379b7ffb68bed5bc376a91032a781be147a6eff1 (diff) |
vcl mscrypto PDF sign: write IssuerSerial sequence
It fixes a problem detected by the PAdES validator from
<https://github.com/esig/dss>, and with this the Windows output is in
sync with NSS.
Change-Id: Iff6eb441eebb730f08e399cb3012e0156f0397d9
Reviewed-on: https://gerrit.libreoffice.org/31376
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 108 |
1 files changed, 85 insertions, 23 deletions
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index cd391ca5481f..5d74d67a674b 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6159,14 +6159,41 @@ namespace { /// Counts how many bytes are needed to encode a given length. -size_t GetLengthOfLength(size_t nLength) +size_t GetDERLengthOfLength(size_t nLength) { - assert(nLength <= 127); - return 1; + size_t nRet = 1; + + if(nLength > 127) + { + // Long form means at least two bytes: the length of the length and the + // length itself. + ++nRet; + while (nLength >> (nRet * 8)) + ++nRet; + } + return nRet; +} + +/// Writes the length part of the header. +void WriteDERLength(SvStream& rStream, size_t nLength) +{ + size_t nLengthOfLength = GetDERLengthOfLength(nLength); + if (nLengthOfLength == 1) + { + // We can use the short form. + rStream.WriteUInt8(nLength); + return; + } + + // 0x80 means that the we use the long form: the first byte is the length + // of length, not the actual length. + rStream.WriteUInt8(0x80 | (nLengthOfLength - 1)); + for (size_t i = 1; i < nLengthOfLength; ++i) + rStream.WriteUInt8(nLength >> ((nLengthOfLength - i - 1) * 8)); } /// Create payload for the 'signing-certificate' signed attribute. -bool CreateSigningCertificateAttribute(vcl::PDFWriter::PDFSignContext& rContext, SvStream& rEncodedCertificate) +bool CreateSigningCertificateAttribute(vcl::PDFWriter::PDFSignContext& rContext, PCCERT_CONTEXT pCertContext, SvStream& rEncodedCertificate) { // CryptEncodeObjectEx() does not support encoding arbitrary ASN.1 // structures, like SigningCertificateV2 from RFC 5035, so let's build it @@ -6213,46 +6240,81 @@ bool CreateSigningCertificateAttribute(vcl::PDFWriter::PDFSignContext& rContext, CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); + // Collect info for IssuerSerial. + BYTE* pIssuer = pCertContext->pCertInfo->Issuer.pbData; + DWORD nIssuer = pCertContext->pCertInfo->Issuer.cbData; + BYTE* pSerial = pCertContext->pCertInfo->SerialNumber.pbData; + DWORD nSerial = pCertContext->pCertInfo->SerialNumber.cbData; + // pSerial is LE, aSerial is BE. + std::vector<BYTE> aSerial(nSerial); + for (size_t i = 0; i < nSerial; ++i) + aSerial[i] = *(pSerial + nSerial - i - 1); + // 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 = 1 + GetLengthOfLength(aSHA256.size()) + aSHA256.size(); - size_t nParameters = 1 + GetLengthOfLength(1); - size_t nAlgorithmIdentifier = 1 + GetLengthOfLength(nAlgorithm + nParameters) + nAlgorithm + nParameters; - size_t nCertHash = 1 + GetLengthOfLength(aHash.size()) + aHash.size(); - size_t nESSCertIDv2 = 1 + GetLengthOfLength(nAlgorithmIdentifier + nCertHash) + nAlgorithmIdentifier + nCertHash; - size_t nESSCertIDv2s = 1 + GetLengthOfLength(nESSCertIDv2) + nESSCertIDv2; + // SEQUENCE: ESSCertIDv2 + // SEQUENCE: AlgorithmIdentifier + // OBJECT: algorithm + // NULL: parameters + // OCTET STRING: certHash + // SEQUENCE: IssuerSerial + // SEQUENCE: GeneralNames + // cont [ 4 ]: Name + // SEQUENCE: Issuer blob + // INTEGER: CertificateSerialNumber + + size_t nAlgorithm = 1 + GetDERLengthOfLength(aSHA256.size()) + aSHA256.size(); + size_t nParameters = 1 + GetDERLengthOfLength(1); + size_t nAlgorithmIdentifier = 1 + GetDERLengthOfLength(nAlgorithm + nParameters) + nAlgorithm + nParameters; + size_t nCertHash = 1 + GetDERLengthOfLength(aHash.size()) + aHash.size(); + size_t nName = 1 + GetDERLengthOfLength(nIssuer) + nIssuer; + size_t nGeneralNames = 1 + GetDERLengthOfLength(nName) + nName; + size_t nCertificateSerialNumber = 1 + GetDERLengthOfLength(nSerial) + nSerial; + size_t nIssuerSerial = 1 + GetDERLengthOfLength(nGeneralNames + nCertificateSerialNumber) + nGeneralNames + nCertificateSerialNumber; + size_t nESSCertIDv2 = 1 + GetDERLengthOfLength(nAlgorithmIdentifier + nCertHash + nIssuerSerial) + nAlgorithmIdentifier + nCertHash + nIssuerSerial; + size_t nESSCertIDv2s = 1 + GetDERLengthOfLength(nESSCertIDv2) + nESSCertIDv2; // Write SigningCertificateV2. rEncodedCertificate.WriteUInt8(0x30); - rEncodedCertificate.WriteUInt8(nESSCertIDv2s); + WriteDERLength(rEncodedCertificate, nESSCertIDv2s); // Write SEQUENCE OF ESSCertIDv2. rEncodedCertificate.WriteUInt8(0x30); - rEncodedCertificate.WriteUInt8(nESSCertIDv2); + WriteDERLength(rEncodedCertificate, nESSCertIDv2); // Write ESSCertIDv2. rEncodedCertificate.WriteUInt8(0x30); - rEncodedCertificate.WriteUInt8(nAlgorithmIdentifier + nCertHash); + WriteDERLength(rEncodedCertificate, nAlgorithmIdentifier + nCertHash + nIssuerSerial); // Write AlgorithmIdentifier. rEncodedCertificate.WriteUInt8(0x30); - rEncodedCertificate.WriteUInt8(nAlgorithm + nParameters); + WriteDERLength(rEncodedCertificate, nAlgorithm + nParameters); // Write algorithm. rEncodedCertificate.WriteUInt8(0x06); - rEncodedCertificate.WriteUInt8(aSHA256.size()); + WriteDERLength(rEncodedCertificate, 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()); + WriteDERLength(rEncodedCertificate, aHash.size()); rEncodedCertificate.WriteBytes(aHash.data(), aHash.size()); + // Write IssuerSerial. + rEncodedCertificate.WriteUInt8(0x30); + WriteDERLength(rEncodedCertificate, nGeneralNames + nCertificateSerialNumber); + // Write GeneralNames. + rEncodedCertificate.WriteUInt8(0x30); + WriteDERLength(rEncodedCertificate, nName); + // Write Name. + // 0xa0 means we're writing an explicit tag on a constructed value, the + // rest is the tag number. + rEncodedCertificate.WriteUInt8(0xa0 | 4); + WriteDERLength(rEncodedCertificate, nIssuer); + rEncodedCertificate.WriteBytes(pIssuer, nIssuer); + // Write CertificateSerialNumber. + rEncodedCertificate.WriteUInt8(0x02); + WriteDERLength(rEncodedCertificate, nSerial); + rEncodedCertificate.WriteBytes(aSerial.data(), aSerial.size()); return true; } @@ -6794,7 +6856,7 @@ bool PDFWriter::Sign(PDFSignContext& rContext) // Add the signing certificate as a signed attribute. CRYPT_INTEGER_BLOB aCertificateBlob; SvMemoryStream aEncodedCertificate; - if (!CreateSigningCertificateAttribute(rContext, aEncodedCertificate)) + if (!CreateSigningCertificateAttribute(rContext, pCertContext, aEncodedCertificate)) { SAL_WARN("vcl.pdfwriter", "CreateSigningCertificateAttribute() failed"); return false; |