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>
This commit is contained in:
Miklos Vajna
2016-11-29 15:41:57 +01:00
parent 379b7ffb68
commit e1446e9e25

View File

@@ -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
// 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 + 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;
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;