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