summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAshod Nakashian <ashod.nakashian@collabora.co.uk>2017-07-14 22:21:25 -0400
committerAshod Nakashian <ashnakash@gmail.com>2017-07-16 05:16:26 +0200
commitd38627b26ee80ae7e330fdedea1058d35a48b92b (patch)
treed0ea105b99b789ea23e6ef26eb48846bc026bf32
parentc7fe625c8d41f648f89765abc40bb7b8fd4ed12a (diff)
vcl: use svl signing and remove moved code
Change-Id: Id875a675d7ab649c9223ecca5de2da69ff4b8786 Reviewed-on: https://gerrit.libreoffice.org/39718 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
-rw-r--r--include/vcl/filter/pdfdocument.hxx2
-rw-r--r--vcl/source/filter/ipdf/pdfdocument.cxx13
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx1846
3 files changed, 18 insertions, 1843 deletions
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, &timestamp) != 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( )
{