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