LibreOffice Module svl (master) 1
cryptosign.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10#include <sal/config.h>
11
12#include <algorithm>
13
14#include <svl/cryptosign.hxx>
15#include <svl/sigstruct.hxx>
16#include <config_crypto.h>
17
18#include <rtl/character.hxx>
19#include <rtl/strbuf.hxx>
20#include <rtl/string.hxx>
21#include <sal/log.hxx>
22#include <tools/datetime.hxx>
23#include <tools/stream.hxx>
24#include <comphelper/base64.hxx>
25#include <comphelper/hash.hxx>
27#include <comphelper/random.hxx>
29#include <comphelper/lok.hxx>
30#include <com/sun/star/security/XCertificate.hpp>
31#include <com/sun/star/uno/Sequence.hxx>
33
34#if USE_CRYPTO_NSS
35// NSS headers for PDF signing
36#include <cert.h>
37#include <keyhi.h>
38#include <pk11pub.h>
39#include <hasht.h>
40#include <secerr.h>
41#include <sechash.h>
42#include <cms.h>
43#include <cmst.h>
44
45// We use curl for RFC3161 time stamp requests
46#include <curl/curl.h>
47
48#include <com/sun/star/xml/crypto/DigestID.hpp>
49#include <com/sun/star/xml/crypto/NSSInitializer.hpp>
50#include <mutex>
51#endif
52
53#if USE_CRYPTO_MSCAPI
54// WinCrypt headers for PDF signing
55// Note: this uses Windows 7 APIs and requires the relevant data types
56#include <prewin.h>
57#include <wincrypt.h>
58#include <postwin.h>
60#endif
61
62using namespace com::sun::star;
63
64namespace {
65
66#if USE_CRYPTO_ANY
67void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer )
68{
69 static const char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
70 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
71 rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] );
72 rBuffer.append( pHexDigits[ nInt & 15 ] );
73}
74#endif
75
76#if USE_CRYPTO_NSS
77char *PDFSigningPKCS7PasswordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg)
78{
79 return PL_strdup(static_cast<char *>(arg));
80}
81
82// ASN.1 used in the (much simpler) time stamp request. From RFC3161
83// and other sources.
84
85/*
86AlgorithmIdentifier ::= SEQUENCE {
87 algorithm OBJECT IDENTIFIER,
88 parameters ANY DEFINED BY algorithm OPTIONAL }
89 -- contains a value of the type
90 -- registered for use with the
91 -- algorithm object identifier value
92
93MessageImprint ::= SEQUENCE {
94 hashAlgorithm AlgorithmIdentifier,
95 hashedMessage OCTET STRING }
96*/
97
98struct MessageImprint {
99 SECAlgorithmID hashAlgorithm;
100 SECItem hashedMessage;
101};
102
103/*
104Extension ::= SEQUENCE {
105 extnID OBJECT IDENTIFIER,
106 critical BOOLEAN DEFAULT FALSE,
107 extnValue OCTET STRING }
108*/
109
110struct Extension {
111 SECItem extnID;
112 SECItem critical;
113 SECItem extnValue;
114};
115
116/*
117Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
118*/
119
120/*
121TSAPolicyId ::= OBJECT IDENTIFIER
122
123TimeStampReq ::= SEQUENCE {
124 version INTEGER { v1(1) },
125 messageImprint MessageImprint,
126 --a hash algorithm OID and the hash value of the data to be
127 --time-stamped
128 reqPolicy TSAPolicyId OPTIONAL,
129 nonce INTEGER OPTIONAL,
130 certReq BOOLEAN DEFAULT FALSE,
131 extensions [0] IMPLICIT Extensions OPTIONAL }
132*/
133
134struct TimeStampReq {
135 SECItem version;
136 MessageImprint messageImprint;
137 SECItem reqPolicy;
138 SECItem nonce;
139 SECItem certReq;
141};
142
146struct GeneralName
147{
148 CERTName name;
149};
150
154struct GeneralNames
155{
156 GeneralName names;
157};
158
162struct IssuerSerial
163{
164 GeneralNames issuer;
165 SECItem serialNumber;
166};
167
172struct ESSCertIDv2
173{
174 SECAlgorithmID hashAlgorithm;
175 SECItem certHash;
176 IssuerSerial issuerSerial;
177};
178
182struct SigningCertificateV2
183{
184 ESSCertIDv2** certs;
185
186 SigningCertificateV2()
187 : certs(nullptr)
188 {
189 }
190};
191
205const SEC_ASN1Template GeneralNameTemplate[] =
206{
207 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralName)},
208 {SEC_ASN1_INLINE, offsetof(GeneralName, name), CERT_NameTemplate, 0},
209 {0, 0, nullptr, 0}
210};
211
215const SEC_ASN1Template GeneralNamesTemplate[] =
216{
217 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralNames)},
218 {SEC_ASN1_INLINE | SEC_ASN1_CONTEXT_SPECIFIC | 4, offsetof(GeneralNames, names), GeneralNameTemplate, 0},
219 {0, 0, nullptr, 0}
220};
221
228const SEC_ASN1Template IssuerSerialTemplate[] =
229{
230 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(IssuerSerial)},
231 {SEC_ASN1_INLINE, offsetof(IssuerSerial, issuer), GeneralNamesTemplate, 0},
232 {SEC_ASN1_INTEGER, offsetof(IssuerSerial, serialNumber), nullptr, 0},
233 {0, 0, nullptr, 0}
234};
235
236
247SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
248
249const SEC_ASN1Template ESSCertIDv2Template[] =
250{
251 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(ESSCertIDv2)},
252 {SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, hashAlgorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), 0},
253 {SEC_ASN1_OCTET_STRING, offsetof(ESSCertIDv2, certHash), nullptr, 0},
254 {SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, issuerSerial), IssuerSerialTemplate, 0},
255 {0, 0, nullptr, 0}
256};
257
262const SEC_ASN1Template SigningCertificateV2Template[] =
263{
264 {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(SigningCertificateV2)},
265 {SEC_ASN1_SEQUENCE_OF, offsetof(SigningCertificateV2, certs), ESSCertIDv2Template, 0},
266 {0, 0, nullptr, 0}
267};
268
269struct PKIStatusInfo {
270 SECItem status;
271 SECItem statusString;
272 SECItem failInfo;
273};
274
275const SEC_ASN1Template PKIStatusInfo_Template[] =
276{
277 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(PKIStatusInfo) },
278 { SEC_ASN1_INTEGER, offsetof(PKIStatusInfo, status), nullptr, 0 },
279 { SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, statusString), nullptr, 0 },
280 { SEC_ASN1_BIT_STRING | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, failInfo), nullptr, 0 },
281 { 0, 0, nullptr, 0 }
282};
283
284const SEC_ASN1Template Any_Template[] =
285{
286 { SEC_ASN1_ANY, 0, nullptr, sizeof(SECItem) }
287};
288
289struct TimeStampResp {
290 PKIStatusInfo status;
291 SECItem timeStampToken;
292};
293
294const SEC_ASN1Template TimeStampResp_Template[] =
295{
296 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampResp) },
297 { SEC_ASN1_INLINE, offsetof(TimeStampResp, status), PKIStatusInfo_Template, 0 },
298 { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, offsetof(TimeStampResp, timeStampToken), Any_Template, 0 },
299 { 0, 0, nullptr, 0 }
300};
301
302const SEC_ASN1Template MessageImprint_Template[] =
303{
304 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(MessageImprint) },
305 { SEC_ASN1_INLINE, offsetof(MessageImprint, hashAlgorithm), SECOID_AlgorithmIDTemplate, 0 },
306 { SEC_ASN1_OCTET_STRING, offsetof(MessageImprint, hashedMessage), nullptr, 0 },
307 { 0, 0, nullptr, 0 }
308};
309
310const SEC_ASN1Template Extension_Template[] =
311{
312 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(Extension) },
313 { SEC_ASN1_OBJECT_ID, offsetof(Extension, extnID), nullptr, 0 },
314 { SEC_ASN1_BOOLEAN, offsetof(Extension, critical), nullptr, 0 },
315 { SEC_ASN1_OCTET_STRING, offsetof(Extension, extnValue), nullptr, 0 },
316 { 0, 0, nullptr, 0 }
317};
318
319const SEC_ASN1Template Extensions_Template[] =
320{
321 { SEC_ASN1_SEQUENCE_OF, 0, Extension_Template, 0 }
322};
323
324const SEC_ASN1Template TimeStampReq_Template[] =
325{
326 { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampReq) },
327 { SEC_ASN1_INTEGER, offsetof(TimeStampReq, version), nullptr, 0 },
328 { SEC_ASN1_INLINE, offsetof(TimeStampReq, messageImprint), MessageImprint_Template, 0 },
329 { SEC_ASN1_OBJECT_ID | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, reqPolicy), nullptr, 0 },
330 { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, nonce), nullptr, 0 },
331 { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, certReq), nullptr, 0 },
332 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(TimeStampReq, extensions), Extensions_Template, 0 },
333 { 0, 0, nullptr, 0 }
334};
335
336size_t AppendToBuffer(char const *ptr, size_t size, size_t nmemb, void *userdata)
337{
338 OStringBuffer *pBuffer = static_cast<OStringBuffer*>(userdata);
339 pBuffer->append(ptr, size*nmemb);
340
341 return size*nmemb;
342}
343
344OUString PKIStatusToString(int n)
345{
346 switch (n)
347 {
348 case 0: return "granted";
349 case 1: return "grantedWithMods";
350 case 2: return "rejection";
351 case 3: return "waiting";
352 case 4: return "revocationWarning";
353 case 5: return "revocationNotification";
354 default: return "unknown (" + OUString::number(n) + ")";
355 }
356}
357
358OUString PKIStatusInfoToString(const PKIStatusInfo& rStatusInfo)
359{
360 OUString result = "{status=";
361 if (rStatusInfo.status.len == 1)
362 result += PKIStatusToString(rStatusInfo.status.data[0]);
363 else
364 result += "unknown (len=" + OUString::number(rStatusInfo.status.len);
365
366 // FIXME: Perhaps look at rStatusInfo.statusString.data but note
367 // that we of course can't assume it contains proper UTF-8. After
368 // all, it is data from an external source. Also, RFC3161 claims
369 // it should be a SEQUENCE (1..MAX) OF UTF8String, but another
370 // source claimed it would be a single UTF8String, hmm?
371
372 // FIXME: Worth it to decode failInfo to cleartext, probably not at least as long as this is only for a SAL_INFO
373
374 result += "}";
375
376 return result;
377}
378
379// SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() are
380// not exported from libsmime, so copy them here. Sigh.
381
382SECStatus
383my_SEC_StringToOID(SECItem *to, const char *from, PRUint32 len)
384{
385 PRUint32 decimal_numbers = 0;
386 PRUint32 result_bytes = 0;
387 SECStatus rv;
388 PRUint8 result[1024];
389
390 static const PRUint32 max_decimal = 0xffffffff / 10;
391 static const char OIDstring[] = {"OID."};
392
393 if (!from || !to) {
394 PORT_SetError(SEC_ERROR_INVALID_ARGS);
395 return SECFailure;
396 }
397 if (!len) {
398 len = PL_strlen(from);
399 }
400 if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
401 from += 4; /* skip leading "OID." if present */
402 len -= 4;
403 }
404 if (!len) {
405bad_data:
406 PORT_SetError(SEC_ERROR_BAD_DATA);
407 return SECFailure;
408 }
409 do {
410 PRUint32 decimal = 0;
411 while (len > 0 && rtl::isAsciiDigit(static_cast<unsigned char>(*from))) {
412 PRUint32 addend = *from++ - '0';
413 --len;
414 if (decimal > max_decimal) /* overflow */
415 goto bad_data;
416 decimal = (decimal * 10) + addend;
417 if (decimal < addend) /* overflow */
418 goto bad_data;
419 }
420 if (len != 0 && *from != '.') {
421 goto bad_data;
422 }
423 if (decimal_numbers == 0) {
424 if (decimal > 2)
425 goto bad_data;
426 result[0] = decimal * 40;
427 result_bytes = 1;
428 } else if (decimal_numbers == 1) {
429 if (decimal > 40)
430 goto bad_data;
431 result[0] += decimal;
432 } else {
433 /* encode the decimal number, */
434 PRUint8 * rp;
435 PRUint32 num_bytes = 0;
436 PRUint32 tmp = decimal;
437 while (tmp) {
438 num_bytes++;
439 tmp >>= 7;
440 }
441 if (!num_bytes )
442 ++num_bytes; /* use one byte for a zero value */
443 if (num_bytes + result_bytes > sizeof result)
444 goto bad_data;
445 tmp = num_bytes;
446 rp = result + result_bytes - 1;
447 rp[tmp] = static_cast<PRUint8>(decimal & 0x7f);
448 decimal >>= 7;
449 while (--tmp > 0) {
450 rp[tmp] = static_cast<PRUint8>(decimal | 0x80);
451 decimal >>= 7;
452 }
453 result_bytes += num_bytes;
454 }
455 ++decimal_numbers;
456 if (len > 0) { /* skip trailing '.' */
457 ++from;
458 --len;
459 }
460 } while (len > 0);
461 /* now result contains result_bytes of data */
462 if (to->data && to->len >= result_bytes) {
463 to->len = result_bytes;
464 PORT_Memcpy(to->data, result, to->len);
465 rv = SECSuccess;
466 } else {
467 SECItem result_item = {siBuffer, nullptr, 0 };
468 result_item.data = result;
469 result_item.len = result_bytes;
470 rv = SECITEM_CopyItem(nullptr, to, &result_item);
471 }
472 return rv;
473}
474
475NSSCMSAttribute *
476my_NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute **attrs, SECOidTag oidtag, PRBool only)
477{
478 SECOidData *oid;
479 NSSCMSAttribute *attr1, *attr2;
480
481 if (attrs == nullptr)
482 return nullptr;
483
484 oid = SECOID_FindOIDByTag(oidtag);
485 if (oid == nullptr)
486 return nullptr;
487
488 while ((attr1 = *attrs++) != nullptr) {
489 if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
490 oid->oid.data,
491 oid->oid.len) == 0)
492 break;
493 }
494
495 if (attr1 == nullptr)
496 return nullptr;
497
498 if (!only)
499 return attr1;
500
501 while ((attr2 = *attrs++) != nullptr) {
502 if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
503 oid->oid.data,
504 oid->oid.len) == 0)
505 break;
506 }
507
508 if (attr2 != nullptr)
509 return nullptr;
510
511 return attr1;
512}
513
514SECStatus
515my_NSS_CMSArray_Add(PLArenaPool *poolp, void ***array, void *obj)
516{
517 int n = 0;
518 void **dest;
519
520 PORT_Assert(array != NULL);
521 if (array == nullptr)
522 return SECFailure;
523
524 if (*array == nullptr) {
525 dest = static_cast<void **>(PORT_ArenaAlloc(poolp, 2 * sizeof(void *)));
526 } else {
527 void **p = *array;
528 while (*p++)
529 n++;
530 dest = static_cast<void **>(PORT_ArenaGrow (poolp,
531 *array,
532 (n + 1) * sizeof(void *),
533 (n + 2) * sizeof(void *)));
534 }
535
536 if (dest == nullptr)
537 return SECFailure;
538
539 dest[n] = obj;
540 dest[n+1] = nullptr;
541 *array = dest;
542 return SECSuccess;
543}
544
545SECOidTag
546my_NSS_CMSAttribute_GetType(const NSSCMSAttribute *attr)
547{
548 SECOidData *typetag;
549
550 typetag = SECOID_FindOID(&(attr->type));
551 if (typetag == nullptr)
552 return SEC_OID_UNKNOWN;
553
554 return typetag->offset;
555}
556
557SECStatus
558my_NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr)
559{
560 NSSCMSAttribute *oattr;
561 void *mark;
562 SECOidTag type;
563
564 mark = PORT_ArenaMark(poolp);
565
566 /* find oidtag of attr */
567 type = my_NSS_CMSAttribute_GetType(attr);
568
569 /* see if we have one already */
570 oattr = my_NSS_CMSAttributeArray_FindAttrByOidTag(*attrs, type, PR_FALSE);
571 PORT_Assert (oattr == NULL);
572 if (oattr != nullptr)
573 goto loser; /* XXX or would it be better to replace it? */
574
575 /* no, shove it in */
576 if (my_NSS_CMSArray_Add(poolp, reinterpret_cast<void ***>(attrs), static_cast<void *>(attr)) != SECSuccess)
577 goto loser;
578
579 PORT_ArenaUnmark(poolp, mark);
580 return SECSuccess;
581
582loser:
583 PORT_ArenaRelease(poolp, mark);
584 return SECFailure;
585}
586
587SECStatus
588my_NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
589{
590 return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
591}
592
593SECStatus
594my_NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
595{
596 return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
597}
598
599NSSCMSMessage *CreateCMSMessage(const PRTime* time,
600 NSSCMSSignedData **cms_sd,
601 NSSCMSSignerInfo **cms_signer,
602 CERTCertificate *cert,
603 SECItem *digest)
604{
605 NSSCMSMessage *result = NSS_CMSMessage_Create(nullptr);
606 if (!result)
607 {
608 SAL_WARN("svl.crypto", "NSS_CMSMessage_Create failed");
609 return nullptr;
610 }
611
612 *cms_sd = NSS_CMSSignedData_Create(result);
613 if (!*cms_sd)
614 {
615 SAL_WARN("svl.crypto", "NSS_CMSSignedData_Create failed");
616 NSS_CMSMessage_Destroy(result);
617 return nullptr;
618 }
619
620 NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(result);
621 if (NSS_CMSContentInfo_SetContent_SignedData(result, cms_cinfo, *cms_sd) != SECSuccess)
622 {
623 SAL_WARN("svl.crypto", "NSS_CMSContentInfo_SetContent_SignedData failed");
624 NSS_CMSSignedData_Destroy(*cms_sd);
625 NSS_CMSMessage_Destroy(result);
626 return nullptr;
627 }
628
629 cms_cinfo = NSS_CMSSignedData_GetContentInfo(*cms_sd);
630
631 // Attach NULL data as detached data
632 if (NSS_CMSContentInfo_SetContent_Data(result, cms_cinfo, nullptr, PR_TRUE) != SECSuccess)
633 {
634 SAL_WARN("svl.crypto", "NSS_CMSContentInfo_SetContent_Data failed");
635 NSS_CMSSignedData_Destroy(*cms_sd);
636 NSS_CMSMessage_Destroy(result);
637 return nullptr;
638 }
639
640 // workaround: with legacy "dbm:", NSS can't find the private key - try out
641 // if it works, and fallback if it doesn't.
642 if (SECKEYPrivateKey * pPrivateKey = PK11_FindKeyByAnyCert(cert, nullptr))
643 {
645 {
646 // pPrivateKey only exists in the memory in the LOK case, don't delete it.
647 SECKEY_DestroyPrivateKey(pPrivateKey);
648 }
649 *cms_signer = NSS_CMSSignerInfo_Create(result, cert, SEC_OID_SHA256);
650 }
651 else
652 {
653 pPrivateKey = PK11_FindKeyByDERCert(cert->slot, cert, nullptr);
654 SECKEYPublicKey *const pPublicKey = CERT_ExtractPublicKey(cert);
655 if (pPublicKey && pPrivateKey)
656 {
657 *cms_signer = NSS_CMSSignerInfo_CreateWithSubjKeyID(result, &cert->subjectKeyID, pPublicKey, pPrivateKey, SEC_OID_SHA256);
658 SECKEY_DestroyPrivateKey(pPrivateKey);
659 SECKEY_DestroyPublicKey(pPublicKey);
660 if (*cms_signer)
661 {
662 // this is required in NSS_CMSSignerInfo_IncludeCerts()
663 // (and NSS_CMSSignerInfo_GetSigningCertificate() doesn't work)
664 (**cms_signer).cert = CERT_DupCertificate(cert);
665 }
666 }
667 }
668 if (!*cms_signer)
669 {
670 SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_Create failed");
671 NSS_CMSSignedData_Destroy(*cms_sd);
672 NSS_CMSMessage_Destroy(result);
673 return nullptr;
674 }
675
676 if (time && NSS_CMSSignerInfo_AddSigningTime(*cms_signer, *time) != SECSuccess)
677 {
678 SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_AddSigningTime failed");
679 NSS_CMSSignedData_Destroy(*cms_sd);
680 NSS_CMSMessage_Destroy(result);
681 return nullptr;
682 }
683
684 if (NSS_CMSSignerInfo_IncludeCerts(*cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
685 {
686 SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_IncludeCerts failed");
687 NSS_CMSSignedData_Destroy(*cms_sd);
688 NSS_CMSMessage_Destroy(result);
689 return nullptr;
690 }
691
692 if (NSS_CMSSignedData_AddCertificate(*cms_sd, cert) != SECSuccess)
693 {
694 SAL_WARN("svl.crypto", "NSS_CMSSignedData_AddCertificate failed");
695 NSS_CMSSignedData_Destroy(*cms_sd);
696 NSS_CMSMessage_Destroy(result);
697 return nullptr;
698 }
699
700 if (NSS_CMSSignedData_AddSignerInfo(*cms_sd, *cms_signer) != SECSuccess)
701 {
702 SAL_WARN("svl.crypto", "NSS_CMSSignedData_AddSignerInfo failed");
703 NSS_CMSSignedData_Destroy(*cms_sd);
704 NSS_CMSMessage_Destroy(result);
705 return nullptr;
706 }
707
708 if (NSS_CMSSignedData_SetDigestValue(*cms_sd, SEC_OID_SHA256, digest) != SECSuccess)
709 {
710 SAL_WARN("svl.crypto", "NSS_CMSSignedData_SetDigestValue failed");
711 NSS_CMSSignedData_Destroy(*cms_sd);
712 NSS_CMSMessage_Destroy(result);
713 return nullptr;
714 }
715
716 return result;
717}
718
719#elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
720
722size_t GetDERLengthOfLength(size_t nLength)
723{
724 size_t nRet = 1;
725
726 if(nLength > 127)
727 {
728 while (nLength >> (nRet * 8))
729 ++nRet;
730 // Long form means one additional byte: the length of the length and
731 // the length itself.
732 ++nRet;
733 }
734 return nRet;
735}
736
738void WriteDERLength(SvStream& rStream, size_t nLength)
739{
740 size_t nLengthOfLength = GetDERLengthOfLength(nLength);
741 if (nLengthOfLength == 1)
742 {
743 // We can use the short form.
744 rStream.WriteUInt8(nLength);
745 return;
746 }
747
748 // 0x80 means that the we use the long form: the first byte is the length
749 // of length with the highest bit set to 1, not the actual length.
750 rStream.WriteUInt8(0x80 | (nLengthOfLength - 1));
751 for (size_t i = 1; i < nLengthOfLength; ++i)
752 rStream.WriteUInt8(nLength >> ((nLengthOfLength - i - 1) * 8));
753}
754
755const unsigned nASN1_INTEGER = 0x02;
756const unsigned nASN1_OCTET_STRING = 0x04;
757const unsigned nASN1_NULL = 0x05;
758const unsigned nASN1_OBJECT_IDENTIFIER = 0x06;
759const unsigned nASN1_SEQUENCE = 0x10;
761const unsigned nASN1_TAGGED_CONSTRUCTED = 0xa0;
762const unsigned nASN1_CONSTRUCTED = 0x20;
763
765bool CreateSigningCertificateAttribute(void const * pDerEncoded, int nDerEncoded, PCCERT_CONTEXT pCertContext, SvStream& rEncodedCertificate)
766{
767 // CryptEncodeObjectEx() does not support encoding arbitrary ASN.1
768 // structures, like SigningCertificateV2 from RFC 5035, so let's build it
769 // manually.
770
771 // Count the certificate hash and put it to aHash.
772 // 2.16.840.1.101.3.4.2.1, i.e. sha256.
773 std::vector<unsigned char> aSHA256{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01};
774
775 HCRYPTPROV hProv = 0;
776 if (!CryptAcquireContextW(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
777 {
778 SAL_WARN("svl.crypto", "CryptAcquireContext() failed");
779 return false;
780 }
781
782 HCRYPTHASH hHash = 0;
783 if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
784 {
785 SAL_WARN("svl.crypto", "CryptCreateHash() failed");
786 return false;
787 }
788
789 if (!CryptHashData(hHash, static_cast<const BYTE*>(pDerEncoded), nDerEncoded, 0))
790 {
791 SAL_WARN("svl.crypto", "CryptHashData() failed");
792 return false;
793 }
794
795 DWORD nHash = 0;
796 if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nHash, 0))
797 {
798 SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash length");
799 return false;
800 }
801
802 std::vector<unsigned char> aHash(nHash);
803 if (!CryptGetHashParam(hHash, HP_HASHVAL, aHash.data(), &nHash, 0))
804 {
805 SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash");
806 return false;
807 }
808
809 CryptDestroyHash(hHash);
810 CryptReleaseContext(hProv, 0);
811
812 // Collect info for IssuerSerial.
813 BYTE* pIssuer = pCertContext->pCertInfo->Issuer.pbData;
814 DWORD nIssuer = pCertContext->pCertInfo->Issuer.cbData;
815 BYTE* pSerial = pCertContext->pCertInfo->SerialNumber.pbData;
816 DWORD nSerial = pCertContext->pCertInfo->SerialNumber.cbData;
817 // pSerial is LE, aSerial is BE.
818 std::vector<BYTE> aSerial(nSerial);
819 for (size_t i = 0; i < nSerial; ++i)
820 aSerial[i] = *(pSerial + nSerial - i - 1);
821
822 // We now have all the info to count the lengths.
823 // The layout of the payload is:
824 // SEQUENCE: SigningCertificateV2
825 // SEQUENCE: SEQUENCE OF ESSCertIDv2
826 // SEQUENCE: ESSCertIDv2
827 // SEQUENCE: AlgorithmIdentifier
828 // OBJECT: algorithm
829 // NULL: parameters
830 // OCTET STRING: certHash
831 // SEQUENCE: IssuerSerial
832 // SEQUENCE: GeneralNames
833 // cont [ 4 ]: Name
834 // SEQUENCE: Issuer blob
835 // INTEGER: CertificateSerialNumber
836
837 size_t nAlgorithm = 1 + GetDERLengthOfLength(aSHA256.size()) + aSHA256.size();
838 size_t nParameters = 1 + GetDERLengthOfLength(1);
839 size_t nAlgorithmIdentifier = 1 + GetDERLengthOfLength(nAlgorithm + nParameters) + nAlgorithm + nParameters;
840 size_t nCertHash = 1 + GetDERLengthOfLength(aHash.size()) + aHash.size();
841 size_t nName = 1 + GetDERLengthOfLength(nIssuer) + nIssuer;
842 size_t nGeneralNames = 1 + GetDERLengthOfLength(nName) + nName;
843 size_t nCertificateSerialNumber = 1 + GetDERLengthOfLength(nSerial) + nSerial;
844 size_t nIssuerSerial = 1 + GetDERLengthOfLength(nGeneralNames + nCertificateSerialNumber) + nGeneralNames + nCertificateSerialNumber;
845 size_t nESSCertIDv2 = 1 + GetDERLengthOfLength(nAlgorithmIdentifier + nCertHash + nIssuerSerial) + nAlgorithmIdentifier + nCertHash + nIssuerSerial;
846 size_t nESSCertIDv2s = 1 + GetDERLengthOfLength(nESSCertIDv2) + nESSCertIDv2;
847
848 // Write SigningCertificateV2.
849 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
850 WriteDERLength(rEncodedCertificate, nESSCertIDv2s);
851 // Write SEQUENCE OF ESSCertIDv2.
852 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
853 WriteDERLength(rEncodedCertificate, nESSCertIDv2);
854 // Write ESSCertIDv2.
855 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
856 WriteDERLength(rEncodedCertificate, nAlgorithmIdentifier + nCertHash + nIssuerSerial);
857 // Write AlgorithmIdentifier.
858 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
859 WriteDERLength(rEncodedCertificate, nAlgorithm + nParameters);
860 // Write algorithm.
861 rEncodedCertificate.WriteUInt8(nASN1_OBJECT_IDENTIFIER);
862 WriteDERLength(rEncodedCertificate, aSHA256.size());
863 rEncodedCertificate.WriteBytes(aSHA256.data(), aSHA256.size());
864 // Write parameters.
865 rEncodedCertificate.WriteUInt8(nASN1_NULL);
866 rEncodedCertificate.WriteUInt8(0);
867 // Write certHash.
868 rEncodedCertificate.WriteUInt8(nASN1_OCTET_STRING);
869 WriteDERLength(rEncodedCertificate, aHash.size());
870 rEncodedCertificate.WriteBytes(aHash.data(), aHash.size());
871 // Write IssuerSerial.
872 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
873 WriteDERLength(rEncodedCertificate, nGeneralNames + nCertificateSerialNumber);
874 // Write GeneralNames.
875 rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
876 WriteDERLength(rEncodedCertificate, nName);
877 // Write Name.
878 rEncodedCertificate.WriteUInt8(nASN1_TAGGED_CONSTRUCTED | 4);
879 WriteDERLength(rEncodedCertificate, nIssuer);
880 rEncodedCertificate.WriteBytes(pIssuer, nIssuer);
881 // Write CertificateSerialNumber.
882 rEncodedCertificate.WriteUInt8(nASN1_INTEGER);
883 WriteDERLength(rEncodedCertificate, nSerial);
884 rEncodedCertificate.WriteBytes(aSerial.data(), aSerial.size());
885
886 return true;
887}
888#endif // USE_CRYPTO_MSCAPI
889
890} // anonymous namespace
891
892namespace svl::crypto {
893
894static int AsHex(char ch)
895{
896 int nRet = 0;
897 if (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
898 nRet = ch - '0';
899 else
900 {
901 if (ch >= 'a' && ch <= 'f')
902 nRet = ch - 'a';
903 else if (ch >= 'A' && ch <= 'F')
904 nRet = ch - 'A';
905 else
906 return -1;
907 nRet += 10;
908 }
909 return nRet;
910}
911
912std::vector<unsigned char> DecodeHexString(std::string_view rHex)
913{
914 std::vector<unsigned char> aRet;
915 size_t nHexLen = rHex.size();
916 {
917 int nByte = 0;
918 int nCount = 2;
919 for (size_t i = 0; i < nHexLen; ++i)
920 {
921 nByte = nByte << 4;
922 sal_Int8 nParsed = AsHex(rHex[i]);
923 if (nParsed == -1)
924 {
925 SAL_WARN("svl.crypto", "DecodeHexString: invalid hex value");
926 return aRet;
927 }
928 nByte += nParsed;
929 --nCount;
930 if (!nCount)
931 {
932 aRet.push_back(nByte);
933 nCount = 2;
934 nByte = 0;
935 }
936 }
937 }
938
939 return aRet;
940}
941
942bool Signing::Sign(OStringBuffer& rCMSHexBuffer)
943{
944#if !USE_CRYPTO_ANY
945 (void)rCMSHexBuffer;
946 return false;
947#else
948 // Create the PKCS#7 object.
949 css::uno::Sequence<sal_Int8> aDerEncoded = m_xCertificate->getEncoded();
950 if (!aDerEncoded.hasElements())
951 {
952 SAL_WARN("svl.crypto", "Crypto::Signing: empty certificate");
953 return false;
954 }
955
956#if USE_CRYPTO_NSS
957 CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(aDerEncoded.getArray()), aDerEncoded.getLength());
958
959 if (!cert)
960 {
961 SAL_WARN("svl.crypto", "CERT_DecodeCertFromPackage failed");
962 return false;
963 }
964
965 std::vector<unsigned char> aHashResult;
966 {
968
969 for (const auto& pair : m_dataBlocks)
970 aHash.update(static_cast<const unsigned char*>(pair.first), pair.second);
971
972 aHashResult = aHash.finalize();
973 }
974 SECItem digest;
975 digest.data = aHashResult.data();
976 digest.len = aHashResult.size();
977
978 PRTime now = PR_Now();
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;
984
985 OString pass(OUStringToOString( m_aSignPassword, RTL_TEXTENCODING_UTF8 ));
986
987 TimeStampReq src;
988 OStringBuffer response_buffer;
989 TimeStampResp response;
990 SECItem response_item;
991 NSSCMSAttribute timestamp;
992 SECItem values[2];
993 SECItem *valuesp[2];
994 valuesp[0] = values;
995 valuesp[1] = nullptr;
996 SECOidData typetag;
997
998 if( !m_aSignTSA.isEmpty() )
999 {
1000 // Create another CMS message with the same contents as cms_msg, because it doesn't seem
1001 // possible to encode a message twice (once to get something to timestamp, and then after
1002 // adding the timestamp attribute).
1003
1004 NSSCMSSignedData *ts_cms_sd;
1005 NSSCMSSignerInfo *ts_cms_signer;
1006 NSSCMSMessage *ts_cms_msg = CreateCMSMessage(&now, &ts_cms_sd, &ts_cms_signer, cert, &digest);
1007 if (!ts_cms_msg)
1008 {
1009 return false;
1010 }
1011
1012 SECItem ts_cms_output;
1013 ts_cms_output.data = nullptr;
1014 ts_cms_output.len = 0;
1015 PLArenaPool *ts_arena = PORT_NewArena(10000);
1016 NSSCMSEncoderContext *ts_cms_ecx;
1017 ts_cms_ecx = NSS_CMSEncoder_Start(ts_cms_msg, nullptr, nullptr, &ts_cms_output, ts_arena, PDFSigningPKCS7PasswordCallback,
1018 const_cast<char*>(pass.getStr()), nullptr, nullptr, nullptr, nullptr);
1019
1020 if (NSS_CMSEncoder_Finish(ts_cms_ecx) != SECSuccess)
1021 {
1022 SAL_WARN("svl.crypto", "NSS_CMSEncoder_Finish failed");
1023 return false;
1024 }
1025
1026 // I have compared the ts_cms_output produced here with the cms_output produced below when
1027 // not actually calling my_NSS_CMSSignerInfo_AddUnauthAttr()), and they are identical.
1028
1029 std::vector<unsigned char> aTsHashResult = comphelper::Hash::calculateHash(ts_cms_signer->encDigest.data, ts_cms_signer->encDigest.len, comphelper::HashType::SHA256);
1030 SECItem ts_digest;
1031 ts_digest.type = siBuffer;
1032 ts_digest.data = aTsHashResult.data();
1033 ts_digest.len = aTsHashResult.size();
1034
1035 unsigned char cOne = 1;
1036 src.version.type = siUnsignedInteger;
1037 src.version.data = &cOne;
1038 src.version.len = sizeof(cOne);
1039
1040 src.messageImprint.hashAlgorithm.algorithm.data = nullptr;
1041 src.messageImprint.hashAlgorithm.parameters.data = nullptr;
1042 SECOID_SetAlgorithmID(nullptr, &src.messageImprint.hashAlgorithm, SEC_OID_SHA256, nullptr);
1043 src.messageImprint.hashedMessage = ts_digest;
1044
1045 src.reqPolicy.type = siBuffer;
1046 src.reqPolicy.data = nullptr;
1047 src.reqPolicy.len = 0;
1048
1050 src.nonce.type = siUnsignedInteger;
1051 src.nonce.data = reinterpret_cast<unsigned char*>(&nNonce);
1052 src.nonce.len = sizeof(nNonce);
1053
1054 src.certReq.type = siUnsignedInteger;
1055 src.certReq.data = &cOne;
1056 src.certReq.len = sizeof(cOne);
1057
1058 src.extensions = nullptr;
1059
1060 SECItem* timestamp_request = SEC_ASN1EncodeItem(nullptr, nullptr, &src, TimeStampReq_Template);
1061 if (timestamp_request == nullptr)
1062 {
1063 SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem failed");
1064 return false;
1065 }
1066
1067 if (timestamp_request->data == nullptr)
1068 {
1069 SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem succeeded but got NULL data");
1070 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1071 return false;
1072 }
1073
1074 SAL_INFO("svl.crypto", "request length=" << timestamp_request->len);
1075
1076 // Send time stamp request to TSA server, receive response
1077
1078 CURL* curl = curl_easy_init();
1079 CURLcode rc;
1080 struct curl_slist* slist = nullptr;
1081
1082 if (!curl)
1083 {
1084 SAL_WARN("svl.crypto", "curl_easy_init failed");
1085 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1086 return false;
1087 }
1088
1089 SAL_INFO("svl.crypto", "Setting curl to verbose: " << (curl_easy_setopt(curl, CURLOPT_VERBOSE, 1) == CURLE_OK ? "OK" : "FAIL"));
1090
1091 if ((rc = curl_easy_setopt(curl, CURLOPT_URL, OUStringToOString(m_aSignTSA, RTL_TEXTENCODING_UTF8).getStr())) != CURLE_OK)
1092 {
1093 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_URL) failed: " << curl_easy_strerror(rc));
1094 curl_easy_cleanup(curl);
1095 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1096 return false;
1097 }
1098
1099 slist = curl_slist_append(slist, "Content-Type: application/timestamp-query");
1100 slist = curl_slist_append(slist, "Accept: application/timestamp-reply");
1101
1102 if ((rc = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist)) != CURLE_OK)
1103 {
1104 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_HTTPHEADER) failed: " << curl_easy_strerror(rc));
1105 curl_slist_free_all(slist);
1106 curl_easy_cleanup(curl);
1107 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1108 return false;
1109 }
1110
1111 if ((rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<tools::Long>(timestamp_request->len))) != CURLE_OK ||
1112 (rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, timestamp_request->data)) != CURLE_OK)
1113 {
1114 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_POSTFIELDSIZE or CURLOPT_POSTFIELDS) failed: " << curl_easy_strerror(rc));
1115 curl_easy_cleanup(curl);
1116 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1117 return false;
1118 }
1119
1120 if ((rc = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_buffer)) != CURLE_OK ||
1121 (rc = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToBuffer)) != CURLE_OK)
1122 {
1123 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_WRITEDATA or CURLOPT_WRITEFUNCTION) failed: " << curl_easy_strerror(rc));
1124 curl_easy_cleanup(curl);
1125 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1126 return false;
1127 }
1128
1129 if ((rc = curl_easy_setopt(curl, CURLOPT_POST, 1)) != CURLE_OK)
1130 {
1131 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_POST) failed: " << curl_easy_strerror(rc));
1132 curl_easy_cleanup(curl);
1133 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1134 return false;
1135 }
1136
1137 char error_buffer[CURL_ERROR_SIZE];
1138 if ((rc = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer)) != CURLE_OK)
1139 {
1140 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_ERRORBUFFER) failed: " << curl_easy_strerror(rc));
1141 curl_easy_cleanup(curl);
1142 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1143 return false;
1144 }
1145
1146 // Use a ten second timeout
1147 if ((rc = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10)) != CURLE_OK ||
1148 (rc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10)) != CURLE_OK)
1149 {
1150 SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_TIMEOUT or CURLOPT_CONNECTTIMEOUT) failed: " << curl_easy_strerror(rc));
1151 curl_easy_cleanup(curl);
1152 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1153 return false;
1154 }
1155
1156 if (curl_easy_perform(curl) != CURLE_OK)
1157 {
1158 SAL_WARN("svl.crypto", "curl_easy_perform failed: " << error_buffer);
1159 curl_easy_cleanup(curl);
1160 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1161 return false;
1162 }
1163
1164 SAL_INFO("svl.crypto", "PDF signing: got response, length=" << response_buffer.getLength());
1165
1166 curl_slist_free_all(slist);
1167 curl_easy_cleanup(curl);
1168 SECITEM_FreeItem(timestamp_request, PR_TRUE);
1169
1170 memset(&response, 0, sizeof(response));
1171
1172 response_item.type = siBuffer;
1173 response_item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(response_buffer.getStr()));
1174 response_item.len = response_buffer.getLength();
1175
1176 if (SEC_ASN1DecodeItem(nullptr, &response, TimeStampResp_Template, &response_item) != SECSuccess)
1177 {
1178 SAL_WARN("svl.crypto", "SEC_ASN1DecodeItem failed");
1179 return false;
1180 }
1181
1182 SAL_INFO("svl.crypto", "TimeStampResp received and decoded, status=" << PKIStatusInfoToString(response.status));
1183
1184 if (response.status.status.len != 1 ||
1185 (response.status.status.data[0] != 0 && response.status.status.data[0] != 1))
1186 {
1187 SAL_WARN("svl.crypto", "Timestamp request was not granted");
1188 return false;
1189 }
1190
1191 // timestamp.type filled in below
1192
1193 // Not sure if we actually need two entries in the values array, now when valuesp is an
1194 // array too, the pointer to the values array followed by a null pointer. But I don't feel
1195 // like experimenting.
1196 values[0] = response.timeStampToken;
1197 values[1].type = siBuffer;
1198 values[1].data = nullptr;
1199 values[1].len = 0;
1200
1201 timestamp.values = valuesp;
1202
1203 typetag.oid.data = nullptr;
1204 // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1)
1205 // member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)
1206 // smime(16) aa(2) 14 }
1207 if (my_SEC_StringToOID(&typetag.oid, "1.2.840.113549.1.9.16.2.14", 0) != SECSuccess)
1208 {
1209 SAL_WARN("svl.crypto", "SEC_StringToOID failed");
1210 return false;
1211 }
1212 typetag.offset = SEC_OID_UNKNOWN; // ???
1213 typetag.desc = "id-aa-timeStampToken";
1214 typetag.mechanism = CKM_SHA_1; // ???
1215 typetag.supportedExtension = UNSUPPORTED_CERT_EXTENSION; // ???
1216 timestamp.typeTag = &typetag;
1217
1218 timestamp.type = typetag.oid; // ???
1219
1220 timestamp.encoded = PR_TRUE; // ???
1221
1222 if (my_NSS_CMSSignerInfo_AddUnauthAttr(cms_signer, &timestamp) != SECSuccess)
1223 {
1224 SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_AddUnauthAttr failed");
1225 return false;
1226 }
1227 }
1228
1229 // Add the signing certificate as a signed attribute.
1230 ESSCertIDv2* aCertIDs[2];
1231 ESSCertIDv2 aCertID;
1232 // Write ESSCertIDv2.hashAlgorithm.
1233 aCertID.hashAlgorithm.algorithm.data = nullptr;
1234 aCertID.hashAlgorithm.parameters.data = nullptr;
1235 SECOID_SetAlgorithmID(nullptr, &aCertID.hashAlgorithm, SEC_OID_SHA256, nullptr);
1236 comphelper::ScopeGuard aAlgoGuard(
1237 [&aCertID] () { SECOID_DestroyAlgorithmID(&aCertID.hashAlgorithm, false); } );
1238 // Write ESSCertIDv2.certHash.
1239 SECItem aCertHashItem;
1240 auto pDerEncoded = reinterpret_cast<const unsigned char *>(aDerEncoded.getArray());
1241 std::vector<unsigned char> aCertHashResult = comphelper::Hash::calculateHash(pDerEncoded, aDerEncoded.getLength(), comphelper::HashType::SHA256);
1242 aCertHashItem.type = siBuffer;
1243 aCertHashItem.data = aCertHashResult.data();
1244 aCertHashItem.len = aCertHashResult.size();
1245 aCertID.certHash = aCertHashItem;
1246 // Write ESSCertIDv2.issuerSerial.
1247 IssuerSerial aSerial;
1248 GeneralName aName;
1249 aName.name = cert->issuer;
1250 aSerial.issuer.names = aName;
1251 aSerial.serialNumber = cert->serialNumber;
1252 aCertID.issuerSerial = aSerial;
1253 // Write SigningCertificateV2.certs.
1254 aCertIDs[0] = &aCertID;
1255 aCertIDs[1] = nullptr;
1256 SigningCertificateV2 aCertificate;
1257 aCertificate.certs = &aCertIDs[0];
1258 SECItem* pEncodedCertificate = SEC_ASN1EncodeItem(nullptr, nullptr, &aCertificate, SigningCertificateV2Template);
1259 if (!pEncodedCertificate)
1260 {
1261 SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem() failed");
1262 return false;
1263 }
1264
1265 NSSCMSAttribute aAttribute;
1266 SECItem aAttributeValues[2];
1267 SECItem* pAttributeValues[2];
1268 pAttributeValues[0] = aAttributeValues;
1269 pAttributeValues[1] = nullptr;
1270 aAttributeValues[0] = *pEncodedCertificate;
1271 aAttributeValues[1].type = siBuffer;
1272 aAttributeValues[1].data = nullptr;
1273 aAttributeValues[1].len = 0;
1274 aAttribute.values = pAttributeValues;
1275
1276 SECOidData aOidData;
1277 aOidData.oid.data = nullptr;
1278 /*
1279 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
1280 * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
1281 * smime(16) id-aa(2) 47 }
1282 */
1283 if (my_SEC_StringToOID(&aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess)
1284 {
1285 SAL_WARN("svl.crypto", "my_SEC_StringToOID() failed");
1286 return false;
1287 }
1289 [&aOidData] () { SECITEM_FreeItem(&aOidData.oid, false); } );
1290 aOidData.offset = SEC_OID_UNKNOWN;
1291 aOidData.desc = "id-aa-signingCertificateV2";
1292 aOidData.mechanism = CKM_SHA_1;
1293 aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
1294 aAttribute.typeTag = &aOidData;
1295 aAttribute.type = aOidData.oid;
1296 aAttribute.encoded = PR_TRUE;
1297
1298 if (my_NSS_CMSSignerInfo_AddAuthAttr(cms_signer, &aAttribute) != SECSuccess)
1299 {
1300 SAL_WARN("svl.crypto", "my_NSS_CMSSignerInfo_AddAuthAttr() failed");
1301 return false;
1302 }
1303
1304 SECItem cms_output;
1305 cms_output.data = nullptr;
1306 cms_output.len = 0;
1307 PLArenaPool *arena = PORT_NewArena(10000);
1308 const ::comphelper::ScopeGuard aScopeGuard(
1309 [&arena]() mutable { PORT_FreeArena(arena, true); } );
1310 NSSCMSEncoderContext *cms_ecx;
1311
1312 // Possibly it would work to even just pass NULL for the password callback function and its
1313 // argument here. After all, at least with the hardware token and associated software I tested
1314 // with, the software itself pops up a dialog asking for the PIN (password). But I am not going
1315 // to test it and risk locking up my token...
1316
1317 cms_ecx = NSS_CMSEncoder_Start(cms_msg, nullptr, nullptr, &cms_output, arena, PDFSigningPKCS7PasswordCallback,
1318 const_cast<char*>(pass.getStr()), nullptr, nullptr, nullptr, nullptr);
1319
1320 if (!cms_ecx)
1321 {
1322 SAL_WARN("svl.crypto", "NSS_CMSEncoder_Start failed");
1323 return false;
1324 }
1325
1326 if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess)
1327 {
1328 SAL_WARN("svl.crypto", "NSS_CMSEncoder_Finish failed");
1329 return false;
1330 }
1331
1332 if (cms_output.len*2 > MAX_SIGNATURE_CONTENT_LENGTH)
1333 {
1334 SAL_WARN("svl.crypto", "Signature requires more space (" << cms_output.len*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
1335 NSS_CMSMessage_Destroy(cms_msg);
1336 return false;
1337 }
1338
1339 for (unsigned int i = 0; i < cms_output.len ; i++)
1340 appendHex(cms_output.data[i], rCMSHexBuffer);
1341
1342 SECITEM_FreeItem(pEncodedCertificate, PR_TRUE);
1343 NSS_CMSMessage_Destroy(cms_msg);
1344
1345 return true;
1346
1347#elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
1348
1349 PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(aDerEncoded.getArray()), aDerEncoded.getLength());
1350 if (pCertContext == nullptr)
1351 {
1352 SAL_WARN("svl.crypto", "CertCreateCertificateContext failed: " << WindowsErrorString(GetLastError()));
1353 return false;
1354 }
1355
1356 CRYPT_SIGN_MESSAGE_PARA aPara = {};
1357 aPara.cbSize = sizeof(aPara);
1358 aPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
1359 aPara.pSigningCert = pCertContext;
1360 aPara.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256);
1361 aPara.HashAlgorithm.Parameters.cbData = 0;
1362 aPara.cMsgCert = 1;
1363 aPara.rgpMsgCert = &pCertContext;
1364
1365 NCRYPT_KEY_HANDLE hCryptKey = 0;
1366 DWORD dwFlags = CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;
1367 HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hCryptKey;
1368 DWORD nKeySpec;
1369 BOOL bFreeNeeded;
1370
1371 if (!CryptAcquireCertificatePrivateKey(pCertContext,
1372 dwFlags,
1373 nullptr,
1374 phCryptProvOrNCryptKey,
1375 &nKeySpec,
1376 &bFreeNeeded))
1377 {
1378 SAL_WARN("svl.crypto", "CryptAcquireCertificatePrivateKey failed: " << WindowsErrorString(GetLastError()));
1379 CertFreeCertificateContext(pCertContext);
1380 return false;
1381 }
1382 assert(!bFreeNeeded);
1383
1384 CMSG_SIGNER_ENCODE_INFO aSignerInfo = {};
1385 aSignerInfo.cbSize = sizeof(aSignerInfo);
1386 aSignerInfo.pCertInfo = pCertContext->pCertInfo;
1387 aSignerInfo.hNCryptKey = hCryptKey;
1388 aSignerInfo.dwKeySpec = nKeySpec;
1389 aSignerInfo.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256);
1390 aSignerInfo.HashAlgorithm.Parameters.cbData = 0;
1391
1392 // Add the signing certificate as a signed attribute.
1393 CRYPT_INTEGER_BLOB aCertificateBlob;
1394 SvMemoryStream aEncodedCertificate;
1395 if (!CreateSigningCertificateAttribute(aDerEncoded.getArray(), aDerEncoded.getLength(), pCertContext, aEncodedCertificate))
1396 {
1397 SAL_WARN("svl.crypto", "CreateSigningCertificateAttribute() failed");
1398 return false;
1399 }
1400 aCertificateBlob.pbData = const_cast<BYTE*>(static_cast<const BYTE*>(aEncodedCertificate.GetData()));
1401 aCertificateBlob.cbData = aEncodedCertificate.GetSize();
1402 CRYPT_ATTRIBUTE aCertificateAttribute;
1403 /*
1404 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
1405 * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
1406 * smime(16) id-aa(2) 47 }
1407 */
1408 aCertificateAttribute.pszObjId = const_cast<LPSTR>("1.2.840.113549.1.9.16.2.47");
1409 aCertificateAttribute.cValue = 1;
1410 aCertificateAttribute.rgValue = &aCertificateBlob;
1411 aSignerInfo.cAuthAttr = 1;
1412 aSignerInfo.rgAuthAttr = &aCertificateAttribute;
1413
1414 CMSG_SIGNED_ENCODE_INFO aSignedInfo = {};
1415 aSignedInfo.cbSize = sizeof(aSignedInfo);
1416 aSignedInfo.cSigners = 1;
1417 aSignedInfo.rgSigners = &aSignerInfo;
1418
1419 CERT_BLOB aCertBlob;
1420
1421 aCertBlob.cbData = pCertContext->cbCertEncoded;
1422 aCertBlob.pbData = pCertContext->pbCertEncoded;
1423
1424 aSignedInfo.cCertEncoded = 1;
1425 aSignedInfo.rgCertEncoded = &aCertBlob;
1426
1427 HCRYPTMSG hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1428 CMSG_DETACHED_FLAG,
1429 CMSG_SIGNED,
1430 &aSignedInfo,
1431 nullptr,
1432 nullptr);
1433 if (!hMsg)
1434 {
1435 SAL_WARN("svl.crypto", "CryptMsgOpenToEncode failed: " << WindowsErrorString(GetLastError()));
1436 CertFreeCertificateContext(pCertContext);
1437 return false;
1438 }
1439
1440 for (size_t i = 0; i < m_dataBlocks.size(); ++i)
1441 {
1442 const bool last = (i == m_dataBlocks.size() - 1);
1443 if (!CryptMsgUpdate(hMsg, static_cast<const BYTE *>(m_dataBlocks[i].first), m_dataBlocks[i].second, last))
1444 {
1445 SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << WindowsErrorString(GetLastError()));
1446 CryptMsgClose(hMsg);
1447 CertFreeCertificateContext(pCertContext);
1448 return false;
1449 }
1450 }
1451
1452 PCRYPT_TIMESTAMP_CONTEXT pTsContext = nullptr;
1453
1454 if( !m_aSignTSA.isEmpty() )
1455 {
1456 HCRYPTMSG hDecodedMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1457 CMSG_DETACHED_FLAG,
1458 CMSG_SIGNED,
1459 0,
1460 nullptr,
1461 nullptr);
1462 if (!hDecodedMsg)
1463 {
1464 SAL_WARN("svl.crypto", "CryptMsgOpenToDecode failed: " << WindowsErrorString(GetLastError()));
1465 CryptMsgClose(hMsg);
1466 CertFreeCertificateContext(pCertContext);
1467 return false;
1468 }
1469
1470 DWORD nTsSigLen = 0;
1471
1472 if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, nullptr, &nTsSigLen))
1473 {
1474 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError()));
1475 CryptMsgClose(hDecodedMsg);
1476 CryptMsgClose(hMsg);
1477 CertFreeCertificateContext(pCertContext);
1478 return false;
1479 }
1480
1481 SAL_INFO("svl.crypto", "nTsSigLen=" << nTsSigLen);
1482
1483 std::unique_ptr<BYTE[]> pTsSig(new BYTE[nTsSigLen]);
1484
1485 if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, pTsSig.get(), &nTsSigLen))
1486 {
1487 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError()));
1488 CryptMsgClose(hDecodedMsg);
1489 CryptMsgClose(hMsg);
1490 CertFreeCertificateContext(pCertContext);
1491 return false;
1492 }
1493
1494 if (!CryptMsgUpdate(hDecodedMsg, pTsSig.get(), nTsSigLen, TRUE))
1495 {
1496 SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << WindowsErrorString(GetLastError()));
1497 CryptMsgClose(hDecodedMsg);
1498 CryptMsgClose(hMsg);
1499 CertFreeCertificateContext(pCertContext);
1500 return false;
1501 }
1502
1503 DWORD nDecodedSignerInfoLen = 0;
1504 if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, nullptr, &nDecodedSignerInfoLen))
1505 {
1506 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsErrorString(GetLastError()));
1507 CryptMsgClose(hDecodedMsg);
1508 CryptMsgClose(hMsg);
1509 CertFreeCertificateContext(pCertContext);
1510 return false;
1511 }
1512
1513 std::unique_ptr<BYTE[]> pDecodedSignerInfoBuf(new BYTE[nDecodedSignerInfoLen]);
1514
1515 if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, pDecodedSignerInfoBuf.get(), &nDecodedSignerInfoLen))
1516 {
1517 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsErrorString(GetLastError()));
1518 CryptMsgClose(hDecodedMsg);
1519 CryptMsgClose(hMsg);
1520 CertFreeCertificateContext(pCertContext);
1521 return false;
1522 }
1523
1524 CMSG_SIGNER_INFO *pDecodedSignerInfo = reinterpret_cast<CMSG_SIGNER_INFO *>(pDecodedSignerInfoBuf.get());
1525
1526 CRYPT_TIMESTAMP_PARA aTsPara;
1528
1529 aTsPara.pszTSAPolicyId = nullptr;
1530 aTsPara.fRequestCerts = TRUE;
1531 aTsPara.Nonce.cbData = sizeof(nNonce);
1532 aTsPara.Nonce.pbData = reinterpret_cast<BYTE *>(&nNonce);
1533 aTsPara.cExtension = 0;
1534 aTsPara.rgExtension = nullptr;
1535
1536 if (!CryptRetrieveTimeStamp(o3tl::toW(m_aSignTSA.getStr()),
1537 0,
1538 10000,
1539 szOID_NIST_sha256,
1540 &aTsPara,
1541 pDecodedSignerInfo->EncryptedHash.pbData,
1542 pDecodedSignerInfo->EncryptedHash.cbData,
1543 &pTsContext,
1544 nullptr,
1545 nullptr))
1546 {
1547 SAL_WARN("svl.crypto", "CryptRetrieveTimeStamp failed: " << WindowsErrorString(GetLastError()));
1548 CryptMsgClose(hDecodedMsg);
1549 CryptMsgClose(hMsg);
1550 CertFreeCertificateContext(pCertContext);
1551 return false;
1552 }
1553
1554 SAL_INFO("svl.crypto", "Time stamp size is " << pTsContext->cbEncoded << " bytes");
1555
1556 // I tried to use CryptMsgControl() with CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR to add the
1557 // timestamp, but that failed with "The parameter is incorrect". Probably it is too late to
1558 // modify the message once its data has already been encoded as part of the
1559 // CryptMsgGetParam() with CMSG_BARE_CONTENT_PARAM above. So close the message and re-do its
1560 // creation steps, but now with an amended aSignerInfo.
1561
1562 CRYPT_INTEGER_BLOB aTimestampBlob;
1563 aTimestampBlob.cbData = pTsContext->cbEncoded;
1564 aTimestampBlob.pbData = pTsContext->pbEncoded;
1565
1566 CRYPT_ATTRIBUTE aTimestampAttribute;
1567 aTimestampAttribute.pszObjId = const_cast<LPSTR>(
1568 "1.2.840.113549.1.9.16.2.14");
1569 aTimestampAttribute.cValue = 1;
1570 aTimestampAttribute.rgValue = &aTimestampBlob;
1571
1572 aSignerInfo.cUnauthAttr = 1;
1573 aSignerInfo.rgUnauthAttr = &aTimestampAttribute;
1574
1575 CryptMsgClose(hMsg);
1576
1577 hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1578 CMSG_DETACHED_FLAG,
1579 CMSG_SIGNED,
1580 &aSignedInfo,
1581 nullptr,
1582 nullptr);
1583
1584 for (size_t i = 0; i < m_dataBlocks.size(); ++i)
1585 {
1586 const bool last = (i == m_dataBlocks.size() - 1);
1587 if (!hMsg ||
1588 !CryptMsgUpdate(hMsg, static_cast<const BYTE *>(m_dataBlocks[i].first), m_dataBlocks[i].second, last))
1589 {
1590 SAL_WARN("svl.crypto", "Re-creating the message failed: " << WindowsErrorString(GetLastError()));
1591 CryptMemFree(pTsContext);
1592 CryptMsgClose(hDecodedMsg);
1593 CryptMsgClose(hMsg);
1594 CertFreeCertificateContext(pCertContext);
1595 return false;
1596 }
1597 }
1598
1599 CryptMsgClose(hDecodedMsg);
1600 }
1601
1602 DWORD nSigLen = 0;
1603
1604 if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, nullptr, &nSigLen))
1605 {
1606 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError()));
1607 if (pTsContext)
1608 CryptMemFree(pTsContext);
1609 CryptMsgClose(hMsg);
1610 CertFreeCertificateContext(pCertContext);
1611 return false;
1612 }
1613
1614 if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
1615 {
1616 SAL_WARN("svl.crypto", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
1617 if (pTsContext)
1618 CryptMemFree(pTsContext);
1619 CryptMsgClose(hMsg);
1620 CertFreeCertificateContext(pCertContext);
1621 return false;
1622 }
1623
1624 SAL_INFO("svl.crypto", "Signature size is " << nSigLen << " bytes");
1625 std::unique_ptr<BYTE[]> pSig(new BYTE[nSigLen]);
1626
1627 if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pSig.get(), &nSigLen))
1628 {
1629 SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsErrorString(GetLastError()));
1630 if (pTsContext)
1631 CryptMemFree(pTsContext);
1632 CryptMsgClose(hMsg);
1633 CertFreeCertificateContext(pCertContext);
1634 return false;
1635 }
1636
1637 // Release resources
1638 if (pTsContext)
1639 CryptMemFree(pTsContext);
1640 CryptMsgClose(hMsg);
1641 CertFreeCertificateContext(pCertContext);
1642
1643 for (unsigned int i = 0; i < nSigLen ; i++)
1644 appendHex(pSig[i], rCMSHexBuffer);
1645
1646 return true;
1647#endif // USE_CRYPTO_MSCAPI
1648#endif // USE_CRYPTO_ANY
1649}
1650
1651namespace
1652{
1653#if USE_CRYPTO_NSS
1655NSSCMSAttribute* CMSAttributeArray_FindAttrByOidData(NSSCMSAttribute** attrs, SECOidData const * oid, PRBool only)
1656{
1657 NSSCMSAttribute* attr1, *attr2;
1658
1659 if (attrs == nullptr)
1660 return nullptr;
1661
1662 if (oid == nullptr)
1663 return nullptr;
1664
1665 while ((attr1 = *attrs++) != nullptr)
1666 {
1667 if (attr1->type.len == oid->oid.len && PORT_Memcmp(attr1->type.data,
1668 oid->oid.data,
1669 oid->oid.len) == 0)
1670 break;
1671 }
1672
1673 if (attr1 == nullptr)
1674 return nullptr;
1675
1676 if (!only)
1677 return attr1;
1678
1679 while ((attr2 = *attrs++) != nullptr)
1680 {
1681 if (attr2->type.len == oid->oid.len && PORT_Memcmp(attr2->type.data,
1682 oid->oid.data,
1683 oid->oid.len) == 0)
1684 break;
1685 }
1686
1687 if (attr2 != nullptr)
1688 return nullptr;
1689
1690 return attr1;
1691}
1692
1694SECStatus StringToOID(SECItem* to, const char* from, PRUint32 len)
1695{
1696 PRUint32 decimal_numbers = 0;
1697 PRUint32 result_bytes = 0;
1698 SECStatus rv;
1699 PRUint8 result[1024];
1700
1701 static const PRUint32 max_decimal = 0xffffffff / 10;
1702 static const char OIDstring[] = {"OID."};
1703
1704 if (!from || !to)
1705 {
1706 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1707 return SECFailure;
1708 }
1709 if (!len)
1710 {
1711 len = PL_strlen(from);
1712 }
1713 if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4))
1714 {
1715 from += 4; /* skip leading "OID." if present */
1716 len -= 4;
1717 }
1718 if (!len)
1719 {
1720bad_data:
1721 PORT_SetError(SEC_ERROR_BAD_DATA);
1722 return SECFailure;
1723 }
1724 do
1725 {
1726 PRUint32 decimal = 0;
1727 while (len > 0 && rtl::isAsciiDigit(static_cast<unsigned char>(*from)))
1728 {
1729 PRUint32 addend = *from++ - '0';
1730 --len;
1731 if (decimal > max_decimal) /* overflow */
1732 goto bad_data;
1733 decimal = (decimal * 10) + addend;
1734 if (decimal < addend) /* overflow */
1735 goto bad_data;
1736 }
1737 if (len != 0 && *from != '.')
1738 {
1739 goto bad_data;
1740 }
1741 if (decimal_numbers == 0)
1742 {
1743 if (decimal > 2)
1744 goto bad_data;
1745 result[0] = decimal * 40;
1746 result_bytes = 1;
1747 }
1748 else if (decimal_numbers == 1)
1749 {
1750 if (decimal > 40)
1751 goto bad_data;
1752 result[0] += decimal;
1753 }
1754 else
1755 {
1756 /* encode the decimal number, */
1757 PRUint8* rp;
1758 PRUint32 num_bytes = 0;
1759 PRUint32 tmp = decimal;
1760 while (tmp)
1761 {
1762 num_bytes++;
1763 tmp >>= 7;
1764 }
1765 if (!num_bytes)
1766 ++num_bytes; /* use one byte for a zero value */
1767 if (static_cast<size_t>(num_bytes) + result_bytes > sizeof result)
1768 goto bad_data;
1769 tmp = num_bytes;
1770 rp = result + result_bytes - 1;
1771 rp[tmp] = static_cast<PRUint8>(decimal & 0x7f);
1772 decimal >>= 7;
1773 while (--tmp > 0)
1774 {
1775 rp[tmp] = static_cast<PRUint8>(decimal | 0x80);
1776 decimal >>= 7;
1777 }
1778 result_bytes += num_bytes;
1779 }
1780 ++decimal_numbers;
1781 if (len > 0) /* skip trailing '.' */
1782 {
1783 ++from;
1784 --len;
1785 }
1786 }
1787 while (len > 0);
1788 /* now result contains result_bytes of data */
1789 if (to->data && to->len >= result_bytes)
1790 {
1791 to->len = result_bytes;
1792 PORT_Memcpy(to->data, result, to->len);
1793 rv = SECSuccess;
1794 }
1795 else
1796 {
1797 SECItem result_item = {siBuffer, nullptr, 0 };
1798 result_item.data = result;
1799 result_item.len = result_bytes;
1800 rv = SECITEM_CopyItem(nullptr, to, &result_item);
1801 }
1802 return rv;
1803}
1804
1805#elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
1806
1808bool VerifyNonDetachedSignature(const std::vector<unsigned char>& aData, const std::vector<BYTE>& rExpectedHash)
1809{
1810 HCRYPTPROV hProv = 0;
1811 if (!CryptAcquireContextW(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
1812 {
1813 SAL_WARN("svl.crypto", "CryptAcquireContext() failed");
1814 return false;
1815 }
1816
1817 HCRYPTHASH hHash = 0;
1818 if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
1819 {
1820 SAL_WARN("svl.crypto", "CryptCreateHash() failed");
1821 return false;
1822 }
1823
1824 if (!CryptHashData(hHash, aData.data(), aData.size(), 0))
1825 {
1826 SAL_WARN("svl.crypto", "CryptHashData() failed");
1827 return false;
1828 }
1829
1830 DWORD nActualHash = 0;
1831 if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nActualHash, 0))
1832 {
1833 SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash length");
1834 return false;
1835 }
1836
1837 std::vector<unsigned char> aActualHash(nActualHash);
1838 if (!CryptGetHashParam(hHash, HP_HASHVAL, aActualHash.data(), &nActualHash, 0))
1839 {
1840 SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash");
1841 return false;
1842 }
1843
1844 CryptDestroyHash(hHash);
1845 CryptReleaseContext(hProv, 0);
1846
1847 return aActualHash.size() == rExpectedHash.size() &&
1848 !std::memcmp(aActualHash.data(), rExpectedHash.data(), aActualHash.size());
1849}
1850
1851OUString GetSubjectName(PCCERT_CONTEXT pCertContext)
1852{
1853 OUString subjectName;
1854
1855 // Get Subject name size.
1856 DWORD dwData = CertGetNameStringW(pCertContext,
1857 CERT_NAME_SIMPLE_DISPLAY_TYPE,
1858 0,
1859 nullptr,
1860 nullptr,
1861 0);
1862 if (!dwData)
1863 {
1864 SAL_WARN("svl.crypto", "ValidateSignature: CertGetNameString failed");
1865 return subjectName;
1866 }
1867
1868 // Allocate memory for subject name.
1869 LPWSTR szName = static_cast<LPWSTR>(
1870 LocalAlloc(LPTR, dwData * sizeof(WCHAR)));
1871 if (!szName)
1872 {
1873 SAL_WARN("svl.crypto", "ValidateSignature: Unable to allocate memory for subject name");
1874 return subjectName;
1875 }
1876
1877 // Get subject name.
1878 if (!CertGetNameStringW(pCertContext,
1879 CERT_NAME_SIMPLE_DISPLAY_TYPE,
1880 0,
1881 nullptr,
1882 szName,
1883 dwData))
1884 {
1885 LocalFree(szName);
1886 SAL_WARN("svl.crypto", "ValidateSignature: CertGetNameString failed");
1887 return subjectName;
1888 }
1889
1890 subjectName = o3tl::toU(szName);
1891 LocalFree(szName);
1892
1893 return subjectName;
1894}
1895#endif // USE_CRYPTO_MSCAPI
1896
1897#if USE_CRYPTO_NSS
1898 void ensureNssInit()
1899 {
1900 // e.g. tdf#122599 ensure NSS library is initialized for NSS_CMSMessage_CreateFromDER
1901 css::uno::Reference<css::xml::crypto::XNSSInitializer>
1902 xNSSInitializer = css::xml::crypto::NSSInitializer::create(comphelper::getProcessComponentContext());
1903
1904 // this calls NSS_Init
1905 xNSSInitializer->getDigestContext(css::xml::crypto::DigestID::SHA256,
1906 uno::Sequence<beans::NamedValue>());
1907 }
1908#endif
1909} // anonymous namespace
1910
1911bool Signing::Verify(const std::vector<unsigned char>& aData,
1912 const bool bNonDetached,
1913 const std::vector<unsigned char>& aSignature,
1914 SignatureInformation& rInformation)
1915{
1916#if USE_CRYPTO_NSS
1917 // ensure NSS_Init() is called before using NSS_CMSMessage_CreateFromDER
1918 static std::once_flag aInitOnce;
1919 std::call_once(aInitOnce, ensureNssInit);
1920
1921 // Validate the signature.
1922 SECItem aSignatureItem;
1923 aSignatureItem.data = const_cast<unsigned char*>(aSignature.data());
1924 aSignatureItem.len = aSignature.size();
1925 NSSCMSMessage* pCMSMessage = NSS_CMSMessage_CreateFromDER(&aSignatureItem,
1926 /*cb=*/nullptr,
1927 /*cb_arg=*/nullptr,
1928 /*pwfn=*/nullptr,
1929 /*pwfn_arg=*/nullptr,
1930 /*decrypt_key_cb=*/nullptr,
1931 /*decrypt_key_cb_arg=*/nullptr);
1932 if (!NSS_CMSMessage_IsSigned(pCMSMessage))
1933 {
1934 SAL_WARN("svl.crypto", "ValidateSignature: message is not signed");
1935 return false;
1936 }
1937
1938 NSSCMSContentInfo* pCMSContentInfo = NSS_CMSMessage_ContentLevel(pCMSMessage, 0);
1939 if (!pCMSContentInfo)
1940 {
1941 SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSMessage_ContentLevel() failed");
1942 return false;
1943 }
1944
1945 auto pCMSSignedData = static_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(pCMSContentInfo));
1946 if (!pCMSSignedData)
1947 {
1948 SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSContentInfo_GetContent() failed");
1949 return false;
1950 }
1951
1952 // Import certificates from the signed data temporarily, so it'll be
1953 // possible to verify the signature, even if we didn't have the certificate
1954 // previously.
1955 std::vector<CERTCertificate*> aDocumentCertificates;
1956 for (size_t i = 0; pCMSSignedData->rawCerts[i]; ++i)
1957 aDocumentCertificates.push_back(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), pCMSSignedData->rawCerts[i], nullptr, 0, 0));
1958
1959 NSSCMSSignerInfo* pCMSSignerInfo = NSS_CMSSignedData_GetSignerInfo(pCMSSignedData, 0);
1960 if (!pCMSSignerInfo)
1961 {
1962 SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSSignedData_GetSignerInfo() failed");
1963 return false;
1964 }
1965
1966 SECItem aAlgorithm = NSS_CMSSignedData_GetDigestAlgs(pCMSSignedData)[0]->algorithm;
1967 SECOidTag eOidTag = SECOID_FindOIDTag(&aAlgorithm);
1968
1969 // Map a sign algorithm to a digest algorithm.
1970 // See NSS_CMSUtil_MapSignAlgs(), which is private to us.
1971 switch (eOidTag)
1972 {
1973 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
1974 eOidTag = SEC_OID_SHA1;
1975 break;
1976 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
1977 eOidTag = SEC_OID_SHA256;
1978 break;
1979 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
1980 eOidTag = SEC_OID_SHA512;
1981 break;
1982 default:
1983 break;
1984 }
1985
1986 HASH_HashType eHashType = HASH_GetHashTypeByOidTag(eOidTag);
1987 HASHContext* pHASHContext = HASH_Create(eHashType);
1988 if (!pHASHContext)
1989 {
1990 SAL_WARN("svl.crypto", "ValidateSignature: HASH_Create() failed");
1991 return false;
1992 }
1993
1994 // We have a hash, update it with the byte ranges.
1995 HASH_Update(pHASHContext, aData.data(), aData.size());
1996
1997 // Find out what is the expected length of the hash.
1998 unsigned int nMaxResultLen = 0;
1999 switch (eOidTag)
2000 {
2001 case SEC_OID_SHA1:
2002 nMaxResultLen = comphelper::SHA1_HASH_LENGTH;
2003 rInformation.nDigestID = xml::crypto::DigestID::SHA1;
2004 break;
2005 case SEC_OID_SHA256:
2006 nMaxResultLen = comphelper::SHA256_HASH_LENGTH;
2007 rInformation.nDigestID = xml::crypto::DigestID::SHA256;
2008 break;
2009 case SEC_OID_SHA512:
2010 nMaxResultLen = comphelper::SHA512_HASH_LENGTH;
2011 rInformation.nDigestID = xml::crypto::DigestID::SHA512;
2012 break;
2013 default:
2014 SAL_WARN("svl.crypto", "ValidateSignature: unrecognized algorithm");
2015 return false;
2016 }
2017
2018 auto pActualResultBuffer = static_cast<unsigned char*>(PORT_Alloc(nMaxResultLen));
2019 unsigned int nActualResultLen;
2020 HASH_End(pHASHContext, pActualResultBuffer, &nActualResultLen, nMaxResultLen);
2021
2022 CERTCertificate* pCertificate = NSS_CMSSignerInfo_GetSigningCertificate(pCMSSignerInfo, CERT_GetDefaultCertDB());
2023 if (!pCertificate)
2024 {
2025 SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSSignerInfo_GetSigningCertificate() failed");
2026 return false;
2027 }
2028 else
2029 {
2030 uno::Sequence<sal_Int8> aDerCert(pCertificate->derCert.len);
2031 auto aDerCertRange = asNonConstRange(aDerCert);
2032 for (size_t i = 0; i < pCertificate->derCert.len; ++i)
2033 aDerCertRange[i] = pCertificate->derCert.data[i];
2034 OUStringBuffer aBuffer;
2037 temp.emplace_back();
2038 temp.back().X509Certificate = aBuffer.makeStringAndClear();
2039 temp.back().X509Subject = OUString(pCertificate->subjectName, PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
2040 rInformation.X509Datas.clear();
2041 rInformation.X509Datas.emplace_back(temp);
2042 }
2043
2044 PRTime nSigningTime;
2045 // This may fail, in which case the date should be taken from the PDF's dictionary's "M" key,
2046 // so not critical for PDF at least.
2047 if (NSS_CMSSignerInfo_GetSigningTime(pCMSSignerInfo, &nSigningTime) == SECSuccess)
2048 {
2049 // First convert the UTC UNIX timestamp to a tools::DateTime.
2050 // nSigningTime is in microseconds.
2051 DateTime aDateTime = DateTime::CreateFromUnixTime(static_cast<double>(nSigningTime) / 1000000);
2052
2053 // Then convert to a local UNO DateTime.
2054 aDateTime.ConvertToLocalTime();
2055 rInformation.stDateTime = aDateTime.GetUNODateTime();
2056 if (rInformation.ouDateTime.isEmpty())
2057 {
2058 OUStringBuffer rBuffer;
2059 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
2060 rBuffer.append('-');
2061 if (aDateTime.GetMonth() < 10)
2062 rBuffer.append('0');
2063 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
2064 rBuffer.append('-');
2065 if (aDateTime.GetDay() < 10)
2066 rBuffer.append('0');
2067 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
2068 rInformation.ouDateTime = rBuffer.makeStringAndClear();
2069 }
2070 }
2071
2072 // Check if we have a signing certificate attribute.
2073 SECOidData aOidData;
2074 aOidData.oid.data = nullptr;
2075 /*
2076 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
2077 * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
2078 * smime(16) id-aa(2) 47 }
2079 */
2080 if (StringToOID(&aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess)
2081 {
2082 SAL_WARN("svl.crypto", "StringToOID() failed");
2083 return false;
2084 }
2085 aOidData.offset = SEC_OID_UNKNOWN;
2086 aOidData.desc = "id-aa-signingCertificateV2";
2087 aOidData.mechanism = CKM_SHA_1;
2088 aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
2089 NSSCMSAttribute* pAttribute = CMSAttributeArray_FindAttrByOidData(pCMSSignerInfo->authAttr, &aOidData, PR_TRUE);
2090 if (pAttribute)
2091 rInformation.bHasSigningCertificate = true;
2092
2093 SECItem* pContentInfoContentData = pCMSSignedData->contentInfo.content.data;
2094 if (bNonDetached && pContentInfoContentData && pContentInfoContentData->data)
2095 {
2096 // Not a detached signature.
2097 if (!std::memcmp(pActualResultBuffer, pContentInfoContentData->data, nMaxResultLen) && nActualResultLen == pContentInfoContentData->len)
2098 rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2099 }
2100 else
2101 {
2102 // Detached, the usual case.
2103 SECItem aActualResultItem;
2104 aActualResultItem.data = pActualResultBuffer;
2105 aActualResultItem.len = nActualResultLen;
2106 if (NSS_CMSSignerInfo_Verify(pCMSSignerInfo, &aActualResultItem, nullptr) == SECSuccess)
2107 rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2108 }
2109
2110 // Everything went fine
2111 SECITEM_FreeItem(&aOidData.oid, false);
2112 PORT_Free(pActualResultBuffer);
2113 HASH_Destroy(pHASHContext);
2114 NSS_CMSSignerInfo_Destroy(pCMSSignerInfo);
2115 for (auto pDocumentCertificate : aDocumentCertificates)
2116 CERT_DestroyCertificate(pDocumentCertificate);
2117
2118 return true;
2119
2120#elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
2121
2122 // Open a message for decoding.
2123 HCRYPTMSG hMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
2124 CMSG_DETACHED_FLAG,
2125 0,
2126 0,
2127 nullptr,
2128 nullptr);
2129 if (!hMsg)
2130 {
2131 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgOpenToDecode() failed");
2132 return false;
2133 }
2134
2135 // Update the message with the encoded header blob.
2136 if (!CryptMsgUpdate(hMsg, aSignature.data(), aSignature.size(), TRUE))
2137 {
2138 SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the header failed: " << WindowsErrorString(GetLastError()));
2139 return false;
2140 }
2141
2142 // Update the message with the content blob.
2143 if (!CryptMsgUpdate(hMsg, aData.data(), aData.size(), FALSE))
2144 {
2145 SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the content failed: " << WindowsErrorString(GetLastError()));
2146 return false;
2147 }
2148
2149 if (!CryptMsgUpdate(hMsg, nullptr, 0, TRUE))
2150 {
2151 SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the last content failed: " << WindowsErrorString(GetLastError()));
2152 return false;
2153 }
2154
2155 // Get the CRYPT_ALGORITHM_IDENTIFIER from the message.
2156 DWORD nDigestID = 0;
2157 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, nullptr, &nDigestID))
2158 {
2159 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed: " << WindowsErrorString(GetLastError()));
2160 return false;
2161 }
2162 std::unique_ptr<BYTE[]> pDigestBytes(new BYTE[nDigestID]);
2163 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, pDigestBytes.get(), &nDigestID))
2164 {
2165 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed: " << WindowsErrorString(GetLastError()));
2166 return false;
2167 }
2168 auto pDigestID = reinterpret_cast<CRYPT_ALGORITHM_IDENTIFIER*>(pDigestBytes.get());
2169 if (std::string_view(szOID_NIST_sha256) == pDigestID->pszObjId)
2170 rInformation.nDigestID = xml::crypto::DigestID::SHA256;
2171 else if (std::string_view(szOID_RSA_SHA1RSA) == pDigestID->pszObjId || std::string_view(szOID_OIWSEC_sha1) == pDigestID->pszObjId)
2172 rInformation.nDigestID = xml::crypto::DigestID::SHA1;
2173 else
2174 // Don't error out here, we can still verify the message digest correctly, just the digest ID won't be set.
2175 SAL_WARN("svl.crypto", "ValidateSignature: unhandled algorithm identifier '"<<pDigestID->pszObjId<<"'");
2176
2177 // Get the signer CERT_INFO from the message.
2178 DWORD nSignerCertInfo = 0;
2179 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, nullptr, &nSignerCertInfo))
2180 {
2181 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2182 return false;
2183 }
2184 std::unique_ptr<BYTE[]> pSignerCertInfoBuf(new BYTE[nSignerCertInfo]);
2185 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, pSignerCertInfoBuf.get(), &nSignerCertInfo))
2186 {
2187 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2188 return false;
2189 }
2190 PCERT_INFO pSignerCertInfo = reinterpret_cast<PCERT_INFO>(pSignerCertInfoBuf.get());
2191
2192 // Open a certificate store in memory using CERT_STORE_PROV_MSG, which
2193 // initializes it with the certificates from the message.
2194 HCERTSTORE hStoreHandle = CertOpenStore(CERT_STORE_PROV_MSG,
2195 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
2196 0,
2197 0,
2198 hMsg);
2199 if (!hStoreHandle)
2200 {
2201 SAL_WARN("svl.crypto", "ValidateSignature: CertOpenStore() failed");
2202 return false;
2203 }
2204
2205 // Find the signer's certificate in the store.
2206 PCCERT_CONTEXT pSignerCertContext = CertGetSubjectCertificateFromStore(hStoreHandle,
2207 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
2208 pSignerCertInfo);
2209 if (!pSignerCertContext)
2210 {
2211 SAL_WARN("svl.crypto", "ValidateSignature: CertGetSubjectCertificateFromStore() failed");
2212 return false;
2213 }
2214 else
2215 {
2216 // Write rInformation.ouX509Certificate.
2217 uno::Sequence<sal_Int8> aDerCert(pSignerCertContext->cbCertEncoded);
2218 std::copy_n(pSignerCertContext->pbCertEncoded, pSignerCertContext->cbCertEncoded,
2219 aDerCert.getArray());
2220 OUStringBuffer aBuffer;
2223 temp.emplace_back();
2224 temp.back().X509Certificate = aBuffer.makeStringAndClear();
2225 temp.back().X509Subject = GetSubjectName(pSignerCertContext);
2226 rInformation.X509Datas.clear();
2227 rInformation.X509Datas.emplace_back(temp);
2228 }
2229
2230 if (bNonDetached)
2231 {
2232 // Not a detached signature.
2233 DWORD nContentParam = 0;
2234 if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, nullptr, &nContentParam))
2235 {
2236 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2237 return false;
2238 }
2239
2240 std::vector<BYTE> aContentParam(nContentParam);
2241 if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, aContentParam.data(), &nContentParam))
2242 {
2243 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2244 return false;
2245 }
2246
2247 if (VerifyNonDetachedSignature(aData, aContentParam))
2248 rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2249 }
2250 else
2251 {
2252 // Detached, the usual case.
2253 // Use the CERT_INFO from the signer certificate to verify the signature.
2254 if (CryptMsgControl(hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE, pSignerCertContext->pCertInfo))
2255 rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2256 }
2257
2258 // Check if we have a signing certificate attribute.
2259 DWORD nSignedAttributes = 0;
2260 if (CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, nullptr, &nSignedAttributes))
2261 {
2262 std::unique_ptr<BYTE[]> pSignedAttributesBuf(new BYTE[nSignedAttributes]);
2263 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, pSignedAttributesBuf.get(), &nSignedAttributes))
2264 {
2265 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() authenticated failed");
2266 return false;
2267 }
2268 auto pSignedAttributes = reinterpret_cast<PCRYPT_ATTRIBUTES>(pSignedAttributesBuf.get());
2269 for (size_t nAttr = 0; nAttr < pSignedAttributes->cAttr; ++nAttr)
2270 {
2271 CRYPT_ATTRIBUTE& rAttr = pSignedAttributes->rgAttr[nAttr];
2272 /*
2273 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
2274 * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
2275 * smime(16) id-aa(2) 47 }
2276 */
2277 if (std::string_view("1.2.840.113549.1.9.16.2.47") == rAttr.pszObjId)
2278 {
2279 rInformation.bHasSigningCertificate = true;
2280 break;
2281 }
2282 }
2283 }
2284
2285 // Get the unauthorized attributes.
2286 nSignedAttributes = 0;
2287 if (CryptMsgGetParam(hMsg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, nullptr, &nSignedAttributes))
2288 {
2289 std::unique_ptr<BYTE[]> pSignedAttributesBuf(new BYTE[nSignedAttributes]);
2290 if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, pSignedAttributesBuf.get(), &nSignedAttributes))
2291 {
2292 SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() unauthenticated failed");
2293 return false;
2294 }
2295 auto pSignedAttributes = reinterpret_cast<PCRYPT_ATTRIBUTES>(pSignedAttributesBuf.get());
2296 for (size_t nAttr = 0; nAttr < pSignedAttributes->cAttr; ++nAttr)
2297 {
2298 CRYPT_ATTRIBUTE& rAttr = pSignedAttributes->rgAttr[nAttr];
2299 // Timestamp blob
2300 if (std::string_view("1.2.840.113549.1.9.16.2.14") == rAttr.pszObjId)
2301 {
2302 PCRYPT_TIMESTAMP_CONTEXT pTsContext;
2303 if (!CryptVerifyTimeStampSignature(rAttr.rgValue->pbData, rAttr.rgValue->cbData, nullptr, 0, nullptr, &pTsContext, nullptr, nullptr))
2304 {
2305 SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << WindowsErrorString(GetLastError()));
2306 break;
2307 }
2308
2309 DateTime aDateTime = DateTime::CreateFromWin32FileDateTime(pTsContext->pTimeStamp->ftTime.dwLowDateTime, pTsContext->pTimeStamp->ftTime.dwHighDateTime);
2310
2311 // Then convert to a local UNO DateTime.
2312 aDateTime.ConvertToLocalTime();
2313 rInformation.stDateTime = aDateTime.GetUNODateTime();
2314 if (rInformation.ouDateTime.isEmpty())
2315 {
2316 OUStringBuffer rBuffer;
2317 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
2318 rBuffer.append('-');
2319 if (aDateTime.GetMonth() < 10)
2320 rBuffer.append('0');
2321 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
2322 rBuffer.append('-');
2323 if (aDateTime.GetDay() < 10)
2324 rBuffer.append('0');
2325 rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
2326 rInformation.ouDateTime = rBuffer.makeStringAndClear();
2327 }
2328 break;
2329 }
2330 }
2331 }
2332
2333 CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
2334 CryptMsgClose(hMsg);
2335 return true;
2336#else
2337 // Not implemented.
2338 (void)aData;
2339 (void)bNonDetached;
2340 (void)aSignature;
2341 (void)rInformation;
2342 return false;
2343#endif
2344}
2345
2347 const std::vector<std::pair<size_t, size_t>>& aByteRanges,
2348 const bool bNonDetached,
2349 const std::vector<unsigned char>& aSignature,
2350 SignatureInformation& rInformation)
2351{
2352#if USE_CRYPTO_ANY
2353 std::vector<unsigned char> buffer;
2354
2355 // Copy the byte ranges into a single buffer.
2356 for (const auto& rByteRange : aByteRanges)
2357 {
2358 rStream.Seek(rByteRange.first);
2359 const size_t size = buffer.size();
2360 buffer.resize(size + rByteRange.second);
2361 rStream.ReadBytes(buffer.data() + size, rByteRange.second);
2362 }
2363
2364 return Verify(buffer, bNonDetached, aSignature, rInformation);
2365
2366#else
2367 // Not implemented.
2368 (void)rStream;
2369 (void)aByteRanges;
2370 (void)bNonDetached;
2371 (void)aSignature;
2372 (void)rInformation;
2373 return false;
2374#endif
2375}
2376
2377}
2378
2379/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
UBlockCode from
UBlockCode to
static DateTime CreateFromUnixTime(const double fSecondsSinceEpoch)
void ConvertToLocalTime()
css::util::DateTime GetUNODateTime() const
static DateTime CreateFromWin32FileDateTime(sal_uInt32 rLower, sal_uInt32 rUpper)
sal_Int16 GetYear() const
sal_uInt16 GetDay() const
sal_uInt16 GetMonth() const
const void * GetData()
sal_uInt64 GetSize()
std::size_t WriteBytes(const void *pData, std::size_t nSize)
SvStream & WriteUInt8(sal_uInt8 nuInt8)
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
static void encode(OUStringBuffer &aStrBuffer, const css::uno::Sequence< sal_Int8 > &aPass)
std::vector< unsigned char > finalize()
static std::vector< unsigned char > calculateHash(const unsigned char *pInput, size_t length, HashType eType)
void update(const unsigned char *pInput, size_t length)
const css::uno::Reference< css::security::XCertificate > m_xCertificate
The certificate to use for signing.
Definition: cryptosign.hxx:87
OUString m_aSignPassword
Definition: cryptosign.hxx:92
bool Sign(OStringBuffer &rCMSHexBuffer)
Signs one or more data blocks (as a single, contiguous, array).
Definition: cryptosign.cxx:942
static bool Verify(const std::vector< unsigned char > &aData, const bool bNonDetached, const std::vector< unsigned char > &aSignature, SignatureInformation &rInformation)
Verify and get Signature Information given a byte array.
std::vector< std::pair< const void *, sal_Int32 > > m_dataBlocks
Data blocks (pointer-size pairs).
Definition: cryptosign.hxx:90
#define MAX_SIGNATURE_CONTENT_LENGTH
Definition: cryptosign.hxx:35
int nCount
#define TRUE
#define FALSE
const char * name
OUString aName
void * p
sal_Int64 n
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
OUString subjectName
DateTime now
if(aStr !=aBuf) UpdateName_Impl(m_xFollowLb.get()
constexpr OUStringLiteral aData
size
unsigned int uniform_uint_distribution(unsigned int a, unsigned int b)
const sal_uInt32 SHA256_HASH_LENGTH
const sal_uInt32 SHA512_HASH_LENGTH
Reference< XComponentContext > getProcessComponentContext()
const sal_uInt32 SHA1_HASH_LENGTH
int i
constexpr OUStringLiteral first
constexpr OUStringLiteral last
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
std::vector< unsigned char > DecodeHexString(std::string_view rHex)
Converts a hex-encoded string into a byte array.
Definition: cryptosign.cxx:912
static int AsHex(char ch)
Definition: cryptosign.cxx:894
pass
long Long
#define CERT_NewTempCertificate
std::vector< char * > values
const wchar_t *typedef BOOL
css::xml::crypto::SecurityOperationStatus nStatus
Definition: sigstruct.hxx:88
bool bHasSigningCertificate
For PDF: has id-aa-signingCertificateV2 as a signed attribute.
Definition: sigstruct.hxx:156
std::vector< X509Data > X509Datas
Definition: sigstruct.hxx:103
sal_Int32 nDigestID
For PDF: digest format, from css::xml::crypto::DigestID.
Definition: sigstruct.hxx:154
std::vector< X509CertInfo > X509Data
Definition: sigstruct.hxx:100
css::util::DateTime stDateTime
Definition: sigstruct.hxx:120
signed char sal_Int8
#define SAL_MAX_UINT32
Any result
ResultType type
unsigned char BYTE
std::unique_ptr< char[]> aBuffer