1 //========================================================================
2 //
3 // SignatureHandler.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright 2015, 2016 André Guerreiro <aguerreiro1985@gmail.com>
8 // Copyright 2015 André Esser <bepandre@hotmail.com>
9 // Copyright 2015, 2016, 2018, 2019, 2021 Albert Astals Cid <aacid@kde.org>
10 // Copyright 2015 Markus Kilås <digital@markuspage.com>
11 // Copyright 2017 Sebastian Rasmussen <sebras@gmail.com>
12 // Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
13 // Copyright 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@protonmail.com>
14 // Copyright 2018 Oliver Sander <oliver.sander@tu-dresden.de>
15 // Copyright 2020 Thorsten Behrens <Thorsten.Behrens@CIB.de>
16 // Copyright 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by Technische Universität Dresden
17 // Copyright 2021 Theofilos Intzoglou <int.teo@gmail.com>
18 // Copyright 2021 Marek Kasik <mkasik@redhat.com>
19 //
20 //========================================================================
21 
22 #include <config.h>
23 
24 #include "SignatureHandler.h"
25 #include "goo/gmem.h"
26 
27 #include <dirent.h>
28 #include <Error.h>
29 
30 /* NSS headers */
31 #include <secmod.h>
32 #include <keyhi.h>
33 #include <secder.h>
34 #include <pk11pub.h>
35 #include <secpkcs7.h>
36 
37 #include <cert.h>
38 #include <hasht.h>
39 #include <secerr.h>
40 #include <sechash.h>
41 #include <cms.h>
42 #include <cmst.h>
43 
44 // ASN.1 used in the (much simpler) time stamp request. From RFC3161
45 // and other sources.
46 
47 /*
48 AlgorithmIdentifier  ::=  SEQUENCE  {
49      algorithm  OBJECT IDENTIFIER,
50      parameters ANY DEFINED BY algorithm OPTIONAL  }
51                    -- contains a value of the type
52                    -- registered for use with the
53                    -- algorithm object identifier value
54 
55 MessageImprint ::= SEQUENCE  {
56     hashAlgorithm AlgorithmIdentifier,
57     hashedMessage OCTET STRING  }
58 */
59 
60 struct MessageImprint
61 {
62     SECAlgorithmID hashAlgorithm;
63     SECItem hashedMessage;
64 };
65 
66 /*
67 Extension  ::=  SEQUENCE  {
68     extnID    OBJECT IDENTIFIER,
69     critical  BOOLEAN DEFAULT FALSE,
70     extnValue OCTET STRING  }
71 */
72 
73 struct Extension
74 {
75     SECItem const extnID;
76     SECItem const critical;
77     SECItem const extnValue;
78 };
79 
80 /*
81 Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
82 */
83 
84 /*
85 TSAPolicyId ::= OBJECT IDENTIFIER
86 
87 TimeStampReq ::= SEQUENCE  {
88     version            INTEGER  { v1(1) },
89     messageImprint     MessageImprint,
90     --a hash algorithm OID and the hash value of the data to be
91     --time-stamped
92     reqPolicy          TSAPolicyId         OPTIONAL,
93     nonce              INTEGER             OPTIONAL,
94     certReq            BOOLEAN             DEFAULT FALSE,
95     extensions     [0] IMPLICIT Extensions OPTIONAL  }
96 */
97 
98 struct TimeStampReq
99 {
100     SECItem version;
101     MessageImprint messageImprint;
102     SECItem reqPolicy;
103     SECItem nonce;
104     SECItem certReq;
105     Extension *extensions;
106 };
107 
108 /**
109  * General name, defined by RFC 3280.
110  */
111 struct GeneralName
112 {
113     CERTName name;
114 };
115 
116 /**
117  * List of general names (only one for now), defined by RFC 3280.
118  */
119 struct GeneralNames
120 {
121     GeneralName names;
122 };
123 
124 /**
125  * Supplies different fields to identify a certificate, defined by RFC 5035.
126  */
127 struct IssuerSerial
128 {
129     GeneralNames issuer;
130     SECItem serialNumber;
131 };
132 
133 /**
134  * Supplies different fields that are used to identify certificates, defined by
135  * RFC 5035.
136  */
137 struct ESSCertIDv2
138 {
139     SECAlgorithmID hashAlgorithm;
140     SECItem certHash;
141     IssuerSerial issuerSerial;
142 };
143 
144 /**
145  * This attribute uses the ESSCertIDv2 structure, defined by RFC 5035.
146  */
147 struct SigningCertificateV2
148 {
149     ESSCertIDv2 **certs;
150 
SigningCertificateV2SigningCertificateV2151     SigningCertificateV2() : certs(nullptr) { }
152 };
153 
154 /**
155  * GeneralName ::= CHOICE {
156  *      otherName                       [0]     OtherName,
157  *      rfc822Name                      [1]     IA5String,
158  *      dNSName                         [2]     IA5String,
159  *      x400Address                     [3]     ORAddress,
160  *      directoryName                   [4]     Name,
161  *      ediPartyName                    [5]     EDIPartyName,
162  *      uniformResourceIdentifier       [6]     IA5String,
163  *      iPAddress                       [7]     OCTET STRING,
164  *      registeredID                    [8]     OBJECT IDENTIFIER
165  * }
166  */
167 const SEC_ASN1Template GeneralNameTemplate[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralName) }, { SEC_ASN1_INLINE, offsetof(GeneralName, name), CERT_NameTemplate, 0 }, { 0, 0, nullptr, 0 } };
168 
169 /**
170  * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
171  */
172 const SEC_ASN1Template GeneralNamesTemplate[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralNames) }, { SEC_ASN1_INLINE | SEC_ASN1_CONTEXT_SPECIFIC | 4, offsetof(GeneralNames, names), GeneralNameTemplate, 0 }, { 0, 0, nullptr, 0 } };
173 
174 /**
175  * IssuerSerial ::= SEQUENCE {
176  *     issuer GeneralNames,
177  *     serialNumber CertificateSerialNumber
178  * }
179  */
180 const SEC_ASN1Template IssuerSerialTemplate[] = {
181     { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(IssuerSerial) }, { SEC_ASN1_INLINE, offsetof(IssuerSerial, issuer), GeneralNamesTemplate, 0 }, { SEC_ASN1_INTEGER, offsetof(IssuerSerial, serialNumber), nullptr, 0 }, { 0, 0, nullptr, 0 }
182 };
183 
184 /**
185  * Hash ::= OCTET STRING
186  *
187  * ESSCertIDv2 ::= SEQUENCE {
188  *     hashAlgorithm AlgorithmIdentifier DEFAULT {algorithm id-sha256},
189  *     certHash Hash,
190  *     issuerSerial IssuerSerial OPTIONAL
191  * }
192  */
193 
194 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
195 
196 const SEC_ASN1Template ESSCertIDv2Template[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(ESSCertIDv2) },
197                                                  { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, hashAlgorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), 0 },
198                                                  { SEC_ASN1_OCTET_STRING, offsetof(ESSCertIDv2, certHash), nullptr, 0 },
199                                                  { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, issuerSerial), IssuerSerialTemplate, 0 },
200                                                  { 0, 0, nullptr, 0 } };
201 
202 /**
203  * SigningCertificateV2 ::= SEQUENCE {
204  * }
205  */
206 const SEC_ASN1Template SigningCertificateV2Template[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(SigningCertificateV2) }, { SEC_ASN1_SEQUENCE_OF, offsetof(SigningCertificateV2, certs), ESSCertIDv2Template, 0 }, { 0, 0, nullptr, 0 } };
207 
208 /*
209 struct PKIStatusInfo
210 {
211     SECItem status;
212     SECItem statusString;
213     SECItem failInfo;
214 };
215 
216 const SEC_ASN1Template PKIStatusInfo_Template[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(PKIStatusInfo) },
217                                                     { SEC_ASN1_INTEGER, offsetof(PKIStatusInfo, status), nullptr, 0 },
218                                                     { SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, statusString), nullptr, 0 },
219                                                     { SEC_ASN1_BIT_STRING | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, failInfo), nullptr, 0 },
220                                                     { 0, 0, nullptr, 0 } };
221 
222 const SEC_ASN1Template Any_Template[] = { { SEC_ASN1_ANY, 0, nullptr, sizeof(SECItem) } };
223 
224 struct TimeStampResp
225 {
226     PKIStatusInfo status;
227     SECItem timeStampToken;
228 };
229 
230 const SEC_ASN1Template TimeStampResp_Template[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampResp) },
231                                                     { SEC_ASN1_INLINE, offsetof(TimeStampResp, status), PKIStatusInfo_Template, 0 },
232                                                     { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, offsetof(TimeStampResp, timeStampToken), Any_Template, 0 },
233                                                     { 0, 0, nullptr, 0 } };
234 
235 const SEC_ASN1Template MessageImprint_Template[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(MessageImprint) },
236                                                      { SEC_ASN1_INLINE, offsetof(MessageImprint, hashAlgorithm), SECOID_AlgorithmIDTemplate, 0 },
237                                                      { SEC_ASN1_OCTET_STRING, offsetof(MessageImprint, hashedMessage), nullptr, 0 },
238                                                      { 0, 0, nullptr, 0 } };
239 
240 const SEC_ASN1Template Extension_Template[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(Extension) },
241                                                 { SEC_ASN1_OBJECT_ID, offsetof(Extension, extnID), nullptr, 0 },
242                                                 { SEC_ASN1_BOOLEAN, offsetof(Extension, critical), nullptr, 0 },
243                                                 { SEC_ASN1_OCTET_STRING, offsetof(Extension, extnValue), nullptr, 0 },
244                                                 { 0, 0, nullptr, 0 } };
245 
246 const SEC_ASN1Template Extensions_Template[] = { { SEC_ASN1_SEQUENCE_OF, 0, Extension_Template, 0 } };
247 
248 const SEC_ASN1Template TimeStampReq_Template[] = { { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampReq) },
249                                                    { SEC_ASN1_INTEGER, offsetof(TimeStampReq, version), nullptr, 0 },
250                                                    { SEC_ASN1_INLINE, offsetof(TimeStampReq, messageImprint), MessageImprint_Template, 0 },
251                                                    { SEC_ASN1_OBJECT_ID | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, reqPolicy), nullptr, 0 },
252                                                    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, nonce), nullptr, 0 },
253                                                    { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, certReq), nullptr, 0 },
254                                                    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(TimeStampReq, extensions), Extensions_Template, 0 },
255                                                    { 0, 0, nullptr, 0 } };
256 */
257 
258 // a dummy, actually
passwordCallback(PK11SlotInfo *,PRBool,void * arg)259 static char *passwordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg)
260 {
261     return PL_strdup(static_cast<char *>(arg));
262 }
263 
shutdownNss()264 static void shutdownNss()
265 {
266     if (NSS_Shutdown() != SECSuccess) {
267         fprintf(stderr, "NSS_Shutdown failed: %s\n", PR_ErrorToString(PORT_GetError(), PR_LANGUAGE_I_DEFAULT));
268     }
269 }
270 
271 // SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() are
272 // not exported from libsmime, so copy them here. Sigh.
273 
my_SEC_StringToOID(SECItem * to,const char * from,PRUint32 len)274 static SECStatus my_SEC_StringToOID(SECItem *to, const char *from, PRUint32 len)
275 {
276     PRUint32 decimal_numbers = 0;
277     PRUint32 result_bytes = 0;
278     SECStatus rv;
279     PRUint8 result[1024];
280 
281     static const PRUint32 max_decimal = 0xffffffff / 10;
282     static const char OIDstring[] = { "OID." };
283 
284     if (!from || !to) {
285         PORT_SetError(SEC_ERROR_INVALID_ARGS);
286         return SECFailure;
287     }
288     if (!len) {
289         len = PL_strlen(from);
290     }
291     if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
292         from += 4; /* skip leading "OID." if present */
293         len -= 4;
294     }
295     if (!len) {
296     bad_data:
297         PORT_SetError(SEC_ERROR_BAD_DATA);
298         return SECFailure;
299     }
300     do {
301         PRUint32 decimal = 0;
302         while (len > 0 && (*from >= '0' && *from <= '9')) {
303             PRUint32 addend = *from++ - '0';
304             --len;
305             if (decimal > max_decimal) /* overflow */
306                 goto bad_data;
307             decimal = (decimal * 10) + addend;
308             if (decimal < addend) /* overflow */
309                 goto bad_data;
310         }
311         if (len != 0 && *from != '.') {
312             goto bad_data;
313         }
314         if (decimal_numbers == 0) {
315             if (decimal > 2)
316                 goto bad_data;
317             result[0] = decimal * 40;
318             result_bytes = 1;
319         } else if (decimal_numbers == 1) {
320             if (decimal > 40)
321                 goto bad_data;
322             result[0] += decimal;
323         } else {
324             /* encode the decimal number,  */
325             PRUint8 *rp;
326             PRUint32 num_bytes = 0;
327             PRUint32 tmp = decimal;
328             while (tmp) {
329                 num_bytes++;
330                 tmp >>= 7;
331             }
332             if (!num_bytes)
333                 ++num_bytes; /* use one byte for a zero value */
334             if (num_bytes + result_bytes > sizeof result)
335                 goto bad_data;
336             tmp = num_bytes;
337             rp = result + result_bytes - 1;
338             rp[tmp] = static_cast<PRUint8>(decimal & 0x7f);
339             decimal >>= 7;
340             while (--tmp > 0) {
341                 rp[tmp] = static_cast<PRUint8>(decimal | 0x80);
342                 decimal >>= 7;
343             }
344             result_bytes += num_bytes;
345         }
346         ++decimal_numbers;
347         if (len > 0) { /* skip trailing '.' */
348             ++from;
349             --len;
350         }
351     } while (len > 0);
352     /* now result contains result_bytes of data */
353     if (to->data && to->len >= result_bytes) {
354         to->len = result_bytes;
355         PORT_Memcpy(to->data, result, to->len);
356         rv = SECSuccess;
357     } else {
358         SECItem result_item = { siBuffer, nullptr, 0 };
359         result_item.data = result;
360         result_item.len = result_bytes;
361         rv = SECITEM_CopyItem(nullptr, to, &result_item);
362     }
363     return rv;
364 }
365 
my_NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute ** attrs,SECOidTag oidtag,PRBool only)366 static NSSCMSAttribute *my_NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute **attrs, SECOidTag oidtag, PRBool only)
367 {
368     SECOidData *oid;
369     NSSCMSAttribute *attr1, *attr2;
370 
371     if (attrs == nullptr)
372         return nullptr;
373 
374     oid = SECOID_FindOIDByTag(oidtag);
375     if (oid == nullptr)
376         return nullptr;
377 
378     while ((attr1 = *attrs++) != nullptr) {
379         if (attr1->type.len == oid->oid.len && PORT_Memcmp(attr1->type.data, oid->oid.data, oid->oid.len) == 0)
380             break;
381     }
382 
383     if (attr1 == nullptr)
384         return nullptr;
385 
386     if (!only)
387         return attr1;
388 
389     while ((attr2 = *attrs++) != nullptr) {
390         if (attr2->type.len == oid->oid.len && PORT_Memcmp(attr2->type.data, oid->oid.data, oid->oid.len) == 0)
391             break;
392     }
393 
394     if (attr2 != nullptr)
395         return nullptr;
396 
397     return attr1;
398 }
399 
my_NSS_CMSArray_Add(PLArenaPool * poolp,void *** array,void * obj)400 static SECStatus my_NSS_CMSArray_Add(PLArenaPool *poolp, void ***array, void *obj)
401 {
402     int n = 0;
403     void **dest;
404 
405     PORT_Assert(array != NULL);
406     if (array == nullptr)
407         return SECFailure;
408 
409     if (*array == nullptr) {
410         dest = static_cast<void **>(PORT_ArenaAlloc(poolp, 2 * sizeof(void *)));
411     } else {
412         void **p = *array;
413         while (*p++)
414             n++;
415         dest = static_cast<void **>(PORT_ArenaGrow(poolp, *array, (n + 1) * sizeof(void *), (n + 2) * sizeof(void *)));
416     }
417 
418     if (dest == nullptr)
419         return SECFailure;
420 
421     dest[n] = obj;
422     dest[n + 1] = nullptr;
423     *array = dest;
424     return SECSuccess;
425 }
426 
my_NSS_CMSAttribute_GetType(NSSCMSAttribute * attr)427 static SECOidTag my_NSS_CMSAttribute_GetType(NSSCMSAttribute *attr)
428 {
429     SECOidData *typetag;
430 
431     typetag = SECOID_FindOID(&(attr->type));
432     if (typetag == nullptr)
433         return SEC_OID_UNKNOWN;
434 
435     return typetag->offset;
436 }
437 
my_NSS_CMSAttributeArray_AddAttr(PLArenaPool * poolp,NSSCMSAttribute *** attrs,NSSCMSAttribute * attr)438 static SECStatus my_NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr)
439 {
440     NSSCMSAttribute *oattr;
441     void *mark;
442     SECOidTag type;
443 
444     mark = PORT_ArenaMark(poolp);
445 
446     /* find oidtag of attr */
447     type = my_NSS_CMSAttribute_GetType(attr);
448 
449     /* see if we have one already */
450     oattr = my_NSS_CMSAttributeArray_FindAttrByOidTag(*attrs, type, PR_FALSE);
451     PORT_Assert(oattr == NULL);
452     if (oattr != nullptr)
453         goto loser; /* XXX or would it be better to replace it? */
454 
455     /* no, shove it in */
456     if (my_NSS_CMSArray_Add(poolp, reinterpret_cast<void ***>(attrs), static_cast<void *>(attr)) != SECSuccess)
457         goto loser;
458 
459     PORT_ArenaUnmark(poolp, mark);
460     return SECSuccess;
461 
462 loser:
463     PORT_ArenaRelease(poolp, mark);
464     return SECFailure;
465 }
466 
my_NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo * signerinfo,NSSCMSAttribute * attr)467 static SECStatus my_NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
468 {
469     return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
470 }
471 
digestLength(SECOidTag digestAlgId)472 unsigned int SignatureHandler::digestLength(SECOidTag digestAlgId)
473 {
474     switch (digestAlgId) {
475     case SEC_OID_SHA1:
476         return 20;
477     case SEC_OID_SHA256:
478         return 32;
479     case SEC_OID_SHA384:
480         return 48;
481     case SEC_OID_SHA512:
482         return 64;
483     default:
484         printf("ERROR: Unrecognized Hash ID\n");
485         return 0;
486     }
487 }
488 
getHashOidTag(const char * digestName)489 SECOidTag SignatureHandler::getHashOidTag(const char *digestName)
490 {
491     SECOidTag tag = SEC_OID_UNKNOWN;
492     if (strcmp(digestName, "SHA1") == 0) {
493         tag = SEC_OID_SHA1;
494     } else if (strcmp(digestName, "SHA256") == 0) {
495         tag = SEC_OID_SHA256;
496     } else if (strcmp(digestName, "SHA384") == 0) {
497         tag = SEC_OID_SHA384;
498     } else if (strcmp(digestName, "SHA512") == 0) {
499         tag = SEC_OID_SHA512;
500     }
501     return tag;
502 }
503 
getSignerName()504 char *SignatureHandler::getSignerName()
505 {
506     char *commonName, *name;
507 
508     if (!CMSSignerInfo || !NSS_IsInitialized())
509         return nullptr;
510 
511     if (!signing_cert)
512         signing_cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
513 
514     if (!signing_cert)
515         return nullptr;
516 
517     commonName = CERT_GetCommonName(&signing_cert->subject);
518     name = strdup(commonName);
519     PORT_Free(commonName);
520 
521     return name;
522 }
523 
getSignerSubjectDN()524 const char *SignatureHandler::getSignerSubjectDN()
525 {
526     if (!signing_cert && !CMSSignerInfo)
527         return nullptr;
528 
529     if (!signing_cert)
530         signing_cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
531 
532     if (!signing_cert)
533         return nullptr;
534 
535     return signing_cert->subjectName;
536 }
537 
getHashAlgorithm()538 HASH_HashType SignatureHandler::getHashAlgorithm()
539 {
540     if (hash_context && hash_context->hashobj) {
541         return hash_context->hashobj->type;
542     }
543     return HASH_AlgNULL;
544 }
545 
getSigningTime()546 time_t SignatureHandler::getSigningTime()
547 {
548     PRTime sTime; // time in microseconds since the epoch
549 
550     if (NSS_CMSSignerInfo_GetSigningTime(CMSSignerInfo, &sTime) != SECSuccess)
551         return 0;
552 
553     return static_cast<time_t>(sTime / 1000000);
554 }
555 
getEntityInfo(CERTName * entityName)556 static X509CertificateInfo::EntityInfo getEntityInfo(CERTName *entityName)
557 {
558     X509CertificateInfo::EntityInfo info;
559 
560     if (!entityName)
561         return info;
562 
563     char *dn = CERT_NameToAscii(entityName);
564     if (dn) {
565         info.distinguishedName = dn;
566         PORT_Free(dn);
567     }
568 
569     char *cn = CERT_GetCommonName(entityName);
570     if (cn) {
571         info.commonName = cn;
572         PORT_Free(cn);
573     }
574 
575     char *email = CERT_GetCertEmailAddress(entityName);
576     if (email) {
577         info.email = email;
578         PORT_Free(email);
579     }
580 
581     char *org = CERT_GetOrgName(entityName);
582     if (org) {
583         info.organization = org;
584         PORT_Free(org);
585     }
586 
587     return info;
588 }
589 
SECItemToGooString(const SECItem & secItem)590 static GooString SECItemToGooString(const SECItem &secItem)
591 {
592     // TODO do we need to handle secItem.type;
593     return GooString((const char *)secItem.data, secItem.len);
594 }
595 
getCertificateInfoFromCERT(CERTCertificate * cert)596 static std::unique_ptr<X509CertificateInfo> getCertificateInfoFromCERT(CERTCertificate *cert)
597 {
598     auto certInfo = std::make_unique<X509CertificateInfo>();
599 
600     certInfo->setVersion(DER_GetInteger(&cert->version) + 1);
601     certInfo->setSerialNumber(SECItemToGooString(cert->serialNumber));
602 
603     // issuer info
604     certInfo->setIssuerInfo(getEntityInfo(&cert->issuer));
605 
606     // validity
607     PRTime notBefore, notAfter;
608     CERT_GetCertTimes(cert, &notBefore, &notAfter);
609     X509CertificateInfo::Validity certValidity;
610     certValidity.notBefore = static_cast<time_t>(notBefore / 1000000);
611     certValidity.notAfter = static_cast<time_t>(notAfter / 1000000);
612     certInfo->setValidity(certValidity);
613 
614     // subject info
615     certInfo->setSubjectInfo(getEntityInfo(&cert->subject));
616 
617     // nickname (as a handle to refer to the CERT later)
618     certInfo->setNickName(GooString(cert->dbnickname));
619 
620     // public key info
621     X509CertificateInfo::PublicKeyInfo pkInfo;
622     SECKEYPublicKey *pk = CERT_ExtractPublicKey(cert);
623     switch (pk->keyType) {
624     case rsaKey:
625         pkInfo.publicKey = SECItemToGooString(pk->u.rsa.modulus);
626         pkInfo.publicKeyType = RSAKEY;
627         break;
628     case dsaKey:
629         pkInfo.publicKey = SECItemToGooString(pk->u.dsa.publicValue);
630         pkInfo.publicKeyType = DSAKEY;
631         break;
632     case ecKey:
633         pkInfo.publicKey = SECItemToGooString(pk->u.ec.publicValue);
634         pkInfo.publicKeyType = ECKEY;
635         break;
636     default:
637         pkInfo.publicKey = SECItemToGooString(cert->subjectPublicKeyInfo.subjectPublicKey);
638         pkInfo.publicKeyType = OTHERKEY;
639         break;
640     }
641     pkInfo.publicKeyStrength = SECKEY_PublicKeyStrengthInBits(pk);
642     certInfo->setPublicKeyInfo(std::move(pkInfo));
643 
644     certInfo->setKeyUsageExtensions(cert->keyUsage);
645     certInfo->setCertificateDER(SECItemToGooString(cert->derCert));
646     certInfo->setIsSelfSigned(CERT_CompareName(&cert->subject, &cert->issuer) == SECEqual);
647 
648     SECKEY_DestroyPublicKey(pk);
649 
650     return certInfo;
651 }
652 
getCertificateInfo() const653 std::unique_ptr<X509CertificateInfo> SignatureHandler::getCertificateInfo() const
654 {
655     if (CMSSignerInfo) {
656         CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
657         if (!cert)
658             return nullptr;
659         return getCertificateInfoFromCERT(cert);
660     } else {
661         if (!signing_cert)
662             return nullptr;
663 
664         return getCertificateInfoFromCERT(signing_cert);
665     }
666 }
667 
getDefaultFirefoxCertDB_Linux()668 static GooString *getDefaultFirefoxCertDB_Linux()
669 {
670     GooString *finalPath = nullptr;
671     DIR *toSearchIn;
672     struct dirent *subFolder;
673 
674     GooString *homePath = new GooString(getenv("HOME"));
675     homePath = homePath->append("/.mozilla/firefox/");
676 
677     if ((toSearchIn = opendir(homePath->c_str())) == nullptr) {
678         error(errInternal, 0, "couldn't find default Firefox Folder");
679         delete homePath;
680         return nullptr;
681     }
682     do {
683         if ((subFolder = readdir(toSearchIn)) != nullptr) {
684             if (strstr(subFolder->d_name, "default") != nullptr) {
685                 finalPath = homePath->append(subFolder->d_name);
686                 closedir(toSearchIn);
687                 return finalPath;
688             }
689         }
690     } while (subFolder != nullptr);
691 
692     closedir(toSearchIn);
693     delete homePath;
694     return nullptr;
695 }
696 
697 std::string SignatureHandler::sNssDir;
698 
699 /**
700  * Initialise NSS
701  */
setNSSDir(const GooString & nssDir)702 void SignatureHandler::setNSSDir(const GooString &nssDir)
703 {
704     static bool setNssDirCalled = false;
705 
706     if (NSS_IsInitialized() && nssDir.getLength() > 0) {
707         error(errInternal, 0, "You need to call setNSSDir before signature validation related operations happen");
708         return;
709     }
710 
711     if (setNssDirCalled)
712         return;
713 
714     setNssDirCalled = true;
715 
716     atexit(shutdownNss);
717 
718     bool initSuccess = false;
719     if (nssDir.getLength() > 0) {
720         initSuccess = (NSS_Init(nssDir.c_str()) == SECSuccess);
721         sNssDir = nssDir.toStr();
722     } else {
723         GooString *certDBPath = getDefaultFirefoxCertDB_Linux();
724         if (certDBPath == nullptr) {
725             initSuccess = (NSS_Init("sql:/etc/pki/nssdb") == SECSuccess);
726             sNssDir = "sql:/etc/pki/nssdb";
727         } else {
728             initSuccess = (NSS_Init(certDBPath->c_str()) == SECSuccess);
729             sNssDir = certDBPath->toStr();
730         }
731         if (!initSuccess) {
732             GooString homeNssDb(getenv("HOME"));
733             homeNssDb.append("/.pki/nssdb");
734             initSuccess = (NSS_Init(homeNssDb.c_str()) == SECSuccess);
735             sNssDir = homeNssDb.toStr();
736             if (!initSuccess) {
737                 NSS_NoDB_Init(nullptr);
738             }
739         }
740         delete certDBPath;
741     }
742 
743     if (initSuccess) {
744         // Make sure NSS root certificates module is loaded
745         SECMOD_AddNewModule("Root Certs", "libnssckbi.so", 0, 0);
746     }
747 }
748 
getNSSDir()749 std::string SignatureHandler::getNSSDir()
750 {
751     return sNssDir;
752 }
753 
754 static std::function<char *(const char *)> PasswordFunction;
755 
setNSSPasswordCallback(const std::function<char * (const char *)> & f)756 void SignatureHandler::setNSSPasswordCallback(const std::function<char *(const char *)> &f)
757 {
758     PasswordFunction = f;
759 }
760 
SignatureHandler(unsigned char * p7,int p7_length)761 SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length) : hash_context(nullptr), CMSMessage(nullptr), CMSSignedData(nullptr), CMSSignerInfo(nullptr), signing_cert(nullptr), temp_certs(nullptr)
762 {
763     setNSSDir({});
764     CMSitem.data = p7;
765     CMSitem.len = p7_length;
766     CMSMessage = CMS_MessageCreate(&CMSitem);
767     CMSSignedData = CMS_SignedDataCreate(CMSMessage);
768     if (CMSSignedData) {
769         CMSSignerInfo = CMS_SignerInfoCreate(CMSSignedData);
770         hash_context = initHashContext();
771     }
772 }
773 
SignatureHandler(const char * certNickname,SECOidTag digestAlgTag)774 SignatureHandler::SignatureHandler(const char *certNickname, SECOidTag digestAlgTag)
775     : hash_length(digestLength(digestAlgTag)), digest_alg_tag(digestAlgTag), CMSitem(), hash_context(nullptr), CMSMessage(nullptr), CMSSignedData(nullptr), CMSSignerInfo(nullptr), signing_cert(nullptr), temp_certs(nullptr)
776 {
777     setNSSDir({});
778     CMSMessage = NSS_CMSMessage_Create(nullptr);
779     signing_cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), certNickname);
780     hash_context = HASH_Create(HASH_GetHashTypeByOidTag(digestAlgTag));
781 }
782 
SignatureHandler()783 SignatureHandler::SignatureHandler() : hash_length(), digest_alg_tag(), CMSitem(), hash_context(nullptr), CMSMessage(nullptr), CMSSignedData(nullptr), CMSSignerInfo(nullptr), signing_cert(nullptr), temp_certs(nullptr)
784 {
785     setNSSDir({});
786     CMSMessage = NSS_CMSMessage_Create(nullptr);
787 }
788 
initHashContext()789 HASHContext *SignatureHandler::initHashContext()
790 {
791 
792     SECItem usedAlgorithm = NSS_CMSSignedData_GetDigestAlgs(CMSSignedData)[0]->algorithm;
793     hash_length = digestLength(SECOID_FindOIDTag(&usedAlgorithm));
794     HASH_HashType hashType;
795     hashType = HASH_GetHashTypeByOidTag(SECOID_FindOIDTag(&usedAlgorithm));
796     return HASH_Create(hashType);
797 }
798 
updateHash(unsigned char * data_block,int data_len)799 void SignatureHandler::updateHash(unsigned char *data_block, int data_len)
800 {
801     if (hash_context) {
802         HASH_Update(hash_context, data_block, data_len);
803     }
804 }
805 
restartHash()806 void SignatureHandler::restartHash()
807 {
808     if (hash_context)
809         HASH_Destroy(hash_context);
810     hash_context = HASH_Create(HASH_GetHashTypeByOidTag(digest_alg_tag));
811 }
812 
~SignatureHandler()813 SignatureHandler::~SignatureHandler()
814 {
815     SECITEM_FreeItem(&CMSitem, PR_FALSE);
816     if (CMSMessage)
817         NSS_CMSMessage_Destroy(CMSMessage);
818 
819     if (hash_context)
820         HASH_Destroy(hash_context);
821 
822     free(temp_certs);
823 }
824 
CMS_MessageCreate(SECItem * cms_item)825 NSSCMSMessage *SignatureHandler::CMS_MessageCreate(SECItem *cms_item)
826 {
827     if (cms_item->data) {
828         return NSS_CMSMessage_CreateFromDER(cms_item, nullptr, nullptr /* Content callback */
829                                             ,
830                                             nullptr, nullptr /*Password callback*/
831                                             ,
832                                             nullptr, nullptr /*Decrypt callback*/);
833     } else {
834         return nullptr;
835     }
836 }
837 
CMS_SignedDataCreate(NSSCMSMessage * cms_msg)838 NSSCMSSignedData *SignatureHandler::CMS_SignedDataCreate(NSSCMSMessage *cms_msg)
839 {
840     if (!NSS_CMSMessage_IsSigned(cms_msg)) {
841         error(errInternal, 0, "Input couldn't be parsed as a CMS signature");
842         return nullptr;
843     }
844 
845     NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(cms_msg, 0);
846     if (!cinfo) {
847         error(errInternal, 0, "Error in NSS_CMSMessage_ContentLevel");
848         return nullptr;
849     }
850 
851     NSSCMSSignedData *signedData = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo);
852     if (!signedData) {
853         error(errInternal, 0, "CError in NSS_CMSContentInfo_GetContent()");
854         return nullptr;
855     }
856 
857     if (signedData->rawCerts) {
858         size_t i;
859         for (i = 0; signedData->rawCerts[i]; ++i) { } // just count the length of the certificate chain
860 
861         // tempCerts field needs to be filled for complete memory release by NSSCMSSignedData_Destroy
862         signedData->tempCerts = (CERTCertificate **)gmallocn(i + 1, sizeof(CERTCertificate *));
863         memset(signedData->tempCerts, 0, (i + 1) * sizeof(CERTCertificate *));
864         // store the addresses of these temporary certificates for future release
865         for (i = 0; signedData->rawCerts[i]; ++i)
866             signedData->tempCerts[i] = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), signedData->rawCerts[i], nullptr, 0, 0);
867 
868         temp_certs = signedData->tempCerts;
869         return signedData;
870     } else {
871         return nullptr;
872     }
873 }
874 
CMS_SignerInfoCreate(NSSCMSSignedData * cms_sig_data)875 NSSCMSSignerInfo *SignatureHandler::CMS_SignerInfoCreate(NSSCMSSignedData *cms_sig_data)
876 {
877     NSSCMSSignerInfo *signerInfo = NSS_CMSSignedData_GetSignerInfo(cms_sig_data, 0);
878     if (!signerInfo) {
879         printf("Error in NSS_CMSSignedData_GetSignerInfo()\n");
880         return nullptr;
881     } else {
882         return signerInfo;
883     }
884 }
885 
NSS_SigTranslate(NSSCMSVerificationStatus nss_code)886 static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_code)
887 {
888     switch (nss_code) {
889     case NSSCMSVS_GoodSignature:
890         return SIGNATURE_VALID;
891 
892     case NSSCMSVS_BadSignature:
893         return SIGNATURE_INVALID;
894 
895     case NSSCMSVS_DigestMismatch:
896         return SIGNATURE_DIGEST_MISMATCH;
897 
898     case NSSCMSVS_ProcessingError:
899         return SIGNATURE_DECODING_ERROR;
900 
901     default:
902         return SIGNATURE_GENERIC_ERROR;
903     }
904 }
905 
validateSignature()906 SignatureValidationStatus SignatureHandler::validateSignature()
907 {
908     unsigned char *digest_buffer = nullptr;
909 
910     if (!CMSSignedData)
911         return SIGNATURE_GENERIC_ERROR;
912 
913     if (!NSS_IsInitialized())
914         return SIGNATURE_GENERIC_ERROR;
915 
916     if (!hash_context)
917         return SIGNATURE_GENERIC_ERROR;
918 
919     digest_buffer = (unsigned char *)PORT_Alloc(hash_length);
920     unsigned int result_len = 0;
921 
922     HASH_End(hash_context, digest_buffer, &result_len, hash_length);
923 
924     SECItem digest;
925     digest.data = digest_buffer;
926     digest.len = hash_length;
927 
928     if ((NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB())) == nullptr)
929         CMSSignerInfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
930 
931     SECItem *content_info_data = CMSSignedData->contentInfo.content.data;
932     if (content_info_data != nullptr && content_info_data->data != nullptr) {
933         /*
934           This means it's not a detached type signature
935           so the digest is contained in SignedData->contentInfo
936         */
937         if (memcmp(digest.data, content_info_data->data, hash_length) == 0 && digest.len == content_info_data->len) {
938             PORT_Free(digest_buffer);
939             return SIGNATURE_VALID;
940         } else {
941             PORT_Free(digest_buffer);
942             return SIGNATURE_DIGEST_MISMATCH;
943         }
944 
945     } else if (NSS_CMSSignerInfo_Verify(CMSSignerInfo, &digest, nullptr) != SECSuccess) {
946 
947         PORT_Free(digest_buffer);
948         return NSS_SigTranslate(CMSSignerInfo->verificationStatus);
949     } else {
950         PORT_Free(digest_buffer);
951         return SIGNATURE_VALID;
952     }
953 }
954 
validateCertificate(time_t validation_time,bool ocspRevocationCheck,bool useAIACertFetch)955 CertificateValidationStatus SignatureHandler::validateCertificate(time_t validation_time, bool ocspRevocationCheck, bool useAIACertFetch)
956 {
957     CERTCertificate *cert;
958 
959     if (!CMSSignerInfo)
960         return CERTIFICATE_GENERIC_ERROR;
961 
962     if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB())) == nullptr)
963         CMSSignerInfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
964 
965     PRTime vTime = 0; // time in microseconds since the epoch, special value 0 means now
966     if (validation_time > 0)
967         vTime = 1000000 * (PRTime)validation_time;
968     CERTValInParam inParams[4];
969     inParams[0].type = cert_pi_revocationFlags;
970     if (ocspRevocationCheck) {
971         inParams[0].value.pointer.revocation = CERT_GetClassicOCSPEnabledSoftFailurePolicy();
972     } else {
973         inParams[0].value.pointer.revocation = CERT_GetClassicOCSPDisabledPolicy();
974     }
975     inParams[1].type = cert_pi_date;
976     inParams[1].value.scalar.time = vTime;
977     if (useAIACertFetch) {
978         inParams[2].type = cert_pi_useAIACertFetch;
979         inParams[2].value.scalar.b = PR_TRUE;
980         inParams[3].type = cert_pi_end;
981     } else {
982         inParams[2].type = cert_pi_end;
983     }
984 
985     CERT_PKIXVerifyCert(cert, certificateUsageEmailSigner, inParams, nullptr, CMSSignerInfo->cmsg->pwfn_arg);
986 
987     switch (PORT_GetError()) {
988     // 0 not defined in SECErrorCodes, it means success for this purpose.
989     case 0:
990         return CERTIFICATE_TRUSTED;
991 
992     case SEC_ERROR_UNKNOWN_ISSUER:
993         return CERTIFICATE_UNKNOWN_ISSUER;
994 
995     case SEC_ERROR_UNTRUSTED_ISSUER:
996         return CERTIFICATE_UNTRUSTED_ISSUER;
997 
998     case SEC_ERROR_REVOKED_CERTIFICATE:
999         return CERTIFICATE_REVOKED;
1000 
1001     case SEC_ERROR_EXPIRED_CERTIFICATE:
1002         return CERTIFICATE_EXPIRED;
1003     }
1004 
1005     return CERTIFICATE_GENERIC_ERROR;
1006 }
1007 
signDetached(const char * password) const1008 std::unique_ptr<GooString> SignatureHandler::signDetached(const char *password) const
1009 {
1010     if (!hash_context)
1011         return nullptr;
1012     unsigned char *digest_buffer = reinterpret_cast<unsigned char *>(PORT_Alloc(hash_length));
1013     unsigned int result_len = 0;
1014     HASH_End(hash_context, digest_buffer, &result_len, hash_length);
1015     SECItem digest;
1016     digest.data = digest_buffer;
1017     digest.len = result_len;
1018 
1019     /////////////////////////////////////
1020     /// Code from LibreOffice under MPLv2
1021     /////////////////////////////////////
1022 
1023     NSSCMSMessage *cms_msg = NSS_CMSMessage_Create(nullptr);
1024     if (!cms_msg)
1025         return nullptr;
1026 
1027     NSSCMSSignedData *cms_sd = NSS_CMSSignedData_Create(cms_msg);
1028     if (!cms_sd)
1029         return nullptr;
1030 
1031     NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(cms_msg);
1032 
1033     if (NSS_CMSContentInfo_SetContent_SignedData(cms_msg, cms_cinfo, cms_sd) != SECSuccess)
1034         return nullptr;
1035 
1036     cms_cinfo = NSS_CMSSignedData_GetContentInfo(cms_sd);
1037 
1038     // Attach NULL data as detached data
1039     if (NSS_CMSContentInfo_SetContent_Data(cms_msg, cms_cinfo, nullptr, PR_TRUE) != SECSuccess)
1040         return nullptr;
1041 
1042     // hardcode SHA256 these days...
1043     NSSCMSSignerInfo *cms_signer = NSS_CMSSignerInfo_Create(cms_msg, signing_cert, SEC_OID_SHA256);
1044     if (!cms_signer)
1045         return nullptr;
1046 
1047     if (NSS_CMSSignerInfo_IncludeCerts(cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
1048         return nullptr;
1049 
1050     if (NSS_CMSSignedData_AddCertificate(cms_sd, signing_cert) != SECSuccess)
1051         return nullptr;
1052 
1053     if (NSS_CMSSignedData_AddSignerInfo(cms_sd, cms_signer) != SECSuccess)
1054         return nullptr;
1055 
1056     if (NSS_CMSSignedData_SetDigestValue(cms_sd, SEC_OID_SHA256, &digest) != SECSuccess)
1057         return nullptr;
1058 
1059     // Add the signing certificate as a signed attribute.
1060     ESSCertIDv2 *aCertIDs[2];
1061     ESSCertIDv2 aCertID;
1062     // Write ESSCertIDv2.hashAlgorithm.
1063     aCertID.hashAlgorithm.algorithm.data = nullptr;
1064     aCertID.hashAlgorithm.parameters.data = nullptr;
1065     SECOID_SetAlgorithmID(nullptr, &aCertID.hashAlgorithm, SEC_OID_SHA256, nullptr);
1066 
1067     // Write ESSCertIDv2.certHash.
1068     SECItem aCertHashItem;
1069     unsigned char certhash[32];
1070     SECStatus rv = PK11_HashBuf(SEC_OID_SHA256, certhash, signing_cert->derCert.data, signing_cert->derCert.len);
1071     if (rv != SECSuccess)
1072         return nullptr;
1073 
1074     aCertHashItem.type = siBuffer;
1075     aCertHashItem.data = certhash;
1076     aCertHashItem.len = 32;
1077     aCertID.certHash = aCertHashItem;
1078 
1079     // Write ESSCertIDv2.issuerSerial.
1080     IssuerSerial aSerial;
1081     GeneralName aName;
1082     aName.name = signing_cert->issuer;
1083     aSerial.issuer.names = aName;
1084     aSerial.serialNumber = signing_cert->serialNumber;
1085     aCertID.issuerSerial = aSerial;
1086     // Write SigningCertificateV2.certs.
1087     aCertIDs[0] = &aCertID;
1088     aCertIDs[1] = nullptr;
1089     SigningCertificateV2 aCertificate;
1090     aCertificate.certs = &aCertIDs[0];
1091 
1092     SECItem *pEncodedCertificate = SEC_ASN1EncodeItem(nullptr, nullptr, &aCertificate, SigningCertificateV2Template);
1093     if (!pEncodedCertificate)
1094         return nullptr;
1095 
1096     NSSCMSAttribute aAttribute;
1097     SECItem aAttributeValues[2];
1098     SECItem *pAttributeValues[2];
1099     pAttributeValues[0] = aAttributeValues;
1100     pAttributeValues[1] = nullptr;
1101     aAttributeValues[0] = *pEncodedCertificate;
1102     aAttributeValues[1].type = siBuffer;
1103     aAttributeValues[1].data = nullptr;
1104     aAttributeValues[1].len = 0;
1105     aAttribute.values = pAttributeValues;
1106 
1107     SECOidData aOidData;
1108     aOidData.oid.data = nullptr;
1109     /*
1110      * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
1111      * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
1112      *   smime(16) id-aa(2) 47 }
1113      */
1114     if (my_SEC_StringToOID(&aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess)
1115         return nullptr;
1116 
1117     aOidData.offset = SEC_OID_UNKNOWN;
1118     aOidData.desc = "id-aa-signingCertificateV2";
1119     aOidData.mechanism = CKM_SHA_1;
1120     aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
1121     aAttribute.typeTag = &aOidData;
1122     aAttribute.type = aOidData.oid;
1123     aAttribute.encoded = PR_TRUE;
1124 
1125     if (my_NSS_CMSSignerInfo_AddAuthAttr(cms_signer, &aAttribute) != SECSuccess)
1126         return nullptr;
1127 
1128     SECItem cms_output;
1129     cms_output.data = nullptr;
1130     cms_output.len = 0;
1131     PLArenaPool *arena = PORT_NewArena(10000);
1132 
1133     NSSCMSEncoderContext *cms_ecx = NSS_CMSEncoder_Start(cms_msg, nullptr, nullptr, &cms_output, arena, passwordCallback, const_cast<char *>(password), nullptr, nullptr, nullptr, nullptr);
1134     if (!cms_ecx) {
1135         PORT_FreeArena(arena, PR_FALSE);
1136         return nullptr;
1137     }
1138 
1139     if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess) {
1140         PORT_FreeArena(arena, PR_FALSE);
1141         return nullptr;
1142     }
1143 
1144     GooString *signature = new GooString(reinterpret_cast<const char *>(cms_output.data), cms_output.len);
1145 
1146     SECITEM_FreeItem(pEncodedCertificate, PR_TRUE);
1147     NSS_CMSMessage_Destroy(cms_msg);
1148     PORT_FreeArena(arena, PR_FALSE);
1149 
1150     return std::unique_ptr<GooString>(signature);
1151 }
1152 
GetPasswordFunction(PK11SlotInfo * slot,PRBool,void *)1153 static char *GetPasswordFunction(PK11SlotInfo *slot, PRBool /*retry*/, void * /*arg*/)
1154 {
1155     const char *name = PK11_GetTokenName(slot);
1156     if (PasswordFunction) {
1157         return PasswordFunction(name);
1158     }
1159     return nullptr;
1160 }
1161 
getAvailableSigningCertificates()1162 std::vector<std::unique_ptr<X509CertificateInfo>> SignatureHandler::getAvailableSigningCertificates()
1163 {
1164     // set callback, in case one of the slots has a password set
1165     PK11_SetPasswordFunc(GetPasswordFunction);
1166     setNSSDir({});
1167 
1168     std::vector<std::unique_ptr<X509CertificateInfo>> certsList;
1169     PK11SlotList *slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, nullptr);
1170     if (slotList) {
1171         for (PK11SlotListElement *slotElement = slotList->head; slotElement; slotElement = slotElement->next) {
1172             PK11SlotInfo *pSlot = slotElement->slot;
1173             if (PK11_NeedLogin(pSlot)) {
1174                 SECStatus nRet = PK11_Authenticate(pSlot, PR_TRUE, nullptr);
1175                 // PK11_Authenticate may fail in case the a slot has not been initialized.
1176                 // this is the case if the user has a new profile, so that they have never
1177                 // added a personal certificate.
1178                 if (nRet != SECSuccess && PORT_GetError() != SEC_ERROR_IO)
1179                     continue;
1180             }
1181 
1182             SECKEYPrivateKeyList *privKeyList = PK11_ListPrivateKeysInSlot(pSlot);
1183             if (privKeyList) {
1184                 for (SECKEYPrivateKeyListNode *curPri = PRIVKEY_LIST_HEAD(privKeyList); !PRIVKEY_LIST_END(curPri, privKeyList) && curPri != nullptr; curPri = PRIVKEY_LIST_NEXT(curPri)) {
1185                     if (curPri->key) {
1186                         CERTCertificate *cert = PK11_GetCertFromPrivateKey(curPri->key);
1187                         if (cert) {
1188                             certsList.push_back(getCertificateInfoFromCERT(cert));
1189                             CERT_DestroyCertificate(cert);
1190                         }
1191                     }
1192                 }
1193                 SECKEY_DestroyPrivateKeyList(privKeyList);
1194             }
1195         }
1196         PK11_FreeSlotList(slotList);
1197     }
1198 
1199     PK11_SetPasswordFunc(nullptr);
1200 
1201     return certsList;
1202 }
1203