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