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