include/vcl/filter/pdfdocument.hxx | 2 vcl/source/filter/ipdf/pdfdocument.cxx | 13 vcl/source/gdi/pdfwriter_impl.cxx | 1846 --------------------------------- 3 files changed, 18 insertions(+), 1843 deletions(-)
New commits: commit d38627b26ee80ae7e330fdedea1058d35a48b92b Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> Date: Fri Jul 14 22:21:25 2017 -0400 vcl: use svl signing and remove moved code Change-Id: Id875a675d7ab649c9223ecca5de2da69ff4b8786 Reviewed-on: https://gerrit.libreoffice.org/39718 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx index 362d5e637e9e..09288326e921 100644 --- a/include/vcl/filter/pdfdocument.hxx +++ b/include/vcl/filter/pdfdocument.hxx @@ -227,7 +227,7 @@ enum class XRefEntryType FREE, /// xref "n" or xref stream "1". NOT_COMPRESSED, - /// xref stream "2. + /// xref stream "2". COMPRESSED }; diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx index 1dd186e92801..6ec4ba98c1ca 100644 --- a/vcl/source/filter/ipdf/pdfdocument.cxx +++ b/vcl/source/filter/ipdf/pdfdocument.cxx @@ -25,6 +25,7 @@ #include <sal/log.hxx> #include <sal/types.h> #include <sax/tools/converter.hxx> +#include <svl/cryptosign.hxx> #include <tools/zcodec.hxx> #include <unotools/calendarwrapper.hxx> #include <unotools/datetime.hxx> @@ -837,14 +838,10 @@ bool PDFDocument::Sign(const uno::Reference<security::XCertificate>& xCertificat m_aEditBuffer.ReadBytes(aBuffer2.get(), nBufferSize2); OStringBuffer aCMSHexBuffer; - vcl::PDFWriter::PDFSignContext aSignContext(aCMSHexBuffer); - aSignContext.m_pDerEncoded = aDerEncoded.getArray(); - aSignContext.m_nDerEncoded = aDerEncoded.getLength(); - aSignContext.m_pByteRange1 = aBuffer1.get(); - aSignContext.m_nByteRange1 = nBufferSize1; - aSignContext.m_pByteRange2 = aBuffer2.get(); - aSignContext.m_nByteRange2 = nBufferSize2; - if (!vcl::PDFWriter::Sign(aSignContext)) + svl::crypto::Signing aSigning(xCertificate); + aSigning.AddDataRange(aBuffer1.get(), nBufferSize1); + aSigning.AddDataRange(aBuffer2.get(), nBufferSize2); + if (!aSigning.Sign(aCMSHexBuffer)) { SAL_WARN("vcl.filter", "PDFDocument::Sign: PDFWriter::Sign() failed"); return false; diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index ac9dec1c54b7..5fa7b9a40350 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -61,6 +61,7 @@ #include <tools/stream.hxx> #include <tools/urlobj.hxx> #include <tools/zcodec.hxx> +#include <svl/cryptosign.hxx> #include <vcl/bitmapex.hxx> #include <vcl/bitmapaccess.hxx> #include <vcl/cvtgrf.hxx> @@ -5382,1765 +5383,8 @@ bool PDFWriterImpl::emitSignature() return true; } -#if HAVE_FEATURE_NSS && !defined(_WIN32) - -namespace { - -char *PDFSigningPKCS7PasswordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg) -{ - return PL_strdup(static_cast<char *>(arg)); -} - -// ASN.1 used in the (much simpler) time stamp request. From RFC3161 -// and other sources. - -/* -AlgorithmIdentifier ::= SEQUENCE { - algorithm OBJECT IDENTIFIER, - parameters ANY DEFINED BY algorithm OPTIONAL } - -- contains a value of the type - -- registered for use with the - -- algorithm object identifier value - -MessageImprint ::= SEQUENCE { - hashAlgorithm AlgorithmIdentifier, - hashedMessage OCTET STRING } -*/ - -typedef struct { - SECAlgorithmID hashAlgorithm; - SECItem hashedMessage; -} MessageImprint; - -/* -Extension ::= SEQUENCE { - extnID OBJECT IDENTIFIER, - critical BOOLEAN DEFAULT FALSE, - extnValue OCTET STRING } -*/ - -typedef struct { - SECItem extnID; - SECItem critical; - SECItem extnValue; -} Extension; - -/* -Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension -*/ - -/* -TSAPolicyId ::= OBJECT IDENTIFIER - -TimeStampReq ::= SEQUENCE { - version INTEGER { v1(1) }, - messageImprint MessageImprint, - --a hash algorithm OID and the hash value of the data to be - --time-stamped - reqPolicy TSAPolicyId OPTIONAL, - nonce INTEGER OPTIONAL, - certReq BOOLEAN DEFAULT FALSE, - extensions [0] IMPLICIT Extensions OPTIONAL } -*/ - -typedef struct { - SECItem version; - MessageImprint messageImprint; - SECItem reqPolicy; - SECItem nonce; - SECItem certReq; - Extension *extensions; -} TimeStampReq; - -/** - * General name, defined by RFC 3280. - */ -struct GeneralName -{ - CERTName name; -}; - -/** - * List of general names (only one for now), defined by RFC 3280. - */ -struct GeneralNames -{ - GeneralName names; -}; - -/** - * Supplies different fields to identify a certificate, defined by RFC 5035. - */ -struct IssuerSerial -{ - GeneralNames issuer; - SECItem serialNumber; -}; - -/** - * Supplies different fields that are used to identify certificates, defined by - * RFC 5035. - */ -struct ESSCertIDv2 -{ - SECAlgorithmID hashAlgorithm; - SECItem certHash; - IssuerSerial issuerSerial; -}; - -/** - * This attribute uses the ESSCertIDv2 structure, defined by RFC 5035. - */ -struct SigningCertificateV2 -{ - ESSCertIDv2** certs; - - SigningCertificateV2() - : certs(nullptr) - { - } -}; - -// (Partial) ASN.1 for the time stamp response. Very complicated. Pulled -// together from various RFCs. - -/* -Accuracy ::= SEQUENCE { - seconds INTEGER OPTIONAL, - millis [0] INTEGER (1..999) OPTIONAL, - micros [1] INTEGER (1..999) OPTIONAL } - -PKIStatus ::= INTEGER { - granted (0), - -- when the PKIStatus contains the value zero a TimeStampToken, as requested, is present. - grantedWithMods (1), - -- when the PKIStatus contains the value one a TimeStampToken, with modifications, is present. - rejection (2), - waiting (3), - revocationWarning (4), - -- this message contains a warning that a revocation is - -- imminent - revocationNotification (5) - -- notification that a revocation has occurred -} - -PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String - -- text encoded as UTF-8 String [RFC3629] (note: each - -- UTF8String MAY include an [RFC3066] language tag - -- to indicate the language of the contained text - -- see [RFC2482] for details) - -PKIFailureInfo ::= BIT STRING { - badAlg (0), - -- unrecognized or unsupported Algorithm Identifier - badRequest (2), - -- transaction not permitted or supported - badDataFormat (5), - -- the data submitted has the wrong format - timeNotAvailable (14), - -- the TSA's time source is not available - unacceptedPolicy (15), - -- the requested TSA policy is not supported by the TSA. - unacceptedExtension (16), - -- the requested extension is not supported by the TSA. - addInfoNotAvailable (17), - -- the additional information requested could not be understood - -- or is not available - systemFailure (25) - -- the request cannot be handled due to system failure -} - -PKIStatusInfo ::= SEQUENCE { - status PKIStatus, - statusString PKIFreeText OPTIONAL, - failInfo PKIFailureInfo OPTIONAL } - -ContentType ::= OBJECT IDENTIFIER - -ContentInfo ::= SEQUENCE { - contentType ContentType, - content [0] EXPLICIT ANY DEFINED BY contentType } - -CMSVersion ::= INTEGER { v0(0), v1(1), v2(2), v3(3), v4(4), v5(5) } - -DigestAlgorithmIdentifier ::= AlgorithmIdentifier - -DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier - -ContentType ::= OBJECT IDENTIFIER - -EncapsulatedContentInfo ::= SEQUENCE { - eContentType ContentType, - eContent [0] EXPLICIT OCTET STRING OPTIONAL } - -OtherCertificateFormat ::= SEQUENCE { - otherCertFormat OBJECT IDENTIFIER, - otherCert ANY DEFINED BY otherCertFormat } - -CertificateChoices ::= CHOICE { - certificate Certificate, - extendedCertificate [0] IMPLICIT ExtendedCertificate, -- Obsolete - v1AttrCert [1] IMPLICIT AttributeCertificateV1, -- Obsolete - v2AttrCert [2] IMPLICIT AttributeCertificateV2, - other [3] IMPLICIT OtherCertificateFormat } - -CertificateSet ::= SET OF CertificateChoices - -CertificateList ::= SEQUENCE { - tbsCertList TBSCertList, - signatureAlgorithm AlgorithmIdentifier, - signatureValue BIT STRING } - -TBSCertList ::= SEQUENCE { - version Version OPTIONAL, - -- if present, MUST be v2 - signature AlgorithmIdentifier, - issuer Name, - thisUpdate Time, - nextUpdate Time OPTIONAL, - revokedCertificates SEQUENCE OF SEQUENCE { - userCertificate CertificateSerialNumber, - revocationDate Time, - crlEntryExtensions Extensions OPTIONAL - -- if present, version MUST be v2 - } OPTIONAL, - crlExtensions [0] EXPLICIT Extensions OPTIONAL - -- if present, version MUST be v2 - } - -OtherRevocationInfoFormat ::= SEQUENCE { - otherRevInfoFormat OBJECT IDENTIFIER, - otherRevInfo ANY DEFINED BY otherRevInfoFormat } - -RevocationInfoChoice ::= CHOICE { - crl CertificateList, - other [1] IMPLICIT OtherRevocationInfoFormat } - -RevocationInfoChoices ::= SET OF RevocationInfoChoice - -SignerIdentifier ::= CHOICE { - issuerAndSerialNumber IssuerAndSerialNumber, - subjectKeyIdentifier [0] SubjectKeyIdentifier } - -AttributeValue ::= ANY - -Attribute ::= SEQUENCE { - attrType OBJECT IDENTIFIER, - attrValues SET OF AttributeValue } - -SignedAttributes ::= SET SIZE (1..MAX) OF Attribute - -SignatureValue ::= OCTET STRING - -UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute - -SignerInfo ::= SEQUENCE { - version CMSVersion, - sid SignerIdentifier, - digestAlgorithm DigestAlgorithmIdentifier, - signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, - signatureAlgorithm SignatureAlgorithmIdentifier, - signature SignatureValue, - unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } - -SignerInfos ::= SET OF SignerInfo - -SignedData ::= SEQUENCE { - version CMSVersion, - digestAlgorithms DigestAlgorithmIdentifiers, - encapContentInfo EncapsulatedContentInfo, - certificates [0] IMPLICIT CertificateSet OPTIONAL, - crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, - signerInfos SignerInfos } - -TimeStampToken ::= ContentInfo - -- contentType is id-signedData as defined in [CMS] - -- content is SignedData as defined in([CMS]) - -- eContentType within SignedData is id-ct-TSTInfo - -- eContent within SignedData is TSTInfo - -TSTInfo ::= SEQUENCE { - version INTEGER { v1(1) }, - policy TSAPolicyId, - messageImprint MessageImprint, - -- MUST have the same value as the similar field in - -- TimeStampReq - serialNumber INTEGER, - -- Time-Stamping users MUST be ready to accommodate integers - -- up to 160 bits. - genTime GeneralizedTime, - accuracy Accuracy OPTIONAL, - ordering BOOLEAN DEFAULT FALSE, - nonce INTEGER OPTIONAL, - -- MUST be present if the similar field was present - -- in TimeStampReq. In that case it MUST have the same value. - tsa [0] GeneralName OPTIONAL, - extensions [1] IMPLICIT Extensions OPTIONAL } - -TimeStampResp ::= SEQUENCE { - status PKIStatusInfo, - timeStampToken TimeStampToken OPTIONAL } -*/ - -const SEC_ASN1Template MessageImprint_Template[] = -{ - { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(MessageImprint) }, - { SEC_ASN1_INLINE, offsetof(MessageImprint, hashAlgorithm), SECOID_AlgorithmIDTemplate, 0 }, - { SEC_ASN1_OCTET_STRING, offsetof(MessageImprint, hashedMessage), nullptr, 0 }, - { 0, 0, nullptr, 0 } -}; - -const SEC_ASN1Template Extension_Template[] = -{ - { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(Extension) }, - { SEC_ASN1_OBJECT_ID, offsetof(Extension, extnID), nullptr, 0 }, - { SEC_ASN1_BOOLEAN, offsetof(Extension, critical), nullptr, 0 }, - { SEC_ASN1_OCTET_STRING, offsetof(Extension, extnValue), nullptr, 0 }, - { 0, 0, nullptr, 0 } -}; - -const SEC_ASN1Template Extensions_Template[] = -{ - { SEC_ASN1_SEQUENCE_OF, 0, Extension_Template, 0 } -}; - -const SEC_ASN1Template TimeStampReq_Template[] = -{ - { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampReq) }, - { SEC_ASN1_INTEGER, offsetof(TimeStampReq, version), nullptr, 0 }, - { SEC_ASN1_INLINE, offsetof(TimeStampReq, messageImprint), MessageImprint_Template, 0 }, - { SEC_ASN1_OBJECT_ID | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, reqPolicy), nullptr, 0 }, - { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, nonce), nullptr, 0 }, - { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, certReq), nullptr, 0 }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(TimeStampReq, extensions), Extensions_Template, 0 }, - { 0, 0, nullptr, 0 } -}; - -/** - * GeneralName ::= CHOICE { - * otherName [0] OtherName, - * rfc822Name [1] IA5String, - * dNSName [2] IA5String, - * x400Address [3] ORAddress, - * directoryName [4] Name, - * ediPartyName [5] EDIPartyName, - * uniformResourceIdentifier [6] IA5String, - * iPAddress [7] OCTET STRING, - * registeredID [8] OBJECT IDENTIFIER - * } - */ -const SEC_ASN1Template GeneralNameTemplate[] = -{ - {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralName)}, - {SEC_ASN1_INLINE, offsetof(GeneralName, name), CERT_NameTemplate, 0}, - {0, 0, nullptr, 0} -}; - -/** - * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName - */ -const SEC_ASN1Template GeneralNamesTemplate[] = -{ - {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralNames)}, - {SEC_ASN1_INLINE | SEC_ASN1_CONTEXT_SPECIFIC | 4, offsetof(GeneralNames, names), GeneralNameTemplate, 0}, - {0, 0, nullptr, 0} -}; - -/** - * IssuerSerial ::= SEQUENCE { - * issuer GeneralNames, - * serialNumber CertificateSerialNumber - * } - */ -const SEC_ASN1Template IssuerSerialTemplate[] = -{ - {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(IssuerSerial)}, - {SEC_ASN1_INLINE, offsetof(IssuerSerial, issuer), GeneralNamesTemplate, 0}, - {SEC_ASN1_INTEGER, offsetof(IssuerSerial, serialNumber), nullptr, 0}, - {0, 0, nullptr, 0} -}; - -/** - * Hash ::= OCTET STRING - * - * ESSCertIDv2 ::= SEQUENCE { - * hashAlgorithm AlgorithmIdentifier DEFAULT {algorithm id-sha256}, - * certHash Hash, - * issuerSerial IssuerSerial OPTIONAL - * } - */ -const SEC_ASN1Template ESSCertIDv2Template[] = -{ - {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(ESSCertIDv2)}, - {SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, hashAlgorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), 0}, - {SEC_ASN1_OCTET_STRING, offsetof(ESSCertIDv2, certHash), nullptr, 0}, - {SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, issuerSerial), IssuerSerialTemplate, 0}, - {0, 0, nullptr, 0} -}; - -/** - * SigningCertificateV2 ::= SEQUENCE { - * } - */ -const SEC_ASN1Template SigningCertificateV2Template[] = -{ - {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(SigningCertificateV2)}, - {SEC_ASN1_SEQUENCE_OF, offsetof(SigningCertificateV2, certs), ESSCertIDv2Template, 0}, - {0, 0, nullptr, 0} -}; - -typedef struct { - SECItem status; - SECItem statusString; - SECItem failInfo; -} PKIStatusInfo; - -const SEC_ASN1Template PKIStatusInfo_Template[] = -{ - { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(PKIStatusInfo) }, - { SEC_ASN1_INTEGER, offsetof(PKIStatusInfo, status), nullptr, 0 }, - { SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, statusString), nullptr, 0 }, - { SEC_ASN1_BIT_STRING | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, failInfo), nullptr, 0 }, - { 0, 0, nullptr, 0 } -}; - -const SEC_ASN1Template Any_Template[] = -{ - { SEC_ASN1_ANY, 0, nullptr, sizeof(SECItem) } -}; - -typedef struct { - PKIStatusInfo status; - SECItem timeStampToken; -} TimeStampResp; - -const SEC_ASN1Template TimeStampResp_Template[] = -{ - { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampResp) }, - { SEC_ASN1_INLINE, offsetof(TimeStampResp, status), PKIStatusInfo_Template, 0 }, - { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, offsetof(TimeStampResp, timeStampToken), Any_Template, 0 }, - { 0, 0, nullptr, 0 } -}; - -/* Will see if these are needed or not -typedef struct { - SECItem seconds; - SECItem millis; - SECItem micros; -} Accuracy; - -const SEC_ASN1Template Integer_Template[] = -{ - { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) } -}; - -const SEC_ASN1Template Accuracy_Template[] = -{ - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(Accuracy) }, - { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(Accuracy, seconds), 0, 0 }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(Accuracy, millis), Integer_Template, 0 }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1, offsetof(Accuracy, micros), Integer_Template, 0 }, - { 0, 0, 0, 0 } -}; -*/ - -size_t AppendToBuffer(char *ptr, size_t size, size_t nmemb, void *userdata) -{ - OStringBuffer *pBuffer = static_cast<OStringBuffer*>(userdata); - pBuffer->append(ptr, size*nmemb); - - return size*nmemb; -} - -OUString PKIStatusToString(int n) -{ - switch (n) - { - case 0: return OUString("granted"); - case 1: return OUString("grantedWithMods"); - case 2: return OUString("rejection"); - case 3: return OUString("waiting"); - case 4: return OUString("revocationWarning"); - case 5: return OUString("revocationNotification"); - default: return "unknown (" + OUString::number(n) + ")"; - } -} - -OUString PKIStatusInfoToString(const PKIStatusInfo& rStatusInfo) -{ - OUString result; - - result += "{status="; - if (rStatusInfo.status.len == 1) - result += PKIStatusToString(rStatusInfo.status.data[0]); - else - result += "unknown (len=" + OUString::number(rStatusInfo.status.len); - - // FIXME: Perhaps look at rStatusInfo.statusString.data but note - // that we of course can't assume it contains proper UTF-8. After - // all, it is data from an external source. Also, RFC3161 claims - // it should be a SEQUENCE (1..MAX) OF UTF8String, but another - // source claimed it would be a single UTF8String, hmm? - - // FIXME: Worth it to decode failInfo to cleartext, probably not at least as long as this is only for a SAL_INFO - - result += "}"; - - return result; -} - -// SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() are -// not exported from libsmime, so copy them here. Sigh. - -SECStatus -my_SEC_StringToOID(SECItem *to, const char *from, PRUint32 len) -{ - PRUint32 decimal_numbers = 0; - PRUint32 result_bytes = 0; - SECStatus rv; - PRUint8 result[1024]; - - static const PRUint32 max_decimal = (0xffffffff / 10); - static const char OIDstring[] = {"OID."}; - - if (!from || !to) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if (!len) { - len = PL_strlen(from); - } - if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) { - from += 4; /* skip leading "OID." if present */ - len -= 4; - } - if (!len) { -bad_data: - PORT_SetError(SEC_ERROR_BAD_DATA); - return SECFailure; - } - do { - PRUint32 decimal = 0; - while (len > 0 && rtl::isAsciiDigit(static_cast<unsigned char>(*from))) { - PRUint32 addend = (*from++ - '0'); - --len; - if (decimal > max_decimal) /* overflow */ - goto bad_data; - decimal = (decimal * 10) + addend; - if (decimal < addend) /* overflow */ - goto bad_data; - } - if (len != 0 && *from != '.') { - goto bad_data; - } - if (decimal_numbers == 0) { - if (decimal > 2) - goto bad_data; - result[0] = decimal * 40; - result_bytes = 1; - } else if (decimal_numbers == 1) { - if (decimal > 40) - goto bad_data; - result[0] += decimal; - } else { - /* encode the decimal number, */ - PRUint8 * rp; - PRUint32 num_bytes = 0; - PRUint32 tmp = decimal; - while (tmp) { - num_bytes++; - tmp >>= 7; - } - if (!num_bytes ) - ++num_bytes; /* use one byte for a zero value */ - if (num_bytes + result_bytes > sizeof result) - goto bad_data; - tmp = num_bytes; - rp = result + result_bytes - 1; - rp[tmp] = (PRUint8)(decimal & 0x7f); - decimal >>= 7; - while (--tmp > 0) { - rp[tmp] = (PRUint8)(decimal | 0x80); - decimal >>= 7; - } - result_bytes += num_bytes; - } - ++decimal_numbers; - if (len > 0) { /* skip trailing '.' */ - ++from; - --len; - } - } while (len > 0); - /* now result contains result_bytes of data */ - if (to->data && to->len >= result_bytes) { - PORT_Memcpy(to->data, result, to->len = result_bytes); - rv = SECSuccess; - } else { - SECItem result_item = {siBuffer, nullptr, 0 }; - result_item.data = result; - result_item.len = result_bytes; - rv = SECITEM_CopyItem(nullptr, to, &result_item); - } - return rv; -} - -NSSCMSAttribute * -my_NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute **attrs, SECOidTag oidtag, PRBool only) -{ - SECOidData *oid; - NSSCMSAttribute *attr1, *attr2; - - if (attrs == nullptr) - return nullptr; - - oid = SECOID_FindOIDByTag(oidtag); - if (oid == nullptr) - return nullptr; - - while ((attr1 = *attrs++) != nullptr) { - if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data, - oid->oid.data, - oid->oid.len) == 0) - break; - } - - if (attr1 == nullptr) - return nullptr; - - if (!only) - return attr1; - - while ((attr2 = *attrs++) != nullptr) { - if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data, - oid->oid.data, - oid->oid.len) == 0) - break; - } - - if (attr2 != nullptr) - return nullptr; - - return attr1; -} - -SECStatus -my_NSS_CMSArray_Add(PLArenaPool *poolp, void ***array, void *obj) -{ - int n = 0; - void **dest; - - PORT_Assert(array != NULL); - if (array == nullptr) - return SECFailure; - - if (*array == nullptr) { - dest = static_cast<void **>(PORT_ArenaAlloc(poolp, 2 * sizeof(void *))); - } else { - void **p = *array; - while (*p++) - n++; - dest = static_cast<void **>(PORT_ArenaGrow (poolp, - *array, - (n + 1) * sizeof(void *), - (n + 2) * sizeof(void *))); - } - - if (dest == nullptr) - return SECFailure; - - dest[n] = obj; - dest[n+1] = nullptr; - *array = dest; - return SECSuccess; -} - -SECOidTag -my_NSS_CMSAttribute_GetType(NSSCMSAttribute *attr) -{ - SECOidData *typetag; - - typetag = SECOID_FindOID(&(attr->type)); - if (typetag == nullptr) - return SEC_OID_UNKNOWN; - - return typetag->offset; -} - -SECStatus -my_NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr) -{ - NSSCMSAttribute *oattr; - void *mark; - SECOidTag type; - - mark = PORT_ArenaMark(poolp); - - /* find oidtag of attr */ - type = my_NSS_CMSAttribute_GetType(attr); - - /* see if we have one already */ - oattr = my_NSS_CMSAttributeArray_FindAttrByOidTag(*attrs, type, PR_FALSE); - PORT_Assert (oattr == NULL); - if (oattr != nullptr) - goto loser; /* XXX or would it be better to replace it? */ - - /* no, shove it in */ - if (my_NSS_CMSArray_Add(poolp, reinterpret_cast<void ***>(attrs), static_cast<void *>(attr)) != SECSuccess) - goto loser; - - PORT_ArenaUnmark(poolp, mark); - return SECSuccess; - -loser: - PORT_ArenaRelease(poolp, mark); - return SECFailure; -} - -SECStatus -my_NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr) -{ - return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr); -} - -SECStatus -my_NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr) -{ - return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr); -} - -NSSCMSMessage *CreateCMSMessage(const PRTime* time, - NSSCMSSignedData **cms_sd, - NSSCMSSignerInfo **cms_signer, - CERTCertificate *cert, - SECItem *digest) -{ - NSSCMSMessage *result = NSS_CMSMessage_Create(nullptr); - if (!result) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSMessage_Create failed"); - return nullptr; - } - - *cms_sd = NSS_CMSSignedData_Create(result); - if (!*cms_sd) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_Create failed"); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(result); - if (NSS_CMSContentInfo_SetContent_SignedData(result, cms_cinfo, *cms_sd) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSContentInfo_SetContent_SignedData failed"); - NSS_CMSSignedData_Destroy(*cms_sd); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - cms_cinfo = NSS_CMSSignedData_GetContentInfo(*cms_sd); - - // Attach NULL data as detached data - if (NSS_CMSContentInfo_SetContent_Data(result, cms_cinfo, nullptr, PR_TRUE) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSContentInfo_SetContent_Data failed"); - NSS_CMSSignedData_Destroy(*cms_sd); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - *cms_signer = NSS_CMSSignerInfo_Create(result, cert, SEC_OID_SHA256); - if (!*cms_signer) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_Create failed"); - NSS_CMSSignedData_Destroy(*cms_sd); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - if (time && NSS_CMSSignerInfo_AddSigningTime(*cms_signer, *time) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_AddSigningTime failed"); - NSS_CMSSignedData_Destroy(*cms_sd); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - if (NSS_CMSSignerInfo_IncludeCerts(*cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_IncludeCerts failed"); - NSS_CMSSignedData_Destroy(*cms_sd); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - if (NSS_CMSSignedData_AddCertificate(*cms_sd, cert) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_AddCertificate failed"); - NSS_CMSSignedData_Destroy(*cms_sd); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - if (NSS_CMSSignedData_AddSignerInfo(*cms_sd, *cms_signer) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_AddSignerInfo failed"); - NSS_CMSSignedData_Destroy(*cms_sd); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - if (NSS_CMSSignedData_SetDigestValue(*cms_sd, SEC_OID_SHA256, digest) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_SetDigestValue failed"); - NSS_CMSSignedData_Destroy(*cms_sd); - NSS_CMSMessage_Destroy(result); - return nullptr; - } - - return result; -} - -} // anonymous namespace - -#endif // HAVE_FEATURE_NSS && !defined(_WIN32) - -#ifdef _WIN32 - -namespace -{ - -/// Counts how many bytes are needed to encode a given length. -size_t GetDERLengthOfLength(size_t nLength) -{ - size_t nRet = 1; - - if(nLength > 127) - { - while (nLength >> (nRet * 8)) - ++nRet; - // Long form means one additional byte: the length of the length and - // the length itself. - ++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 with the highest bit set to 1, not the actual length. - rStream.WriteUInt8(0x80 | (nLengthOfLength - 1)); - for (size_t i = 1; i < nLengthOfLength; ++i) - rStream.WriteUInt8(nLength >> ((nLengthOfLength - i - 1) * 8)); -} - -const unsigned nASN1_INTEGER = 0x02; -const unsigned nASN1_OCTET_STRING = 0x04; -const unsigned nASN1_NULL = 0x05; -const unsigned nASN1_OBJECT_IDENTIFIER = 0x06; -const unsigned nASN1_SEQUENCE = 0x10; -/// An explicit tag on a constructed value. -const unsigned nASN1_TAGGED_CONSTRUCTED = 0xa0; -const unsigned nASN1_CONSTRUCTED = 0x20; - -/// Create payload for the 'signing-certificate' signed attribute. -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 - // 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); - - // 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: 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(nASN1_SEQUENCE | nASN1_CONSTRUCTED); - WriteDERLength(rEncodedCertificate, nESSCertIDv2s); - // Write SEQUENCE OF ESSCertIDv2. - rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED); - WriteDERLength(rEncodedCertificate, nESSCertIDv2); - // Write ESSCertIDv2. - rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED); - WriteDERLength(rEncodedCertificate, nAlgorithmIdentifier + nCertHash + nIssuerSerial); - // Write AlgorithmIdentifier. - rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED); - WriteDERLength(rEncodedCertificate, nAlgorithm + nParameters); - // Write algorithm. - rEncodedCertificate.WriteUInt8(nASN1_OBJECT_IDENTIFIER); - WriteDERLength(rEncodedCertificate, aSHA256.size()); - rEncodedCertificate.WriteBytes(aSHA256.data(), aSHA256.size()); - // Write parameters. - rEncodedCertificate.WriteUInt8(nASN1_NULL); - rEncodedCertificate.WriteUInt8(0); - // Write certHash. - rEncodedCertificate.WriteUInt8(nASN1_OCTET_STRING); - WriteDERLength(rEncodedCertificate, aHash.size()); - rEncodedCertificate.WriteBytes(aHash.data(), aHash.size()); - // Write IssuerSerial. - rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED); - WriteDERLength(rEncodedCertificate, nGeneralNames + nCertificateSerialNumber); - // Write GeneralNames. - rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED); - WriteDERLength(rEncodedCertificate, nName); - // Write Name. - rEncodedCertificate.WriteUInt8(nASN1_TAGGED_CONSTRUCTED | 4); - WriteDERLength(rEncodedCertificate, nIssuer); - rEncodedCertificate.WriteBytes(pIssuer, nIssuer); - // Write CertificateSerialNumber. - rEncodedCertificate.WriteUInt8(nASN1_INTEGER); - WriteDERLength(rEncodedCertificate, nSerial); - rEncodedCertificate.WriteBytes(aSerial.data(), aSerial.size()); - - return true; -} -} // anonymous namespace - -#endif - -bool PDFWriter::Sign(PDFSignContext& rContext) -{ -#ifndef _WIN32 - - CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(rContext.m_pDerEncoded), rContext.m_nDerEncoded); - - if (!cert) - { - SAL_WARN("vcl.pdfwriter", "CERT_DecodeCertFromPackage failed"); - return false; - } - - std::vector<unsigned char> aHashResult; - { - comphelper::Hash aHash(comphelper::HashType::SHA256); - - aHash.update(static_cast<const unsigned char*>(rContext.m_pByteRange1), rContext.m_nByteRange1); - - aHash.update(static_cast<const unsigned char*>(rContext.m_pByteRange2), rContext.m_nByteRange2); - - aHashResult = aHash.finalize(); - } - SECItem digest; - digest.data = aHashResult.data(); - digest.len = aHashResult.size(); - -#ifdef DBG_UTIL - { - FILE *out = fopen("PDFWRITER.hash.data", "wb"); - fwrite(aHashResult.data(), SHA256_LENGTH, 1, out); - fclose(out); - } -#endif - - PRTime now = PR_Now(); - NSSCMSSignedData *cms_sd; - NSSCMSSignerInfo *cms_signer; - NSSCMSMessage *cms_msg = CreateCMSMessage(nullptr, &cms_sd, &cms_signer, cert, &digest); - if (!cms_msg) - return false; - - OString pass(OUStringToOString( rContext.m_aSignPassword, RTL_TEXTENCODING_UTF8 )); - - TimeStampReq src; - OStringBuffer response_buffer; - TimeStampResp response; - SECItem response_item; - NSSCMSAttribute timestamp; - SECItem values[2]; - SECItem *valuesp[2]; - valuesp[0] = values; - valuesp[1] = nullptr; - SECOidData typetag; - - if( !rContext.m_aSignTSA.isEmpty() ) - { - // Create another CMS message with the same contents as cms_msg, because it doesn't seem - // possible to encode a message twice (once to get something to timestamp, and then after - // adding the timestamp attribute). - - NSSCMSSignedData *ts_cms_sd; - NSSCMSSignerInfo *ts_cms_signer; - NSSCMSMessage *ts_cms_msg = CreateCMSMessage(&now, &ts_cms_sd, &ts_cms_signer, cert, &digest); - if (!ts_cms_msg) - { - return false; - } - - SECItem ts_cms_output; - ts_cms_output.data = nullptr; - ts_cms_output.len = 0; - PLArenaPool *ts_arena = PORT_NewArena(10000); - NSSCMSEncoderContext *ts_cms_ecx; - ts_cms_ecx = NSS_CMSEncoder_Start(ts_cms_msg, nullptr, nullptr, &ts_cms_output, ts_arena, PDFSigningPKCS7PasswordCallback, - const_cast<sal_Char*>(pass.getStr()), nullptr, nullptr, nullptr, nullptr); - - if (NSS_CMSEncoder_Finish(ts_cms_ecx) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSEncoder_Finish failed"); - return false; - } - - // I have compared the ts_cms_output produced here with the cms_output produced below, with - // the DONTCALLADDUNAUTHATTR env var set (i.e. without actually calling - // my_NSS_CMSSignerInfo_AddUnauthAttr()), and they are identical. - -#ifdef DBG_UTIL - { - FILE *out = fopen("PDFWRITER.ts_cms.data", "wb"); - fwrite(ts_cms_output.data, ts_cms_output.len, 1, out); - fclose(out); - } -#endif - - std::vector<unsigned char> aTsHashResult = comphelper::Hash::calculateHash(ts_cms_signer->encDigest.data, ts_cms_signer->encDigest.len, comphelper::HashType::SHA256); - SECItem ts_digest; - ts_digest.type = siBuffer; - ts_digest.data = aTsHashResult.data(); - ts_digest.len = aTsHashResult.size(); - -#ifdef DBG_UTIL - { - FILE *out = fopen("PDFWRITER.ts_hash.data", "wb"); - fwrite(aTsHashResult.data(), SHA256_LENGTH, 1, out); - fclose(out); - } -#endif - - unsigned char cOne = 1; - src.version.type = siUnsignedInteger; - src.version.data = &cOne; - src.version.len = sizeof(cOne); - - src.messageImprint.hashAlgorithm.algorithm.data = nullptr; - src.messageImprint.hashAlgorithm.parameters.data = nullptr; - SECOID_SetAlgorithmID(nullptr, &src.messageImprint.hashAlgorithm, SEC_OID_SHA256, nullptr); - src.messageImprint.hashedMessage = ts_digest; - - src.reqPolicy.type = siBuffer; - src.reqPolicy.data = nullptr; - src.reqPolicy.len = 0; - - unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32); - src.nonce.type = siUnsignedInteger; - src.nonce.data = reinterpret_cast<unsigned char*>(&nNonce); - src.nonce.len = sizeof(nNonce); - - src.certReq.type = siUnsignedInteger; - src.certReq.data = &cOne; - src.certReq.len = sizeof(cOne); - - src.extensions = nullptr; - - SECItem* timestamp_request = SEC_ASN1EncodeItem(nullptr, nullptr, &src, TimeStampReq_Template); - if (timestamp_request == nullptr) - { - SAL_WARN("vcl.pdfwriter", "SEC_ASN1EncodeItem failed"); - return false; - } - - if (timestamp_request->data == nullptr) - { - SAL_WARN("vcl.pdfwriter", "SEC_ASN1EncodeItem succeeded but got NULL data"); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - SAL_INFO("vcl.pdfwriter", "request length=" << timestamp_request->len); - -#ifdef DBG_UTIL - { - FILE *out = fopen("PDFWRITER.timestampreq.data", "wb"); - fwrite(timestamp_request->data, timestamp_request->len, 1, out); - fclose(out); - } -#endif - - // Send time stamp request to TSA server, receive response - - CURL* curl = curl_easy_init(); - CURLcode rc; - struct curl_slist* slist = nullptr; - - if (!curl) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_init failed"); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - SAL_INFO("vcl.pdfwriter", "Setting curl to verbose: " << (curl_easy_setopt(curl, CURLOPT_VERBOSE, 1) == CURLE_OK ? "OK" : "FAIL")); - - if ((rc = curl_easy_setopt(curl, CURLOPT_URL, OUStringToOString(rContext.m_aSignTSA, RTL_TEXTENCODING_UTF8).getStr())) != CURLE_OK) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_URL) failed: " << curl_easy_strerror(rc)); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - slist = curl_slist_append(slist, "Content-Type: application/timestamp-query"); - slist = curl_slist_append(slist, "Accept: application/timestamp-reply"); - - if ((rc = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist)) != CURLE_OK) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_HTTPHEADER) failed: " << curl_easy_strerror(rc)); - curl_slist_free_all(slist); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - if ((rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(timestamp_request->len))) != CURLE_OK || - (rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, timestamp_request->data)) != CURLE_OK) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_POSTFIELDSIZE or CURLOPT_POSTFIELDS) failed: " << curl_easy_strerror(rc)); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - if ((rc = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_buffer)) != CURLE_OK || - (rc = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToBuffer)) != CURLE_OK) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_WRITEDATA or CURLOPT_WRITEFUNCTION) failed: " << curl_easy_strerror(rc)); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - if ((rc = curl_easy_setopt(curl, CURLOPT_POST, 1)) != CURLE_OK) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_POST) failed: " << curl_easy_strerror(rc)); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - char error_buffer[CURL_ERROR_SIZE]; - if ((rc = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer)) != CURLE_OK) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_ERRORBUFFER) failed: " << curl_easy_strerror(rc)); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - // Use a ten second timeout - if ((rc = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10)) != CURLE_OK || - (rc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10)) != CURLE_OK) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_TIMEOUT or CURLOPT_CONNECTTIMEOUT) failed: " << curl_easy_strerror(rc)); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - if (curl_easy_perform(curl) != CURLE_OK) - { - SAL_WARN("vcl.pdfwriter", "curl_easy_perform failed: " << error_buffer); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - return false; - } - - SAL_INFO("vcl.pdfwriter", "PDF signing: got response, length=" << response_buffer.getLength()); - -#ifdef DBG_UTIL - { - FILE *out = fopen("PDFWRITER.reply.data", "wb"); - fwrite(response_buffer.getStr(), response_buffer.getLength(), 1, out); - fclose(out); - } -#endif - - curl_slist_free_all(slist); - curl_easy_cleanup(curl); - SECITEM_FreeItem(timestamp_request, PR_TRUE); - - memset(&response, 0, sizeof(response)); - - response_item.type = siBuffer; - response_item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(response_buffer.getStr())); - response_item.len = response_buffer.getLength(); - - if (SEC_ASN1DecodeItem(nullptr, &response, TimeStampResp_Template, &response_item) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "SEC_ASN1DecodeItem failed"); - return false; - } - - SAL_INFO("vcl.pdfwriter", "TimeStampResp received and decoded, status=" << PKIStatusInfoToString(response.status)); - - if (response.status.status.len != 1 || - (response.status.status.data[0] != 0 && response.status.status.data[0] != 1)) - { - SAL_WARN("vcl.pdfwriter", "Timestamp request was not granted"); - return false; - } - - // timestamp.type filled in below - - // Not sure if we actually need two entries in the values array, now when valuesp is an - // array too, the pointer to the values array followed by a null pointer. But I don't feel - // like experimenting. - values[0] = response.timeStampToken; - values[1].type = siBuffer; - values[1].data = nullptr; - values[1].len = 0; - - timestamp.values = valuesp; - - typetag.oid.data = nullptr; - // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1) - // member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) - // smime(16) aa(2) 14 } - if (my_SEC_StringToOID(&typetag.oid, "1.2.840.113549.1.9.16.2.14", 0) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "SEC_StringToOID failed"); - return false; - } - typetag.offset = SEC_OID_UNKNOWN; // ??? - typetag.desc = "id-aa-timeStampToken"; - typetag.mechanism = CKM_SHA_1; // ??? - typetag.supportedExtension = UNSUPPORTED_CERT_EXTENSION; // ??? - timestamp.typeTag = &typetag; - - timestamp.type = typetag.oid; // ??? - - timestamp.encoded = PR_TRUE; // ??? - -#ifdef DBG_UTIL - if (getenv("DONTCALLADDUNAUTHATTR")) - ; - else -#endif - if (my_NSS_CMSSignerInfo_AddUnauthAttr(cms_signer, ×tamp) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_AddUnauthAttr failed"); - return false; - } - } - - // Add the signing certificate as a signed attribute. - ESSCertIDv2* aCertIDs[2]; - ESSCertIDv2 aCertID; - // Write ESSCertIDv2.hashAlgorithm. - aCertID.hashAlgorithm.algorithm.data = nullptr; - aCertID.hashAlgorithm.parameters.data = nullptr; - SECOID_SetAlgorithmID(nullptr, &aCertID.hashAlgorithm, SEC_OID_SHA256, nullptr); - // Write ESSCertIDv2.certHash. - SECItem aCertHashItem; - auto pDerEncoded = reinterpret_cast<const unsigned char *>(rContext.m_pDerEncoded); - std::vector<unsigned char> aCertHashResult = comphelper::Hash::calculateHash(pDerEncoded, rContext.m_nDerEncoded, comphelper::HashType::SHA256); - aCertHashItem.type = siBuffer; - aCertHashItem.data = aCertHashResult.data(); - aCertHashItem.len = aCertHashResult.size(); - aCertID.certHash = aCertHashItem; - // Write ESSCertIDv2.issuerSerial. - IssuerSerial aSerial; - GeneralName aName; - aName.name = cert->issuer; - aSerial.issuer.names = aName; - aSerial.serialNumber = cert->serialNumber; - aCertID.issuerSerial = aSerial; - // Write SigningCertificateV2.certs. - aCertIDs[0] = &aCertID; - aCertIDs[1] = nullptr; - SigningCertificateV2 aCertificate; - aCertificate.certs = &aCertIDs[0]; - SECItem* pEncodedCertificate = SEC_ASN1EncodeItem(nullptr, nullptr, &aCertificate, SigningCertificateV2Template); - if (!pEncodedCertificate) - { - SAL_WARN("vcl.pdfwriter", "SEC_ASN1EncodeItem() failed"); - return false; - } - - NSSCMSAttribute aAttribute; - SECItem aAttributeValues[2]; - SECItem* pAttributeValues[2]; - pAttributeValues[0] = aAttributeValues; - pAttributeValues[1] = nullptr; - aAttributeValues[0] = *pEncodedCertificate; - aAttributeValues[1].type = siBuffer; - aAttributeValues[1].data = nullptr; - aAttributeValues[1].len = 0; - aAttribute.values = pAttributeValues; - - SECOidData aOidData; - aOidData.oid.data = nullptr; - /* - * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= - * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) - * smime(16) id-aa(2) 47 } - */ - if (my_SEC_StringToOID(&aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "my_SEC_StringToOID() failed"); - return false; - } - aOidData.offset = SEC_OID_UNKNOWN; - aOidData.desc = "id-aa-signingCertificateV2"; - aOidData.mechanism = CKM_SHA_1; - aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION; - aAttribute.typeTag = &aOidData; - aAttribute.type = aOidData.oid; - aAttribute.encoded = PR_TRUE; - - if (my_NSS_CMSSignerInfo_AddAuthAttr(cms_signer, &aAttribute) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "my_NSS_CMSSignerInfo_AddAuthAttr() failed"); - return false; - } - - SECItem cms_output; - cms_output.data = nullptr; - cms_output.len = 0; - PLArenaPool *arena = PORT_NewArena(10000); - NSSCMSEncoderContext *cms_ecx; - - // Possibly it would work to even just pass NULL for the password callback function and its - // argument here. After all, at least with the hardware token and associated software I tested - // with, the software itself pops up a dialog asking for the PIN (password). But I am not going - // to test it and risk locking up my token... - - cms_ecx = NSS_CMSEncoder_Start(cms_msg, nullptr, nullptr, &cms_output, arena, PDFSigningPKCS7PasswordCallback, - const_cast<sal_Char*>(pass.getStr()), nullptr, nullptr, nullptr, nullptr); - - if (!cms_ecx) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSEncoder_Start failed"); - return false; - } - - if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess) - { - SAL_WARN("vcl.pdfwriter", "NSS_CMSEncoder_Finish failed"); - return false; - } - -#ifdef DBG_UTIL - { - FILE *out = fopen("PDFWRITER.cms.data", "wb"); - fwrite(cms_output.data, cms_output.len, 1, out); - fclose(out); - } -#endif - - if (cms_output.len*2 > MAX_SIGNATURE_CONTENT_LENGTH) - { - SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << cms_output.len*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")"); - NSS_CMSMessage_Destroy(cms_msg); - return false; - } - - for (unsigned int i = 0; i < cms_output.len ; i++) - appendHex(cms_output.data[i], rContext.m_rCMSHexBuffer); - - SECITEM_FreeItem(pEncodedCertificate, PR_TRUE); - NSS_CMSMessage_Destroy(cms_msg); - - return true; - -#else // _WIN32 - PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(rContext.m_pDerEncoded), rContext.m_nDerEncoded); - if (pCertContext == nullptr) - { - SAL_WARN("vcl.pdfwriter", "CertCreateCertificateContext failed: " << WindowsErrorString(GetLastError())); - return false; - } - - CRYPT_SIGN_MESSAGE_PARA aPara; - - memset(&aPara, 0, sizeof(aPara)); - aPara.cbSize = sizeof(aPara); - aPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING; - aPara.pSigningCert = pCertContext; - aPara.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256); - aPara.HashAlgorithm.Parameters.cbData = 0; - aPara.cMsgCert = 1; - aPara.rgpMsgCert = &pCertContext; - - HCRYPTPROV hCryptProv; - DWORD nKeySpec; - BOOL bFreeNeeded; - - if (!CryptAcquireCertificatePrivateKey(pCertContext, - CRYPT_ACQUIRE_CACHE_FLAG, - nullptr, - &hCryptProv, - &nKeySpec, - &bFreeNeeded)) - { - SAL_WARN("vcl.pdfwriter", "CryptAcquireCertificatePrivateKey failed: " << WindowsErrorString(GetLastError())); - CertFreeCertificateContext(pCertContext); - return false; - } - assert(!bFreeNeeded); - - CMSG_SIGNER_ENCODE_INFO aSignerInfo; - - memset(&aSignerInfo, 0, sizeof(aSignerInfo)); - aSignerInfo.cbSize = sizeof(aSignerInfo); - aSignerInfo.pCertInfo = pCertContext->pCertInfo; - aSignerInfo.hCryptProv = hCryptProv; - aSignerInfo.dwKeySpec = nKeySpec; - aSignerInfo.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256); - aSignerInfo.HashAlgorithm.Parameters.cbData = 0; - - // Add the signing certificate as a signed attribute. - CRYPT_INTEGER_BLOB aCertificateBlob; - SvMemoryStream aEncodedCertificate; - if (!CreateSigningCertificateAttribute(rContext, pCertContext, 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 ::= - * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) - * smime(16) id-aa(2) 47 } - */ - aCertificateAttribute.pszObjId = const_cast<LPSTR>("1.2.840.113549.1.9.16.2.47"); - aCertificateAttribute.cValue = 1; - aCertificateAttribute.rgValue = &aCertificateBlob; - aSignerInfo.cAuthAttr = 1; - aSignerInfo.rgAuthAttr = &aCertificateAttribute; - - CMSG_SIGNED_ENCODE_INFO aSignedInfo; - memset(&aSignedInfo, 0, sizeof(aSignedInfo)); - aSignedInfo.cbSize = sizeof(aSignedInfo); - aSignedInfo.cSigners = 1; - aSignedInfo.rgSigners = &aSignerInfo; - - CERT_BLOB aCertBlob; - - aCertBlob.cbData = pCertContext->cbCertEncoded; - aCertBlob.pbData = pCertContext->pbCertEncoded; - - aSignedInfo.cCertEncoded = 1; - aSignedInfo.rgCertEncoded = &aCertBlob; - - HCRYPTMSG hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, - CMSG_DETACHED_FLAG, - CMSG_SIGNED, - &aSignedInfo, - nullptr, - nullptr); - if (!hMsg) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgOpenToEncode failed: " << WindowsErrorString(GetLastError())); - CertFreeCertificateContext(pCertContext); - return false; - } - - if (!CryptMsgUpdate(hMsg, static_cast<const BYTE *>(rContext.m_pByteRange1), rContext.m_nByteRange1, FALSE) || - !CryptMsgUpdate(hMsg, static_cast<const BYTE *>(rContext.m_pByteRange2), rContext.m_nByteRange2, TRUE)) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgUpdate failed: " << WindowsErrorString(GetLastError())); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - PCRYPT_TIMESTAMP_CONTEXT pTsContext = nullptr; - - if( !rContext.m_aSignTSA.isEmpty() ) - { - HCRYPTMSG hDecodedMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, - CMSG_DETACHED_FLAG, - CMSG_SIGNED, - NULL, - nullptr, - nullptr); - if (!hDecodedMsg) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgOpenToDecode failed: " << WindowsErrorString(GetLastError())); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - DWORD nTsSigLen = 0; - - if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, nullptr, &nTsSigLen)) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError())); - CryptMsgClose(hDecodedMsg); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - SAL_INFO("vcl.pdfwriter", "nTsSigLen=" << nTsSigLen); - - std::unique_ptr<BYTE[]> pTsSig(new BYTE[nTsSigLen]); - - if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, pTsSig.get(), &nTsSigLen)) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError())); - CryptMsgClose(hDecodedMsg); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - if (!CryptMsgUpdate(hDecodedMsg, pTsSig.get(), nTsSigLen, TRUE)) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgUpdate failed: " << WindowsErrorString(GetLastError())); - CryptMsgClose(hDecodedMsg); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - DWORD nDecodedSignerInfoLen = 0; - if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, nullptr, &nDecodedSignerInfoLen)) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsErrorString(GetLastError())); - CryptMsgClose(hDecodedMsg); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - std::unique_ptr<BYTE[]> pDecodedSignerInfoBuf(new BYTE[nDecodedSignerInfoLen]); - - if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, pDecodedSignerInfoBuf.get(), &nDecodedSignerInfoLen)) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsErrorString(GetLastError())); - CryptMsgClose(hDecodedMsg); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - CMSG_SIGNER_INFO *pDecodedSignerInfo = reinterpret_cast<CMSG_SIGNER_INFO *>(pDecodedSignerInfoBuf.get()); - - CRYPT_TIMESTAMP_PARA aTsPara; - unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32); - - aTsPara.pszTSAPolicyId = nullptr; - aTsPara.fRequestCerts = TRUE; - aTsPara.Nonce.cbData = sizeof(nNonce); - aTsPara.Nonce.pbData = reinterpret_cast<BYTE *>(&nNonce); - aTsPara.cExtension = 0; - aTsPara.rgExtension = nullptr; - - if (!CryptRetrieveTimeStamp(SAL_W(rContext.m_aSignTSA.getStr()), - 0, - 10000, - szOID_NIST_sha256, - &aTsPara, - pDecodedSignerInfo->EncryptedHash.pbData, - pDecodedSignerInfo->EncryptedHash.cbData, - &pTsContext, - nullptr, - nullptr)) - { - SAL_WARN("vcl.pdfwriter", "CryptRetrieveTimeStamp failed: " << WindowsErrorString(GetLastError())); - CryptMsgClose(hDecodedMsg); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - SAL_INFO("vcl.pdfwriter", "Time stamp size is " << pTsContext->cbEncoded << " bytes"); - -#ifdef DBG_UTIL - { - FILE *out = fopen("PDFWRITER.tstoken.data", "wb"); - fwrite(pTsContext->pbEncoded, pTsContext->cbEncoded, 1, out); - fclose(out); - } -#endif - - // I tried to use CryptMsgControl() with CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR to add the - // timestamp, but that failed with "The parameter is incorrect". Probably it is too late to - // modify the message once its data has already been encoded as part of the - // CryptMsgGetParam() with CMSG_BARE_CONTENT_PARAM above. So close the message and re-do its - // creation steps, but now with an amended aSignerInfo. - - CRYPT_INTEGER_BLOB aTimestampBlob; - aTimestampBlob.cbData = pTsContext->cbEncoded; - aTimestampBlob.pbData = pTsContext->pbEncoded; - - CRYPT_ATTRIBUTE aTimestampAttribute; - aTimestampAttribute.pszObjId = const_cast<LPSTR>( - "1.2.840.113549.1.9.16.2.14"); - aTimestampAttribute.cValue = 1; - aTimestampAttribute.rgValue = &aTimestampBlob; - - aSignerInfo.cUnauthAttr = 1; - aSignerInfo.rgUnauthAttr = &aTimestampAttribute; - - CryptMsgClose(hMsg); - - hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, - CMSG_DETACHED_FLAG, - CMSG_SIGNED, - &aSignedInfo, - nullptr, - nullptr); - if (!hMsg || - !CryptMsgUpdate(hMsg, static_cast<const BYTE *>(rContext.m_pByteRange1), rContext.m_nByteRange1, FALSE) || - !CryptMsgUpdate(hMsg, static_cast<const BYTE *>(rContext.m_pByteRange1), rContext.m_nByteRange2, TRUE)) - { - SAL_WARN("vcl.pdfwriter", "Re-creating the message failed: " << WindowsErrorString(GetLastError())); - CryptMemFree(pTsContext); - CryptMsgClose(hDecodedMsg); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - CryptMsgClose(hDecodedMsg); - } - - DWORD nSigLen = 0; - - if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, nullptr, &nSigLen)) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError())); - if (pTsContext) - CryptMemFree(pTsContext); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH) - { - SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")"); - if (pTsContext) - CryptMemFree(pTsContext); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - - SAL_INFO("vcl.pdfwriter", "Signature size is " << nSigLen << " bytes"); - std::unique_ptr<BYTE[]> pSig(new BYTE[nSigLen]); - - if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pSig.get(), &nSigLen)) - { - SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError())); - if (pTsContext) - CryptMemFree(pTsContext); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - return false; - } - -#ifdef DBG_UTIL - { - FILE *out = fopen("PDFWRITER.signature.data", "wb"); - fwrite(pSig.get(), nSigLen, 1, out); - fclose(out); - } -#endif - - // Release resources - if (pTsContext) - CryptMemFree(pTsContext); - CryptMsgClose(hMsg); - CertFreeCertificateContext(pCertContext); - - for (unsigned int i = 0; i < nSigLen ; i++) - appendHex(pSig[i], rContext.m_rCMSHexBuffer); - - return true; -#endif -} - bool PDFWriterImpl::finalizeSignature() { - if (!m_aContext.SignCertificate.is()) return false; @@ -7164,15 +5408,6 @@ bool PDFWriterImpl::finalizeSignature() } // 3- create the PKCS#7 object using NSS - css::uno::Sequence< sal_Int8 > derEncoded = m_aContext.SignCertificate->getEncoded(); - - if (!derEncoded.hasElements()) - return false; - - sal_Int8* n_derArray = derEncoded.getArray(); - sal_Int32 n_derLength = derEncoded.getLength(); - -#ifndef _WIN32 // Prepare buffer and calculate PDF file digest CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, 0)) ); @@ -7181,51 +5416,6 @@ bool PDFWriterImpl::finalizeSignature() sal_uInt64 bytesRead1; //FIXME: Check if hash is calculated from the correct byterange - CHECK_RETURN( (osl::File::E_None == m_aFile.read(buffer1.get(), m_nSignatureContentOffset - 1 , bytesRead1)) ); - if (bytesRead1 != (sal_uInt64)m_nSignatureContentOffset - 1) - SAL_WARN("vcl.pdfwriter", "First buffer read failed"); - - CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1)) ); - std::unique_ptr<char[]> buffer2(new char[nLastByteRangeNo + 1]); - sal_uInt64 bytesRead2; - CHECK_RETURN( (osl::File::E_None == m_aFile.read(buffer2.get(), nLastByteRangeNo, bytesRead2)) ); - if (bytesRead2 != (sal_uInt64) nLastByteRangeNo) - SAL_WARN("vcl.pdfwriter", "Second buffer read failed"); - - OStringBuffer cms_hexbuffer; - PDFWriter::PDFSignContext aSignContext(cms_hexbuffer); - aSignContext.m_pDerEncoded = n_derArray; - aSignContext.m_nDerEncoded = n_derLength; - aSignContext.m_pByteRange1 = buffer1.get(); - aSignContext.m_nByteRange1 = bytesRead1; - aSignContext.m_pByteRange2 = buffer2.get(); - aSignContext.m_nByteRange2 = bytesRead2; - aSignContext.m_aSignTSA = m_aContext.SignTSA; - aSignContext.m_aSignPassword = m_aContext.SignPassword; - if (!PDFWriter::Sign(aSignContext)) - { - SAL_WARN("vcl.pdfwriter", "PDFWriter::Sign() failed"); - return false; - } - - assert(cms_hexbuffer.getLength() <= MAX_SIGNATURE_CONTENT_LENGTH); - - // Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object - nWritten = 0; - CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset)) ); - m_aFile.write(cms_hexbuffer.getStr(), cms_hexbuffer.getLength(), nWritten); - - CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, nOffset)) ); - return true; - -#else - - // Prepare buffer and calculate PDF file digest - CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, 0)) ); - - std::unique_ptr<char[]> buffer1(new char[m_nSignatureContentOffset - 1]); - sal_uInt64 bytesRead1; - if (osl::File::E_None != m_aFile.read(buffer1.get(), m_nSignatureContentOffset - 1 , bytesRead1) || bytesRead1 != (sal_uInt64)m_nSignatureContentOffset - 1) { @@ -7233,7 +5423,7 @@ bool PDFWriterImpl::finalizeSignature() return false; } - std::unique_ptr<char[]> buffer2(new char[nLastByteRangeNo]); + std::unique_ptr<char[]> buffer2(new char[nLastByteRangeNo + 1]); sal_uInt64 bytesRead2; if (osl::File::E_None != m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1) || @@ -7244,42 +5434,30 @@ bool PDFWriterImpl::finalizeSignature() return false; } - OStringBuffer cms_hexbuffer; - PDFWriter::PDFSignContext aSignContext(cms_hexbuffer); - aSignContext.m_pDerEncoded = n_derArray; - aSignContext.m_nDerEncoded = n_derLength; - aSignContext.m_pByteRange1 = buffer1.get(); - aSignContext.m_nByteRange1 = bytesRead1; - aSignContext.m_pByteRange2 = buffer2.get(); - aSignContext.m_nByteRange2 = bytesRead2; - aSignContext.m_aSignTSA = m_aContext.SignTSA; - aSignContext.m_aSignPassword = m_aContext.SignPassword; - if (!PDFWriter::Sign(aSignContext)) + OStringBuffer aCMSHexBuffer; + svl::crypto::Signing aSigning(m_aContext.SignCertificate); + aSigning.AddDataRange(buffer1.get(), bytesRead1); + aSigning.AddDataRange(buffer2.get(), bytesRead2); + aSigning.SetSignTSA(m_aContext.SignTSA); + aSigning.SetSignPassword(m_aContext.SignPassword); + if (!aSigning.Sign(aCMSHexBuffer)) { SAL_WARN("vcl.pdfwriter", "PDFWriter::Sign() failed"); return false; } - assert(cms_hexbuffer.getLength() <= MAX_SIGNATURE_CONTENT_LENGTH); + assert(aCMSHexBuffer.getLength() <= MAX_SIGNATURE_CONTENT_LENGTH); // Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object nWritten = 0; CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset)) ); - m_aFile.write(cms_hexbuffer.getStr(), cms_hexbuffer.getLength(), nWritten); + m_aFile.write(aCMSHexBuffer.getStr(), aCMSHexBuffer.getLength(), nWritten); CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, nOffset)) ); - return true; -#endif } -#else // !HAVE_FEATURE_NSS -bool PDFWriter::Sign(PDFSignContext& /*rContext*/) -{ - // Not implemented. - return false; -} -#endif +#endif //HAVE_FEATURE_NSS sal_Int32 PDFWriterImpl::emitInfoDict( ) { _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits