Update git submodules
[LibreOffice.git] / svl / source / crypto / cryptosign.cxx
blobc1f18f64796204a5a14da373b36d044cf51742c9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <sal/config.h>
12 #include <algorithm>
14 #include <svl/cryptosign.hxx>
15 #include <svl/sigstruct.hxx>
16 #include <config_crypto.h>
17 #include <o3tl/numeric.hxx>
19 #if USE_CRYPTO_NSS
20 #include <systools/curlinit.hxx>
21 #endif
23 #include <rtl/character.hxx>
24 #include <rtl/strbuf.hxx>
25 #include <rtl/string.hxx>
26 #include <sal/log.hxx>
27 #include <tools/datetime.hxx>
28 #include <tools/stream.hxx>
29 #include <comphelper/base64.hxx>
30 #include <comphelper/hash.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/random.hxx>
33 #include <comphelper/scopeguard.hxx>
34 #include <comphelper/lok.hxx>
35 #include <com/sun/star/security/XCertificate.hpp>
36 #include <com/sun/star/uno/Sequence.hxx>
37 #include <o3tl/char16_t2wchar_t.hxx>
39 #if USE_CRYPTO_NSS
40 // NSS headers for PDF signing
41 #include <cert.h>
42 #include <keyhi.h>
43 #include <pk11pub.h>
44 #include <hasht.h>
45 #include <secerr.h>
46 #include <sechash.h>
47 #include <cms.h>
48 #include <cmst.h>
50 // We use curl for RFC3161 time stamp requests
51 #include <curl/curl.h>
53 #include <com/sun/star/xml/crypto/DigestID.hpp>
54 #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
55 #include <mutex>
56 #endif
58 #if USE_CRYPTO_MSCAPI
59 // WinCrypt headers for PDF signing
60 // Note: this uses Windows 7 APIs and requires the relevant data types
61 #include <prewin.h>
62 #include <wincrypt.h>
63 #include <postwin.h>
64 #include <comphelper/windowserrorstring.hxx>
65 #endif
67 using namespace com::sun::star;
69 namespace {
70 #if USE_CRYPTO_NSS
71 char *PDFSigningPKCS7PasswordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg)
73 return PL_strdup(static_cast<char *>(arg));
76 // ASN.1 used in the (much simpler) time stamp request. From RFC3161
77 // and other sources.
80 AlgorithmIdentifier ::= SEQUENCE {
81 algorithm OBJECT IDENTIFIER,
82 parameters ANY DEFINED BY algorithm OPTIONAL }
83 -- contains a value of the type
84 -- registered for use with the
85 -- algorithm object identifier value
87 MessageImprint ::= SEQUENCE {
88 hashAlgorithm AlgorithmIdentifier,
89 hashedMessage OCTET STRING }
92 struct MessageImprint {
93 SECAlgorithmID hashAlgorithm;
94 SECItem hashedMessage;
98 Extension ::= SEQUENCE {
99 extnID OBJECT IDENTIFIER,
100 critical BOOLEAN DEFAULT FALSE,
101 extnValue OCTET STRING }
104 struct Extension {
105 SECItem extnID;
106 SECItem critical;
107 SECItem extnValue;
111 Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
115 TSAPolicyId ::= OBJECT IDENTIFIER
117 TimeStampReq ::= SEQUENCE {
118 version INTEGER { v1(1) },
119 messageImprint MessageImprint,
120 --a hash algorithm OID and the hash value of the data to be
121 --time-stamped
122 reqPolicy TSAPolicyId OPTIONAL,
123 nonce INTEGER OPTIONAL,
124 certReq BOOLEAN DEFAULT FALSE,
125 extensions [0] IMPLICIT Extensions OPTIONAL }
128 struct TimeStampReq {
129 SECItem version;
130 MessageImprint messageImprint;
131 SECItem reqPolicy;
132 SECItem nonce;
133 SECItem certReq;
134 Extension *extensions;
138 * General name, defined by RFC 3280.
140 struct GeneralName
142 CERTName name;
146 * List of general names (only one for now), defined by RFC 3280.
148 struct GeneralNames
150 GeneralName names;
154 * Supplies different fields to identify a certificate, defined by RFC 5035.
156 struct IssuerSerial
158 GeneralNames issuer;
159 SECItem serialNumber;
163 * Supplies different fields that are used to identify certificates, defined by
164 * RFC 5035.
166 struct ESSCertIDv2
168 SECAlgorithmID hashAlgorithm;
169 SECItem certHash;
170 IssuerSerial issuerSerial;
174 * This attribute uses the ESSCertIDv2 structure, defined by RFC 5035.
176 struct SigningCertificateV2
178 ESSCertIDv2** certs;
180 SigningCertificateV2()
181 : certs(nullptr)
187 * GeneralName ::= CHOICE {
188 * otherName [0] OtherName,
189 * rfc822Name [1] IA5String,
190 * dNSName [2] IA5String,
191 * x400Address [3] ORAddress,
192 * directoryName [4] Name,
193 * ediPartyName [5] EDIPartyName,
194 * uniformResourceIdentifier [6] IA5String,
195 * iPAddress [7] OCTET STRING,
196 * registeredID [8] OBJECT IDENTIFIER
199 const SEC_ASN1Template GeneralNameTemplate[] =
201 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralName)},
202 {SEC_ASN1_INLINE, offsetof(GeneralName, name), CERT_NameTemplate, 0},
203 {0, 0, nullptr, 0}
207 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
209 const SEC_ASN1Template GeneralNamesTemplate[] =
211 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralNames)},
212 {SEC_ASN1_INLINE | SEC_ASN1_CONTEXT_SPECIFIC | 4, offsetof(GeneralNames, names), GeneralNameTemplate, 0},
213 {0, 0, nullptr, 0}
217 * IssuerSerial ::= SEQUENCE {
218 * issuer GeneralNames,
219 * serialNumber CertificateSerialNumber
222 const SEC_ASN1Template IssuerSerialTemplate[] =
224 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(IssuerSerial)},
225 {SEC_ASN1_INLINE, offsetof(IssuerSerial, issuer), GeneralNamesTemplate, 0},
226 {SEC_ASN1_INTEGER, offsetof(IssuerSerial, serialNumber), nullptr, 0},
227 {0, 0, nullptr, 0}
232 * Hash ::= OCTET STRING
234 * ESSCertIDv2 ::= SEQUENCE {
235 * hashAlgorithm AlgorithmIdentifier DEFAULT {algorithm id-sha256},
236 * certHash Hash,
237 * issuerSerial IssuerSerial OPTIONAL
241 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
243 const SEC_ASN1Template ESSCertIDv2Template[] =
245 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(ESSCertIDv2)},
246 {SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, hashAlgorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), 0},
247 {SEC_ASN1_OCTET_STRING, offsetof(ESSCertIDv2, certHash), nullptr, 0},
248 {SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, issuerSerial), IssuerSerialTemplate, 0},
249 {0, 0, nullptr, 0}
253 * SigningCertificateV2 ::= SEQUENCE {
256 const SEC_ASN1Template SigningCertificateV2Template[] =
258 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(SigningCertificateV2)},
259 {SEC_ASN1_SEQUENCE_OF, offsetof(SigningCertificateV2, certs), ESSCertIDv2Template, 0},
260 {0, 0, nullptr, 0}
263 struct PKIStatusInfo {
264 SECItem status;
265 SECItem statusString;
266 SECItem failInfo;
269 const SEC_ASN1Template PKIStatusInfo_Template[] =
271 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(PKIStatusInfo) },
272 { SEC_ASN1_INTEGER, offsetof(PKIStatusInfo, status), nullptr, 0 },
273 { SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, statusString), nullptr, 0 },
274 { SEC_ASN1_BIT_STRING | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, failInfo), nullptr, 0 },
275 { 0, 0, nullptr, 0 }
278 const SEC_ASN1Template Any_Template[] =
280 { SEC_ASN1_ANY, 0, nullptr, sizeof(SECItem) }
283 struct TimeStampResp {
284 PKIStatusInfo status;
285 SECItem timeStampToken;
288 const SEC_ASN1Template TimeStampResp_Template[] =
290 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampResp) },
291 { SEC_ASN1_INLINE, offsetof(TimeStampResp, status), PKIStatusInfo_Template, 0 },
292 { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, offsetof(TimeStampResp, timeStampToken), Any_Template, 0 },
293 { 0, 0, nullptr, 0 }
296 const SEC_ASN1Template MessageImprint_Template[] =
298 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(MessageImprint) },
299 { SEC_ASN1_INLINE, offsetof(MessageImprint, hashAlgorithm), SECOID_AlgorithmIDTemplate, 0 },
300 { SEC_ASN1_OCTET_STRING, offsetof(MessageImprint, hashedMessage), nullptr, 0 },
301 { 0, 0, nullptr, 0 }
304 const SEC_ASN1Template Extension_Template[] =
306 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(Extension) },
307 { SEC_ASN1_OBJECT_ID, offsetof(Extension, extnID), nullptr, 0 },
308 { SEC_ASN1_BOOLEAN, offsetof(Extension, critical), nullptr, 0 },
309 { SEC_ASN1_OCTET_STRING, offsetof(Extension, extnValue), nullptr, 0 },
310 { 0, 0, nullptr, 0 }
313 const SEC_ASN1Template Extensions_Template[] =
315 { SEC_ASN1_SEQUENCE_OF, 0, Extension_Template, 0 }
318 const SEC_ASN1Template TimeStampReq_Template[] =
320 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampReq) },
321 { SEC_ASN1_INTEGER, offsetof(TimeStampReq, version), nullptr, 0 },
322 { SEC_ASN1_INLINE, offsetof(TimeStampReq, messageImprint), MessageImprint_Template, 0 },
323 { SEC_ASN1_OBJECT_ID | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, reqPolicy), nullptr, 0 },
324 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, nonce), nullptr, 0 },
325 { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, certReq), nullptr, 0 },
326 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(TimeStampReq, extensions), Extensions_Template, 0 },
327 { 0, 0, nullptr, 0 }
330 size_t AppendToBuffer(char const *ptr, size_t size, size_t nmemb, void *userdata)
332 OStringBuffer *pBuffer = static_cast<OStringBuffer*>(userdata);
333 pBuffer->append(ptr, size*nmemb);
335 return size*nmemb;
338 OUString PKIStatusToString(int n)
340 switch (n)
342 case 0: return u"granted"_ustr;
343 case 1: return u"grantedWithMods"_ustr;
344 case 2: return u"rejection"_ustr;
345 case 3: return u"waiting"_ustr;
346 case 4: return u"revocationWarning"_ustr;
347 case 5: return u"revocationNotification"_ustr;
348 default: return "unknown (" + OUString::number(n) + ")";
352 OUString PKIStatusInfoToString(const PKIStatusInfo& rStatusInfo)
354 OUString result = u"{status="_ustr;
355 if (rStatusInfo.status.len == 1)
356 result += PKIStatusToString(rStatusInfo.status.data[0]);
357 else
358 result += "unknown (len=" + OUString::number(rStatusInfo.status.len);
360 // FIXME: Perhaps look at rStatusInfo.statusString.data but note
361 // that we of course can't assume it contains proper UTF-8. After
362 // all, it is data from an external source. Also, RFC3161 claims
363 // it should be a SEQUENCE (1..MAX) OF UTF8String, but another
364 // source claimed it would be a single UTF8String, hmm?
366 // FIXME: Worth it to decode failInfo to cleartext, probably not at least as long as this is only for a SAL_INFO
368 result += "}";
370 return result;
373 // SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() are
374 // not exported from libsmime, so copy them here. Sigh.
376 SECStatus
377 my_SEC_StringToOID(SECItem *to, const char *from, PRUint32 len)
379 PRUint32 decimal_numbers = 0;
380 PRUint32 result_bytes = 0;
381 SECStatus rv;
382 PRUint8 result[1024];
384 static const PRUint32 max_decimal = 0xffffffff / 10;
385 static const char OIDstring[] = {"OID."};
387 if (!from || !to) {
388 PORT_SetError(SEC_ERROR_INVALID_ARGS);
389 return SECFailure;
391 if (!len) {
392 len = PL_strlen(from);
394 if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
395 from += 4; /* skip leading "OID." if present */
396 len -= 4;
398 if (!len) {
399 bad_data:
400 PORT_SetError(SEC_ERROR_BAD_DATA);
401 return SECFailure;
403 do {
404 PRUint32 decimal = 0;
405 while (len > 0 && rtl::isAsciiDigit(static_cast<unsigned char>(*from))) {
406 PRUint32 addend = *from++ - '0';
407 --len;
408 if (decimal > max_decimal) /* overflow */
409 goto bad_data;
410 decimal = (decimal * 10) + addend;
411 if (decimal < addend) /* overflow */
412 goto bad_data;
414 if (len != 0 && *from != '.') {
415 goto bad_data;
417 if (decimal_numbers == 0) {
418 if (decimal > 2)
419 goto bad_data;
420 result[0] = decimal * 40;
421 result_bytes = 1;
422 } else if (decimal_numbers == 1) {
423 if (decimal > 40)
424 goto bad_data;
425 result[0] += decimal;
426 } else {
427 /* encode the decimal number, */
428 PRUint8 * rp;
429 PRUint32 num_bytes = 0;
430 PRUint32 tmp = decimal;
431 while (tmp) {
432 num_bytes++;
433 tmp >>= 7;
435 if (!num_bytes )
436 ++num_bytes; /* use one byte for a zero value */
437 if (num_bytes + result_bytes > sizeof result)
438 goto bad_data;
439 tmp = num_bytes;
440 rp = result + result_bytes - 1;
441 rp[tmp] = static_cast<PRUint8>(decimal & 0x7f);
442 decimal >>= 7;
443 while (--tmp > 0) {
444 rp[tmp] = static_cast<PRUint8>(decimal | 0x80);
445 decimal >>= 7;
447 result_bytes += num_bytes;
449 ++decimal_numbers;
450 if (len > 0) { /* skip trailing '.' */
451 ++from;
452 --len;
454 } while (len > 0);
455 /* now result contains result_bytes of data */
456 if (to->data && to->len >= result_bytes) {
457 to->len = result_bytes;
458 PORT_Memcpy(to->data, result, to->len);
459 rv = SECSuccess;
460 } else {
461 SECItem result_item = {siBuffer, nullptr, 0 };
462 result_item.data = result;
463 result_item.len = result_bytes;
464 rv = SECITEM_CopyItem(nullptr, to, &result_item);
466 return rv;
469 NSSCMSAttribute *
470 my_NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute **attrs, SECOidTag oidtag, PRBool only)
472 SECOidData *oid;
473 NSSCMSAttribute *attr1, *attr2;
475 if (attrs == nullptr)
476 return nullptr;
478 oid = SECOID_FindOIDByTag(oidtag);
479 if (oid == nullptr)
480 return nullptr;
482 while ((attr1 = *attrs++) != nullptr) {
483 if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
484 oid->oid.data,
485 oid->oid.len) == 0)
486 break;
489 if (attr1 == nullptr)
490 return nullptr;
492 if (!only)
493 return attr1;
495 while ((attr2 = *attrs++) != nullptr) {
496 if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
497 oid->oid.data,
498 oid->oid.len) == 0)
499 break;
502 if (attr2 != nullptr)
503 return nullptr;
505 return attr1;
508 SECStatus
509 my_NSS_CMSArray_Add(PLArenaPool *poolp, void ***array, void *obj)
511 int n = 0;
512 void **dest;
514 PORT_Assert(array != NULL);
515 if (array == nullptr)
516 return SECFailure;
518 if (*array == nullptr) {
519 dest = static_cast<void **>(PORT_ArenaAlloc(poolp, 2 * sizeof(void *)));
520 } else {
521 void **p = *array;
522 while (*p++)
523 n++;
524 dest = static_cast<void **>(PORT_ArenaGrow (poolp,
525 *array,
526 (n + 1) * sizeof(void *),
527 (n + 2) * sizeof(void *)));
530 if (dest == nullptr)
531 return SECFailure;
533 dest[n] = obj;
534 dest[n+1] = nullptr;
535 *array = dest;
536 return SECSuccess;
539 SECOidTag
540 my_NSS_CMSAttribute_GetType(const NSSCMSAttribute *attr)
542 SECOidData *typetag;
544 typetag = SECOID_FindOID(&(attr->type));
545 if (typetag == nullptr)
546 return SEC_OID_UNKNOWN;
548 return typetag->offset;
551 SECStatus
552 my_NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr)
554 NSSCMSAttribute *oattr;
555 void *mark;
556 SECOidTag type;
558 mark = PORT_ArenaMark(poolp);
560 /* find oidtag of attr */
561 type = my_NSS_CMSAttribute_GetType(attr);
563 /* see if we have one already */
564 oattr = my_NSS_CMSAttributeArray_FindAttrByOidTag(*attrs, type, PR_FALSE);
565 PORT_Assert (oattr == NULL);
566 if (oattr != nullptr)
567 goto loser; /* XXX or would it be better to replace it? */
569 /* no, shove it in */
570 if (my_NSS_CMSArray_Add(poolp, reinterpret_cast<void ***>(attrs), static_cast<void *>(attr)) != SECSuccess)
571 goto loser;
573 PORT_ArenaUnmark(poolp, mark);
574 return SECSuccess;
576 loser:
577 PORT_ArenaRelease(poolp, mark);
578 return SECFailure;
581 SECStatus
582 my_NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
584 return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
587 SECStatus
588 my_NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
590 return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
593 NSSCMSMessage *CreateCMSMessage(const PRTime* time,
594 NSSCMSSignedData **cms_sd,
595 NSSCMSSignerInfo **cms_signer,
596 CERTCertificate *cert,
597 SECItem *digest)
599 NSSCMSMessage *result = NSS_CMSMessage_Create(nullptr);
600 if (!result)
602 SAL_WARN("svl.crypto", "NSS_CMSMessage_Create failed");
603 return nullptr;
606 *cms_sd = NSS_CMSSignedData_Create(result);
607 if (!*cms_sd)
609 SAL_WARN("svl.crypto", "NSS_CMSSignedData_Create failed");
610 NSS_CMSMessage_Destroy(result);
611 return nullptr;
614 NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(result);
615 if (NSS_CMSContentInfo_SetContent_SignedData(result, cms_cinfo, *cms_sd) != SECSuccess)
617 SAL_WARN("svl.crypto", "NSS_CMSContentInfo_SetContent_SignedData failed");
618 NSS_CMSSignedData_Destroy(*cms_sd);
619 NSS_CMSMessage_Destroy(result);
620 return nullptr;
623 cms_cinfo = NSS_CMSSignedData_GetContentInfo(*cms_sd);
625 // Attach NULL data as detached data
626 if (NSS_CMSContentInfo_SetContent_Data(result, cms_cinfo, nullptr, PR_TRUE) != SECSuccess)
628 SAL_WARN("svl.crypto", "NSS_CMSContentInfo_SetContent_Data failed");
629 NSS_CMSSignedData_Destroy(*cms_sd);
630 NSS_CMSMessage_Destroy(result);
631 return nullptr;
634 // workaround: with legacy "dbm:", NSS can't find the private key - try out
635 // if it works, and fallback if it doesn't.
636 if (SECKEYPrivateKey * pPrivateKey = PK11_FindKeyByAnyCert(cert, nullptr))
638 if (!comphelper::LibreOfficeKit::isActive())
640 // pPrivateKey only exists in the memory in the LOK case, don't delete it.
641 SECKEY_DestroyPrivateKey(pPrivateKey);
643 *cms_signer = NSS_CMSSignerInfo_Create(result, cert, SEC_OID_SHA256);
645 else
647 pPrivateKey = PK11_FindKeyByDERCert(cert->slot, cert, nullptr);
648 SECKEYPublicKey *const pPublicKey = CERT_ExtractPublicKey(cert);
649 if (pPublicKey && pPrivateKey)
651 *cms_signer = NSS_CMSSignerInfo_CreateWithSubjKeyID(result, &cert->subjectKeyID, pPublicKey, pPrivateKey, SEC_OID_SHA256);
652 SECKEY_DestroyPrivateKey(pPrivateKey);
653 SECKEY_DestroyPublicKey(pPublicKey);
654 if (*cms_signer)
656 // this is required in NSS_CMSSignerInfo_IncludeCerts()
657 // (and NSS_CMSSignerInfo_GetSigningCertificate() doesn't work)
658 (**cms_signer).cert = CERT_DupCertificate(cert);
662 if (!*cms_signer)
664 SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_Create failed");
665 NSS_CMSSignedData_Destroy(*cms_sd);
666 NSS_CMSMessage_Destroy(result);
667 return nullptr;
670 if (time && NSS_CMSSignerInfo_AddSigningTime(*cms_signer, *time) != SECSuccess)
672 SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_AddSigningTime failed");
673 NSS_CMSSignedData_Destroy(*cms_sd);
674 NSS_CMSMessage_Destroy(result);
675 return nullptr;
678 if (NSS_CMSSignerInfo_IncludeCerts(*cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
680 SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_IncludeCerts failed");
681 NSS_CMSSignedData_Destroy(*cms_sd);
682 NSS_CMSMessage_Destroy(result);
683 return nullptr;
686 if (NSS_CMSSignedData_AddCertificate(*cms_sd, cert) != SECSuccess)
688 SAL_WARN("svl.crypto", "NSS_CMSSignedData_AddCertificate failed");
689 NSS_CMSSignedData_Destroy(*cms_sd);
690 NSS_CMSMessage_Destroy(result);
691 return nullptr;
694 if (NSS_CMSSignedData_AddSignerInfo(*cms_sd, *cms_signer) != SECSuccess)
696 SAL_WARN("svl.crypto", "NSS_CMSSignedData_AddSignerInfo failed");
697 NSS_CMSSignedData_Destroy(*cms_sd);
698 NSS_CMSMessage_Destroy(result);
699 return nullptr;
702 if (NSS_CMSSignedData_SetDigestValue(*cms_sd, SEC_OID_SHA256, digest) != SECSuccess)
704 SAL_WARN("svl.crypto", "NSS_CMSSignedData_SetDigestValue failed");
705 NSS_CMSSignedData_Destroy(*cms_sd);
706 NSS_CMSMessage_Destroy(result);
707 return nullptr;
710 return result;
713 #elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
715 /// Counts how many bytes are needed to encode a given length.
716 size_t GetDERLengthOfLength(size_t nLength)
718 size_t nRet = 1;
720 if(nLength > 127)
722 while (nLength >> (nRet * 8))
723 ++nRet;
724 // Long form means one additional byte: the length of the length and
725 // the length itself.
726 ++nRet;
728 return nRet;
731 /// Writes the length part of the header.
732 void WriteDERLength(SvStream& rStream, size_t nLength)
734 size_t nLengthOfLength = GetDERLengthOfLength(nLength);
735 if (nLengthOfLength == 1)
737 // We can use the short form.
738 rStream.WriteUInt8(nLength);
739 return;
742 // 0x80 means that the we use the long form: the first byte is the length
743 // of length with the highest bit set to 1, not the actual length.
744 rStream.WriteUInt8(0x80 | (nLengthOfLength - 1));
745 for (size_t i = 1; i < nLengthOfLength; ++i)
746 rStream.WriteUInt8(nLength >> ((nLengthOfLength - i - 1) * 8));
749 const unsigned nASN1_INTEGER = 0x02;
750 const unsigned nASN1_OCTET_STRING = 0x04;
751 const unsigned nASN1_NULL = 0x05;
752 const unsigned nASN1_OBJECT_IDENTIFIER = 0x06;
753 const unsigned nASN1_SEQUENCE = 0x10;
754 /// An explicit tag on a constructed value.
755 const unsigned nASN1_TAGGED_CONSTRUCTED = 0xa0;
756 const unsigned nASN1_CONSTRUCTED = 0x20;
758 /// Create payload for the 'signing-certificate' signed attribute.
759 bool CreateSigningCertificateAttribute(void const * pDerEncoded, int nDerEncoded, PCCERT_CONTEXT pCertContext, SvStream& rEncodedCertificate)
761 // CryptEncodeObjectEx() does not support encoding arbitrary ASN.1
762 // structures, like SigningCertificateV2 from RFC 5035, so let's build it
763 // manually.
765 // Count the certificate hash and put it to aHash.
766 // 2.16.840.1.101.3.4.2.1, i.e. sha256.
767 std::vector<unsigned char> aSHA256{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01};
769 HCRYPTPROV hProv = 0;
770 if (!CryptAcquireContextW(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
772 SAL_WARN("svl.crypto", "CryptAcquireContext() failed");
773 return false;
776 HCRYPTHASH hHash = 0;
777 if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
779 SAL_WARN("svl.crypto", "CryptCreateHash() failed");
780 return false;
783 if (!CryptHashData(hHash, static_cast<const BYTE*>(pDerEncoded), nDerEncoded, 0))
785 SAL_WARN("svl.crypto", "CryptHashData() failed");
786 return false;
789 DWORD nHash = 0;
790 if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nHash, 0))
792 SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash length");
793 return false;
796 std::vector<unsigned char> aHash(nHash);
797 if (!CryptGetHashParam(hHash, HP_HASHVAL, aHash.data(), &nHash, 0))
799 SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash");
800 return false;
803 CryptDestroyHash(hHash);
804 CryptReleaseContext(hProv, 0);
806 // Collect info for IssuerSerial.
807 BYTE* pIssuer = pCertContext->pCertInfo->Issuer.pbData;
808 DWORD nIssuer = pCertContext->pCertInfo->Issuer.cbData;
809 BYTE* pSerial = pCertContext->pCertInfo->SerialNumber.pbData;
810 DWORD nSerial = pCertContext->pCertInfo->SerialNumber.cbData;
811 // pSerial is LE, aSerial is BE.
812 std::vector<BYTE> aSerial(nSerial);
813 for (size_t i = 0; i < nSerial; ++i)
814 aSerial[i] = *(pSerial + nSerial - i - 1);
816 // We now have all the info to count the lengths.
817 // The layout of the payload is:
818 // SEQUENCE: SigningCertificateV2
819 // SEQUENCE: SEQUENCE OF ESSCertIDv2
820 // SEQUENCE: ESSCertIDv2
821 // SEQUENCE: AlgorithmIdentifier
822 // OBJECT: algorithm
823 // NULL: parameters
824 // OCTET STRING: certHash
825 // SEQUENCE: IssuerSerial
826 // SEQUENCE: GeneralNames
827 // cont [ 4 ]: Name
828 // SEQUENCE: Issuer blob
829 // INTEGER: CertificateSerialNumber
831 size_t nAlgorithm = 1 + GetDERLengthOfLength(aSHA256.size()) + aSHA256.size();
832 size_t nParameters = 1 + GetDERLengthOfLength(1);
833 size_t nAlgorithmIdentifier = 1 + GetDERLengthOfLength(nAlgorithm + nParameters) + nAlgorithm + nParameters;
834 size_t nCertHash = 1 + GetDERLengthOfLength(aHash.size()) + aHash.size();
835 size_t nName = 1 + GetDERLengthOfLength(nIssuer) + nIssuer;
836 size_t nGeneralNames = 1 + GetDERLengthOfLength(nName) + nName;
837 size_t nCertificateSerialNumber = 1 + GetDERLengthOfLength(nSerial) + nSerial;
838 size_t nIssuerSerial = 1 + GetDERLengthOfLength(nGeneralNames + nCertificateSerialNumber) + nGeneralNames + nCertificateSerialNumber;
839 size_t nESSCertIDv2 = 1 + GetDERLengthOfLength(nAlgorithmIdentifier + nCertHash + nIssuerSerial) + nAlgorithmIdentifier + nCertHash + nIssuerSerial;
840 size_t nESSCertIDv2s = 1 + GetDERLengthOfLength(nESSCertIDv2) + nESSCertIDv2;
842 // Write SigningCertificateV2.
843 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
844 WriteDERLength(rEncodedCertificate, nESSCertIDv2s);
845 // Write SEQUENCE OF ESSCertIDv2.
846 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
847 WriteDERLength(rEncodedCertificate, nESSCertIDv2);
848 // Write ESSCertIDv2.
849 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
850 WriteDERLength(rEncodedCertificate, nAlgorithmIdentifier + nCertHash + nIssuerSerial);
851 // Write AlgorithmIdentifier.
852 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
853 WriteDERLength(rEncodedCertificate, nAlgorithm + nParameters);
854 // Write algorithm.
855 rEncodedCertificate.WriteUInt8(nASN1_OBJECT_IDENTIFIER);
856 WriteDERLength(rEncodedCertificate, aSHA256.size());
857 rEncodedCertificate.WriteBytes(aSHA256.data(), aSHA256.size());
858 // Write parameters.
859 rEncodedCertificate.WriteUInt8(nASN1_NULL);
860 rEncodedCertificate.WriteUInt8(0);
861 // Write certHash.
862 rEncodedCertificate.WriteUInt8(nASN1_OCTET_STRING);
863 WriteDERLength(rEncodedCertificate, aHash.size());
864 rEncodedCertificate.WriteBytes(aHash.data(), aHash.size());
865 // Write IssuerSerial.
866 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
867 WriteDERLength(rEncodedCertificate, nGeneralNames + nCertificateSerialNumber);
868 // Write GeneralNames.
869 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
870 WriteDERLength(rEncodedCertificate, nName);
871 // Write Name.
872 rEncodedCertificate.WriteUInt8(nASN1_TAGGED_CONSTRUCTED | 4);
873 WriteDERLength(rEncodedCertificate, nIssuer);
874 rEncodedCertificate.WriteBytes(pIssuer, nIssuer);
875 // Write CertificateSerialNumber.
876 rEncodedCertificate.WriteUInt8(nASN1_INTEGER);
877 WriteDERLength(rEncodedCertificate, nSerial);
878 rEncodedCertificate.WriteBytes(aSerial.data(), aSerial.size());
880 return true;
882 #endif // USE_CRYPTO_MSCAPI
884 } // anonymous namespace
886 namespace svl::crypto {
888 std::vector<unsigned char> DecodeHexString(std::string_view rHex)
890 std::vector<unsigned char> aRet;
891 size_t nHexLen = rHex.size();
893 int nByte = 0;
894 int nCount = 2;
895 for (size_t i = 0; i < nHexLen; ++i)
897 nByte = nByte << 4;
898 sal_Int8 nParsed = o3tl::convertToHex<int>(rHex[i]);
899 if (nParsed == -1)
901 SAL_WARN("svl.crypto", "DecodeHexString: invalid hex value");
902 return aRet;
904 nByte += nParsed;
905 --nCount;
906 if (!nCount)
908 aRet.push_back(nByte);
909 nCount = 2;
910 nByte = 0;
915 return aRet;
918 bool Signing::Sign(OStringBuffer& rCMSHexBuffer)
920 #if !USE_CRYPTO_ANY
921 (void)rCMSHexBuffer;
922 (void)m_rSigningContext;
923 return false;
924 #else
925 // Create the PKCS#7 object.
926 css::uno::Sequence<sal_Int8> aDerEncoded;
927 if (m_rSigningContext.m_xCertificate.is())
929 aDerEncoded = m_rSigningContext.m_xCertificate->getEncoded();
930 if (!aDerEncoded.hasElements())
932 SAL_WARN("svl.crypto", "Crypto::Signing: empty certificate");
933 return false;
937 #if USE_CRYPTO_NSS
938 std::vector<unsigned char> aHashResult;
940 comphelper::Hash aHash(comphelper::HashType::SHA256);
942 for (const auto& pair : m_dataBlocks)
943 aHash.update(static_cast<const unsigned char*>(pair.first), pair.second);
945 aHashResult = aHash.finalize();
947 SECItem digest;
948 digest.data = aHashResult.data();
949 digest.len = aHashResult.size();
951 PRTime now = PR_Now();
953 // The context unit is milliseconds, PR_Now() unit is microseconds.
954 if (m_rSigningContext.m_nSignatureTime)
956 now = m_rSigningContext.m_nSignatureTime * 1000;
958 else
960 m_rSigningContext.m_nSignatureTime = now / 1000;
963 if (!m_rSigningContext.m_xCertificate.is())
965 m_rSigningContext.m_aDigest = std::move(aHashResult);
966 // No certificate is provided: don't actually sign -- just update the context with the
967 // parameters for the signing and return.
968 return false;
971 CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(aDerEncoded.getArray()), aDerEncoded.getLength());
973 if (!cert)
975 SAL_WARN("svl.crypto", "CERT_DecodeCertFromPackage failed");
976 return false;
979 NSSCMSSignedData *cms_sd(nullptr);
980 NSSCMSSignerInfo *cms_signer(nullptr);
981 NSSCMSMessage *cms_msg = CreateCMSMessage(nullptr, &cms_sd, &cms_signer, cert, &digest);
982 if (!cms_msg)
983 return false;
985 OString pass(OUStringToOString( m_aSignPassword, RTL_TEXTENCODING_UTF8 ));
987 // Add the signing certificate as a signed attribute.
988 ESSCertIDv2* aCertIDs[2];
989 ESSCertIDv2 aCertID;
990 // Write ESSCertIDv2.hashAlgorithm.
991 aCertID.hashAlgorithm.algorithm.data = nullptr;
992 aCertID.hashAlgorithm.parameters.data = nullptr;
993 SECOID_SetAlgorithmID(nullptr, &aCertID.hashAlgorithm, SEC_OID_SHA256, nullptr);
994 comphelper::ScopeGuard aAlgoGuard(
995 [&aCertID] () { SECOID_DestroyAlgorithmID(&aCertID.hashAlgorithm, false); } );
996 // Write ESSCertIDv2.certHash.
997 SECItem aCertHashItem;
998 auto pDerEncoded = reinterpret_cast<const unsigned char *>(aDerEncoded.getArray());
999 std::vector<unsigned char> aCertHashResult = comphelper::Hash::calculateHash(pDerEncoded, aDerEncoded.getLength(), comphelper::HashType::SHA256);
1000 aCertHashItem.type = siBuffer;
1001 aCertHashItem.data = aCertHashResult.data();
1002 aCertHashItem.len = aCertHashResult.size();
1003 aCertID.certHash = aCertHashItem;
1004 // Write ESSCertIDv2.issuerSerial.
1005 IssuerSerial aSerial;
1006 GeneralName aName;
1007 aName.name = cert->issuer;
1008 aSerial.issuer.names = aName;
1009 aSerial.serialNumber = cert->serialNumber;
1010 aCertID.issuerSerial = aSerial;
1011 // Write SigningCertificateV2.certs.
1012 aCertIDs[0] = &aCertID;
1013 aCertIDs[1] = nullptr;
1014 SigningCertificateV2 aCertificate;
1015 aCertificate.certs = &aCertIDs[0];
1016 SECItem* pEncodedCertificate = SEC_ASN1EncodeItem(nullptr, nullptr, &aCertificate, SigningCertificateV2Template);
1017 if (!pEncodedCertificate)
1019 SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem() failed");
1020 return false;
1023 NSSCMSAttribute aAttribute;
1024 SECItem aAttributeValues[2];
1025 SECItem* pAttributeValues[2];
1026 pAttributeValues[0] = aAttributeValues;
1027 pAttributeValues[1] = nullptr;
1028 aAttributeValues[0] = *pEncodedCertificate;
1029 aAttributeValues[1].type = siBuffer;
1030 aAttributeValues[1].data = nullptr;
1031 aAttributeValues[1].len = 0;
1032 aAttribute.values = pAttributeValues;
1034 SECOidData aOidData;
1035 aOidData.oid.data = nullptr;
1037 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
1038 * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
1039 * smime(16) id-aa(2) 47 }
1041 if (my_SEC_StringToOID(&aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess)
1043 SAL_WARN("svl.crypto", "my_SEC_StringToOID() failed");
1044 return false;
1046 comphelper::ScopeGuard aGuard(
1047 [&aOidData] () { SECITEM_FreeItem(&aOidData.oid, false); } );
1048 aOidData.offset = SEC_OID_UNKNOWN;
1049 aOidData.desc = "id-aa-signingCertificateV2";
1050 aOidData.mechanism = CKM_SHA_1;
1051 aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
1052 aAttribute.typeTag = &aOidData;
1053 aAttribute.type = aOidData.oid;
1054 aAttribute.encoded = PR_TRUE;
1056 if (my_NSS_CMSSignerInfo_AddAuthAttr(cms_signer, &aAttribute) != SECSuccess)
1058 SAL_WARN("svl.crypto", "my_NSS_CMSSignerInfo_AddAuthAttr() failed");
1059 return false;
1062 TimeStampReq src;
1063 OStringBuffer response_buffer;
1064 TimeStampResp response;
1065 SECItem response_item;
1066 NSSCMSAttribute timestamp;
1067 SECItem values[2];
1068 SECItem *valuesp[2];
1069 valuesp[0] = values;
1070 valuesp[1] = nullptr;
1071 SECOidData typetag;
1073 //NOTE: All signed/authenticated attributes are to be added before the following hash computation
1074 if( !m_aSignTSA.isEmpty() )
1076 // Create another CMS message with the same contents as cms_msg, because it doesn't seem
1077 // possible to encode a message twice (once to get something to timestamp, and then after
1078 // adding the timestamp attribute).
1080 NSSCMSSignedData *ts_cms_sd;
1081 NSSCMSSignerInfo *ts_cms_signer;
1082 NSSCMSMessage *ts_cms_msg = CreateCMSMessage(&now, &ts_cms_sd, &ts_cms_signer, cert, &digest);
1083 if (!ts_cms_msg)
1085 return false;
1088 PORT_Memcpy(ts_cms_signer, cms_signer, sizeof(NSSCMSSignerInfo));
1090 SECItem ts_cms_output;
1091 ts_cms_output.data = nullptr;
1092 ts_cms_output.len = 0;
1093 PLArenaPool *ts_arena = PORT_NewArena(10000);
1094 NSSCMSEncoderContext *ts_cms_ecx;
1095 ts_cms_ecx = NSS_CMSEncoder_Start(ts_cms_msg, nullptr, nullptr, &ts_cms_output, ts_arena, PDFSigningPKCS7PasswordCallback,
1096 const_cast<char*>(pass.getStr()), nullptr, nullptr, nullptr, nullptr);
1098 if (NSS_CMSEncoder_Finish(ts_cms_ecx) != SECSuccess)
1100 SAL_WARN("svl.crypto", "NSS_CMSEncoder_Finish failed");
1101 return false;
1104 // I have compared the ts_cms_output produced here with the cms_output produced below when
1105 // not actually calling my_NSS_CMSSignerInfo_AddUnauthAttr()), and they are identical.
1107 std::vector<unsigned char> aTsHashResult = comphelper::Hash::calculateHash(ts_cms_signer->encDigest.data, ts_cms_signer->encDigest.len, comphelper::HashType::SHA256);
1108 SECItem ts_digest;
1109 ts_digest.type = siBuffer;
1110 ts_digest.data = aTsHashResult.data();
1111 ts_digest.len = aTsHashResult.size();
1113 unsigned char cOne = 1;
1114 unsigned char cTRUE = 0xff; // under DER rules true is 0xff, false is 0x00
1115 src.version.type = siUnsignedInteger;
1116 src.version.data = &cOne;
1117 src.version.len = sizeof(cOne);
1119 src.messageImprint.hashAlgorithm.algorithm.data = nullptr;
1120 src.messageImprint.hashAlgorithm.parameters.data = nullptr;
1121 SECOID_SetAlgorithmID(nullptr, &src.messageImprint.hashAlgorithm, SEC_OID_SHA256, nullptr);
1122 src.messageImprint.hashedMessage = ts_digest;
1124 src.reqPolicy.type = siBuffer;
1125 src.reqPolicy.data = nullptr;
1126 src.reqPolicy.len = 0;
1128 unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
1129 src.nonce.type = siUnsignedInteger;
1130 src.nonce.data = reinterpret_cast<unsigned char*>(&nNonce);
1131 src.nonce.len = sizeof(nNonce);
1133 src.certReq.type = siUnsignedInteger;
1134 src.certReq.data = &cTRUE;
1135 src.certReq.len = sizeof(cTRUE);
1137 src.extensions = nullptr;
1139 SECItem* timestamp_request = SEC_ASN1EncodeItem(nullptr, nullptr, &src, TimeStampReq_Template);
1140 if (timestamp_request == nullptr)
1142 SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem failed");
1143 return false;
1146 if (timestamp_request->data == nullptr)
1148 SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem succeeded but got NULL data");
1149 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1150 return false;
1153 SAL_INFO("svl.crypto", "request length=" << timestamp_request->len);
1155 // Send time stamp request to TSA server, receive response
1157 CURL* curl = curl_easy_init();
1158 CURLcode rc;
1159 struct curl_slist* slist = nullptr;
1161 if (!curl)
1163 SAL_WARN("svl.crypto", "curl_easy_init failed");
1164 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1165 return false;
1168 ::InitCurl_easy(curl);
1170 SAL_INFO("svl.crypto", "Setting curl to verbose: " << (curl_easy_setopt(curl, CURLOPT_VERBOSE, 1) == CURLE_OK ? "OK" : "FAIL"));
1172 if ((rc = curl_easy_setopt(curl, CURLOPT_URL, OUStringToOString(m_aSignTSA, RTL_TEXTENCODING_UTF8).getStr())) != CURLE_OK)
1174 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_URL) failed: " << curl_easy_strerror(rc));
1175 curl_easy_cleanup(curl);
1176 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1177 return false;
1180 slist = curl_slist_append(slist, "Content-Type: application/timestamp-query");
1181 slist = curl_slist_append(slist, "Accept: application/timestamp-reply");
1183 if ((rc = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist)) != CURLE_OK)
1185 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_HTTPHEADER) failed: " << curl_easy_strerror(rc));
1186 curl_slist_free_all(slist);
1187 curl_easy_cleanup(curl);
1188 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1189 return false;
1192 if ((rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<tools::Long>(timestamp_request->len))) != CURLE_OK ||
1193 (rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, timestamp_request->data)) != CURLE_OK)
1195 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_POSTFIELDSIZE or CURLOPT_POSTFIELDS) failed: " << curl_easy_strerror(rc));
1196 curl_easy_cleanup(curl);
1197 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1198 return false;
1201 if ((rc = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_buffer)) != CURLE_OK ||
1202 (rc = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToBuffer)) != CURLE_OK)
1204 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_WRITEDATA or CURLOPT_WRITEFUNCTION) failed: " << curl_easy_strerror(rc));
1205 curl_easy_cleanup(curl);
1206 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1207 return false;
1210 if ((rc = curl_easy_setopt(curl, CURLOPT_POST, 1)) != CURLE_OK)
1212 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_POST) failed: " << curl_easy_strerror(rc));
1213 curl_easy_cleanup(curl);
1214 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1215 return false;
1218 char error_buffer[CURL_ERROR_SIZE];
1219 if ((rc = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer)) != CURLE_OK)
1221 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_ERRORBUFFER) failed: " << curl_easy_strerror(rc));
1222 curl_easy_cleanup(curl);
1223 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1224 return false;
1227 // Use a ten second timeout
1228 if ((rc = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10)) != CURLE_OK ||
1229 (rc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10)) != CURLE_OK)
1231 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_TIMEOUT or CURLOPT_CONNECTTIMEOUT) failed: " << curl_easy_strerror(rc));
1232 curl_easy_cleanup(curl);
1233 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1234 return false;
1237 if (curl_easy_perform(curl) != CURLE_OK)
1239 SAL_WARN("svl.crypto", "curl_easy_perform failed: " << error_buffer);
1240 curl_easy_cleanup(curl);
1241 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1242 return false;
1245 SAL_INFO("svl.crypto", "PDF signing: got response, length=" << response_buffer.getLength());
1247 curl_slist_free_all(slist);
1248 curl_easy_cleanup(curl);
1249 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1251 memset(&response, 0, sizeof(response));
1253 response_item.type = siBuffer;
1254 response_item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(response_buffer.getStr()));
1255 response_item.len = response_buffer.getLength();
1257 if (SEC_ASN1DecodeItem(nullptr, &response, TimeStampResp_Template, &response_item) != SECSuccess)
1259 SAL_WARN("svl.crypto", "SEC_ASN1DecodeItem failed");
1260 return false;
1263 SAL_INFO("svl.crypto", "TimeStampResp received and decoded, status=" << PKIStatusInfoToString(response.status));
1265 if (response.status.status.len != 1 ||
1266 (response.status.status.data[0] != 0 && response.status.status.data[0] != 1))
1268 SAL_WARN("svl.crypto", "Timestamp request was not granted");
1269 return false;
1272 // timestamp.type filled in below
1274 // Not sure if we actually need two entries in the values array, now when valuesp is an
1275 // array too, the pointer to the values array followed by a null pointer. But I don't feel
1276 // like experimenting.
1277 values[0] = response.timeStampToken;
1278 values[1].type = siBuffer;
1279 values[1].data = nullptr;
1280 values[1].len = 0;
1282 timestamp.values = valuesp;
1284 typetag.oid.data = nullptr;
1285 // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1)
1286 // member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)
1287 // smime(16) aa(2) 14 }
1288 if (my_SEC_StringToOID(&typetag.oid, "1.2.840.113549.1.9.16.2.14", 0) != SECSuccess)
1290 SAL_WARN("svl.crypto", "SEC_StringToOID failed");
1291 return false;
1293 typetag.offset = SEC_OID_UNKNOWN; // ???
1294 typetag.desc = "id-aa-timeStampToken";
1295 typetag.mechanism = CKM_SHA_1; // ???
1296 typetag.supportedExtension = UNSUPPORTED_CERT_EXTENSION; // ???
1297 timestamp.typeTag = &typetag;
1299 timestamp.type = typetag.oid; // ???
1301 timestamp.encoded = PR_TRUE; // ???
1303 if (my_NSS_CMSSignerInfo_AddUnauthAttr(cms_signer, &timestamp) != SECSuccess)
1305 SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_AddUnauthAttr failed");
1306 return false;
1310 SECItem cms_output;
1311 cms_output.data = nullptr;
1312 cms_output.len = 0;
1313 PLArenaPool *arena = PORT_NewArena(10000);
1314 const ::comphelper::ScopeGuard aScopeGuard(
1315 [&arena]() mutable { PORT_FreeArena(arena, true); } );
1316 NSSCMSEncoderContext *cms_ecx;
1318 // Possibly it would work to even just pass NULL for the password callback function and its
1319 // argument here. After all, at least with the hardware token and associated software I tested
1320 // with, the software itself pops up a dialog asking for the PIN (password). But I am not going
1321 // to test it and risk locking up my token...
1323 cms_ecx = NSS_CMSEncoder_Start(cms_msg, nullptr, nullptr, &cms_output, arena, PDFSigningPKCS7PasswordCallback,
1324 const_cast<char*>(pass.getStr()), nullptr, nullptr, nullptr, nullptr);
1326 if (!cms_ecx)
1328 SAL_WARN("svl.crypto", "NSS_CMSEncoder_Start failed");
1329 return false;
1332 if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess)
1334 SAL_WARN("svl.crypto", "NSS_CMSEncoder_Finish failed");
1335 return false;
1338 if (cms_output.len*2 > MAX_SIGNATURE_CONTENT_LENGTH)
1340 SAL_WARN("svl.crypto", "Signature requires more space (" << cms_output.len*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
1341 NSS_CMSMessage_Destroy(cms_msg);
1342 return false;
1345 for (unsigned int i = 0; i < cms_output.len ; i++)
1346 appendHex(cms_output.data[i], rCMSHexBuffer);
1348 SECITEM_FreeItem(pEncodedCertificate, PR_TRUE);
1349 NSS_CMSMessage_Destroy(cms_msg);
1351 return true;
1353 #elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
1355 PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(aDerEncoded.getArray()), aDerEncoded.getLength());
1356 if (pCertContext == nullptr)
1358 SAL_WARN("svl.crypto", "CertCreateCertificateContext failed: " << WindowsErrorString(GetLastError()));
1359 return false;
1362 CRYPT_SIGN_MESSAGE_PARA aPara = {};
1363 aPara.cbSize = sizeof(aPara);
1364 aPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
1365 aPara.pSigningCert = pCertContext;
1366 aPara.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256);
1367 aPara.HashAlgorithm.Parameters.cbData = 0;
1368 aPara.cMsgCert = 1;
1369 aPara.rgpMsgCert = &pCertContext;
1371 NCRYPT_KEY_HANDLE hCryptKey = 0;
1372 DWORD dwFlags = CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;
1373 HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hCryptKey;
1374 DWORD nKeySpec;
1375 BOOL bFreeNeeded;
1377 if (!CryptAcquireCertificatePrivateKey(pCertContext,
1378 dwFlags,
1379 nullptr,
1380 phCryptProvOrNCryptKey,
1381 &nKeySpec,
1382 &bFreeNeeded))
1384 SAL_WARN("svl.crypto", "CryptAcquireCertificatePrivateKey failed: " << WindowsErrorString(GetLastError()));
1385 CertFreeCertificateContext(pCertContext);
1386 return false;
1388 assert(!bFreeNeeded);
1390 CMSG_SIGNER_ENCODE_INFO aSignerInfo = {};
1391 aSignerInfo.cbSize = sizeof(aSignerInfo);
1392 aSignerInfo.pCertInfo = pCertContext->pCertInfo;
1393 aSignerInfo.hNCryptKey = hCryptKey;
1394 aSignerInfo.dwKeySpec = nKeySpec;
1395 aSignerInfo.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256);
1396 aSignerInfo.HashAlgorithm.Parameters.cbData = 0;
1398 // Add the signing certificate as a signed attribute.
1399 CRYPT_INTEGER_BLOB aCertificateBlob;
1400 SvMemoryStream aEncodedCertificate;
1401 if (!CreateSigningCertificateAttribute(aDerEncoded.getArray(), aDerEncoded.getLength(), pCertContext, aEncodedCertificate))
1403 SAL_WARN("svl.crypto", "CreateSigningCertificateAttribute() failed");
1404 return false;
1406 aCertificateBlob.pbData = const_cast<BYTE*>(static_cast<const BYTE*>(aEncodedCertificate.GetData()));
1407 aCertificateBlob.cbData = aEncodedCertificate.GetSize();
1408 CRYPT_ATTRIBUTE aCertificateAttribute;
1410 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
1411 * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
1412 * smime(16) id-aa(2) 47 }
1414 aCertificateAttribute.pszObjId = const_cast<LPSTR>("1.2.840.113549.1.9.16.2.47");
1415 aCertificateAttribute.cValue = 1;
1416 aCertificateAttribute.rgValue = &aCertificateBlob;
1417 aSignerInfo.cAuthAttr = 1;
1418 aSignerInfo.rgAuthAttr = &aCertificateAttribute;
1420 CMSG_SIGNED_ENCODE_INFO aSignedInfo = {};
1421 aSignedInfo.cbSize = sizeof(aSignedInfo);
1422 aSignedInfo.cSigners = 1;
1423 aSignedInfo.rgSigners = &aSignerInfo;
1425 CERT_BLOB aCertBlob;
1427 aCertBlob.cbData = pCertContext->cbCertEncoded;
1428 aCertBlob.pbData = pCertContext->pbCertEncoded;
1430 aSignedInfo.cCertEncoded = 1;
1431 aSignedInfo.rgCertEncoded = &aCertBlob;
1433 HCRYPTMSG hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1434 CMSG_DETACHED_FLAG,
1435 CMSG_SIGNED,
1436 &aSignedInfo,
1437 nullptr,
1438 nullptr);
1439 if (!hMsg)
1441 SAL_WARN("svl.crypto", "CryptMsgOpenToEncode failed: " << WindowsErrorString(GetLastError()));
1442 CertFreeCertificateContext(pCertContext);
1443 return false;
1446 for (size_t i = 0; i < m_dataBlocks.size(); ++i)
1448 const bool last = (i == m_dataBlocks.size() - 1);
1449 if (!CryptMsgUpdate(hMsg, static_cast<const BYTE *>(m_dataBlocks[i].first), m_dataBlocks[i].second, last))
1451 SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << WindowsErrorString(GetLastError()));
1452 CryptMsgClose(hMsg);
1453 CertFreeCertificateContext(pCertContext);
1454 return false;
1458 PCRYPT_TIMESTAMP_CONTEXT pTsContext = nullptr;
1460 if( !m_aSignTSA.isEmpty() )
1462 HCRYPTMSG hDecodedMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1463 CMSG_DETACHED_FLAG,
1464 CMSG_SIGNED,
1466 nullptr,
1467 nullptr);
1468 if (!hDecodedMsg)
1470 SAL_WARN("svl.crypto", "CryptMsgOpenToDecode failed: " << WindowsErrorString(GetLastError()));
1471 CryptMsgClose(hMsg);
1472 CertFreeCertificateContext(pCertContext);
1473 return false;
1476 DWORD nTsSigLen = 0;
1478 if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, nullptr, &nTsSigLen))
1480 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError()));
1481 CryptMsgClose(hDecodedMsg);
1482 CryptMsgClose(hMsg);
1483 CertFreeCertificateContext(pCertContext);
1484 return false;
1487 SAL_INFO("svl.crypto", "nTsSigLen=" << nTsSigLen);
1489 std::unique_ptr<BYTE[]> pTsSig(new BYTE[nTsSigLen]);
1491 if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, pTsSig.get(), &nTsSigLen))
1493 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError()));
1494 CryptMsgClose(hDecodedMsg);
1495 CryptMsgClose(hMsg);
1496 CertFreeCertificateContext(pCertContext);
1497 return false;
1500 if (!CryptMsgUpdate(hDecodedMsg, pTsSig.get(), nTsSigLen, TRUE))
1502 SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << WindowsErrorString(GetLastError()));
1503 CryptMsgClose(hDecodedMsg);
1504 CryptMsgClose(hMsg);
1505 CertFreeCertificateContext(pCertContext);
1506 return false;
1509 DWORD nDecodedSignerInfoLen = 0;
1510 if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, nullptr, &nDecodedSignerInfoLen))
1512 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsErrorString(GetLastError()));
1513 CryptMsgClose(hDecodedMsg);
1514 CryptMsgClose(hMsg);
1515 CertFreeCertificateContext(pCertContext);
1516 return false;
1519 std::unique_ptr<BYTE[]> pDecodedSignerInfoBuf(new BYTE[nDecodedSignerInfoLen]);
1521 if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, pDecodedSignerInfoBuf.get(), &nDecodedSignerInfoLen))
1523 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsErrorString(GetLastError()));
1524 CryptMsgClose(hDecodedMsg);
1525 CryptMsgClose(hMsg);
1526 CertFreeCertificateContext(pCertContext);
1527 return false;
1530 CMSG_SIGNER_INFO *pDecodedSignerInfo = reinterpret_cast<CMSG_SIGNER_INFO *>(pDecodedSignerInfoBuf.get());
1532 CRYPT_TIMESTAMP_PARA aTsPara;
1533 unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
1535 aTsPara.pszTSAPolicyId = nullptr;
1536 aTsPara.fRequestCerts = TRUE;
1537 aTsPara.Nonce.cbData = sizeof(nNonce);
1538 aTsPara.Nonce.pbData = reinterpret_cast<BYTE *>(&nNonce);
1539 aTsPara.cExtension = 0;
1540 aTsPara.rgExtension = nullptr;
1542 if (!CryptRetrieveTimeStamp(o3tl::toW(m_aSignTSA.getStr()),
1544 10000,
1545 szOID_NIST_sha256,
1546 &aTsPara,
1547 pDecodedSignerInfo->EncryptedHash.pbData,
1548 pDecodedSignerInfo->EncryptedHash.cbData,
1549 &pTsContext,
1550 nullptr,
1551 nullptr))
1553 SAL_WARN("svl.crypto", "CryptRetrieveTimeStamp failed: " << WindowsErrorString(GetLastError()));
1554 CryptMsgClose(hDecodedMsg);
1555 CryptMsgClose(hMsg);
1556 CertFreeCertificateContext(pCertContext);
1557 return false;
1560 SAL_INFO("svl.crypto", "Time stamp size is " << pTsContext->cbEncoded << " bytes");
1562 // I tried to use CryptMsgControl() with CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR to add the
1563 // timestamp, but that failed with "The parameter is incorrect". Probably it is too late to
1564 // modify the message once its data has already been encoded as part of the
1565 // CryptMsgGetParam() with CMSG_BARE_CONTENT_PARAM above. So close the message and re-do its
1566 // creation steps, but now with an amended aSignerInfo.
1568 CRYPT_INTEGER_BLOB aTimestampBlob;
1569 aTimestampBlob.cbData = pTsContext->cbEncoded;
1570 aTimestampBlob.pbData = pTsContext->pbEncoded;
1572 CRYPT_ATTRIBUTE aTimestampAttribute;
1573 aTimestampAttribute.pszObjId = const_cast<LPSTR>(
1574 "1.2.840.113549.1.9.16.2.14");
1575 aTimestampAttribute.cValue = 1;
1576 aTimestampAttribute.rgValue = &aTimestampBlob;
1578 aSignerInfo.cUnauthAttr = 1;
1579 aSignerInfo.rgUnauthAttr = &aTimestampAttribute;
1581 CryptMsgClose(hMsg);
1583 hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1584 CMSG_DETACHED_FLAG,
1585 CMSG_SIGNED,
1586 &aSignedInfo,
1587 nullptr,
1588 nullptr);
1590 for (size_t i = 0; i < m_dataBlocks.size(); ++i)
1592 const bool last = (i == m_dataBlocks.size() - 1);
1593 if (!hMsg ||
1594 !CryptMsgUpdate(hMsg, static_cast<const BYTE *>(m_dataBlocks[i].first), m_dataBlocks[i].second, last))
1596 SAL_WARN("svl.crypto", "Re-creating the message failed: " << WindowsErrorString(GetLastError()));
1597 CryptMemFree(pTsContext);
1598 CryptMsgClose(hDecodedMsg);
1599 CryptMsgClose(hMsg);
1600 CertFreeCertificateContext(pCertContext);
1601 return false;
1605 CryptMsgClose(hDecodedMsg);
1608 DWORD nSigLen = 0;
1610 if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, nullptr, &nSigLen))
1612 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError()));
1613 if (pTsContext)
1614 CryptMemFree(pTsContext);
1615 CryptMsgClose(hMsg);
1616 CertFreeCertificateContext(pCertContext);
1617 return false;
1620 if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
1622 SAL_WARN("svl.crypto", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
1623 if (pTsContext)
1624 CryptMemFree(pTsContext);
1625 CryptMsgClose(hMsg);
1626 CertFreeCertificateContext(pCertContext);
1627 return false;
1630 SAL_INFO("svl.crypto", "Signature size is " << nSigLen << " bytes");
1631 std::unique_ptr<BYTE[]> pSig(new BYTE[nSigLen]);
1633 if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pSig.get(), &nSigLen))
1635 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError()));
1636 if (pTsContext)
1637 CryptMemFree(pTsContext);
1638 CryptMsgClose(hMsg);
1639 CertFreeCertificateContext(pCertContext);
1640 return false;
1643 // Release resources
1644 if (pTsContext)
1645 CryptMemFree(pTsContext);
1646 CryptMsgClose(hMsg);
1647 CertFreeCertificateContext(pCertContext);
1649 for (unsigned int i = 0; i < nSigLen ; i++)
1650 appendHex(pSig[i], rCMSHexBuffer);
1652 return true;
1653 #endif // USE_CRYPTO_MSCAPI
1654 #endif // USE_CRYPTO_ANY
1657 namespace
1659 #if USE_CRYPTO_NSS
1660 /// Similar to NSS_CMSAttributeArray_FindAttrByOidTag(), but works directly with a SECOidData.
1661 NSSCMSAttribute* CMSAttributeArray_FindAttrByOidData(NSSCMSAttribute** attrs, SECOidData const * oid, PRBool only)
1663 NSSCMSAttribute* attr1, *attr2;
1665 if (attrs == nullptr)
1666 return nullptr;
1668 if (oid == nullptr)
1669 return nullptr;
1671 while ((attr1 = *attrs++) != nullptr)
1673 if (attr1->type.len == oid->oid.len && PORT_Memcmp(attr1->type.data,
1674 oid->oid.data,
1675 oid->oid.len) == 0)
1676 break;
1679 if (attr1 == nullptr)
1680 return nullptr;
1682 if (!only)
1683 return attr1;
1685 while ((attr2 = *attrs++) != nullptr)
1687 if (attr2->type.len == oid->oid.len && PORT_Memcmp(attr2->type.data,
1688 oid->oid.data,
1689 oid->oid.len) == 0)
1690 break;
1693 if (attr2 != nullptr)
1694 return nullptr;
1696 return attr1;
1699 /// Same as SEC_StringToOID(), which is private to us.
1700 SECStatus StringToOID(SECItem* to, const char* from, PRUint32 len)
1702 PRUint32 decimal_numbers = 0;
1703 PRUint32 result_bytes = 0;
1704 SECStatus rv;
1705 PRUint8 result[1024];
1707 static const PRUint32 max_decimal = 0xffffffff / 10;
1708 static const char OIDstring[] = {"OID."};
1710 if (!from || !to)
1712 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1713 return SECFailure;
1715 if (!len)
1717 len = PL_strlen(from);
1719 if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4))
1721 from += 4; /* skip leading "OID." if present */
1722 len -= 4;
1724 if (!len)
1726 bad_data:
1727 PORT_SetError(SEC_ERROR_BAD_DATA);
1728 return SECFailure;
1732 PRUint32 decimal = 0;
1733 while (len > 0 && rtl::isAsciiDigit(static_cast<unsigned char>(*from)))
1735 PRUint32 addend = *from++ - '0';
1736 --len;
1737 if (decimal > max_decimal) /* overflow */
1738 goto bad_data;
1739 decimal = (decimal * 10) + addend;
1740 if (decimal < addend) /* overflow */
1741 goto bad_data;
1743 if (len != 0 && *from != '.')
1745 goto bad_data;
1747 if (decimal_numbers == 0)
1749 if (decimal > 2)
1750 goto bad_data;
1751 result[0] = decimal * 40;
1752 result_bytes = 1;
1754 else if (decimal_numbers == 1)
1756 if (decimal > 40)
1757 goto bad_data;
1758 result[0] += decimal;
1760 else
1762 /* encode the decimal number, */
1763 PRUint8* rp;
1764 PRUint32 num_bytes = 0;
1765 PRUint32 tmp = decimal;
1766 while (tmp)
1768 num_bytes++;
1769 tmp >>= 7;
1771 if (!num_bytes)
1772 ++num_bytes; /* use one byte for a zero value */
1773 if (static_cast<size_t>(num_bytes) + result_bytes > sizeof result)
1774 goto bad_data;
1775 tmp = num_bytes;
1776 rp = result + result_bytes - 1;
1777 rp[tmp] = static_cast<PRUint8>(decimal & 0x7f);
1778 decimal >>= 7;
1779 while (--tmp > 0)
1781 rp[tmp] = static_cast<PRUint8>(decimal | 0x80);
1782 decimal >>= 7;
1784 result_bytes += num_bytes;
1786 ++decimal_numbers;
1787 if (len > 0) /* skip trailing '.' */
1789 ++from;
1790 --len;
1793 while (len > 0);
1794 /* now result contains result_bytes of data */
1795 if (to->data && to->len >= result_bytes)
1797 to->len = result_bytes;
1798 PORT_Memcpy(to->data, result, to->len);
1799 rv = SECSuccess;
1801 else
1803 SECItem result_item = {siBuffer, nullptr, 0 };
1804 result_item.data = result;
1805 result_item.len = result_bytes;
1806 rv = SECITEM_CopyItem(nullptr, to, &result_item);
1808 return rv;
1811 #elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
1813 /// Verifies a non-detached signature using CryptoAPI.
1814 bool VerifyNonDetachedSignature(const std::vector<unsigned char>& aData, const std::vector<BYTE>& rExpectedHash)
1816 HCRYPTPROV hProv = 0;
1817 if (!CryptAcquireContextW(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
1819 SAL_WARN("svl.crypto", "CryptAcquireContext() failed");
1820 return false;
1823 HCRYPTHASH hHash = 0;
1824 if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
1826 SAL_WARN("svl.crypto", "CryptCreateHash() failed");
1827 return false;
1830 if (!CryptHashData(hHash, aData.data(), aData.size(), 0))
1832 SAL_WARN("svl.crypto", "CryptHashData() failed");
1833 return false;
1836 DWORD nActualHash = 0;
1837 if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nActualHash, 0))
1839 SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash length");
1840 return false;
1843 std::vector<unsigned char> aActualHash(nActualHash);
1844 if (!CryptGetHashParam(hHash, HP_HASHVAL, aActualHash.data(), &nActualHash, 0))
1846 SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash");
1847 return false;
1850 CryptDestroyHash(hHash);
1851 CryptReleaseContext(hProv, 0);
1853 return aActualHash.size() == rExpectedHash.size() &&
1854 !std::memcmp(aActualHash.data(), rExpectedHash.data(), aActualHash.size());
1857 OUString GetSubjectName(PCCERT_CONTEXT pCertContext)
1859 OUString subjectName;
1861 // Get Subject name size.
1862 DWORD dwData = CertGetNameStringW(pCertContext,
1863 CERT_NAME_SIMPLE_DISPLAY_TYPE,
1865 nullptr,
1866 nullptr,
1868 if (!dwData)
1870 SAL_WARN("svl.crypto", "ValidateSignature: CertGetNameString failed");
1871 return subjectName;
1874 // Allocate memory for subject name.
1875 LPWSTR szName = static_cast<LPWSTR>(
1876 LocalAlloc(LPTR, dwData * sizeof(WCHAR)));
1877 if (!szName)
1879 SAL_WARN("svl.crypto", "ValidateSignature: Unable to allocate memory for subject name");
1880 return subjectName;
1883 // Get subject name.
1884 if (!CertGetNameStringW(pCertContext,
1885 CERT_NAME_SIMPLE_DISPLAY_TYPE,
1887 nullptr,
1888 szName,
1889 dwData))
1891 LocalFree(szName);
1892 SAL_WARN("svl.crypto", "ValidateSignature: CertGetNameString failed");
1893 return subjectName;
1896 subjectName = o3tl::toU(szName);
1897 LocalFree(szName);
1899 return subjectName;
1901 #endif // USE_CRYPTO_MSCAPI
1903 #if USE_CRYPTO_NSS
1904 void ensureNssInit()
1906 // e.g. tdf#122599 ensure NSS library is initialized for NSS_CMSMessage_CreateFromDER
1907 css::uno::Reference<css::xml::crypto::XNSSInitializer>
1908 xNSSInitializer = css::xml::crypto::NSSInitializer::create(comphelper::getProcessComponentContext());
1910 // this calls NSS_Init
1911 xNSSInitializer->getDigestContext(css::xml::crypto::DigestID::SHA256,
1912 uno::Sequence<beans::NamedValue>());
1914 #endif
1915 } // anonymous namespace
1917 bool Signing::Verify(const std::vector<unsigned char>& aData,
1918 const bool bNonDetached,
1919 const std::vector<unsigned char>& aSignature,
1920 SignatureInformation& rInformation)
1922 #if USE_CRYPTO_NSS
1923 // ensure NSS_Init() is called before using NSS_CMSMessage_CreateFromDER
1924 static std::once_flag aInitOnce;
1925 std::call_once(aInitOnce, ensureNssInit);
1927 // Validate the signature.
1928 SECItem aSignatureItem;
1929 aSignatureItem.data = const_cast<unsigned char*>(aSignature.data());
1930 aSignatureItem.len = aSignature.size();
1931 NSSCMSMessage* pCMSMessage = NSS_CMSMessage_CreateFromDER(&aSignatureItem,
1932 /*cb=*/nullptr,
1933 /*cb_arg=*/nullptr,
1934 /*pwfn=*/nullptr,
1935 /*pwfn_arg=*/nullptr,
1936 /*decrypt_key_cb=*/nullptr,
1937 /*decrypt_key_cb_arg=*/nullptr);
1938 if (!NSS_CMSMessage_IsSigned(pCMSMessage))
1940 SAL_WARN("svl.crypto", "ValidateSignature: message is not signed");
1941 return false;
1944 NSSCMSContentInfo* pCMSContentInfo = NSS_CMSMessage_ContentLevel(pCMSMessage, 0);
1945 if (!pCMSContentInfo)
1947 SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSMessage_ContentLevel() failed");
1948 return false;
1951 auto pCMSSignedData = static_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(pCMSContentInfo));
1952 if (!pCMSSignedData)
1954 SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSContentInfo_GetContent() failed");
1955 return false;
1958 // Import certificates from the signed data temporarily, so it'll be
1959 // possible to verify the signature, even if we didn't have the certificate
1960 // previously.
1961 std::vector<CERTCertificate*> aDocumentCertificates;
1962 for (size_t i = 0; pCMSSignedData->rawCerts[i]; ++i)
1963 aDocumentCertificates.push_back(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), pCMSSignedData->rawCerts[i], nullptr, 0, 0));
1965 NSSCMSSignerInfo* pCMSSignerInfo = NSS_CMSSignedData_GetSignerInfo(pCMSSignedData, 0);
1966 if (!pCMSSignerInfo)
1968 SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSSignedData_GetSignerInfo() failed");
1969 return false;
1972 SECItem aAlgorithm = NSS_CMSSignedData_GetDigestAlgs(pCMSSignedData)[0]->algorithm;
1973 SECOidTag eOidTag = SECOID_FindOIDTag(&aAlgorithm);
1975 // Map a sign algorithm to a digest algorithm.
1976 // See NSS_CMSUtil_MapSignAlgs(), which is private to us.
1977 switch (eOidTag)
1979 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
1980 eOidTag = SEC_OID_SHA1;
1981 break;
1982 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
1983 eOidTag = SEC_OID_SHA256;
1984 break;
1985 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
1986 eOidTag = SEC_OID_SHA512;
1987 break;
1988 default:
1989 break;
1992 HASH_HashType eHashType = HASH_GetHashTypeByOidTag(eOidTag);
1993 HASHContext* pHASHContext = HASH_Create(eHashType);
1994 if (!pHASHContext)
1996 SAL_WARN("svl.crypto", "ValidateSignature: HASH_Create() failed");
1997 return false;
2000 // We have a hash, update it with the byte ranges.
2001 HASH_Update(pHASHContext, aData.data(), aData.size());
2003 // Find out what is the expected length of the hash.
2004 unsigned int nMaxResultLen = 0;
2005 switch (eOidTag)
2007 case SEC_OID_SHA1:
2008 nMaxResultLen = comphelper::SHA1_HASH_LENGTH;
2009 rInformation.nDigestID = xml::crypto::DigestID::SHA1;
2010 break;
2011 case SEC_OID_SHA256:
2012 nMaxResultLen = comphelper::SHA256_HASH_LENGTH;
2013 rInformation.nDigestID = xml::crypto::DigestID::SHA256;
2014 break;
2015 case SEC_OID_SHA512:
2016 nMaxResultLen = comphelper::SHA512_HASH_LENGTH;
2017 rInformation.nDigestID = xml::crypto::DigestID::SHA512;
2018 break;
2019 default:
2020 SAL_WARN("svl.crypto", "ValidateSignature: unrecognized algorithm");
2021 return false;
2024 auto pActualResultBuffer = static_cast<unsigned char*>(PORT_Alloc(nMaxResultLen));
2025 unsigned int nActualResultLen;
2026 HASH_End(pHASHContext, pActualResultBuffer, &nActualResultLen, nMaxResultLen);
2028 CERTCertificate* pCertificate = NSS_CMSSignerInfo_GetSigningCertificate(pCMSSignerInfo, CERT_GetDefaultCertDB());
2029 if (!pCertificate)
2031 SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSSignerInfo_GetSigningCertificate() failed");
2032 return false;
2034 else
2036 uno::Sequence<sal_Int8> aDerCert(pCertificate->derCert.len);
2037 auto aDerCertRange = asNonConstRange(aDerCert);
2038 for (size_t i = 0; i < pCertificate->derCert.len; ++i)
2039 aDerCertRange[i] = pCertificate->derCert.data[i];
2040 OUStringBuffer aBuffer;
2041 comphelper::Base64::encode(aBuffer, aDerCert);
2042 SignatureInformation::X509Data temp;
2043 temp.emplace_back();
2044 temp.back().X509Certificate = aBuffer.makeStringAndClear();
2045 temp.back().X509Subject = OUString(pCertificate->subjectName, PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
2046 rInformation.X509Datas.clear();
2047 rInformation.X509Datas.emplace_back(temp);
2050 PRTime nSigningTime;
2051 // This may fail, in which case the date should be taken from the PDF's dictionary's "M" key,
2052 // so not critical for PDF at least.
2053 if (NSS_CMSSignerInfo_GetSigningTime(pCMSSignerInfo, &nSigningTime) == SECSuccess)
2055 // First convert the UTC UNIX timestamp to a tools::DateTime.
2056 // nSigningTime is in microseconds.
2057 DateTime aDateTime = DateTime::CreateFromUnixTime(static_cast<double>(nSigningTime) / 1000000);
2059 // Then convert to a local UNO DateTime.
2060 aDateTime.ConvertToLocalTime();
2061 rInformation.stDateTime = aDateTime.GetUNODateTime();
2062 if (rInformation.ouDateTime.isEmpty())
2064 OUStringBuffer rBuffer;
2065 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
2066 rBuffer.append('-');
2067 if (aDateTime.GetMonth() < 10)
2068 rBuffer.append('0');
2069 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
2070 rBuffer.append('-');
2071 if (aDateTime.GetDay() < 10)
2072 rBuffer.append('0');
2073 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
2074 rInformation.ouDateTime = rBuffer.makeStringAndClear();
2078 // Check if we have a signing certificate attribute.
2079 SECOidData aOidData;
2080 aOidData.oid.data = nullptr;
2082 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
2083 * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
2084 * smime(16) id-aa(2) 47 }
2086 if (StringToOID(&aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess)
2088 SAL_WARN("svl.crypto", "StringToOID() failed");
2089 return false;
2091 aOidData.offset = SEC_OID_UNKNOWN;
2092 aOidData.desc = "id-aa-signingCertificateV2";
2093 aOidData.mechanism = CKM_SHA_1;
2094 aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
2095 NSSCMSAttribute* pAttribute = CMSAttributeArray_FindAttrByOidData(pCMSSignerInfo->authAttr, &aOidData, PR_TRUE);
2096 if (pAttribute)
2097 rInformation.bHasSigningCertificate = true;
2099 SECItem* pContentInfoContentData = pCMSSignedData->contentInfo.content.data;
2100 if (bNonDetached && pContentInfoContentData && pContentInfoContentData->data)
2102 // Not a detached signature.
2103 if (!std::memcmp(pActualResultBuffer, pContentInfoContentData->data, nMaxResultLen) && nActualResultLen == pContentInfoContentData->len)
2104 rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2106 else
2108 // Detached, the usual case.
2109 SECItem aActualResultItem;
2110 aActualResultItem.data = pActualResultBuffer;
2111 aActualResultItem.len = nActualResultLen;
2112 if (NSS_CMSSignerInfo_Verify(pCMSSignerInfo, &aActualResultItem, nullptr) == SECSuccess)
2113 rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2116 // Everything went fine
2117 SECITEM_FreeItem(&aOidData.oid, false);
2118 PORT_Free(pActualResultBuffer);
2119 HASH_Destroy(pHASHContext);
2120 NSS_CMSSignerInfo_Destroy(pCMSSignerInfo);
2121 for (auto pDocumentCertificate : aDocumentCertificates)
2122 CERT_DestroyCertificate(pDocumentCertificate);
2124 return true;
2126 #elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
2128 // Open a message for decoding.
2129 HCRYPTMSG hMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
2130 CMSG_DETACHED_FLAG,
2133 nullptr,
2134 nullptr);
2135 if (!hMsg)
2137 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgOpenToDecode() failed");
2138 return false;
2141 // Update the message with the encoded header blob.
2142 if (!CryptMsgUpdate(hMsg, aSignature.data(), aSignature.size(), TRUE))
2144 SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the header failed: " << WindowsErrorString(GetLastError()));
2145 return false;
2148 // Update the message with the content blob.
2149 if (!CryptMsgUpdate(hMsg, aData.data(), aData.size(), FALSE))
2151 SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the content failed: " << WindowsErrorString(GetLastError()));
2152 return false;
2155 if (!CryptMsgUpdate(hMsg, nullptr, 0, TRUE))
2157 SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the last content failed: " << WindowsErrorString(GetLastError()));
2158 return false;
2161 // Get the CRYPT_ALGORITHM_IDENTIFIER from the message.
2162 DWORD nDigestID = 0;
2163 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, nullptr, &nDigestID))
2165 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed: " << WindowsErrorString(GetLastError()));
2166 return false;
2168 std::unique_ptr<BYTE[]> pDigestBytes(new BYTE[nDigestID]);
2169 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, pDigestBytes.get(), &nDigestID))
2171 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed: " << WindowsErrorString(GetLastError()));
2172 return false;
2174 auto pDigestID = reinterpret_cast<CRYPT_ALGORITHM_IDENTIFIER*>(pDigestBytes.get());
2175 if (std::string_view(szOID_NIST_sha256) == pDigestID->pszObjId)
2176 rInformation.nDigestID = xml::crypto::DigestID::SHA256;
2177 else if (std::string_view(szOID_RSA_SHA1RSA) == pDigestID->pszObjId || std::string_view(szOID_OIWSEC_sha1) == pDigestID->pszObjId)
2178 rInformation.nDigestID = xml::crypto::DigestID::SHA1;
2179 else
2180 // Don't error out here, we can still verify the message digest correctly, just the digest ID won't be set.
2181 SAL_WARN("svl.crypto", "ValidateSignature: unhandled algorithm identifier '"<<pDigestID->pszObjId<<"'");
2183 // Get the signer CERT_INFO from the message.
2184 DWORD nSignerCertInfo = 0;
2185 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, nullptr, &nSignerCertInfo))
2187 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2188 return false;
2190 std::unique_ptr<BYTE[]> pSignerCertInfoBuf(new BYTE[nSignerCertInfo]);
2191 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, pSignerCertInfoBuf.get(), &nSignerCertInfo))
2193 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2194 return false;
2196 PCERT_INFO pSignerCertInfo = reinterpret_cast<PCERT_INFO>(pSignerCertInfoBuf.get());
2198 // Open a certificate store in memory using CERT_STORE_PROV_MSG, which
2199 // initializes it with the certificates from the message.
2200 HCERTSTORE hStoreHandle = CertOpenStore(CERT_STORE_PROV_MSG,
2201 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
2204 hMsg);
2205 if (!hStoreHandle)
2207 SAL_WARN("svl.crypto", "ValidateSignature: CertOpenStore() failed");
2208 return false;
2211 // Find the signer's certificate in the store.
2212 PCCERT_CONTEXT pSignerCertContext = CertGetSubjectCertificateFromStore(hStoreHandle,
2213 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
2214 pSignerCertInfo);
2215 if (!pSignerCertContext)
2217 SAL_WARN("svl.crypto", "ValidateSignature: CertGetSubjectCertificateFromStore() failed");
2218 return false;
2220 else
2222 // Write rInformation.ouX509Certificate.
2223 uno::Sequence<sal_Int8> aDerCert(pSignerCertContext->cbCertEncoded);
2224 std::copy_n(pSignerCertContext->pbCertEncoded, pSignerCertContext->cbCertEncoded,
2225 aDerCert.getArray());
2226 OUStringBuffer aBuffer;
2227 comphelper::Base64::encode(aBuffer, aDerCert);
2228 SignatureInformation::X509Data temp;
2229 temp.emplace_back();
2230 temp.back().X509Certificate = aBuffer.makeStringAndClear();
2231 temp.back().X509Subject = GetSubjectName(pSignerCertContext);
2232 rInformation.X509Datas.clear();
2233 rInformation.X509Datas.emplace_back(temp);
2236 if (bNonDetached)
2238 // Not a detached signature.
2239 DWORD nContentParam = 0;
2240 if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, nullptr, &nContentParam))
2242 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2243 return false;
2246 std::vector<BYTE> aContentParam(nContentParam);
2247 if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, aContentParam.data(), &nContentParam))
2249 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2250 return false;
2253 if (VerifyNonDetachedSignature(aData, aContentParam))
2254 rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2256 else
2258 // Detached, the usual case.
2259 // Use the CERT_INFO from the signer certificate to verify the signature.
2260 if (CryptMsgControl(hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE, pSignerCertContext->pCertInfo))
2261 rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2264 // Check if we have a signing certificate attribute.
2265 DWORD nSignedAttributes = 0;
2266 if (CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, nullptr, &nSignedAttributes))
2268 std::unique_ptr<BYTE[]> pSignedAttributesBuf(new BYTE[nSignedAttributes]);
2269 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, pSignedAttributesBuf.get(), &nSignedAttributes))
2271 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() authenticated failed");
2272 return false;
2274 auto pSignedAttributes = reinterpret_cast<PCRYPT_ATTRIBUTES>(pSignedAttributesBuf.get());
2275 for (size_t nAttr = 0; nAttr < pSignedAttributes->cAttr; ++nAttr)
2277 CRYPT_ATTRIBUTE& rAttr = pSignedAttributes->rgAttr[nAttr];
2279 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
2280 * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
2281 * smime(16) id-aa(2) 47 }
2283 if (std::string_view("1.2.840.113549.1.9.16.2.47") == rAttr.pszObjId)
2285 rInformation.bHasSigningCertificate = true;
2286 break;
2291 // Get the unauthorized attributes.
2292 nSignedAttributes = 0;
2293 if (CryptMsgGetParam(hMsg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, nullptr, &nSignedAttributes))
2295 std::unique_ptr<BYTE[]> pSignedAttributesBuf(new BYTE[nSignedAttributes]);
2296 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, pSignedAttributesBuf.get(), &nSignedAttributes))
2298 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() unauthenticated failed");
2299 return false;
2301 auto pSignedAttributes = reinterpret_cast<PCRYPT_ATTRIBUTES>(pSignedAttributesBuf.get());
2302 for (size_t nAttr = 0; nAttr < pSignedAttributes->cAttr; ++nAttr)
2304 CRYPT_ATTRIBUTE& rAttr = pSignedAttributes->rgAttr[nAttr];
2305 // Timestamp blob
2306 if (std::string_view("1.2.840.113549.1.9.16.2.14") == rAttr.pszObjId)
2308 PCRYPT_TIMESTAMP_CONTEXT pTsContext;
2309 if (!CryptVerifyTimeStampSignature(rAttr.rgValue->pbData, rAttr.rgValue->cbData, nullptr, 0, nullptr, &pTsContext, nullptr, nullptr))
2311 SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << WindowsErrorString(GetLastError()));
2312 break;
2315 DateTime aDateTime = DateTime::CreateFromWin32FileDateTime(pTsContext->pTimeStamp->ftTime.dwLowDateTime, pTsContext->pTimeStamp->ftTime.dwHighDateTime);
2317 // Then convert to a local UNO DateTime.
2318 aDateTime.ConvertToLocalTime();
2319 rInformation.stDateTime = aDateTime.GetUNODateTime();
2320 if (rInformation.ouDateTime.isEmpty())
2322 OUStringBuffer rBuffer;
2323 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
2324 rBuffer.append('-');
2325 if (aDateTime.GetMonth() < 10)
2326 rBuffer.append('0');
2327 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
2328 rBuffer.append('-');
2329 if (aDateTime.GetDay() < 10)
2330 rBuffer.append('0');
2331 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
2332 rInformation.ouDateTime = rBuffer.makeStringAndClear();
2334 break;
2339 CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
2340 CryptMsgClose(hMsg);
2341 return true;
2342 #else
2343 // Not implemented.
2344 (void)aData;
2345 (void)bNonDetached;
2346 (void)aSignature;
2347 (void)rInformation;
2348 return false;
2349 #endif
2352 bool Signing::Verify(SvStream& rStream,
2353 const std::vector<std::pair<size_t, size_t>>& aByteRanges,
2354 const bool bNonDetached,
2355 const std::vector<unsigned char>& aSignature,
2356 SignatureInformation& rInformation)
2358 #if USE_CRYPTO_ANY
2359 std::vector<unsigned char> buffer;
2361 // Copy the byte ranges into a single buffer.
2362 for (const auto& rByteRange : aByteRanges)
2364 rStream.Seek(rByteRange.first);
2365 const size_t size = buffer.size();
2366 buffer.resize(size + rByteRange.second);
2367 rStream.ReadBytes(buffer.data() + size, rByteRange.second);
2370 return Verify(buffer, bNonDetached, aSignature, rInformation);
2372 #else
2373 // Not implemented.
2374 (void)rStream;
2375 (void)aByteRanges;
2376 (void)bNonDetached;
2377 (void)aSignature;
2378 (void)rInformation;
2379 return false;
2380 #endif
2383 void Signing::appendHex(sal_Int8 nInt, OStringBuffer& rBuffer)
2385 static const char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
2386 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
2387 rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] );
2388 rBuffer.append( pHexDigits[ nInt & 15 ] );
2391 bool CertificateOrName::Is() const
2393 return m_xCertificate.is() || !m_aName.isEmpty();
2397 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */