[Libreoffice-commits] core.git: vcl/source

Miklos Vajna vmiklos at collabora.co.uk
Wed Nov 30 08:04:28 UTC 2016


 vcl/source/gdi/pdfwriter_impl.cxx |  108 +++++++++++++++++++++++++++++---------
 1 file changed, 85 insertions(+), 23 deletions(-)

New commits:
commit e1446e9e25f784a730c0399ba64b52b36a01a91c
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Nov 29 15:41:57 2016 +0100

    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 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 cd391ca..5d74d67 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;


More information about the Libreoffice-commits mailing list