[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