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