1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5  * This file manages PKCS #11 instances of certificates.
6  */
7 
8 #include <stddef.h>
9 
10 #include "secport.h"
11 #include "seccomon.h"
12 #include "secmod.h"
13 #include "secmodi.h"
14 #include "secmodti.h"
15 #include "pkcs11.h"
16 #include "pk11func.h"
17 #include "cert.h"
18 #include "certi.h"
19 #include "secitem.h"
20 #include "keyhi.h"
21 #include "secoid.h"
22 #include "pkcs7t.h"
23 #include "cmsreclist.h"
24 
25 #include "certdb.h"
26 #include "secerr.h"
27 #include "sslerr.h"
28 
29 #include "pki3hack.h"
30 #include "dev3hack.h"
31 
32 #include "devm.h"
33 #include "nsspki.h"
34 #include "pki.h"
35 #include "pkim.h"
36 #include "pkitm.h"
37 #include "pkistore.h" /* to remove temp cert */
38 #include "devt.h"
39 #include "ckhelper.h"
40 #include "pkcs11uri.h"
41 
42 extern const NSSError NSS_ERROR_NOT_FOUND;
43 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
44 
45 struct nss3_cert_cbstr {
46     SECStatus (*callback)(CERTCertificate *, void *);
47     nssList *cached;
48     void *arg;
49 };
50 
51 /* Translate from NSSCertificate to CERTCertificate, then pass the latter
52  * to a callback.
53  */
54 static PRStatus
convert_cert(NSSCertificate * c,void * arg)55 convert_cert(NSSCertificate *c, void *arg)
56 {
57     CERTCertificate *nss3cert;
58     SECStatus secrv;
59     struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg;
60     /* 'c' is not adopted. caller will free it */
61     nss3cert = STAN_GetCERTCertificate(c);
62     if (!nss3cert)
63         return PR_FAILURE;
64     secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg);
65     return (secrv) ? PR_FAILURE : PR_SUCCESS;
66 }
67 
68 /*
69  * build a cert nickname based on the token name and the label of the
70  * certificate If the label in NULL, build a label based on the ID.
71  */
72 static int
toHex(int x)73 toHex(int x)
74 {
75     return (x < 10) ? (x + '0') : (x + 'a' - 10);
76 }
77 #define MAX_CERT_ID 4
78 #define DEFAULT_STRING "Cert ID "
79 static char *
pk11_buildNickname(PK11SlotInfo * slot,CK_ATTRIBUTE * cert_label,CK_ATTRIBUTE * key_label,CK_ATTRIBUTE * cert_id)80 pk11_buildNickname(PK11SlotInfo *slot, CK_ATTRIBUTE *cert_label,
81                    CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id)
82 {
83     int prefixLen = PORT_Strlen(slot->token_name);
84     int suffixLen = 0;
85     char *suffix = NULL;
86     char buildNew[sizeof(DEFAULT_STRING) + MAX_CERT_ID * 2];
87     char *next, *nickname;
88 
89     if (cert_label && (cert_label->ulValueLen)) {
90         suffixLen = cert_label->ulValueLen;
91         suffix = (char *)cert_label->pValue;
92     } else if (key_label && (key_label->ulValueLen)) {
93         suffixLen = key_label->ulValueLen;
94         suffix = (char *)key_label->pValue;
95     } else if (cert_id && cert_id->ulValueLen > 0) {
96         int i, first = cert_id->ulValueLen - MAX_CERT_ID;
97         int offset = sizeof(DEFAULT_STRING);
98         char *idValue = (char *)cert_id->pValue;
99 
100         PORT_Memcpy(buildNew, DEFAULT_STRING, sizeof(DEFAULT_STRING) - 1);
101         next = buildNew + offset;
102         if (first < 0)
103             first = 0;
104         for (i = first; i < (int)cert_id->ulValueLen; i++) {
105             *next++ = toHex((idValue[i] >> 4) & 0xf);
106             *next++ = toHex(idValue[i] & 0xf);
107         }
108         *next++ = 0;
109         suffix = buildNew;
110         suffixLen = PORT_Strlen(buildNew);
111     } else {
112         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
113         return NULL;
114     }
115 
116     /* if is internal key slot, add code to skip the prefix!! */
117     next = nickname = (char *)PORT_Alloc(prefixLen + 1 + suffixLen + 1);
118     if (nickname == NULL)
119         return NULL;
120 
121     PORT_Memcpy(next, slot->token_name, prefixLen);
122     next += prefixLen;
123     *next++ = ':';
124     PORT_Memcpy(next, suffix, suffixLen);
125     next += suffixLen;
126     *next++ = 0;
127     return nickname;
128 }
129 
130 PRBool
PK11_IsUserCert(PK11SlotInfo * slot,CERTCertificate * cert,CK_OBJECT_HANDLE certID)131 PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert,
132                 CK_OBJECT_HANDLE certID)
133 {
134     CK_OBJECT_CLASS theClass;
135 
136     if (slot == NULL)
137         return PR_FALSE;
138     if (cert == NULL)
139         return PR_FALSE;
140 
141     theClass = CKO_PRIVATE_KEY;
142     if (pk11_LoginStillRequired(slot, NULL)) {
143         theClass = CKO_PUBLIC_KEY;
144     }
145     if (PK11_MatchItem(slot, certID, theClass) != CK_INVALID_HANDLE) {
146         return PR_TRUE;
147     }
148 
149     if (theClass == CKO_PUBLIC_KEY) {
150         SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert);
151         CK_ATTRIBUTE theTemplate;
152 
153         if (pubKey == NULL) {
154             return PR_FALSE;
155         }
156 
157         PK11_SETATTRS(&theTemplate, 0, NULL, 0);
158         switch (pubKey->keyType) {
159             case rsaKey:
160             case rsaPssKey:
161             case rsaOaepKey:
162                 PK11_SETATTRS(&theTemplate, CKA_MODULUS, pubKey->u.rsa.modulus.data,
163                               pubKey->u.rsa.modulus.len);
164                 break;
165             case dsaKey:
166                 PK11_SETATTRS(&theTemplate, CKA_VALUE, pubKey->u.dsa.publicValue.data,
167                               pubKey->u.dsa.publicValue.len);
168                 break;
169             case dhKey:
170                 PK11_SETATTRS(&theTemplate, CKA_VALUE, pubKey->u.dh.publicValue.data,
171                               pubKey->u.dh.publicValue.len);
172                 break;
173             case ecKey:
174                 PK11_SETATTRS(&theTemplate, CKA_EC_POINT,
175                               pubKey->u.ec.publicValue.data,
176                               pubKey->u.ec.publicValue.len);
177                 break;
178             case keaKey:
179             case fortezzaKey:
180             case nullKey:
181                 /* fall through and return false */
182                 break;
183         }
184 
185         if (theTemplate.ulValueLen == 0) {
186             SECKEY_DestroyPublicKey(pubKey);
187             return PR_FALSE;
188         }
189         if (pubKey->keyType != ecKey) {
190             pk11_SignedToUnsigned(&theTemplate);
191         }
192         if (pk11_FindObjectByTemplate(slot, &theTemplate, 1) != CK_INVALID_HANDLE) {
193             SECKEY_DestroyPublicKey(pubKey);
194             return PR_TRUE;
195         }
196         SECKEY_DestroyPublicKey(pubKey);
197     }
198     return PR_FALSE;
199 }
200 
201 /*
202  * Check out if a cert has ID of zero. This is a magic ID that tells
203  * NSS that this cert may be an automagically trusted cert.
204  * The Cert has to be self signed as well. That check is done elsewhere.
205  *
206  */
207 PRBool
pk11_isID0(PK11SlotInfo * slot,CK_OBJECT_HANDLE certID)208 pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID)
209 {
210     CK_ATTRIBUTE keyID = { CKA_ID, NULL, 0 };
211     PRBool isZero = PR_FALSE;
212     int i;
213     CK_RV crv;
214 
215     crv = PK11_GetAttributes(NULL, slot, certID, &keyID, 1);
216     if (crv != CKR_OK) {
217         return isZero;
218     }
219 
220     if (keyID.ulValueLen != 0) {
221         char *value = (char *)keyID.pValue;
222         isZero = PR_TRUE; /* ID exists, may be zero */
223         for (i = 0; i < (int)keyID.ulValueLen; i++) {
224             if (value[i] != 0) {
225                 isZero = PR_FALSE; /* nope */
226                 break;
227             }
228         }
229     }
230     PORT_Free(keyID.pValue);
231     return isZero;
232 }
233 
234 /*
235  * Create an NSSCertificate from a slot/certID pair, return it as a
236  * CERTCertificate.  Optionally, output the nickname string.
237  */
238 static CERTCertificate *
pk11_fastCert(PK11SlotInfo * slot,CK_OBJECT_HANDLE certID,CK_ATTRIBUTE * privateLabel,char ** nickptr)239 pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID,
240               CK_ATTRIBUTE *privateLabel, char **nickptr)
241 {
242     NSSCertificate *c;
243     nssCryptokiObject *co = NULL;
244     nssPKIObject *pkio;
245     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
246 
247     /* Get the cryptoki object from the handle */
248     NSSToken *token = PK11Slot_GetNSSToken(slot);
249     if (!token || !token->defaultSession) {
250         (void)nssToken_Destroy(token); /* null token is ok */
251         PORT_SetError(SEC_ERROR_NO_TOKEN);
252         return NULL;
253     }
254     co = nssCryptokiObject_Create(token, token->defaultSession, certID);
255     (void)nssToken_Destroy(token);
256     if (!co) {
257         return NULL;
258     }
259 
260     /* Create a PKI object from the cryptoki instance */
261     pkio = nssPKIObject_Create(NULL, co, td, NULL, nssPKIMonitor);
262     if (!pkio) {
263         nssCryptokiObject_Destroy(co);
264         return NULL;
265     }
266 
267     /* Create a certificate */
268     c = nssCertificate_Create(pkio);
269     if (!c) {
270         nssPKIObject_Destroy(pkio);
271         return NULL;
272     }
273 
274     /* Build and output a nickname, if desired.
275      * This must be done before calling nssTrustDomain_AddCertsToCache
276      * because that function may destroy c, pkio and co!
277      */
278     if ((nickptr) && (co->label)) {
279         CK_ATTRIBUTE label, id;
280 
281         label.type = CKA_LABEL;
282         label.pValue = co->label;
283         label.ulValueLen = PORT_Strlen(co->label);
284 
285         id.type = CKA_ID;
286         id.pValue = c->id.data;
287         id.ulValueLen = c->id.size;
288 
289         *nickptr = pk11_buildNickname(slot, &label, privateLabel, &id);
290     }
291 
292     /* This function may destroy the cert in "c" and all its subordinate
293      * structures, and replace the value in "c" with the address of a
294      * different NSSCertificate that it found in the cache.
295      * Presumably, the nickname which we just output above remains valid. :)
296      */
297     (void)nssTrustDomain_AddCertsToCache(td, &c, 1);
298     return STAN_GetCERTCertificateOrRelease(c);
299 }
300 
301 /*
302  * Build an CERTCertificate structure from a PKCS#11 object ID.... certID
303  * Must be a CertObject. This code does not explicitly checks that.
304  */
305 CERTCertificate *
PK11_MakeCertFromHandle(PK11SlotInfo * slot,CK_OBJECT_HANDLE certID,CK_ATTRIBUTE * privateLabel)306 PK11_MakeCertFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID,
307                         CK_ATTRIBUTE *privateLabel)
308 {
309     char *nickname = NULL;
310     CERTCertificate *cert = NULL;
311     CERTCertTrust *trust;
312 
313     if (slot == NULL || certID == CK_INVALID_HANDLE) {
314         PORT_SetError(SEC_ERROR_INVALID_ARGS);
315         return NULL;
316     }
317 
318     cert = pk11_fastCert(slot, certID, privateLabel, &nickname);
319     if (cert == NULL) {
320         goto loser;
321     }
322 
323     if (nickname) {
324         if (cert->nickname != NULL) {
325             cert->dbnickname = cert->nickname;
326         }
327         cert->nickname = PORT_ArenaStrdup(cert->arena, nickname);
328         PORT_Free(nickname);
329         nickname = NULL;
330     }
331 
332     /* remember where this cert came from.... If we have just looked
333      * it up from the database and it already has a slot, don't add a new
334      * one. */
335     if (cert->slot == NULL) {
336         cert->slot = PK11_ReferenceSlot(slot);
337         cert->pkcs11ID = certID;
338         cert->ownSlot = PR_TRUE;
339         cert->series = slot->series;
340     }
341 
342     trust = (CERTCertTrust *)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust));
343     if (trust == NULL)
344         goto loser;
345     PORT_Memset(trust, 0, sizeof(CERTCertTrust));
346 
347     if (!pk11_HandleTrustObject(slot, cert, trust)) {
348         unsigned int type;
349 
350         /* build some cert trust flags */
351         if (CERT_IsCACert(cert, &type)) {
352             unsigned int trustflags = CERTDB_VALID_CA;
353 
354             /* Allow PKCS #11 modules to give us trusted CA's. We only accept
355              * valid CA's which are self-signed here. They must have an object
356              * ID of '0'.  */
357             if (pk11_isID0(slot, certID) &&
358                 cert->isRoot) {
359                 trustflags |= CERTDB_TRUSTED_CA;
360                 /* is the slot a fortezza card? allow the user or
361                  * admin to turn on objectSigning, but don't turn
362                  * full trust on explicitly */
363                 if (PK11_DoesMechanism(slot, CKM_KEA_KEY_DERIVE)) {
364                     trust->objectSigningFlags |= CERTDB_VALID_CA;
365                 }
366             }
367             if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
368                 trust->sslFlags |= trustflags;
369             }
370             if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) {
371                 trust->emailFlags |= trustflags;
372             }
373             if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA) == NS_CERT_TYPE_OBJECT_SIGNING_CA) {
374                 trust->objectSigningFlags |= trustflags;
375             }
376         }
377     }
378 
379     if (PK11_IsUserCert(slot, cert, certID)) {
380         trust->sslFlags |= CERTDB_USER;
381         trust->emailFlags |= CERTDB_USER;
382         /*    trust->objectSigningFlags |= CERTDB_USER; */
383     }
384     CERT_LockCertTrust(cert);
385     cert->trust = trust;
386     CERT_UnlockCertTrust(cert);
387 
388     return cert;
389 
390 loser:
391     if (nickname)
392         PORT_Free(nickname);
393     if (cert)
394         CERT_DestroyCertificate(cert);
395     return NULL;
396 }
397 
398 /*
399  * Build get a certificate from a private key
400  */
401 CERTCertificate *
PK11_GetCertFromPrivateKey(SECKEYPrivateKey * privKey)402 PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey)
403 {
404     PK11SlotInfo *slot = privKey->pkcs11Slot;
405     CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
406     CK_OBJECT_HANDLE certID =
407         PK11_MatchItem(slot, handle, CKO_CERTIFICATE);
408     CERTCertificate *cert;
409 
410     if (certID == CK_INVALID_HANDLE) {
411         PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
412         return NULL;
413     }
414     cert = PK11_MakeCertFromHandle(slot, certID, NULL);
415     return (cert);
416 }
417 
418 CK_OBJECT_HANDLE *
PK11_FindCertHandlesForKeyHandle(PK11SlotInfo * slot,CK_OBJECT_HANDLE keyHandle,int * certHandleCountOut)419 PK11_FindCertHandlesForKeyHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle,
420                                  int *certHandleCountOut)
421 {
422     if (!slot || !certHandleCountOut || keyHandle == CK_INVALID_HANDLE) {
423         PORT_SetError(SEC_ERROR_INVALID_ARGS);
424         return NULL;
425     }
426 
427     PORTCheapArenaPool arena;
428     PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
429     CK_ATTRIBUTE idTemplate[] = {
430         { CKA_ID, NULL, 0 },
431     };
432     const int idAttrCount = sizeof(idTemplate) / sizeof(idTemplate[0]);
433     CK_RV crv = PK11_GetAttributes(&arena.arena, slot, keyHandle, idTemplate, idAttrCount);
434     if (crv != CKR_OK) {
435         PORT_DestroyCheapArena(&arena);
436         PORT_SetError(PK11_MapError(crv));
437         return NULL;
438     }
439 
440     if ((idTemplate[0].ulValueLen == 0) || (idTemplate[0].ulValueLen == -1)) {
441         PORT_DestroyCheapArena(&arena);
442         PORT_SetError(SEC_ERROR_BAD_KEY);
443         return NULL;
444     }
445 
446     CK_OBJECT_CLASS searchClass = CKO_CERTIFICATE;
447     CK_ATTRIBUTE searchTemplate[] = {
448         idTemplate[0],
449         { CKA_CLASS, &searchClass, sizeof(searchClass) }
450     };
451     const size_t searchAttrCount = sizeof(searchTemplate) / sizeof(searchTemplate[0]);
452     CK_OBJECT_HANDLE *ids = pk11_FindObjectsByTemplate(slot, searchTemplate, searchAttrCount, certHandleCountOut);
453 
454     PORT_DestroyCheapArena(&arena);
455     return ids;
456 }
457 
458 CERTCertList *
PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey * privKey)459 PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey *privKey)
460 {
461     if (!privKey) {
462         PORT_SetError(SEC_ERROR_INVALID_ARGS);
463         return NULL;
464     }
465     CERTCertList *certs = CERT_NewCertList();
466     if (!certs) {
467         PORT_SetError(SEC_ERROR_NO_MEMORY);
468         return NULL;
469     }
470     PK11SlotInfo *slot = privKey->pkcs11Slot;
471     CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
472     CK_OBJECT_HANDLE certID = PK11_MatchItem(slot, handle, CKO_CERTIFICATE);
473     /* If we can't get a matching certID, there are no matching certificates,
474      * which is not an error. */
475     if (certID == CK_INVALID_HANDLE) {
476         return certs;
477     }
478     int certHandleCount = 0;
479     CK_OBJECT_HANDLE *certHandles = PK11_FindCertHandlesForKeyHandle(slot, handle, &certHandleCount);
480     if (!certHandles) {
481         /* If certHandleCount is 0, there are no matching certificates, which is
482          * not an error. */
483         if (certHandleCount == 0) {
484             return certs;
485         }
486         CERT_DestroyCertList(certs);
487         return NULL;
488     }
489     int i;
490     for (i = 0; i < certHandleCount; i++) {
491         CERTCertificate *cert = PK11_MakeCertFromHandle(slot, certHandles[i], NULL);
492         /* If PK11_MakeCertFromHandle fails for one handle, optimistically
493            assume other handles may succeed (i.e. this is best-effort). */
494         if (!cert) {
495             continue;
496         }
497         if (CERT_AddCertToListTail(certs, cert) != SECSuccess) {
498             CERT_DestroyCertificate(cert);
499         }
500     }
501     PORT_Free(certHandles);
502     return certs;
503 }
504 
505 /*
506  * delete a cert and it's private key (if no other certs are pointing to the
507  * private key.
508  */
509 SECStatus
PK11_DeleteTokenCertAndKey(CERTCertificate * cert,void * wincx)510 PK11_DeleteTokenCertAndKey(CERTCertificate *cert, void *wincx)
511 {
512     SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert, wincx);
513     CK_OBJECT_HANDLE pubKey;
514     PK11SlotInfo *slot = NULL;
515 
516     pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx);
517     if (privKey) {
518         /* For 3.4, utilize the generic cert delete function */
519         SEC_DeletePermCertificate(cert);
520         PK11_DeleteTokenPrivateKey(privKey, PR_FALSE);
521     }
522     if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) {
523         PK11_DestroyTokenObject(slot, pubKey);
524         PK11_FreeSlot(slot);
525     }
526     return SECSuccess;
527 }
528 
529 /*
530  * cert callback structure
531  */
532 typedef struct pk11DoCertCallbackStr {
533     SECStatus (*callback)(PK11SlotInfo *slot, CERTCertificate *, void *);
534     SECStatus (*noslotcallback)(CERTCertificate *, void *);
535     SECStatus (*itemcallback)(CERTCertificate *, SECItem *, void *);
536     void *callbackArg;
537 } pk11DoCertCallback;
538 
539 typedef struct pk11CertCallbackStr {
540     SECStatus (*callback)(CERTCertificate *, SECItem *, void *);
541     void *callbackArg;
542 } pk11CertCallback;
543 
544 struct fake_der_cb_argstr {
545     SECStatus (*callback)(CERTCertificate *, SECItem *, void *);
546     void *arg;
547 };
548 
549 static SECStatus
fake_der_cb(CERTCertificate * c,void * a)550 fake_der_cb(CERTCertificate *c, void *a)
551 {
552     struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a;
553     return (*fda->callback)(c, &c->derCert, fda->arg);
554 }
555 
556 /*
557  * Extract all the certs on a card from a slot.
558  */
559 SECStatus
PK11_TraverseSlotCerts(SECStatus (* callback)(CERTCertificate *,SECItem *,void *),void * arg,void * wincx)560 PK11_TraverseSlotCerts(SECStatus (*callback)(CERTCertificate *, SECItem *, void *),
561                        void *arg, void *wincx)
562 {
563     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
564     struct fake_der_cb_argstr fda;
565     struct nss3_cert_cbstr pk11cb;
566 
567     /* authenticate to the tokens first */
568     (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
569 
570     fda.callback = callback;
571     fda.arg = arg;
572     pk11cb.callback = fake_der_cb;
573     pk11cb.arg = &fda;
574     NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
575     return SECSuccess;
576 }
577 
578 static void
transfer_token_certs_to_collection(nssList * certList,NSSToken * token,nssPKIObjectCollection * collection)579 transfer_token_certs_to_collection(nssList *certList, NSSToken *token,
580                                    nssPKIObjectCollection *collection)
581 {
582     NSSCertificate **certs;
583     PRUint32 i, count;
584     NSSToken **tokens, **tp;
585     count = nssList_Count(certList);
586     if (count == 0) {
587         return;
588     }
589     certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
590     if (!certs) {
591         return;
592     }
593     nssList_GetArray(certList, (void **)certs, count);
594     for (i = 0; i < count; i++) {
595         tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
596         if (tokens) {
597             for (tp = tokens; *tp; tp++) {
598                 if (*tp == token) {
599                     nssPKIObjectCollection_AddObject(collection,
600                                                      (nssPKIObject *)certs[i]);
601                 }
602             }
603             nssTokenArray_Destroy(tokens);
604         }
605         CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i]));
606     }
607     nss_ZFreeIf(certs);
608 }
609 
610 static void
transfer_uri_certs_to_collection(nssList * certList,PK11URI * uri,nssPKIObjectCollection * collection)611 transfer_uri_certs_to_collection(nssList *certList, PK11URI *uri,
612                                  nssPKIObjectCollection *collection)
613 {
614 
615     NSSCertificate **certs;
616     PRUint32 i, count;
617     NSSToken **tokens, **tp;
618     PK11SlotInfo *slot;
619     const char *id;
620 
621     id = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_ID);
622     count = nssList_Count(certList);
623     if (count == 0) {
624         return;
625     }
626     certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
627     if (!certs) {
628         return;
629     }
630     nssList_GetArray(certList, (void **)certs, count);
631     for (i = 0; i < count; i++) {
632         /*
633 	 * Filter the subject matched certs based on the
634 	 * CKA_ID from the URI
635 	 */
636         if (id && (strlen(id) != certs[i]->id.size ||
637                    memcmp(id, certs[i]->id.data, certs[i]->id.size)))
638             continue;
639         tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
640         if (tokens) {
641             for (tp = tokens; *tp; tp++) {
642                 const char *value;
643                 slot = (*tp)->pk11slot;
644 
645                 value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TOKEN);
646                 if (value &&
647                     !pk11_MatchString(value,
648                                       (char *)slot->tokenInfo.label,
649                                       sizeof(slot->tokenInfo.label))) {
650                     continue;
651                 }
652 
653                 value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MANUFACTURER);
654                 if (value &&
655                     !pk11_MatchString(value,
656                                       (char *)slot->tokenInfo.manufacturerID,
657                                       sizeof(slot->tokenInfo.manufacturerID))) {
658                     continue;
659                 }
660 
661                 value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MODEL);
662                 if (value &&
663                     !pk11_MatchString(value,
664                                       (char *)slot->tokenInfo.model,
665                                       sizeof(slot->tokenInfo.model))) {
666                     continue;
667                 }
668 
669                 nssPKIObjectCollection_AddObject(collection,
670                                                  (nssPKIObject *)certs[i]);
671                 break;
672             }
673             nssTokenArray_Destroy(tokens);
674         }
675         CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i]));
676     }
677     nss_ZFreeIf(certs);
678 }
679 
680 static NSSCertificate **
find_certs_from_uri(const char * uriString,void * wincx)681 find_certs_from_uri(const char *uriString, void *wincx)
682 {
683     PK11URI *uri = NULL;
684     CK_ATTRIBUTE attributes[10];
685     CK_ULONG nattributes = 0;
686     const char *label;
687     PK11SlotInfo *slotinfo;
688     nssCryptokiObject **instances;
689     PRStatus status;
690     nssPKIObjectCollection *collection = NULL;
691     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
692     NSSCertificate **certs = NULL;
693     nssList *certList = NULL;
694     SECStatus rv;
695     CK_OBJECT_CLASS s_class = CKO_CERTIFICATE;
696     static const CK_BBOOL s_true = CK_TRUE;
697     NSSToken **tokens, **tok;
698 
699     uri = PK11URI_ParseURI(uriString);
700     if (uri == NULL) {
701         goto loser;
702     }
703 
704     collection = nssCertificateCollection_Create(defaultTD, NULL);
705     if (!collection) {
706         goto loser;
707     }
708     certList = nssList_Create(NULL, PR_FALSE);
709     if (!certList) {
710         goto loser;
711     }
712 
713     label = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_OBJECT);
714     if (label) {
715         (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
716                                                           (const char *)label,
717                                                           certList);
718     } else {
719         (void)nssTrustDomain_GetCertsFromCache(defaultTD, certList);
720     }
721 
722     transfer_uri_certs_to_collection(certList, uri, collection);
723 
724     /* add the CKA_CLASS and CKA_TOKEN attributes manually */
725     attributes[nattributes].type = CKA_CLASS;
726     attributes[nattributes].pValue = (void *)&s_class;
727     attributes[nattributes].ulValueLen = sizeof(s_class);
728     nattributes++;
729 
730     attributes[nattributes].type = CKA_TOKEN;
731     attributes[nattributes].pValue = (void *)&s_true;
732     attributes[nattributes].ulValueLen = sizeof(s_true);
733     nattributes++;
734 
735     if (label) {
736         attributes[nattributes].type = CKA_LABEL;
737         attributes[nattributes].pValue = (void *)label;
738         attributes[nattributes].ulValueLen = strlen(label);
739         nattributes++;
740     }
741 
742     tokens = NSSTrustDomain_FindTokensByURI(defaultTD, uri);
743     for (tok = tokens; tok && *tok; tok++) {
744         if (nssToken_IsPresent(*tok)) {
745             slotinfo = (*tok)->pk11slot;
746 
747             rv = pk11_AuthenticateUnfriendly(slotinfo, PR_TRUE, wincx);
748             if (rv != SECSuccess) {
749                 continue;
750             }
751             instances = nssToken_FindObjectsByTemplate(*tok, NULL,
752                                                        attributes,
753                                                        nattributes,
754                                                        0, &status);
755             nssPKIObjectCollection_AddInstances(collection, instances, 0);
756             nss_ZFreeIf(instances);
757         }
758         (void)nssToken_Destroy(*tok);
759     }
760     nss_ZFreeIf(tokens);
761     nssList_Destroy(certList);
762     certs = nssPKIObjectCollection_GetCertificates(collection, NULL, 0, NULL);
763 
764 loser:
765     if (collection) {
766         nssPKIObjectCollection_Destroy(collection);
767     }
768     if (uri) {
769         PK11URI_DestroyURI(uri);
770     }
771     return certs;
772 }
773 
774 CERTCertificate *
PK11_FindCertFromURI(const char * uri,void * wincx)775 PK11_FindCertFromURI(const char *uri, void *wincx)
776 {
777     static const NSSUsage usage = { PR_TRUE /* ... */ };
778     NSSCertificate *cert = NULL;
779     NSSCertificate **certs = NULL;
780     CERTCertificate *rvCert = NULL;
781 
782     certs = find_certs_from_uri(uri, wincx);
783     if (certs) {
784         cert = nssCertificateArray_FindBestCertificate(certs, NULL,
785                                                        &usage, NULL);
786         if (cert) {
787             rvCert = STAN_GetCERTCertificateOrRelease(cert);
788         }
789         nssCertificateArray_Destroy(certs);
790     }
791     return rvCert;
792 }
793 
794 CERTCertList *
PK11_FindCertsFromURI(const char * uri,void * wincx)795 PK11_FindCertsFromURI(const char *uri, void *wincx)
796 {
797     int i;
798     CERTCertList *certList = NULL;
799     NSSCertificate **foundCerts;
800     NSSCertificate *c;
801 
802     foundCerts = find_certs_from_uri(uri, wincx);
803     if (foundCerts) {
804         PRTime now = PR_Now();
805         certList = CERT_NewCertList();
806         for (i = 0, c = *foundCerts; c; c = foundCerts[++i]) {
807             if (certList) {
808                 CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c);
809                 /* c may be invalid after this, don't reference it */
810                 if (certCert) {
811                     /* CERT_AddCertToListSorted adopts certCert  */
812                     CERT_AddCertToListSorted(certList, certCert,
813                                              CERT_SortCBValidity, &now);
814                 }
815             } else {
816                 nssCertificate_Destroy(c);
817             }
818         }
819         if (certList && CERT_LIST_HEAD(certList) == NULL) {
820             CERT_DestroyCertList(certList);
821             certList = NULL;
822         }
823         /* all the certs have been adopted or freed, free the  raw array */
824         nss_ZFreeIf(foundCerts);
825     }
826     return certList;
827 }
828 
829 static NSSCertificate **
find_certs_from_nickname(const char * nickname,void * wincx)830 find_certs_from_nickname(const char *nickname, void *wincx)
831 {
832     PRStatus status;
833     NSSCertificate **certs = NULL;
834     NSSToken *token = NULL;
835     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
836     PK11SlotInfo *slot = NULL;
837     SECStatus rv;
838     char *nickCopy;
839     char *delimit = NULL;
840     char *tokenName;
841 
842     if (!PORT_Strncasecmp(nickname, "pkcs11:", strlen("pkcs11:"))) {
843         certs = find_certs_from_uri(nickname, wincx);
844         if (certs)
845             return certs;
846     }
847     nickCopy = PORT_Strdup(nickname);
848     if (!nickCopy) {
849         /* error code is set */
850         return NULL;
851     }
852     if ((delimit = PORT_Strchr(nickCopy, ':')) != NULL) {
853         tokenName = nickCopy;
854         nickname = delimit + 1;
855         *delimit = '\0';
856         /* find token by name */
857         token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
858         if (token) {
859             slot = PK11_ReferenceSlot(token->pk11slot);
860         } else {
861             PORT_SetError(SEC_ERROR_NO_TOKEN);
862         }
863         *delimit = ':';
864     } else {
865         slot = PK11_GetInternalKeySlot();
866         token = PK11Slot_GetNSSToken(slot);
867         if (!token) {
868             PORT_SetError(SEC_ERROR_NO_TOKEN);
869         }
870     }
871     if (token) {
872         nssList *certList;
873         nssCryptokiObject **instances;
874         nssPKIObjectCollection *collection;
875         nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
876         if (!PK11_IsPresent(slot)) {
877             goto loser;
878         }
879         rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
880         if (rv != SECSuccess) {
881             goto loser;
882         }
883         collection = nssCertificateCollection_Create(defaultTD, NULL);
884         if (!collection) {
885             goto loser;
886         }
887         certList = nssList_Create(NULL, PR_FALSE);
888         if (!certList) {
889             nssPKIObjectCollection_Destroy(collection);
890             goto loser;
891         }
892         (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
893                                                           nickname,
894                                                           certList);
895         transfer_token_certs_to_collection(certList, token, collection);
896         instances = nssToken_FindCertificatesByNickname(token,
897                                                         NULL,
898                                                         nickname,
899                                                         tokenOnly,
900                                                         0,
901                                                         &status);
902         nssPKIObjectCollection_AddInstances(collection, instances, 0);
903         nss_ZFreeIf(instances);
904         /* if it wasn't found, repeat the process for email address */
905         if (nssPKIObjectCollection_Count(collection) == 0 &&
906             PORT_Strchr(nickname, '@') != NULL) {
907             char *lowercaseName = CERT_FixupEmailAddr(nickname);
908             if (lowercaseName) {
909                 (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD,
910                                                                       lowercaseName,
911                                                                       certList);
912                 transfer_token_certs_to_collection(certList, token, collection);
913                 instances = nssToken_FindCertificatesByEmail(token,
914                                                              NULL,
915                                                              lowercaseName,
916                                                              tokenOnly,
917                                                              0,
918                                                              &status);
919                 nssPKIObjectCollection_AddInstances(collection, instances, 0);
920                 nss_ZFreeIf(instances);
921                 PORT_Free(lowercaseName);
922             }
923         }
924         certs = nssPKIObjectCollection_GetCertificates(collection,
925                                                        NULL, 0, NULL);
926         nssPKIObjectCollection_Destroy(collection);
927         nssList_Destroy(certList);
928     }
929 loser:
930     if (token) {
931         (void)nssToken_Destroy(token);
932     }
933     if (slot) {
934         PK11_FreeSlot(slot);
935     }
936     if (nickCopy)
937         PORT_Free(nickCopy);
938     return certs;
939 }
940 
941 CERTCertificate *
PK11_FindCertFromNickname(const char * nickname,void * wincx)942 PK11_FindCertFromNickname(const char *nickname, void *wincx)
943 {
944     CERTCertificate *rvCert = NULL;
945     NSSCertificate *cert = NULL;
946     NSSCertificate **certs = NULL;
947     static const NSSUsage usage = { PR_TRUE /* ... */ };
948 
949     certs = find_certs_from_nickname(nickname, wincx);
950     if (certs) {
951         cert = nssCertificateArray_FindBestCertificate(certs, NULL,
952                                                        &usage, NULL);
953         if (cert) {
954             rvCert = STAN_GetCERTCertificateOrRelease(cert);
955         }
956         nssCertificateArray_Destroy(certs);
957     }
958     return rvCert;
959 }
960 
961 /* Traverse slots callback */
962 typedef struct FindCertsEmailArgStr {
963     char *email;
964     CERTCertList *certList;
965 } FindCertsEmailArg;
966 
967 SECStatus
FindCertsEmailCallback(CERTCertificate * cert,SECItem * item,void * arg)968 FindCertsEmailCallback(CERTCertificate *cert, SECItem *item, void *arg)
969 {
970     FindCertsEmailArg *cbparam = (FindCertsEmailArg *)arg;
971     const char *cert_email = CERT_GetFirstEmailAddress(cert);
972     PRBool found = PR_FALSE;
973 
974     /* Email address present in certificate? */
975     if (cert_email == NULL) {
976         return SECSuccess;
977     }
978 
979     /* Parameter correctly set? */
980     if (cbparam->email == NULL) {
981         return SECFailure;
982     }
983 
984     /* Loop over all email addresses */
985     do {
986         if (!strcmp(cert_email, cbparam->email)) {
987             /* found one matching email address */
988             PRTime now = PR_Now();
989             found = PR_TRUE;
990             CERT_AddCertToListSorted(cbparam->certList,
991                                      CERT_DupCertificate(cert),
992                                      CERT_SortCBValidity, &now);
993         }
994         cert_email = CERT_GetNextEmailAddress(cert, cert_email);
995     } while (cert_email && !found);
996 
997     return SECSuccess;
998 }
999 
1000 /* Find all certificates with matching email address */
1001 CERTCertList *
PK11_FindCertsFromEmailAddress(const char * email,void * wincx)1002 PK11_FindCertsFromEmailAddress(const char *email, void *wincx)
1003 {
1004     FindCertsEmailArg cbparam;
1005     SECStatus rv;
1006 
1007     cbparam.certList = CERT_NewCertList();
1008     if (cbparam.certList == NULL) {
1009         return NULL;
1010     }
1011 
1012     cbparam.email = CERT_FixupEmailAddr(email);
1013     if (cbparam.email == NULL) {
1014         CERT_DestroyCertList(cbparam.certList);
1015         return NULL;
1016     }
1017 
1018     rv = PK11_TraverseSlotCerts(FindCertsEmailCallback, &cbparam, NULL);
1019     if (rv != SECSuccess) {
1020         CERT_DestroyCertList(cbparam.certList);
1021         PORT_Free(cbparam.email);
1022         return NULL;
1023     }
1024 
1025     /* empty list? */
1026     if (CERT_LIST_EMPTY(cbparam.certList)) {
1027         CERT_DestroyCertList(cbparam.certList);
1028         cbparam.certList = NULL;
1029     }
1030 
1031     PORT_Free(cbparam.email);
1032     return cbparam.certList;
1033 }
1034 
1035 CERTCertList *
PK11_FindCertsFromNickname(const char * nickname,void * wincx)1036 PK11_FindCertsFromNickname(const char *nickname, void *wincx)
1037 {
1038     int i;
1039     CERTCertList *certList = NULL;
1040     NSSCertificate **foundCerts = NULL;
1041     NSSCertificate *c;
1042 
1043     foundCerts = find_certs_from_nickname(nickname, wincx);
1044     if (foundCerts) {
1045         PRTime now = PR_Now();
1046         certList = CERT_NewCertList();
1047         for (i = 0, c = *foundCerts; c; c = foundCerts[++i]) {
1048             if (certList) {
1049                 CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c);
1050                 /* c may be invalid after this, don't reference it */
1051                 if (certCert) {
1052                     /* CERT_AddCertToListSorted adopts certCert  */
1053                     CERT_AddCertToListSorted(certList, certCert,
1054                                              CERT_SortCBValidity, &now);
1055                 }
1056             } else {
1057                 nssCertificate_Destroy(c);
1058             }
1059         }
1060         /* all the certs have been adopted or freed, free the  raw array */
1061         nss_ZFreeIf(foundCerts);
1062     }
1063     return certList;
1064 }
1065 
1066 /*
1067  * extract a key ID for a certificate...
1068  * NOTE: We call this function from PKCS11.c If we ever use
1069  * pkcs11 to extract the public key (we currently do not), this will break.
1070  */
1071 SECItem *
PK11_GetPubIndexKeyID(CERTCertificate * cert)1072 PK11_GetPubIndexKeyID(CERTCertificate *cert)
1073 {
1074     SECKEYPublicKey *pubk;
1075     SECItem *newItem = NULL;
1076 
1077     pubk = CERT_ExtractPublicKey(cert);
1078     if (pubk == NULL)
1079         return NULL;
1080 
1081     switch (pubk->keyType) {
1082         case rsaKey:
1083             newItem = SECITEM_DupItem(&pubk->u.rsa.modulus);
1084             break;
1085         case dsaKey:
1086             newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue);
1087             break;
1088         case dhKey:
1089             newItem = SECITEM_DupItem(&pubk->u.dh.publicValue);
1090             break;
1091         case ecKey:
1092             newItem = SECITEM_DupItem(&pubk->u.ec.publicValue);
1093             break;
1094         case fortezzaKey:
1095         default:
1096             newItem = NULL; /* Fortezza Fix later... */
1097     }
1098     SECKEY_DestroyPublicKey(pubk);
1099     /* make hash of it */
1100     return newItem;
1101 }
1102 
1103 /*
1104  * generate a CKA_ID from a certificate.
1105  */
1106 SECItem *
pk11_mkcertKeyID(CERTCertificate * cert)1107 pk11_mkcertKeyID(CERTCertificate *cert)
1108 {
1109     SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert);
1110     SECItem *certCKA_ID;
1111 
1112     if (pubKeyData == NULL)
1113         return NULL;
1114 
1115     certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData);
1116     SECITEM_FreeItem(pubKeyData, PR_TRUE);
1117     return certCKA_ID;
1118 }
1119 
1120 /*
1121  * Write the cert into the token.
1122  */
1123 SECStatus
PK11_ImportCert(PK11SlotInfo * slot,CERTCertificate * cert,CK_OBJECT_HANDLE key,const char * nickname,PRBool includeTrust)1124 PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert,
1125                 CK_OBJECT_HANDLE key, const char *nickname,
1126                 PRBool includeTrust)
1127 {
1128     PRStatus status;
1129     NSSCertificate *c;
1130     nssCryptokiObject *keyobj, *certobj;
1131     NSSToken *token = NULL;
1132     char *emailAddr = NULL;
1133     nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
1134     nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
1135     SECItem *keyID = pk11_mkcertKeyID(cert);
1136     if (keyID == NULL) {
1137         goto loser; /* error code should be set already */
1138     }
1139     token = PK11Slot_GetNSSToken(slot);
1140     if (!token) {
1141         PORT_SetError(SEC_ERROR_NO_TOKEN);
1142         goto loser;
1143     }
1144 
1145     if (PK11_IsInternal(slot) && cert->emailAddr && cert->emailAddr[0]) {
1146         emailAddr = cert->emailAddr;
1147     }
1148 
1149     /* need to get the cert as a stan cert */
1150     CERT_LockCertTempPerm(cert);
1151     NSSCertificate *nssCert = cert->nssCertificate;
1152     CERT_UnlockCertTempPerm(cert);
1153     if (nssCert) {
1154         c = nssCert;
1155     } else {
1156         c = STAN_GetNSSCertificate(cert);
1157         if (c == NULL) {
1158             goto loser;
1159         }
1160     }
1161 
1162     /* set the id for the cert */
1163     nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
1164     if (!c->id.data) {
1165         goto loser;
1166     }
1167 
1168     if (key != CK_INVALID_HANDLE) {
1169         /* create an object for the key, ... */
1170         keyobj = nss_ZNEW(NULL, nssCryptokiObject);
1171         if (!keyobj) {
1172             goto loser;
1173         }
1174         keyobj->token = nssToken_AddRef(token);
1175         keyobj->handle = key;
1176         keyobj->isTokenObject = PR_TRUE;
1177 
1178         /* ... in order to set matching attributes for the key */
1179         status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname,
1180                                                       &c->id, &c->subject);
1181         nssCryptokiObject_Destroy(keyobj);
1182         if (status != PR_SUCCESS) {
1183             goto loser;
1184         }
1185     }
1186 
1187     /* do the token import */
1188     certobj = nssToken_ImportCertificate(token, NULL,
1189                                          NSSCertificateType_PKIX,
1190                                          &c->id,
1191                                          nickname,
1192                                          &c->encoding,
1193                                          &c->issuer,
1194                                          &c->subject,
1195                                          &c->serial,
1196                                          emailAddr,
1197                                          PR_TRUE);
1198     if (!certobj) {
1199         if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
1200             PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
1201             SECITEM_FreeItem(keyID, PR_TRUE);
1202             return SECFailure;
1203         }
1204         goto loser;
1205     }
1206 
1207     if (c->object.cryptoContext) {
1208         /* Delete the temp instance */
1209         NSSCryptoContext *cc = c->object.cryptoContext;
1210         nssCertificateStore_Lock(cc->certStore, &lockTrace);
1211         nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
1212         nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace);
1213         c->object.cryptoContext = NULL;
1214         CERT_LockCertTempPerm(cert);
1215         cert->istemp = PR_FALSE;
1216         cert->isperm = PR_TRUE;
1217         CERT_UnlockCertTempPerm(cert);
1218     }
1219 
1220     /* add the new instance to the cert, force an update of the
1221      * CERTCertificate, and finish
1222      */
1223     nssPKIObject_AddInstance(&c->object, certobj);
1224     /* nssTrustDomain_AddCertsToCache may release a reference to 'c' and
1225      * replace 'c' with a different value. So we add a reference to 'c' to
1226      * prevent 'c' from being destroyed. */
1227     nssCertificate_AddRef(c);
1228     nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
1229     (void)STAN_ForceCERTCertificateUpdate(c);
1230     nssCertificate_Destroy(c);
1231     SECITEM_FreeItem(keyID, PR_TRUE);
1232     (void)nssToken_Destroy(token);
1233     return SECSuccess;
1234 loser:
1235     if (token) {
1236         (void)nssToken_Destroy(token);
1237     }
1238     CERT_MapStanError();
1239     SECITEM_FreeItem(keyID, PR_TRUE);
1240     if (PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
1241         PORT_SetError(SEC_ERROR_ADDING_CERT);
1242     }
1243     return SECFailure;
1244 }
1245 
1246 SECStatus
PK11_ImportDERCert(PK11SlotInfo * slot,SECItem * derCert,CK_OBJECT_HANDLE key,char * nickname,PRBool includeTrust)1247 PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert,
1248                    CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust)
1249 {
1250     CERTCertificate *cert;
1251     SECStatus rv;
1252 
1253     cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
1254                                    derCert, NULL, PR_FALSE, PR_TRUE);
1255     if (cert == NULL)
1256         return SECFailure;
1257 
1258     rv = PK11_ImportCert(slot, cert, key, nickname, includeTrust);
1259     CERT_DestroyCertificate(cert);
1260     return rv;
1261 }
1262 
1263 /*
1264  * return the private key From a given Cert
1265  */
1266 SECKEYPrivateKey *
PK11_FindPrivateKeyFromCert(PK11SlotInfo * slot,CERTCertificate * cert,void * wincx)1267 PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert,
1268                             void *wincx)
1269 {
1270     int err;
1271     CK_OBJECT_HANDLE certh;
1272     CK_OBJECT_HANDLE keyh;
1273     PRBool needLogin;
1274     SECStatus rv;
1275 
1276     certh = PK11_FindCertInSlot(slot, cert, wincx);
1277     if (certh == CK_INVALID_HANDLE) {
1278         return NULL;
1279     }
1280     /*
1281      * prevent a login race condition. If slot is logged in between
1282      * our call to pk11_LoginStillRequired and the
1283      * PK11_MatchItem. The matchItem call will either succeed, or
1284      * we will call it one more time after calling PK11_Authenticate
1285      * (which is a noop on an authenticated token).
1286      */
1287     needLogin = pk11_LoginStillRequired(slot, wincx);
1288     keyh = PK11_MatchItem(slot, certh, CKO_PRIVATE_KEY);
1289     if ((keyh == CK_INVALID_HANDLE) && needLogin &&
1290         (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
1291          SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
1292         /* try it again authenticated */
1293         rv = PK11_Authenticate(slot, PR_TRUE, wincx);
1294         if (rv != SECSuccess) {
1295             return NULL;
1296         }
1297         keyh = PK11_MatchItem(slot, certh, CKO_PRIVATE_KEY);
1298     }
1299     if (keyh == CK_INVALID_HANDLE) {
1300         return NULL;
1301     }
1302     return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx);
1303 }
1304 
1305 /*
1306  * import a cert for a private key we have already generated. Set the label
1307  * on both to be the nickname. This is for the Key Gen, orphaned key case.
1308  */
1309 PK11SlotInfo *
PK11_KeyForCertExists(CERTCertificate * cert,CK_OBJECT_HANDLE * keyPtr,void * wincx)1310 PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr,
1311                       void *wincx)
1312 {
1313     PK11SlotList *list;
1314     PK11SlotListElement *le;
1315     SECItem *keyID;
1316     CK_OBJECT_HANDLE key;
1317     PK11SlotInfo *slot = NULL;
1318     SECStatus rv;
1319     int err;
1320 
1321     keyID = pk11_mkcertKeyID(cert);
1322     /* get them all! */
1323     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx);
1324     if ((keyID == NULL) || (list == NULL)) {
1325         if (keyID)
1326             SECITEM_FreeItem(keyID, PR_TRUE);
1327         if (list)
1328             PK11_FreeSlotList(list);
1329         return NULL;
1330     }
1331 
1332     /* Look for the slot that holds the Key */
1333     for (le = list->head; le; le = le->next) {
1334         /*
1335          * prevent a login race condition. If le->slot is logged in between
1336          * our call to pk11_LoginStillRequired and the
1337          * pk11_FindPrivateKeyFromCertID, the find will either succeed, or
1338          * we will call it one more time after calling PK11_Authenticate
1339          * (which is a noop on an authenticated token).
1340          */
1341         PRBool needLogin = pk11_LoginStillRequired(le->slot, wincx);
1342         key = pk11_FindPrivateKeyFromCertID(le->slot, keyID);
1343         if ((key == CK_INVALID_HANDLE) && needLogin &&
1344             (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
1345              SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
1346             /* authenticate and try again */
1347             rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
1348             if (rv != SECSuccess)
1349                 continue;
1350             key = pk11_FindPrivateKeyFromCertID(le->slot, keyID);
1351         }
1352         if (key != CK_INVALID_HANDLE) {
1353             slot = PK11_ReferenceSlot(le->slot);
1354             if (keyPtr)
1355                 *keyPtr = key;
1356             break;
1357         }
1358     }
1359 
1360     SECITEM_FreeItem(keyID, PR_TRUE);
1361     PK11_FreeSlotList(list);
1362     return slot;
1363 }
1364 /*
1365  * import a cert for a private key we have already generated. Set the label
1366  * on both to be the nickname. This is for the Key Gen, orphaned key case.
1367  */
1368 PK11SlotInfo *
PK11_KeyForDERCertExists(SECItem * derCert,CK_OBJECT_HANDLE * keyPtr,void * wincx)1369 PK11_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr,
1370                          void *wincx)
1371 {
1372     CERTCertificate *cert;
1373     PK11SlotInfo *slot = NULL;
1374 
1375     /* letting this use go -- the only thing that the cert is used for is
1376      * to get the ID attribute.
1377      */
1378     cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
1379     if (cert == NULL)
1380         return NULL;
1381 
1382     slot = PK11_KeyForCertExists(cert, keyPtr, wincx);
1383     CERT_DestroyCertificate(cert);
1384     return slot;
1385 }
1386 
1387 PK11SlotInfo *
PK11_ImportCertForKey(CERTCertificate * cert,const char * nickname,void * wincx)1388 PK11_ImportCertForKey(CERTCertificate *cert, const char *nickname,
1389                       void *wincx)
1390 {
1391     PK11SlotInfo *slot = NULL;
1392     CK_OBJECT_HANDLE key;
1393 
1394     slot = PK11_KeyForCertExists(cert, &key, wincx);
1395 
1396     if (slot) {
1397         if (PK11_ImportCert(slot, cert, key, nickname, PR_FALSE) != SECSuccess) {
1398             PK11_FreeSlot(slot);
1399             slot = NULL;
1400         }
1401     } else {
1402         PORT_SetError(SEC_ERROR_ADDING_CERT);
1403     }
1404 
1405     return slot;
1406 }
1407 
1408 PK11SlotInfo *
PK11_ImportDERCertForKey(SECItem * derCert,char * nickname,void * wincx)1409 PK11_ImportDERCertForKey(SECItem *derCert, char *nickname, void *wincx)
1410 {
1411     CERTCertificate *cert;
1412     PK11SlotInfo *slot = NULL;
1413 
1414     cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
1415                                    derCert, NULL, PR_FALSE, PR_TRUE);
1416     if (cert == NULL)
1417         return NULL;
1418 
1419     slot = PK11_ImportCertForKey(cert, nickname, wincx);
1420     CERT_DestroyCertificate(cert);
1421     return slot;
1422 }
1423 
1424 static CK_OBJECT_HANDLE
pk11_FindCertObjectByTemplate(PK11SlotInfo ** slotPtr,CK_ATTRIBUTE * searchTemplate,size_t count,void * wincx)1425 pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr,
1426                               CK_ATTRIBUTE *searchTemplate, size_t count, void *wincx)
1427 {
1428     PK11SlotList *list;
1429     PK11SlotListElement *le;
1430     CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE;
1431     PK11SlotInfo *slot = NULL;
1432     SECStatus rv;
1433 
1434     *slotPtr = NULL;
1435 
1436     /* get them all! */
1437     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx);
1438     if (list == NULL) {
1439         return CK_INVALID_HANDLE;
1440     }
1441 
1442     /* Look for the slot that holds the Key */
1443     for (le = list->head; le; le = le->next) {
1444         rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
1445         if (rv != SECSuccess)
1446             continue;
1447 
1448         certHandle = pk11_FindObjectByTemplate(le->slot, searchTemplate, count);
1449         if (certHandle != CK_INVALID_HANDLE) {
1450             slot = PK11_ReferenceSlot(le->slot);
1451             break;
1452         }
1453     }
1454 
1455     PK11_FreeSlotList(list);
1456 
1457     if (slot == NULL) {
1458         return CK_INVALID_HANDLE;
1459     }
1460     *slotPtr = slot;
1461     return certHandle;
1462 }
1463 
1464 CERTCertificate *
PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo * slot,CERTIssuerAndSN * issuerSN,void * wincx)1465 PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo *slot,
1466                                   CERTIssuerAndSN *issuerSN, void *wincx)
1467 {
1468     CERTCertificate *rvCert = NULL;
1469     NSSCertificate *cert = NULL;
1470     NSSDER issuer, serial;
1471     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
1472     NSSToken *token = NULL;
1473     nssSession *session;
1474     nssCryptokiObject *instance = NULL;
1475     nssPKIObject *object = NULL;
1476     SECItem *derSerial;
1477     PRStatus status;
1478 
1479     if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
1480         !issuerSN->serialNumber.data || !issuerSN->serialNumber.len ||
1481         issuerSN->derIssuer.len > CERT_MAX_DN_BYTES ||
1482         issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES) {
1483         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1484         return NULL;
1485     }
1486 
1487     token = PK11Slot_GetNSSToken(slot);
1488     if (!token) {
1489         PORT_SetError(SEC_ERROR_NO_TOKEN);
1490         return NULL;
1491     }
1492 
1493     session = nssToken_GetDefaultSession(token); /* non-owning */
1494     if (!session) {
1495         (void)nssToken_Destroy(token);
1496         return NULL;
1497     }
1498 
1499     /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
1500      * CERTIssuerAndSN that actually has the encoded value and pass that
1501      * to PKCS#11 (and the crypto context).
1502      */
1503     derSerial = SEC_ASN1EncodeItem(NULL, NULL,
1504                                    &issuerSN->serialNumber,
1505                                    SEC_ASN1_GET(SEC_IntegerTemplate));
1506     if (!derSerial) {
1507         (void)nssToken_Destroy(token);
1508         return NULL;
1509     }
1510 
1511     NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
1512     NSSITEM_FROM_SECITEM(&serial, derSerial);
1513 
1514     instance = nssToken_FindCertificateByIssuerAndSerialNumber(token, session,
1515                                                                &issuer, &serial, nssTokenSearchType_TokenForced, &status);
1516 
1517     (void)nssToken_Destroy(token);
1518     SECITEM_FreeItem(derSerial, PR_TRUE);
1519 
1520     if (!instance) {
1521         goto loser;
1522     }
1523     object = nssPKIObject_Create(NULL, instance, td, NULL, nssPKIMonitor);
1524     if (!object) {
1525         goto loser;
1526     }
1527     instance = NULL; /* adopted by the previous call */
1528     cert = nssCertificate_Create(object);
1529     if (!cert) {
1530         goto loser;
1531     }
1532     object = NULL; /* adopted by the previous call */
1533     nssTrustDomain_AddCertsToCache(td, &cert, 1);
1534     /* on failure, cert is freed below */
1535     rvCert = STAN_GetCERTCertificate(cert);
1536     if (!rvCert) {
1537         goto loser;
1538     }
1539     return rvCert;
1540 
1541 loser:
1542     if (instance) {
1543         nssCryptokiObject_Destroy(instance);
1544     }
1545     if (object) {
1546         nssPKIObject_Destroy(object);
1547     }
1548     if (cert) {
1549         nssCertificate_Destroy(cert);
1550     }
1551     return NULL;
1552 }
1553 
1554 static PRCallOnceType keyIDHashCallOnce;
1555 
1556 static PRStatus PR_CALLBACK
pk11_keyIDHash_populate(void * wincx)1557 pk11_keyIDHash_populate(void *wincx)
1558 {
1559     CERTCertList *certList;
1560     CERTCertListNode *node = NULL;
1561     SECItem subjKeyID = { siBuffer, NULL, 0 };
1562     SECItem *slotid = NULL;
1563     SECMODModuleList *modules, *mlp;
1564     SECMODListLock *moduleLock;
1565     int i;
1566 
1567     certList = PK11_ListCerts(PK11CertListUser, wincx);
1568     if (!certList) {
1569         return PR_FAILURE;
1570     }
1571 
1572     for (node = CERT_LIST_HEAD(certList);
1573          !CERT_LIST_END(node, certList);
1574          node = CERT_LIST_NEXT(node)) {
1575         if (CERT_FindSubjectKeyIDExtension(node->cert,
1576                                            &subjKeyID) == SECSuccess &&
1577             subjKeyID.data != NULL) {
1578             cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert);
1579             SECITEM_FreeItem(&subjKeyID, PR_FALSE);
1580         }
1581     }
1582     CERT_DestroyCertList(certList);
1583 
1584     /*
1585      * Record the state of each slot in a hash. The concatenation of slotID
1586      * and moduleID is used as its key, with the slot series as its value.
1587      */
1588     slotid = SECITEM_AllocItem(NULL, NULL,
1589                                sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID));
1590     if (!slotid) {
1591         PORT_SetError(SEC_ERROR_NO_MEMORY);
1592         return PR_FAILURE;
1593     }
1594     moduleLock = SECMOD_GetDefaultModuleListLock();
1595     if (!moduleLock) {
1596         SECITEM_FreeItem(slotid, PR_TRUE);
1597         PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1598         return PR_FAILURE;
1599     }
1600     SECMOD_GetReadLock(moduleLock);
1601     modules = SECMOD_GetDefaultModuleList();
1602     for (mlp = modules; mlp; mlp = mlp->next) {
1603         for (i = 0; i < mlp->module->slotCount; i++) {
1604             memcpy(slotid->data, &mlp->module->slots[i]->slotID,
1605                    sizeof(CK_SLOT_ID));
1606             memcpy(&slotid->data[sizeof(CK_SLOT_ID)], &mlp->module->moduleID,
1607                    sizeof(SECMODModuleID));
1608             cert_UpdateSubjectKeyIDSlotCheck(slotid,
1609                                              mlp->module->slots[i]->series);
1610         }
1611     }
1612     SECMOD_ReleaseReadLock(moduleLock);
1613     SECITEM_FreeItem(slotid, PR_TRUE);
1614 
1615     return PR_SUCCESS;
1616 }
1617 
1618 /*
1619  * We're looking for a cert which we have the private key for that's on the
1620  * list of recipients. This searches one slot.
1621  * this is the new version for NSS SMIME code
1622  * this stuff should REALLY be in the SMIME code, but some things in here are not public
1623  * (they should be!)
1624  */
1625 static CERTCertificate *
pk11_FindCertObjectByRecipientNew(PK11SlotInfo * slot,NSSCMSRecipient ** recipientlist,int * rlIndex,void * pwarg)1626 pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist,
1627                                   int *rlIndex, void *pwarg)
1628 {
1629     NSSCMSRecipient *ri = NULL;
1630     int i;
1631     PRBool tokenRescanDone = PR_FALSE;
1632     CERTCertTrust trust;
1633 
1634     for (i = 0; (ri = recipientlist[i]) != NULL; i++) {
1635         CERTCertificate *cert = NULL;
1636         if (ri->kind == RLSubjKeyID) {
1637             SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
1638             if (!derCert && !tokenRescanDone) {
1639                 /*
1640                  * We didn't find the cert by its key ID. If we have slots
1641                  * with removable tokens, a failure from
1642                  * cert_FindDERCertBySubjectKeyID doesn't necessarily imply
1643                  * that the cert is unavailable - the token might simply
1644                  * have been inserted after the initial run of
1645                  * pk11_keyIDHash_populate (wrapped by PR_CallOnceWithArg),
1646                  * or a different token might have been present in that
1647                  * slot, initially. Let's check for new tokens...
1648                  */
1649                 PK11SlotList *sl = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
1650                                                      PR_FALSE, PR_FALSE, pwarg);
1651                 if (sl) {
1652                     PK11SlotListElement *le;
1653                     SECItem *slotid = SECITEM_AllocItem(NULL, NULL,
1654                                                         sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID));
1655                     if (!slotid) {
1656                         PORT_SetError(SEC_ERROR_NO_MEMORY);
1657                         PK11_FreeSlotList(sl);
1658                         return NULL;
1659                     }
1660                     for (le = sl->head; le; le = le->next) {
1661                         memcpy(slotid->data, &le->slot->slotID,
1662                                sizeof(CK_SLOT_ID));
1663                         memcpy(&slotid->data[sizeof(CK_SLOT_ID)],
1664                                &le->slot->module->moduleID,
1665                                sizeof(SECMODModuleID));
1666                         /*
1667                          * Any changes with the slot since our last check?
1668                          * If so, re-read the certs in that specific slot.
1669                          */
1670                         if (cert_SubjectKeyIDSlotCheckSeries(slotid) != PK11_GetSlotSeries(le->slot)) {
1671                             CERTCertListNode *node = NULL;
1672                             SECItem subjKeyID = { siBuffer, NULL, 0 };
1673                             CERTCertList *cl = PK11_ListCertsInSlot(le->slot);
1674                             if (!cl) {
1675                                 continue;
1676                             }
1677                             for (node = CERT_LIST_HEAD(cl);
1678                                  !CERT_LIST_END(node, cl);
1679                                  node = CERT_LIST_NEXT(node)) {
1680                                 if (CERT_IsUserCert(node->cert) &&
1681                                     CERT_FindSubjectKeyIDExtension(node->cert,
1682                                                                    &subjKeyID) == SECSuccess) {
1683                                     if (subjKeyID.data) {
1684                                         cert_AddSubjectKeyIDMapping(&subjKeyID,
1685                                                                     node->cert);
1686                                         cert_UpdateSubjectKeyIDSlotCheck(slotid,
1687                                                                          PK11_GetSlotSeries(le->slot));
1688                                     }
1689                                     SECITEM_FreeItem(&subjKeyID, PR_FALSE);
1690                                 }
1691                             }
1692                             CERT_DestroyCertList(cl);
1693                         }
1694                     }
1695                     PK11_FreeSlotList(sl);
1696                     SECITEM_FreeItem(slotid, PR_TRUE);
1697                 }
1698                 /* only check once per message/recipientlist */
1699                 tokenRescanDone = PR_TRUE;
1700                 /* do another lookup (hopefully we found that cert...) */
1701                 derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
1702             }
1703             if (derCert) {
1704                 cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg);
1705                 SECITEM_FreeItem(derCert, PR_TRUE);
1706             }
1707         } else {
1708             cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN,
1709                                                      pwarg);
1710         }
1711         if (cert) {
1712             /* this isn't our cert */
1713             if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
1714                 ((trust.emailFlags & CERTDB_USER) != CERTDB_USER)) {
1715                 CERT_DestroyCertificate(cert);
1716                 continue;
1717             }
1718             ri->slot = PK11_ReferenceSlot(slot);
1719             *rlIndex = i;
1720             return cert;
1721         }
1722     }
1723     *rlIndex = -1;
1724     return NULL;
1725 }
1726 
1727 /*
1728  * This function is the same as above, but it searches all the slots.
1729  * this is the new version for NSS SMIME code
1730  * this stuff should REALLY be in the SMIME code, but some things in here are not public
1731  * (they should be!)
1732  */
1733 static CERTCertificate *
pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient ** recipientlist,void * wincx,int * rlIndex)1734 pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex)
1735 {
1736     PK11SlotList *list;
1737     PK11SlotListElement *le;
1738     CERTCertificate *cert = NULL;
1739     SECStatus rv;
1740 
1741     /* get them all! */
1742     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx);
1743     if (list == NULL) {
1744         return CK_INVALID_HANDLE;
1745     }
1746 
1747     /* Look for the slot that holds the Key */
1748     for (le = list->head; le; le = le->next) {
1749         rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
1750         if (rv != SECSuccess)
1751             continue;
1752 
1753         cert = pk11_FindCertObjectByRecipientNew(le->slot,
1754                                                  recipientlist, rlIndex, wincx);
1755         if (cert)
1756             break;
1757     }
1758 
1759     PK11_FreeSlotList(list);
1760 
1761     return cert;
1762 }
1763 
1764 /*
1765  * We're looking for a cert which we have the private key for that's on the
1766  * list of recipients. This searches one slot.
1767  */
1768 static CERTCertificate *
pk11_FindCertObjectByRecipient(PK11SlotInfo * slot,SEC_PKCS7RecipientInfo ** recipientArray,SEC_PKCS7RecipientInfo ** rip,void * pwarg)1769 pk11_FindCertObjectByRecipient(PK11SlotInfo *slot,
1770                                SEC_PKCS7RecipientInfo **recipientArray,
1771                                SEC_PKCS7RecipientInfo **rip, void *pwarg)
1772 {
1773     SEC_PKCS7RecipientInfo *ri = NULL;
1774     CERTCertTrust trust;
1775     int i;
1776 
1777     for (i = 0; (ri = recipientArray[i]) != NULL; i++) {
1778         CERTCertificate *cert;
1779 
1780         cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->issuerAndSN,
1781                                                  pwarg);
1782         if (cert) {
1783             /* this isn't our cert */
1784             if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
1785                 ((trust.emailFlags & CERTDB_USER) != CERTDB_USER)) {
1786                 CERT_DestroyCertificate(cert);
1787                 continue;
1788             }
1789             *rip = ri;
1790             return cert;
1791         }
1792     }
1793     *rip = NULL;
1794     return NULL;
1795 }
1796 
1797 /*
1798  * This function is the same as above, but it searches all the slots.
1799  */
1800 static CERTCertificate *
pk11_AllFindCertObjectByRecipient(PK11SlotInfo ** slotPtr,SEC_PKCS7RecipientInfo ** recipientArray,SEC_PKCS7RecipientInfo ** rip,void * wincx)1801 pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr,
1802                                   SEC_PKCS7RecipientInfo **recipientArray,
1803                                   SEC_PKCS7RecipientInfo **rip,
1804                                   void *wincx)
1805 {
1806     PK11SlotList *list;
1807     PK11SlotListElement *le;
1808     CERTCertificate *cert = NULL;
1809     PK11SlotInfo *slot = NULL;
1810     SECStatus rv;
1811 
1812     *slotPtr = NULL;
1813 
1814     /* get them all! */
1815     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx);
1816     if (list == NULL) {
1817         return CK_INVALID_HANDLE;
1818     }
1819 
1820     *rip = NULL;
1821 
1822     /* Look for the slot that holds the Key */
1823     for (le = list->head; le; le = le->next) {
1824         rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
1825         if (rv != SECSuccess)
1826             continue;
1827 
1828         cert = pk11_FindCertObjectByRecipient(le->slot, recipientArray,
1829                                               rip, wincx);
1830         if (cert) {
1831             slot = PK11_ReferenceSlot(le->slot);
1832             break;
1833         }
1834     }
1835 
1836     PK11_FreeSlotList(list);
1837 
1838     if (slot == NULL) {
1839         return NULL;
1840     }
1841     *slotPtr = slot;
1842     PORT_Assert(cert != NULL);
1843     return cert;
1844 }
1845 
1846 /*
1847  * We need to invert the search logic for PKCS 7 because if we search for
1848  * each cert on the list over all the slots, we wind up with lots of spurious
1849  * password prompts. This way we get only one password prompt per slot, at
1850  * the max, and most of the time we can find the cert, and only prompt for
1851  * the key...
1852  */
1853 CERTCertificate *
PK11_FindCertAndKeyByRecipientList(PK11SlotInfo ** slotPtr,SEC_PKCS7RecipientInfo ** array,SEC_PKCS7RecipientInfo ** rip,SECKEYPrivateKey ** privKey,void * wincx)1854 PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr,
1855                                    SEC_PKCS7RecipientInfo **array,
1856                                    SEC_PKCS7RecipientInfo **rip,
1857                                    SECKEYPrivateKey **privKey, void *wincx)
1858 {
1859     CERTCertificate *cert = NULL;
1860 
1861     *privKey = NULL;
1862     *slotPtr = NULL;
1863     cert = pk11_AllFindCertObjectByRecipient(slotPtr, array, rip, wincx);
1864     if (!cert) {
1865         return NULL;
1866     }
1867 
1868     *privKey = PK11_FindKeyByAnyCert(cert, wincx);
1869     if (*privKey == NULL) {
1870         goto loser;
1871     }
1872 
1873     return cert;
1874 loser:
1875     if (cert)
1876         CERT_DestroyCertificate(cert);
1877     if (*slotPtr)
1878         PK11_FreeSlot(*slotPtr);
1879     *slotPtr = NULL;
1880     return NULL;
1881 }
1882 
1883 /*
1884  * This is the new version of the above function for NSS SMIME code
1885  * this stuff should REALLY be in the SMIME code, but some things in here are not public
1886  * (they should be!)
1887  */
1888 int
PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient ** recipientlist,void * wincx)1889 PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx)
1890 {
1891     CERTCertificate *cert;
1892     NSSCMSRecipient *rl;
1893     PRStatus rv;
1894     int rlIndex;
1895 
1896     rv = PR_CallOnceWithArg(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx);
1897     if (rv != PR_SUCCESS)
1898         return -1;
1899 
1900     cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex);
1901     if (!cert) {
1902         return -1;
1903     }
1904 
1905     rl = recipientlist[rlIndex];
1906 
1907     /* at this point, rl->slot is set */
1908 
1909     rl->privkey = PK11_FindKeyByAnyCert(cert, wincx);
1910     if (rl->privkey == NULL) {
1911         goto loser;
1912     }
1913 
1914     /* make a cert from the cert handle */
1915     rl->cert = cert;
1916     return rlIndex;
1917 
1918 loser:
1919     if (cert)
1920         CERT_DestroyCertificate(cert);
1921     if (rl->slot)
1922         PK11_FreeSlot(rl->slot);
1923     rl->slot = NULL;
1924     return -1;
1925 }
1926 
1927 CERTCertificate *
PK11_FindCertByIssuerAndSN(PK11SlotInfo ** slotPtr,CERTIssuerAndSN * issuerSN,void * wincx)1928 PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN,
1929                            void *wincx)
1930 {
1931     CERTCertificate *rvCert = NULL;
1932     NSSCertificate *cert;
1933     NSSDER issuer, serial;
1934     NSSCryptoContext *cc;
1935     SECItem *derSerial;
1936 
1937     if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
1938         !issuerSN->serialNumber.data || !issuerSN->serialNumber.len ||
1939         issuerSN->derIssuer.len > CERT_MAX_DN_BYTES ||
1940         issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES) {
1941         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1942         return NULL;
1943     }
1944 
1945     if (slotPtr)
1946         *slotPtr = NULL;
1947 
1948     /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
1949      * CERTIssuerAndSN that actually has the encoded value and pass that
1950      * to PKCS#11 (and the crypto context).
1951      */
1952     derSerial = SEC_ASN1EncodeItem(NULL, NULL,
1953                                    &issuerSN->serialNumber,
1954                                    SEC_ASN1_GET(SEC_IntegerTemplate));
1955     if (!derSerial) {
1956         return NULL;
1957     }
1958 
1959     NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
1960     NSSITEM_FROM_SECITEM(&serial, derSerial);
1961 
1962     cc = STAN_GetDefaultCryptoContext();
1963     cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc,
1964                                                                    &issuer,
1965                                                                    &serial);
1966     if (cert) {
1967         SECITEM_FreeItem(derSerial, PR_TRUE);
1968         return STAN_GetCERTCertificateOrRelease(cert);
1969     }
1970 
1971     do {
1972         /* free the old cert on retry. Associated slot was not present */
1973         if (rvCert) {
1974             CERT_DestroyCertificate(rvCert);
1975             rvCert = NULL;
1976         }
1977 
1978         cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
1979             STAN_GetDefaultTrustDomain(),
1980             &issuer,
1981             &serial);
1982         if (!cert) {
1983             break;
1984         }
1985 
1986         rvCert = STAN_GetCERTCertificateOrRelease(cert);
1987         if (rvCert == NULL) {
1988             break;
1989         }
1990 
1991         /* Check to see if the cert's token is still there */
1992     } while (!PK11_IsPresent(rvCert->slot));
1993 
1994     if (rvCert && slotPtr)
1995         *slotPtr = PK11_ReferenceSlot(rvCert->slot);
1996 
1997     SECITEM_FreeItem(derSerial, PR_TRUE);
1998     return rvCert;
1999 }
2000 
2001 CK_OBJECT_HANDLE
PK11_FindObjectForCert(CERTCertificate * cert,void * wincx,PK11SlotInfo ** pSlot)2002 PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot)
2003 {
2004     CK_OBJECT_HANDLE certHandle;
2005     CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
2006     CK_ATTRIBUTE *attr;
2007     CK_ATTRIBUTE searchTemplate[] = {
2008         { CKA_CLASS, NULL, 0 },
2009         { CKA_VALUE, NULL, 0 },
2010     };
2011     const size_t templateSize = sizeof(searchTemplate) / sizeof(searchTemplate[0]);
2012 
2013     attr = searchTemplate;
2014     PK11_SETATTRS(attr, CKA_CLASS, &certClass, sizeof(certClass));
2015     attr++;
2016     PK11_SETATTRS(attr, CKA_VALUE, cert->derCert.data, cert->derCert.len);
2017 
2018     if (cert->slot) {
2019         certHandle = PK11_FindCertInSlot(cert->slot, cert, wincx);
2020         if (certHandle != CK_INVALID_HANDLE) {
2021             *pSlot = PK11_ReferenceSlot(cert->slot);
2022             return certHandle;
2023         }
2024     }
2025 
2026     certHandle = pk11_FindCertObjectByTemplate(pSlot, searchTemplate,
2027                                                templateSize, wincx);
2028     if (certHandle != CK_INVALID_HANDLE) {
2029         if (cert->slot == NULL) {
2030             cert->slot = PK11_ReferenceSlot(*pSlot);
2031             cert->pkcs11ID = certHandle;
2032             cert->ownSlot = PR_TRUE;
2033             cert->series = cert->slot->series;
2034         }
2035     }
2036 
2037     return (certHandle);
2038 }
2039 
2040 SECKEYPrivateKey *
PK11_FindKeyByAnyCert(CERTCertificate * cert,void * wincx)2041 PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx)
2042 {
2043     CK_OBJECT_HANDLE certHandle;
2044     CK_OBJECT_HANDLE keyHandle;
2045     PK11SlotInfo *slot = NULL;
2046     SECKEYPrivateKey *privKey = NULL;
2047     PRBool needLogin;
2048     SECStatus rv;
2049     int err;
2050 
2051     certHandle = PK11_FindObjectForCert(cert, wincx, &slot);
2052     if (certHandle == CK_INVALID_HANDLE) {
2053         return NULL;
2054     }
2055     /*
2056      * prevent a login race condition. If slot is logged in between
2057      * our call to pk11_LoginStillRequired and the
2058      * PK11_MatchItem. The matchItem call will either succeed, or
2059      * we will call it one more time after calling PK11_Authenticate
2060      * (which is a noop on an authenticated token).
2061      */
2062     needLogin = pk11_LoginStillRequired(slot, wincx);
2063     keyHandle = PK11_MatchItem(slot, certHandle, CKO_PRIVATE_KEY);
2064     if ((keyHandle == CK_INVALID_HANDLE) && needLogin &&
2065         (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
2066          SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
2067         /* authenticate and try again */
2068         rv = PK11_Authenticate(slot, PR_TRUE, wincx);
2069         if (rv == SECSuccess) {
2070             keyHandle = PK11_MatchItem(slot, certHandle, CKO_PRIVATE_KEY);
2071         }
2072     }
2073     if (keyHandle != CK_INVALID_HANDLE) {
2074         privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
2075     }
2076     if (slot) {
2077         PK11_FreeSlot(slot);
2078     }
2079     return privKey;
2080 }
2081 
2082 CK_OBJECT_HANDLE
pk11_FindPubKeyByAnyCert(CERTCertificate * cert,PK11SlotInfo ** slot,void * wincx)2083 pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx)
2084 {
2085     CK_OBJECT_HANDLE certHandle;
2086     CK_OBJECT_HANDLE keyHandle;
2087 
2088     certHandle = PK11_FindObjectForCert(cert, wincx, slot);
2089     if (certHandle == CK_INVALID_HANDLE) {
2090         return CK_INVALID_HANDLE;
2091     }
2092     keyHandle = PK11_MatchItem(*slot, certHandle, CKO_PUBLIC_KEY);
2093     if (keyHandle == CK_INVALID_HANDLE) {
2094         PK11_FreeSlot(*slot);
2095         return CK_INVALID_HANDLE;
2096     }
2097     return keyHandle;
2098 }
2099 
2100 /*
2101  * find the number of certs in the slot with the same subject name
2102  */
2103 int
PK11_NumberCertsForCertSubject(CERTCertificate * cert)2104 PK11_NumberCertsForCertSubject(CERTCertificate *cert)
2105 {
2106     CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
2107     CK_ATTRIBUTE theTemplate[] = {
2108         { CKA_CLASS, NULL, 0 },
2109         { CKA_SUBJECT, NULL, 0 },
2110     };
2111     CK_ATTRIBUTE *attr = theTemplate;
2112     int templateSize = sizeof(theTemplate) / sizeof(theTemplate[0]);
2113 
2114     PK11_SETATTRS(attr, CKA_CLASS, &certClass, sizeof(certClass));
2115     attr++;
2116     PK11_SETATTRS(attr, CKA_SUBJECT, cert->derSubject.data, cert->derSubject.len);
2117 
2118     if (cert->slot == NULL) {
2119         PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
2120                                                PR_FALSE, PR_TRUE, NULL);
2121         PK11SlotListElement *le;
2122         int count = 0;
2123 
2124         if (!list) {
2125             /* error code is set */
2126             return 0;
2127         }
2128 
2129         /* loop through all the fortezza tokens */
2130         for (le = list->head; le; le = le->next) {
2131             count += PK11_NumberObjectsFor(le->slot, theTemplate, templateSize);
2132         }
2133         PK11_FreeSlotList(list);
2134         return count;
2135     }
2136 
2137     return PK11_NumberObjectsFor(cert->slot, theTemplate, templateSize);
2138 }
2139 
2140 /*
2141  *  Walk all the certs with the same subject
2142  */
2143 SECStatus
PK11_TraverseCertsForSubject(CERTCertificate * cert,SECStatus (* callback)(CERTCertificate *,void *),void * arg)2144 PK11_TraverseCertsForSubject(CERTCertificate *cert,
2145                              SECStatus (*callback)(CERTCertificate *, void *), void *arg)
2146 {
2147     if (!cert) {
2148         return SECFailure;
2149     }
2150     if (cert->slot == NULL) {
2151         PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
2152                                                PR_FALSE, PR_TRUE, NULL);
2153         PK11SlotListElement *le;
2154 
2155         if (!list) {
2156             /* error code is set */
2157             return SECFailure;
2158         }
2159         /* loop through all the tokens */
2160         for (le = list->head; le; le = le->next) {
2161             PK11_TraverseCertsForSubjectInSlot(cert, le->slot, callback, arg);
2162         }
2163         PK11_FreeSlotList(list);
2164         return SECSuccess;
2165     }
2166 
2167     return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg);
2168 }
2169 
2170 SECStatus
PK11_TraverseCertsForSubjectInSlot(CERTCertificate * cert,PK11SlotInfo * slot,SECStatus (* callback)(CERTCertificate *,void *),void * arg)2171 PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot,
2172                                    SECStatus (*callback)(CERTCertificate *, void *), void *arg)
2173 {
2174     PRStatus nssrv = PR_SUCCESS;
2175     NSSToken *token;
2176     NSSDER subject;
2177     NSSTrustDomain *td;
2178     nssList *subjectList;
2179     nssPKIObjectCollection *collection;
2180     nssCryptokiObject **instances;
2181     NSSCertificate **certs;
2182     nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
2183     td = STAN_GetDefaultTrustDomain();
2184     NSSITEM_FROM_SECITEM(&subject, &cert->derSubject);
2185     token = PK11Slot_GetNSSToken(slot);
2186     if (!token) {
2187         return SECSuccess;
2188     }
2189     if (!nssToken_IsPresent(token)) {
2190         (void)nssToken_Destroy(token);
2191         return SECSuccess;
2192     }
2193     collection = nssCertificateCollection_Create(td, NULL);
2194     if (!collection) {
2195         (void)nssToken_Destroy(token);
2196         return SECFailure;
2197     }
2198     subjectList = nssList_Create(NULL, PR_FALSE);
2199     if (!subjectList) {
2200         nssPKIObjectCollection_Destroy(collection);
2201         (void)nssToken_Destroy(token);
2202         return SECFailure;
2203     }
2204     (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject,
2205                                                      subjectList);
2206     transfer_token_certs_to_collection(subjectList, token, collection);
2207     instances = nssToken_FindCertificatesBySubject(token, NULL,
2208                                                    &subject,
2209                                                    tokenOnly, 0, &nssrv);
2210     nssPKIObjectCollection_AddInstances(collection, instances, 0);
2211     nss_ZFreeIf(instances);
2212     nssList_Destroy(subjectList);
2213     certs = nssPKIObjectCollection_GetCertificates(collection,
2214                                                    NULL, 0, NULL);
2215     nssPKIObjectCollection_Destroy(collection);
2216     (void)nssToken_Destroy(token);
2217     if (certs) {
2218         CERTCertificate *oldie;
2219         NSSCertificate **cp;
2220         for (cp = certs; *cp; cp++) {
2221             oldie = STAN_GetCERTCertificate(*cp);
2222             if (!oldie) {
2223                 continue;
2224             }
2225             if ((*callback)(oldie, arg) != SECSuccess) {
2226                 nssrv = PR_FAILURE;
2227                 break;
2228             }
2229         }
2230         nssCertificateArray_Destroy(certs);
2231     }
2232     return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
2233 }
2234 
2235 SECStatus
PK11_TraverseCertsForNicknameInSlot(SECItem * nickname,PK11SlotInfo * slot,SECStatus (* callback)(CERTCertificate *,void *),void * arg)2236 PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
2237                                     SECStatus (*callback)(CERTCertificate *, void *), void *arg)
2238 {
2239     PRStatus nssrv = PR_SUCCESS;
2240     NSSToken *token;
2241     NSSTrustDomain *td;
2242     NSSUTF8 *nick;
2243     PRBool created = PR_FALSE;
2244     nssCryptokiObject **instances;
2245     nssPKIObjectCollection *collection = NULL;
2246     NSSCertificate **certs;
2247     nssList *nameList = NULL;
2248     nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
2249     token = PK11Slot_GetNSSToken(slot);
2250     if (!token || !nssToken_IsPresent(token)) {
2251         (void)nssToken_Destroy(token);
2252         return SECSuccess;
2253     }
2254     if (nickname->data[nickname->len - 1] != '\0') {
2255         nick = nssUTF8_Create(NULL, nssStringType_UTF8String,
2256                               nickname->data, nickname->len);
2257         created = PR_TRUE;
2258     } else {
2259         nick = (NSSUTF8 *)nickname->data;
2260     }
2261     td = STAN_GetDefaultTrustDomain();
2262     collection = nssCertificateCollection_Create(td, NULL);
2263     if (!collection) {
2264         goto loser;
2265     }
2266     nameList = nssList_Create(NULL, PR_FALSE);
2267     if (!nameList) {
2268         goto loser;
2269     }
2270     (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList);
2271     transfer_token_certs_to_collection(nameList, token, collection);
2272     instances = nssToken_FindCertificatesByNickname(token, NULL,
2273                                                     nick,
2274                                                     tokenOnly, 0, &nssrv);
2275     nssPKIObjectCollection_AddInstances(collection, instances, 0);
2276     nss_ZFreeIf(instances);
2277     nssList_Destroy(nameList);
2278     certs = nssPKIObjectCollection_GetCertificates(collection,
2279                                                    NULL, 0, NULL);
2280     nssPKIObjectCollection_Destroy(collection);
2281     (void)nssToken_Destroy(token);
2282     if (certs) {
2283         CERTCertificate *oldie;
2284         NSSCertificate **cp;
2285         for (cp = certs; *cp; cp++) {
2286             oldie = STAN_GetCERTCertificate(*cp);
2287             if (!oldie) {
2288                 continue;
2289             }
2290             if ((*callback)(oldie, arg) != SECSuccess) {
2291                 nssrv = PR_FAILURE;
2292                 break;
2293             }
2294         }
2295         nssCertificateArray_Destroy(certs);
2296     }
2297     if (created)
2298         nss_ZFreeIf(nick);
2299     return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
2300 loser:
2301     (void)nssToken_Destroy(token);
2302     if (created) {
2303         nss_ZFreeIf(nick);
2304     }
2305     if (collection) {
2306         nssPKIObjectCollection_Destroy(collection);
2307     }
2308     if (nameList) {
2309         nssList_Destroy(nameList);
2310     }
2311     return SECFailure;
2312 }
2313 
2314 SECStatus
PK11_TraverseCertsInSlot(PK11SlotInfo * slot,SECStatus (* callback)(CERTCertificate *,void *),void * arg)2315 PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
2316                          SECStatus (*callback)(CERTCertificate *, void *), void *arg)
2317 {
2318     PRStatus nssrv;
2319     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
2320     NSSToken *tok;
2321     nssList *certList = NULL;
2322     nssCryptokiObject **instances;
2323     nssPKIObjectCollection *collection;
2324     NSSCertificate **certs;
2325     nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
2326     tok = PK11Slot_GetNSSToken(slot);
2327     if (!tok) {
2328         return SECSuccess;
2329     }
2330     if (!nssToken_IsPresent(tok)) {
2331         (void)nssToken_Destroy(tok);
2332         return SECSuccess;
2333     }
2334     collection = nssCertificateCollection_Create(td, NULL);
2335     if (!collection) {
2336         (void)nssToken_Destroy(tok);
2337         return SECFailure;
2338     }
2339     certList = nssList_Create(NULL, PR_FALSE);
2340     if (!certList) {
2341         nssPKIObjectCollection_Destroy(collection);
2342         (void)nssToken_Destroy(tok);
2343         return SECFailure;
2344     }
2345     (void)nssTrustDomain_GetCertsFromCache(td, certList);
2346     transfer_token_certs_to_collection(certList, tok, collection);
2347     instances = nssToken_FindObjects(tok, NULL, CKO_CERTIFICATE,
2348                                      tokenOnly, 0, &nssrv);
2349     nssPKIObjectCollection_AddInstances(collection, instances, 0);
2350     nss_ZFreeIf(instances);
2351     nssList_Destroy(certList);
2352     certs = nssPKIObjectCollection_GetCertificates(collection,
2353                                                    NULL, 0, NULL);
2354     nssPKIObjectCollection_Destroy(collection);
2355     (void)nssToken_Destroy(tok);
2356     if (certs) {
2357         CERTCertificate *oldie;
2358         NSSCertificate **cp;
2359         for (cp = certs; *cp; cp++) {
2360             oldie = STAN_GetCERTCertificate(*cp);
2361             if (!oldie) {
2362                 continue;
2363             }
2364             if ((*callback)(oldie, arg) != SECSuccess) {
2365                 nssrv = PR_FAILURE;
2366                 break;
2367             }
2368         }
2369         nssCertificateArray_Destroy(certs);
2370     }
2371     return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
2372 }
2373 
2374 /*
2375  * return the certificate associated with a derCert
2376  */
2377 CERTCertificate *
PK11_FindCertFromDERCert(PK11SlotInfo * slot,CERTCertificate * cert,void * wincx)2378 PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
2379                          void *wincx)
2380 {
2381     return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx);
2382 }
2383 
2384 CERTCertificate *
PK11_FindCertFromDERCertItem(PK11SlotInfo * slot,const SECItem * inDerCert,void * wincx)2385 PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, const SECItem *inDerCert,
2386                              void *wincx)
2387 
2388 {
2389     NSSDER derCert;
2390     NSSToken *tok;
2391     nssCryptokiObject *co = NULL;
2392     SECStatus rv;
2393     CERTCertificate *cert = NULL;
2394 
2395     NSSITEM_FROM_SECITEM(&derCert, inDerCert);
2396     rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
2397     if (rv != SECSuccess) {
2398         PK11_FreeSlot(slot);
2399         return NULL;
2400     }
2401 
2402     tok = PK11Slot_GetNSSToken(slot);
2403     if (!tok) {
2404         PK11_FreeSlot(slot);
2405         return NULL;
2406     }
2407     co = nssToken_FindCertificateByEncodedCertificate(tok, NULL, &derCert,
2408                                                       nssTokenSearchType_TokenOnly, NULL);
2409     (void)nssToken_Destroy(tok);
2410 
2411     if (co) {
2412         cert = PK11_MakeCertFromHandle(slot, co->handle, NULL);
2413         nssCryptokiObject_Destroy(co);
2414     }
2415 
2416     return cert;
2417 }
2418 
2419 /*
2420  * import a cert for a private key we have already generated. Set the label
2421  * on both to be the nickname.
2422  */
2423 static CK_OBJECT_HANDLE
pk11_findKeyObjectByDERCert(PK11SlotInfo * slot,CERTCertificate * cert,void * wincx)2424 pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
2425                             void *wincx)
2426 {
2427     SECItem *keyID;
2428     CK_OBJECT_HANDLE key;
2429     SECStatus rv;
2430     PRBool needLogin;
2431     int err;
2432 
2433     if ((slot == NULL) || (cert == NULL)) {
2434         return CK_INVALID_HANDLE;
2435     }
2436 
2437     keyID = pk11_mkcertKeyID(cert);
2438     if (keyID == NULL) {
2439         return CK_INVALID_HANDLE;
2440     }
2441 
2442     /*
2443      * prevent a login race condition. If slot is logged in between
2444      * our call to pk11_LoginStillRequired and the
2445      * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or
2446      * we will call it one more time after calling PK11_Authenticate
2447      * (which is a noop on an authenticated token).
2448      */
2449     needLogin = pk11_LoginStillRequired(slot, wincx);
2450     key = pk11_FindPrivateKeyFromCertID(slot, keyID);
2451     if ((key == CK_INVALID_HANDLE) && needLogin &&
2452         (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
2453          SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
2454         /* authenticate and try again */
2455         rv = PK11_Authenticate(slot, PR_TRUE, wincx);
2456         if (rv != SECSuccess)
2457             goto loser;
2458         key = pk11_FindPrivateKeyFromCertID(slot, keyID);
2459     }
2460 
2461 loser:
2462     SECITEM_ZfreeItem(keyID, PR_TRUE);
2463     return key;
2464 }
2465 
2466 SECKEYPrivateKey *
PK11_FindKeyByDERCert(PK11SlotInfo * slot,CERTCertificate * cert,void * wincx)2467 PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
2468                       void *wincx)
2469 {
2470     CK_OBJECT_HANDLE keyHandle;
2471 
2472     if ((slot == NULL) || (cert == NULL)) {
2473         return NULL;
2474     }
2475 
2476     keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
2477     if (keyHandle == CK_INVALID_HANDLE) {
2478         return NULL;
2479     }
2480 
2481     return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
2482 }
2483 
2484 SECStatus
PK11_ImportCertForKeyToSlot(PK11SlotInfo * slot,CERTCertificate * cert,char * nickname,PRBool addCertUsage,void * wincx)2485 PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert,
2486                             char *nickname,
2487                             PRBool addCertUsage, void *wincx)
2488 {
2489     CK_OBJECT_HANDLE keyHandle;
2490 
2491     if ((slot == NULL) || (cert == NULL) || (nickname == NULL)) {
2492         return SECFailure;
2493     }
2494 
2495     keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
2496     if (keyHandle == CK_INVALID_HANDLE) {
2497         return SECFailure;
2498     }
2499 
2500     return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage);
2501 }
2502 
2503 /* remove when the real version comes out */
2504 #define SEC_OID_MISSI_KEA 300 /* until we have v3 stuff merged */
2505 PRBool
KEAPQGCompare(CERTCertificate * server,CERTCertificate * cert)2506 KEAPQGCompare(CERTCertificate *server, CERTCertificate *cert)
2507 {
2508 
2509     /* not implemented */
2510     return PR_FALSE;
2511 }
2512 
2513 PRBool
PK11_FortezzaHasKEA(CERTCertificate * cert)2514 PK11_FortezzaHasKEA(CERTCertificate *cert)
2515 {
2516     /* look at the subject and see if it is a KEA for MISSI key */
2517     SECOidData *oid;
2518     CERTCertTrust trust;
2519 
2520     if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
2521         ((trust.sslFlags & CERTDB_USER) != CERTDB_USER)) {
2522         return PR_FALSE;
2523     }
2524 
2525     oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm);
2526     if (!oid) {
2527         return PR_FALSE;
2528     }
2529 
2530     return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) ||
2531                     (oid->offset == SEC_OID_MISSI_KEA_DSS) ||
2532                     (oid->offset == SEC_OID_MISSI_KEA));
2533 }
2534 
2535 /*
2536  * Find a kea cert on this slot that matches the domain of it's peer
2537  */
2538 static CERTCertificate
2539     *
pk11_GetKEAMate(PK11SlotInfo * slot,CERTCertificate * peer)2540     pk11_GetKEAMate(PK11SlotInfo *slot, CERTCertificate *peer)
2541 {
2542     int i;
2543     CERTCertificate *returnedCert = NULL;
2544 
2545     for (i = 0; i < slot->cert_count; i++) {
2546         CERTCertificate *cert = slot->cert_array[i];
2547 
2548         if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer, cert)) {
2549             returnedCert = CERT_DupCertificate(cert);
2550             break;
2551         }
2552     }
2553     return returnedCert;
2554 }
2555 
2556 /*
2557  * The following is a FORTEZZA only Certificate request. We call this when we
2558  * are doing a non-client auth SSL connection. We are only interested in the
2559  * fortezza slots, and we are only interested in certs that share the same root
2560  * key as the server.
2561  */
2562 CERTCertificate *
PK11_FindBestKEAMatch(CERTCertificate * server,void * wincx)2563 PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx)
2564 {
2565     PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE,
2566                                               PR_FALSE, PR_TRUE, wincx);
2567     PK11SlotListElement *le;
2568     CERTCertificate *returnedCert = NULL;
2569     SECStatus rv;
2570 
2571     if (!keaList) {
2572         /* error code is set */
2573         return NULL;
2574     }
2575 
2576     /* loop through all the fortezza tokens */
2577     for (le = keaList->head; le; le = le->next) {
2578         rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
2579         if (rv != SECSuccess)
2580             continue;
2581         if (le->slot->session == CK_INVALID_HANDLE) {
2582             continue;
2583         }
2584         returnedCert = pk11_GetKEAMate(le->slot, server);
2585         if (returnedCert)
2586             break;
2587     }
2588     PK11_FreeSlotList(keaList);
2589 
2590     return returnedCert;
2591 }
2592 
2593 /*
2594  * find a matched pair of kea certs to key exchange parameters from one
2595  * fortezza card to another as necessary.
2596  */
2597 SECStatus
PK11_GetKEAMatchedCerts(PK11SlotInfo * slot1,PK11SlotInfo * slot2,CERTCertificate ** cert1,CERTCertificate ** cert2)2598 PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2,
2599                         CERTCertificate **cert1, CERTCertificate **cert2)
2600 {
2601     CERTCertificate *returnedCert = NULL;
2602     int i;
2603 
2604     for (i = 0; i < slot1->cert_count; i++) {
2605         CERTCertificate *cert = slot1->cert_array[i];
2606 
2607         if (PK11_FortezzaHasKEA(cert)) {
2608             returnedCert = pk11_GetKEAMate(slot2, cert);
2609             if (returnedCert != NULL) {
2610                 *cert2 = returnedCert;
2611                 *cert1 = CERT_DupCertificate(cert);
2612                 return SECSuccess;
2613             }
2614         }
2615     }
2616     return SECFailure;
2617 }
2618 
2619 CK_OBJECT_HANDLE
PK11_FindEncodedCertInSlot(PK11SlotInfo * slot,SECItem * derCert,void * wincx)2620 PK11_FindEncodedCertInSlot(PK11SlotInfo *slot, SECItem *derCert, void *wincx)
2621 {
2622     if (!slot || !derCert) {
2623         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2624         return SECFailure;
2625     }
2626 
2627     CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
2628     CK_ATTRIBUTE theTemplate[] = {
2629         { CKA_VALUE, NULL, 0 },
2630         { CKA_CLASS, NULL, 0 }
2631     };
2632     const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
2633     CK_ATTRIBUTE *attrs = theTemplate;
2634 
2635     PK11_SETATTRS(attrs, CKA_VALUE, derCert->data, derCert->len);
2636     attrs++;
2637     PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
2638 
2639     SECStatus rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
2640     if (rv != SECSuccess) {
2641         return CK_INVALID_HANDLE;
2642     }
2643 
2644     return pk11_FindObjectByTemplate(slot, theTemplate, tsize);
2645 }
2646 
2647 CK_OBJECT_HANDLE
PK11_FindCertInSlot(PK11SlotInfo * slot,CERTCertificate * cert,void * wincx)2648 PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx)
2649 {
2650     CK_OBJECT_HANDLE certh;
2651 
2652     if (cert->slot == slot) {
2653         certh = cert->pkcs11ID;
2654         if ((certh == CK_INVALID_HANDLE) ||
2655             (cert->series != slot->series)) {
2656             certh = PK11_FindEncodedCertInSlot(slot, &cert->derCert, wincx);
2657             cert->pkcs11ID = certh;
2658             cert->series = slot->series;
2659         }
2660     } else {
2661         certh = PK11_FindEncodedCertInSlot(slot, &cert->derCert, wincx);
2662     }
2663     return certh;
2664 }
2665 
2666 /* Looking for PK11_GetKeyIDFromCert?
2667  * Use PK11_GetLowLevelKeyIDForCert instead.
2668  */
2669 
2670 struct listCertsStr {
2671     PK11CertListType type;
2672     CERTCertList *certList;
2673 };
2674 
2675 static PRStatus
pk11ListCertCallback(NSSCertificate * c,void * arg)2676 pk11ListCertCallback(NSSCertificate *c, void *arg)
2677 {
2678     struct listCertsStr *listCertP = (struct listCertsStr *)arg;
2679     CERTCertificate *newCert = NULL;
2680     PK11CertListType type = listCertP->type;
2681     CERTCertList *certList = listCertP->certList;
2682     PRBool isUnique = PR_FALSE;
2683     PRBool isCA = PR_FALSE;
2684     char *nickname = NULL;
2685     unsigned int certType;
2686     SECStatus rv;
2687 
2688     if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique) ||
2689         (type == PK11CertListCAUnique) || (type == PK11CertListUserUnique)) {
2690         /* only list one instance of each certificate, even if several exist */
2691         isUnique = PR_TRUE;
2692     }
2693     if ((type == PK11CertListCA) || (type == PK11CertListRootUnique) ||
2694         (type == PK11CertListCAUnique)) {
2695         isCA = PR_TRUE;
2696     }
2697 
2698     /* if we want user certs and we don't have one skip this cert */
2699     if (((type == PK11CertListUser) || (type == PK11CertListUserUnique)) &&
2700         !NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) {
2701         return PR_SUCCESS;
2702     }
2703 
2704     /* PK11CertListRootUnique means we want CA certs without a private key.
2705      * This is for legacy app support . PK11CertListCAUnique should be used
2706      * instead to get all CA certs, regardless of private key
2707      */
2708     if ((type == PK11CertListRootUnique) &&
2709         NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) {
2710         return PR_SUCCESS;
2711     }
2712 
2713     /* caller still owns the reference to 'c' */
2714     newCert = STAN_GetCERTCertificate(c);
2715     if (!newCert) {
2716         return PR_SUCCESS;
2717     }
2718     /* if we want CA certs and it ain't one, skip it */
2719     if (isCA && (!CERT_IsCACert(newCert, &certType))) {
2720         return PR_SUCCESS;
2721     }
2722     if (isUnique) {
2723         CERT_DupCertificate(newCert);
2724 
2725         nickname = STAN_GetCERTCertificateName(certList->arena, c);
2726 
2727         /* put slot certs at the end */
2728         if (newCert->slot && !PK11_IsInternal(newCert->slot)) {
2729             rv = CERT_AddCertToListTailWithData(certList, newCert, nickname);
2730         } else {
2731             rv = CERT_AddCertToListHeadWithData(certList, newCert, nickname);
2732         }
2733         /* if we didn't add the cert to the list, don't leak it */
2734         if (rv != SECSuccess) {
2735             CERT_DestroyCertificate(newCert);
2736         }
2737     } else {
2738         /* add multiple instances to the cert list */
2739         nssCryptokiObject **ip;
2740         nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
2741         if (!instances) {
2742             return PR_SUCCESS;
2743         }
2744         for (ip = instances; *ip; ip++) {
2745             nssCryptokiObject *instance = *ip;
2746             PK11SlotInfo *slot = instance->token->pk11slot;
2747 
2748             /* put the same CERTCertificate in the list for all instances */
2749             CERT_DupCertificate(newCert);
2750 
2751             nickname = STAN_GetCERTCertificateNameForInstance(
2752                 certList->arena, c, instance);
2753 
2754             /* put slot certs at the end */
2755             if (slot && !PK11_IsInternal(slot)) {
2756                 rv = CERT_AddCertToListTailWithData(certList, newCert, nickname);
2757             } else {
2758                 rv = CERT_AddCertToListHeadWithData(certList, newCert, nickname);
2759             }
2760             /* if we didn't add the cert to the list, don't leak it */
2761             if (rv != SECSuccess) {
2762                 CERT_DestroyCertificate(newCert);
2763             }
2764         }
2765         nssCryptokiObjectArray_Destroy(instances);
2766     }
2767     return PR_SUCCESS;
2768 }
2769 
2770 CERTCertList *
PK11_ListCerts(PK11CertListType type,void * pwarg)2771 PK11_ListCerts(PK11CertListType type, void *pwarg)
2772 {
2773     NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
2774     CERTCertList *certList = NULL;
2775     struct listCertsStr listCerts;
2776     certList = CERT_NewCertList();
2777     listCerts.type = type;
2778     listCerts.certList = certList;
2779 
2780     /* authenticate to the slots */
2781     (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, pwarg);
2782     NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback,
2783                                         &listCerts);
2784     return certList;
2785 }
2786 
2787 SECItem *
PK11_GetLowLevelKeyIDForCert(PK11SlotInfo * slot,CERTCertificate * cert,void * wincx)2788 PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
2789                              CERTCertificate *cert, void *wincx)
2790 {
2791     CK_OBJECT_HANDLE certHandle;
2792     PK11SlotInfo *slotRef = NULL;
2793     SECItem *item;
2794 
2795     if (slot) {
2796         certHandle = PK11_FindCertInSlot(slot, cert, wincx);
2797     } else {
2798         certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef);
2799         if (certHandle == CK_INVALID_HANDLE) {
2800             return pk11_mkcertKeyID(cert);
2801         }
2802         slot = slotRef;
2803     }
2804 
2805     if (certHandle == CK_INVALID_HANDLE) {
2806         return NULL;
2807     }
2808 
2809     item = pk11_GetLowLevelKeyFromHandle(slot, certHandle);
2810     if (slotRef)
2811         PK11_FreeSlot(slotRef);
2812     return item;
2813 }
2814 
2815 /* argument type for listCertsCallback */
2816 typedef struct {
2817     CERTCertList *list;
2818     PK11SlotInfo *slot;
2819 } ListCertsArg;
2820 
2821 static SECStatus
listCertsCallback(CERTCertificate * cert,void * arg)2822 listCertsCallback(CERTCertificate *cert, void *arg)
2823 {
2824     ListCertsArg *cdata = (ListCertsArg *)arg;
2825     char *nickname = NULL;
2826     nssCryptokiObject *instance, **ci;
2827     nssCryptokiObject **instances;
2828     NSSCertificate *c = STAN_GetNSSCertificate(cert);
2829     SECStatus rv;
2830 
2831     if (c == NULL) {
2832         return SECFailure;
2833     }
2834     instances = nssPKIObject_GetInstances(&c->object);
2835     if (!instances) {
2836         return SECFailure;
2837     }
2838     instance = NULL;
2839     for (ci = instances; *ci; ci++) {
2840         if ((*ci)->token->pk11slot == cdata->slot) {
2841             instance = *ci;
2842             break;
2843         }
2844     }
2845     PORT_Assert(instance != NULL);
2846     if (!instance) {
2847         nssCryptokiObjectArray_Destroy(instances);
2848         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2849         return SECFailure;
2850     }
2851     nickname = STAN_GetCERTCertificateNameForInstance(cdata->list->arena,
2852                                                       c, instance);
2853     nssCryptokiObjectArray_Destroy(instances);
2854 
2855     CERT_DupCertificate(cert);
2856     rv = CERT_AddCertToListTailWithData(cdata->list, cert, nickname);
2857     if (rv != SECSuccess) {
2858         CERT_DestroyCertificate(cert);
2859     }
2860     return rv;
2861 }
2862 
2863 CERTCertList *
PK11_ListCertsInSlot(PK11SlotInfo * slot)2864 PK11_ListCertsInSlot(PK11SlotInfo *slot)
2865 {
2866     SECStatus status;
2867     CERTCertList *certs;
2868     ListCertsArg cdata;
2869 
2870     certs = CERT_NewCertList();
2871     if (certs == NULL)
2872         return NULL;
2873     cdata.list = certs;
2874     cdata.slot = slot;
2875 
2876     status = PK11_TraverseCertsInSlot(slot, listCertsCallback,
2877                                       &cdata);
2878 
2879     if (status != SECSuccess) {
2880         CERT_DestroyCertList(certs);
2881         certs = NULL;
2882     }
2883 
2884     return certs;
2885 }
2886 
2887 PK11SlotList *
PK11_GetAllSlotsForCert(CERTCertificate * cert,void * arg)2888 PK11_GetAllSlotsForCert(CERTCertificate *cert, void *arg)
2889 {
2890     nssCryptokiObject **ip;
2891     PK11SlotList *slotList;
2892     NSSCertificate *c;
2893     nssCryptokiObject **instances;
2894     PRBool found = PR_FALSE;
2895 
2896     if (!cert) {
2897         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2898         return NULL;
2899     }
2900 
2901     c = STAN_GetNSSCertificate(cert);
2902     if (!c) {
2903         CERT_MapStanError();
2904         return NULL;
2905     }
2906 
2907     /* add multiple instances to the cert list */
2908     instances = nssPKIObject_GetInstances(&c->object);
2909     if (!instances) {
2910         PORT_SetError(SEC_ERROR_NO_TOKEN);
2911         return NULL;
2912     }
2913 
2914     slotList = PK11_NewSlotList();
2915     if (!slotList) {
2916         nssCryptokiObjectArray_Destroy(instances);
2917         return NULL;
2918     }
2919 
2920     for (ip = instances; *ip; ip++) {
2921         nssCryptokiObject *instance = *ip;
2922         PK11SlotInfo *slot = instance->token->pk11slot;
2923         if (slot) {
2924             PK11_AddSlotToList(slotList, slot, PR_TRUE);
2925             found = PR_TRUE;
2926         }
2927     }
2928     if (!found) {
2929         PK11_FreeSlotList(slotList);
2930         PORT_SetError(SEC_ERROR_NO_TOKEN);
2931         slotList = NULL;
2932     }
2933 
2934     nssCryptokiObjectArray_Destroy(instances);
2935     return slotList;
2936 }
2937 
2938 /*
2939  * Using __PK11_SetCertificateNickname is *DANGEROUS*.
2940  *
2941  * The API will update the NSS database, but it *will NOT* update the in-memory data.
2942  * As a result, after calling this API, there will be INCONSISTENCY between
2943  * in-memory data and the database.
2944  *
2945  * Use of the API should be limited to short-lived tools, which will exit immediately
2946  * after using this API.
2947  *
2948  * If you ignore this warning, your process is TAINTED and will most likely misbehave.
2949  */
2950 SECStatus
__PK11_SetCertificateNickname(CERTCertificate * cert,const char * nickname)2951 __PK11_SetCertificateNickname(CERTCertificate *cert, const char *nickname)
2952 {
2953     /* Can't set nickname of temp cert. */
2954     if (!cert->slot || cert->pkcs11ID == CK_INVALID_HANDLE) {
2955         PORT_SetError(SEC_ERROR_INVALID_ARGS);
2956         return SECFailure;
2957     }
2958     return PK11_SetObjectNickname(cert->slot, cert->pkcs11ID, nickname);
2959 }
2960