Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / pk11wrap / pk11cert.c
blob89571f1d37698a112435263e458e416d4edb4cc0
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 * This file manages PKCS #11 instances of certificates.
41 #include "secport.h"
42 #include "seccomon.h"
43 #include "secmod.h"
44 #include "secmodi.h"
45 #include "secmodti.h"
46 #include "pkcs11.h"
47 #include "pk11func.h"
48 #include "cert.h"
49 #include "certi.h"
50 #include "secitem.h"
51 #include "key.h"
52 #include "secoid.h"
53 #include "pkcs7t.h"
54 #include "cmsreclist.h"
56 #include "certdb.h"
57 #include "secerr.h"
58 #include "sslerr.h"
60 #ifndef NSS_3_4_CODE
61 #define NSS_3_4_CODE
62 #endif /* NSS_3_4_CODE */
63 #include "pki3hack.h"
64 #include "dev3hack.h"
66 #include "devm.h"
67 #include "nsspki.h"
68 #include "pki.h"
69 #include "pkim.h"
70 #include "pkitm.h"
71 #include "pkistore.h" /* to remove temp cert */
72 #include "devt.h"
74 extern const NSSError NSS_ERROR_NOT_FOUND;
75 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
77 struct nss3_cert_cbstr {
78 SECStatus(* callback)(CERTCertificate*, void *);
79 nssList *cached;
80 void *arg;
83 /* Translate from NSSCertificate to CERTCertificate, then pass the latter
84 * to a callback.
86 static PRStatus convert_cert(NSSCertificate *c, void *arg)
88 CERTCertificate *nss3cert;
89 SECStatus secrv;
90 struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg;
91 /* 'c' is not adopted. caller will free it */
92 nss3cert = STAN_GetCERTCertificate(c);
93 if (!nss3cert) return PR_FAILURE;
94 secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg);
95 return (secrv) ? PR_FAILURE : PR_SUCCESS;
99 * build a cert nickname based on the token name and the label of the
100 * certificate If the label in NULL, build a label based on the ID.
102 static int toHex(int x) { return (x < 10) ? (x+'0') : (x+'a'-10); }
103 #define MAX_CERT_ID 4
104 #define DEFAULT_STRING "Cert ID "
105 static char *
106 pk11_buildNickname(PK11SlotInfo *slot,CK_ATTRIBUTE *cert_label,
107 CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id)
109 int prefixLen = PORT_Strlen(slot->token_name);
110 int suffixLen = 0;
111 char *suffix = NULL;
112 char buildNew[sizeof(DEFAULT_STRING)+MAX_CERT_ID*2];
113 char *next,*nickname;
115 if (cert_label && (cert_label->ulValueLen)) {
116 suffixLen = cert_label->ulValueLen;
117 suffix = (char*)cert_label->pValue;
118 } else if (key_label && (key_label->ulValueLen)) {
119 suffixLen = key_label->ulValueLen;
120 suffix = (char*)key_label->pValue;
121 } else if (cert_id && cert_id->ulValueLen > 0) {
122 int i,first = cert_id->ulValueLen - MAX_CERT_ID;
123 int offset = sizeof(DEFAULT_STRING);
124 char *idValue = (char *)cert_id->pValue;
126 PORT_Memcpy(buildNew,DEFAULT_STRING,sizeof(DEFAULT_STRING)-1);
127 next = buildNew + offset;
128 if (first < 0) first = 0;
129 for (i=first; i < (int) cert_id->ulValueLen; i++) {
130 *next++ = toHex((idValue[i] >> 4) & 0xf);
131 *next++ = toHex(idValue[i] & 0xf);
133 *next++ = 0;
134 suffix = buildNew;
135 suffixLen = PORT_Strlen(buildNew);
136 } else {
137 PORT_SetError( SEC_ERROR_LIBRARY_FAILURE );
138 return NULL;
141 /* if is internal key slot, add code to skip the prefix!! */
142 next = nickname = (char *)PORT_Alloc(prefixLen+1+suffixLen+1);
143 if (nickname == NULL) return NULL;
145 PORT_Memcpy(next,slot->token_name,prefixLen);
146 next += prefixLen;
147 *next++ = ':';
148 PORT_Memcpy(next,suffix,suffixLen);
149 next += suffixLen;
150 *next++ = 0;
151 return nickname;
154 PRBool
155 PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert,
156 CK_OBJECT_HANDLE certID)
158 CK_OBJECT_CLASS theClass;
160 if (slot == NULL) return PR_FALSE;
161 if (cert == NULL) return PR_FALSE;
163 theClass = CKO_PRIVATE_KEY;
164 if (pk11_LoginStillRequired(slot,NULL)) {
165 theClass = CKO_PUBLIC_KEY;
167 if (PK11_MatchItem(slot, certID , theClass) != CK_INVALID_HANDLE) {
168 return PR_TRUE;
171 if (theClass == CKO_PUBLIC_KEY) {
172 SECKEYPublicKey *pubKey= CERT_ExtractPublicKey(cert);
173 CK_ATTRIBUTE theTemplate;
175 if (pubKey == NULL) {
176 return PR_FALSE;
179 PK11_SETATTRS(&theTemplate,0,NULL,0);
180 switch (pubKey->keyType) {
181 case rsaKey:
182 PK11_SETATTRS(&theTemplate,CKA_MODULUS, pubKey->u.rsa.modulus.data,
183 pubKey->u.rsa.modulus.len);
184 break;
185 case dsaKey:
186 PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dsa.publicValue.data,
187 pubKey->u.dsa.publicValue.len);
188 break;
189 case dhKey:
190 PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dh.publicValue.data,
191 pubKey->u.dh.publicValue.len);
192 break;
193 case ecKey:
194 PK11_SETATTRS(&theTemplate,CKA_EC_POINT,
195 pubKey->u.ec.publicValue.data,
196 pubKey->u.ec.publicValue.len);
197 break;
198 case keaKey:
199 case fortezzaKey:
200 case nullKey:
201 /* fall through and return false */
202 break;
205 if (theTemplate.ulValueLen == 0) {
206 SECKEY_DestroyPublicKey(pubKey);
207 return PR_FALSE;
209 pk11_SignedToUnsigned(&theTemplate);
210 if (pk11_FindObjectByTemplate(slot,&theTemplate,1) != CK_INVALID_HANDLE) {
211 SECKEY_DestroyPublicKey(pubKey);
212 return PR_TRUE;
214 SECKEY_DestroyPublicKey(pubKey);
216 return PR_FALSE;
220 * Check out if a cert has ID of zero. This is a magic ID that tells
221 * NSS that this cert may be an automagically trusted cert.
222 * The Cert has to be self signed as well. That check is done elsewhere.
225 PRBool
226 pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID)
228 CK_ATTRIBUTE keyID = {CKA_ID, NULL, 0};
229 PRBool isZero = PR_FALSE;
230 int i;
231 CK_RV crv;
234 crv = PK11_GetAttributes(NULL,slot,certID,&keyID,1);
235 if (crv != CKR_OK) {
236 return isZero;
239 if (keyID.ulValueLen != 0) {
240 char *value = (char *)keyID.pValue;
241 isZero = PR_TRUE; /* ID exists, may be zero */
242 for (i=0; i < (int) keyID.ulValueLen; i++) {
243 if (value[i] != 0) {
244 isZero = PR_FALSE; /* nope */
245 break;
249 PORT_Free(keyID.pValue);
250 return isZero;
255 * Create an NSSCertificate from a slot/certID pair, return it as a
256 * CERTCertificate.
258 static CERTCertificate
259 *pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID,
260 CK_ATTRIBUTE *privateLabel, char **nickptr)
262 NSSCertificate *c;
263 nssCryptokiObject *co;
264 nssPKIObject *pkio;
265 NSSToken *token;
266 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
268 /* Get the cryptoki object from the handle */
269 token = PK11Slot_GetNSSToken(slot);
270 co = nssCryptokiObject_Create(token, token->defaultSession, certID);
271 if (!co) {
272 return NULL;
275 /* Create a PKI object from the cryptoki instance */
276 pkio = nssPKIObject_Create(NULL, co, td, NULL, nssPKIMonitor);
277 if (!pkio) {
278 nssCryptokiObject_Destroy(co);
279 return NULL;
282 /* Create a certificate */
283 c = nssCertificate_Create(pkio);
284 if (!c) {
285 nssPKIObject_Destroy(pkio);
286 return NULL;
289 nssTrustDomain_AddCertsToCache(td, &c, 1);
291 /* Build the old-fashioned nickname */
292 if ((nickptr) && (co->label)) {
293 CK_ATTRIBUTE label, id;
294 label.type = CKA_LABEL;
295 label.pValue = co->label;
296 label.ulValueLen = PORT_Strlen(co->label);
297 id.type = CKA_ID;
298 id.pValue = c->id.data;
299 id.ulValueLen = c->id.size;
300 *nickptr = pk11_buildNickname(slot, &label, privateLabel, &id);
302 return STAN_GetCERTCertificateOrRelease(c);
306 * Build an CERTCertificate structure from a PKCS#11 object ID.... certID
307 * Must be a CertObject. This code does not explicitly checks that.
309 CERTCertificate *
310 PK11_MakeCertFromHandle(PK11SlotInfo *slot,CK_OBJECT_HANDLE certID,
311 CK_ATTRIBUTE *privateLabel)
313 char * nickname = NULL;
314 CERTCertificate *cert = NULL;
315 CERTCertTrust *trust;
316 PRBool isFortezzaRootCA = PR_FALSE;
317 PRBool swapNickname = PR_FALSE;
319 cert = pk11_fastCert(slot,certID,privateLabel, &nickname);
320 if (cert == NULL) goto loser;
322 if (nickname) {
323 if (cert->nickname != NULL) {
324 cert->dbnickname = cert->nickname;
326 cert->nickname = PORT_ArenaStrdup(cert->arena,nickname);
327 PORT_Free(nickname);
328 nickname = NULL;
329 swapNickname = PR_TRUE;
332 /* remember where this cert came from.... If we have just looked
333 * it up from the database and it already has a slot, don't add a new
334 * one. */
335 if (cert->slot == NULL) {
336 cert->slot = PK11_ReferenceSlot(slot);
337 cert->pkcs11ID = certID;
338 cert->ownSlot = PR_TRUE;
339 cert->series = slot->series;
342 trust = (CERTCertTrust*)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust));
343 if (trust == NULL) goto loser;
344 PORT_Memset(trust,0, sizeof(CERTCertTrust));
345 cert->trust = trust;
349 if(! pk11_HandleTrustObject(slot, cert, trust) ) {
350 unsigned int type;
352 /* build some cert trust flags */
353 if (CERT_IsCACert(cert, &type)) {
354 unsigned int trustflags = CERTDB_VALID_CA;
356 /* Allow PKCS #11 modules to give us trusted CA's. We only accept
357 * valid CA's which are self-signed here. They must have an object
358 * ID of '0'. */
359 if (pk11_isID0(slot,certID) &&
360 SECITEM_CompareItem(&cert->derSubject,&cert->derIssuer)
361 == SECEqual) {
362 trustflags |= CERTDB_TRUSTED_CA;
363 /* is the slot a fortezza card? allow the user or
364 * admin to turn on objectSigning, but don't turn
365 * full trust on explicitly */
366 if (PK11_DoesMechanism(slot,CKM_KEA_KEY_DERIVE)) {
367 trust->objectSigningFlags |= CERTDB_VALID_CA;
368 isFortezzaRootCA = PR_TRUE;
371 if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
372 trust->sslFlags |= trustflags;
374 if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) {
375 trust->emailFlags |= trustflags;
377 if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA)
378 == NS_CERT_TYPE_OBJECT_SIGNING_CA) {
379 trust->objectSigningFlags |= trustflags;
384 if (PK11_IsUserCert(slot,cert,certID)) {
385 trust->sslFlags |= CERTDB_USER;
386 trust->emailFlags |= CERTDB_USER;
387 /* trust->objectSigningFlags |= CERTDB_USER; */
390 return cert;
392 loser:
393 if (nickname) PORT_Free(nickname);
394 if (cert) CERT_DestroyCertificate(cert);
395 return NULL;
400 * Build get a certificate from a private key
402 CERTCertificate *
403 PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey)
405 PK11SlotInfo *slot = privKey->pkcs11Slot;
406 CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
407 CK_OBJECT_HANDLE certID =
408 PK11_MatchItem(slot,handle,CKO_CERTIFICATE);
409 CERTCertificate *cert;
411 if (certID == CK_INVALID_HANDLE) {
412 PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
413 return NULL;
415 cert = PK11_MakeCertFromHandle(slot,certID,NULL);
416 return (cert);
421 * delete a cert and it's private key (if no other certs are pointing to the
422 * private key.
424 SECStatus
425 PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx)
427 SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert,wincx);
428 CK_OBJECT_HANDLE pubKey;
429 PK11SlotInfo *slot = NULL;
431 pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx);
432 if (privKey) {
433 /* For 3.4, utilize the generic cert delete function */
434 SEC_DeletePermCertificate(cert);
435 PK11_DeleteTokenPrivateKey(privKey, PR_FALSE);
437 if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) {
438 PK11_DestroyTokenObject(slot,pubKey);
439 PK11_FreeSlot(slot);
441 return SECSuccess;
445 * cert callback structure
447 typedef struct pk11DoCertCallbackStr {
448 SECStatus(* callback)(PK11SlotInfo *slot, CERTCertificate*, void *);
449 SECStatus(* noslotcallback)(CERTCertificate*, void *);
450 SECStatus(* itemcallback)(CERTCertificate*, SECItem *, void *);
451 void *callbackArg;
452 } pk11DoCertCallback;
455 typedef struct pk11CertCallbackStr {
456 SECStatus(* callback)(CERTCertificate*,SECItem *,void *);
457 void *callbackArg;
458 } pk11CertCallback;
460 struct fake_der_cb_argstr
462 SECStatus(* callback)(CERTCertificate*, SECItem *, void *);
463 void *arg;
466 static SECStatus fake_der_cb(CERTCertificate *c, void *a)
468 struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a;
469 return (*fda->callback)(c, &c->derCert, fda->arg);
473 * Extract all the certs on a card from a slot.
475 SECStatus
476 PK11_TraverseSlotCerts(SECStatus(* callback)(CERTCertificate*,SECItem *,void *),
477 void *arg, void *wincx)
479 NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
480 struct fake_der_cb_argstr fda;
481 struct nss3_cert_cbstr pk11cb;
483 /* authenticate to the tokens first */
484 (void) pk11_TraverseAllSlots( NULL, NULL, PR_TRUE, wincx);
486 fda.callback = callback;
487 fda.arg = arg;
488 pk11cb.callback = fake_der_cb;
489 pk11cb.arg = &fda;
490 NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
491 return SECSuccess;
494 static void
495 transfer_token_certs_to_collection(nssList *certList, NSSToken *token,
496 nssPKIObjectCollection *collection)
498 NSSCertificate **certs;
499 PRUint32 i, count;
500 NSSToken **tokens, **tp;
501 count = nssList_Count(certList);
502 if (count == 0) {
503 return;
505 certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
506 if (!certs) {
507 return;
509 nssList_GetArray(certList, (void **)certs, count);
510 for (i=0; i<count; i++) {
511 tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
512 if (tokens) {
513 for (tp = tokens; *tp; tp++) {
514 if (*tp == token) {
515 nssPKIObjectCollection_AddObject(collection,
516 (nssPKIObject *)certs[i]);
519 nssTokenArray_Destroy(tokens);
521 CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i]));
523 nss_ZFreeIf(certs);
526 CERTCertificate *
527 PK11_FindCertFromNickname(char *nickname, void *wincx)
529 PRStatus status;
530 CERTCertificate *rvCert = NULL;
531 NSSCertificate *cert = NULL;
532 NSSCertificate **certs = NULL;
533 static const NSSUsage usage = {PR_TRUE /* ... */ };
534 NSSToken *token;
535 NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
536 PK11SlotInfo *slot = NULL;
537 SECStatus rv;
538 char *nickCopy;
539 char *delimit = NULL;
540 char *tokenName;
542 nickCopy = PORT_Strdup(nickname);
543 if (!nickCopy) {
544 /* error code is set */
545 return NULL;
547 if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
548 tokenName = nickCopy;
549 nickname = delimit + 1;
550 *delimit = '\0';
551 /* find token by name */
552 token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
553 if (token) {
554 slot = PK11_ReferenceSlot(token->pk11slot);
556 *delimit = ':';
557 } else {
558 slot = PK11_GetInternalKeySlot();
559 token = PK11Slot_GetNSSToken(slot);
561 if (token) {
562 nssList *certList;
563 nssCryptokiObject **instances;
564 nssPKIObjectCollection *collection;
565 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
566 if (!PK11_IsPresent(slot)) {
567 goto loser;
569 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
570 if (rv != SECSuccess) {
571 goto loser;
573 collection = nssCertificateCollection_Create(defaultTD, NULL);
574 if (!collection) {
575 goto loser;
577 certList = nssList_Create(NULL, PR_FALSE);
578 if (!certList) {
579 nssPKIObjectCollection_Destroy(collection);
580 goto loser;
582 (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
583 nickname,
584 certList);
585 transfer_token_certs_to_collection(certList, token, collection);
586 instances = nssToken_FindCertificatesByNickname(token,
587 NULL,
588 nickname,
589 tokenOnly,
591 &status);
592 nssPKIObjectCollection_AddInstances(collection, instances, 0);
593 nss_ZFreeIf(instances);
594 /* if it wasn't found, repeat the process for email address */
595 if (nssPKIObjectCollection_Count(collection) == 0 &&
596 PORT_Strchr(nickname, '@') != NULL)
598 char* lowercaseName = CERT_FixupEmailAddr(nickname);
599 if (lowercaseName) {
600 (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD,
601 lowercaseName,
602 certList);
603 transfer_token_certs_to_collection(certList, token, collection);
604 instances = nssToken_FindCertificatesByEmail(token,
605 NULL,
606 lowercaseName,
607 tokenOnly,
609 &status);
610 nssPKIObjectCollection_AddInstances(collection, instances, 0);
611 nss_ZFreeIf(instances);
612 PORT_Free(lowercaseName);
615 certs = nssPKIObjectCollection_GetCertificates(collection,
616 NULL, 0, NULL);
617 nssPKIObjectCollection_Destroy(collection);
618 if (certs) {
619 cert = nssCertificateArray_FindBestCertificate(certs, NULL,
620 &usage, NULL);
621 if (cert) {
622 rvCert = STAN_GetCERTCertificateOrRelease(cert);
624 nssCertificateArray_Destroy(certs);
626 nssList_Destroy(certList);
628 if (slot) {
629 PK11_FreeSlot(slot);
631 if (nickCopy) PORT_Free(nickCopy);
632 return rvCert;
633 loser:
634 if (slot) {
635 PK11_FreeSlot(slot);
637 if (nickCopy) PORT_Free(nickCopy);
638 return NULL;
641 CERTCertList *
642 PK11_FindCertsFromNickname(char *nickname, void *wincx)
644 char *nickCopy;
645 char *delimit = NULL;
646 char *tokenName;
647 int i;
648 CERTCertList *certList = NULL;
649 nssPKIObjectCollection *collection = NULL;
650 NSSCertificate **foundCerts = NULL;
651 NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
652 NSSCertificate *c;
653 NSSToken *token;
654 PK11SlotInfo *slot;
655 SECStatus rv;
657 nickCopy = PORT_Strdup(nickname);
658 if (!nickCopy) {
659 /* error code is set */
660 return NULL;
662 if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
663 tokenName = nickCopy;
664 nickname = delimit + 1;
665 *delimit = '\0';
666 /* find token by name */
667 token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
668 if (token) {
669 slot = PK11_ReferenceSlot(token->pk11slot);
670 } else {
671 slot = NULL;
673 *delimit = ':';
674 } else {
675 slot = PK11_GetInternalKeySlot();
676 token = PK11Slot_GetNSSToken(slot);
678 if (token) {
679 PRStatus status;
680 nssList *nameList;
681 nssCryptokiObject **instances;
682 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
683 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
684 if (rv != SECSuccess) {
685 PK11_FreeSlot(slot);
686 if (nickCopy) PORT_Free(nickCopy);
687 return NULL;
689 collection = nssCertificateCollection_Create(defaultTD, NULL);
690 if (!collection) {
691 PK11_FreeSlot(slot);
692 if (nickCopy) PORT_Free(nickCopy);
693 return NULL;
695 nameList = nssList_Create(NULL, PR_FALSE);
696 if (!nameList) {
697 PK11_FreeSlot(slot);
698 if (nickCopy) PORT_Free(nickCopy);
699 return NULL;
701 (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
702 nickname,
703 nameList);
704 transfer_token_certs_to_collection(nameList, token, collection);
705 instances = nssToken_FindCertificatesByNickname(token,
706 NULL,
707 nickname,
708 tokenOnly,
710 &status);
711 nssPKIObjectCollection_AddInstances(collection, instances, 0);
712 nss_ZFreeIf(instances);
714 /* if it wasn't found, repeat the process for email address */
715 if (nssPKIObjectCollection_Count(collection) == 0 &&
716 PORT_Strchr(nickname, '@') != NULL)
718 char* lowercaseName = CERT_FixupEmailAddr(nickname);
719 if (lowercaseName) {
720 (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD,
721 lowercaseName,
722 nameList);
723 transfer_token_certs_to_collection(nameList, token, collection);
724 instances = nssToken_FindCertificatesByEmail(token,
725 NULL,
726 lowercaseName,
727 tokenOnly,
729 &status);
730 nssPKIObjectCollection_AddInstances(collection, instances, 0);
731 nss_ZFreeIf(instances);
732 PORT_Free(lowercaseName);
736 nssList_Destroy(nameList);
737 foundCerts = nssPKIObjectCollection_GetCertificates(collection,
738 NULL, 0, NULL);
739 nssPKIObjectCollection_Destroy(collection);
741 if (slot) {
742 PK11_FreeSlot(slot);
744 if (nickCopy) PORT_Free(nickCopy);
745 if (foundCerts) {
746 PRTime now = PR_Now();
747 certList = CERT_NewCertList();
748 for (i=0, c = *foundCerts; c; c = foundCerts[++i]) {
749 if (certList) {
750 CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c);
751 /* c may be invalid after this, don't reference it */
752 if (certCert) {
753 /* CERT_AddCertToListSorted adopts certCert */
754 CERT_AddCertToListSorted(certList, certCert,
755 CERT_SortCBValidity, &now);
757 } else {
758 nssCertificate_Destroy(c);
761 if (certList && CERT_LIST_HEAD(certList) == NULL) {
762 CERT_DestroyCertList(certList);
763 certList = NULL;
765 /* all the certs have been adopted or freed, free the raw array */
766 nss_ZFreeIf(foundCerts);
768 return certList;
772 * extract a key ID for a certificate...
773 * NOTE: We call this function from PKCS11.c If we ever use
774 * pkcs11 to extract the public key (we currently do not), this will break.
776 SECItem *
777 PK11_GetPubIndexKeyID(CERTCertificate *cert) {
778 SECKEYPublicKey *pubk;
779 SECItem *newItem = NULL;
781 pubk = CERT_ExtractPublicKey(cert);
782 if (pubk == NULL) return NULL;
784 switch (pubk->keyType) {
785 case rsaKey:
786 newItem = SECITEM_DupItem(&pubk->u.rsa.modulus);
787 break;
788 case dsaKey:
789 newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue);
790 break;
791 case dhKey:
792 newItem = SECITEM_DupItem(&pubk->u.dh.publicValue);
793 break;
794 case ecKey:
795 newItem = SECITEM_DupItem(&pubk->u.ec.publicValue);
796 break;
797 case fortezzaKey:
798 default:
799 newItem = NULL; /* Fortezza Fix later... */
801 SECKEY_DestroyPublicKey(pubk);
802 /* make hash of it */
803 return newItem;
807 * generate a CKA_ID from a certificate.
809 SECItem *
810 pk11_mkcertKeyID(CERTCertificate *cert) {
811 SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert) ;
812 SECItem *certCKA_ID;
814 if (pubKeyData == NULL) return NULL;
816 certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData);
817 SECITEM_FreeItem(pubKeyData,PR_TRUE);
818 return certCKA_ID;
822 * Write the cert into the token.
824 SECStatus
825 PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert,
826 CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust)
828 PRStatus status;
829 NSSCertificate *c;
830 nssCryptokiObject *keyobj, *certobj;
831 NSSToken *token = PK11Slot_GetNSSToken(slot);
832 SECItem *keyID = pk11_mkcertKeyID(cert);
833 char *emailAddr = NULL;
834 nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
835 nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
837 if (keyID == NULL) {
838 goto loser;
841 if (PK11_IsInternal(slot) && cert->emailAddr && cert->emailAddr[0]) {
842 emailAddr = cert->emailAddr;
845 /* need to get the cert as a stan cert */
846 if (cert->nssCertificate) {
847 c = cert->nssCertificate;
848 } else {
849 c = STAN_GetNSSCertificate(cert);
850 if (c == NULL) {
851 goto loser;
855 if (c->object.cryptoContext) {
856 /* Delete the temp instance */
857 NSSCryptoContext *cc = c->object.cryptoContext;
858 nssCertificateStore_Lock(cc->certStore, &lockTrace);
859 nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
860 nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace);
861 nssCertificateStore_Check(&lockTrace, &unlockTrace);
862 c->object.cryptoContext = NULL;
863 cert->istemp = PR_FALSE;
864 cert->isperm = PR_TRUE;
867 /* set the id for the cert */
868 nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
869 if (!c->id.data) {
870 goto loser;
873 if (key != CK_INVALID_HANDLE) {
874 /* create an object for the key, ... */
875 keyobj = nss_ZNEW(NULL, nssCryptokiObject);
876 if (!keyobj) {
877 goto loser;
879 keyobj->token = nssToken_AddRef(token);
880 keyobj->handle = key;
881 keyobj->isTokenObject = PR_TRUE;
883 /* ... in order to set matching attributes for the key */
884 status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname,
885 &c->id, &c->subject);
886 nssCryptokiObject_Destroy(keyobj);
887 if (status != PR_SUCCESS) {
888 goto loser;
892 /* do the token import */
893 certobj = nssToken_ImportCertificate(token, NULL,
894 NSSCertificateType_PKIX,
895 &c->id,
896 nickname,
897 &c->encoding,
898 &c->issuer,
899 &c->subject,
900 &c->serial,
901 emailAddr,
902 PR_TRUE);
903 if (!certobj) {
904 if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
905 PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
906 SECITEM_FreeItem(keyID,PR_TRUE);
907 return SECFailure;
909 goto loser;
911 /* add the new instance to the cert, force an update of the
912 * CERTCertificate, and finish
914 nssPKIObject_AddInstance(&c->object, certobj);
915 nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
916 (void)STAN_ForceCERTCertificateUpdate(c);
917 SECITEM_FreeItem(keyID,PR_TRUE);
918 return SECSuccess;
919 loser:
920 SECITEM_FreeItem(keyID,PR_TRUE);
921 PORT_SetError(SEC_ERROR_ADDING_CERT);
922 return SECFailure;
925 SECStatus
926 PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert,
927 CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) {
928 CERTCertificate *cert;
929 SECStatus rv;
931 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
932 derCert, NULL, PR_FALSE, PR_TRUE);
933 if (cert == NULL) return SECFailure;
935 rv = PK11_ImportCert(slot, cert, key, nickname, includeTrust);
936 CERT_DestroyCertificate (cert);
937 return rv;
941 * get a certificate handle, look at the cached handle first..
943 CK_OBJECT_HANDLE
944 pk11_getcerthandle(PK11SlotInfo *slot, CERTCertificate *cert,
945 CK_ATTRIBUTE *theTemplate,int tsize)
947 CK_OBJECT_HANDLE certh;
949 if (cert->slot == slot) {
950 certh = cert->pkcs11ID;
951 if ((certh == CK_INVALID_HANDLE) ||
952 (cert->series != slot->series)) {
953 certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
954 cert->pkcs11ID = certh;
955 cert->series = slot->series;
957 } else {
958 certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
960 return certh;
964 * return the private key From a given Cert
966 SECKEYPrivateKey *
967 PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert,
968 void *wincx) {
969 int err;
970 CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
971 CK_ATTRIBUTE theTemplate[] = {
972 { CKA_VALUE, NULL, 0 },
973 { CKA_CLASS, NULL, 0 }
975 /* if you change the array, change the variable below as well */
976 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
977 CK_OBJECT_HANDLE certh;
978 CK_OBJECT_HANDLE keyh;
979 CK_ATTRIBUTE *attrs = theTemplate;
980 PRBool needLogin;
981 SECStatus rv;
983 PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
984 cert->derCert.len); attrs++;
985 PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
988 * issue the find
990 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
991 if (rv != SECSuccess) {
992 return NULL;
995 certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
996 if (certh == CK_INVALID_HANDLE) {
997 return NULL;
1000 * prevent a login race condition. If slot is logged in between
1001 * our call to pk11_LoginStillRequired and the
1002 * PK11_MatchItem. The matchItem call will either succeed, or
1003 * we will call it one more time after calling PK11_Authenticate
1004 * (which is a noop on an authenticated token).
1006 needLogin = pk11_LoginStillRequired(slot,wincx);
1007 keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
1008 if ((keyh == CK_INVALID_HANDLE) && needLogin &&
1009 (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
1010 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
1011 /* try it again authenticated */
1012 rv = PK11_Authenticate(slot, PR_TRUE, wincx);
1013 if (rv != SECSuccess) {
1014 return NULL;
1016 keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
1018 if (keyh == CK_INVALID_HANDLE) {
1019 return NULL;
1021 return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx);
1025 * import a cert for a private key we have already generated. Set the label
1026 * on both to be the nickname. This is for the Key Gen, orphaned key case.
1028 PK11SlotInfo *
1029 PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr,
1030 void *wincx) {
1031 PK11SlotList *list;
1032 PK11SlotListElement *le;
1033 SECItem *keyID;
1034 CK_OBJECT_HANDLE key;
1035 PK11SlotInfo *slot = NULL;
1036 SECStatus rv;
1037 int err;
1039 keyID = pk11_mkcertKeyID(cert);
1040 /* get them all! */
1041 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
1042 if ((keyID == NULL) || (list == NULL)) {
1043 if (keyID) SECITEM_FreeItem(keyID,PR_TRUE);
1044 if (list) PK11_FreeSlotList(list);
1045 return NULL;
1048 /* Look for the slot that holds the Key */
1049 for (le = list->head ; le; le = le->next) {
1051 * prevent a login race condition. If le->slot is logged in between
1052 * our call to pk11_LoginStillRequired and the
1053 * pk11_FindPrivateKeyFromCertID, the find will either succeed, or
1054 * we will call it one more time after calling PK11_Authenticate
1055 * (which is a noop on an authenticated token).
1057 PRBool needLogin = pk11_LoginStillRequired(le->slot,wincx);
1058 key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
1059 if ((key == CK_INVALID_HANDLE) && needLogin &&
1060 (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
1061 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
1062 /* authenticate and try again */
1063 rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
1064 if (rv != SECSuccess) continue;
1065 key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
1067 if (key != CK_INVALID_HANDLE) {
1068 slot = PK11_ReferenceSlot(le->slot);
1069 if (keyPtr) *keyPtr = key;
1070 break;
1074 SECITEM_FreeItem(keyID,PR_TRUE);
1075 PK11_FreeSlotList(list);
1076 return slot;
1080 * import a cert for a private key we have already generated. Set the label
1081 * on both to be the nickname. This is for the Key Gen, orphaned key case.
1083 PK11SlotInfo *
1084 PK11_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr,
1085 void *wincx) {
1086 CERTCertificate *cert;
1087 PK11SlotInfo *slot = NULL;
1089 /* letting this use go -- the only thing that the cert is used for is
1090 * to get the ID attribute.
1092 cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
1093 if (cert == NULL) return NULL;
1095 slot = PK11_KeyForCertExists(cert, keyPtr, wincx);
1096 CERT_DestroyCertificate (cert);
1097 return slot;
1100 PK11SlotInfo *
1101 PK11_ImportCertForKey(CERTCertificate *cert, char *nickname,void *wincx) {
1102 PK11SlotInfo *slot = NULL;
1103 CK_OBJECT_HANDLE key;
1105 slot = PK11_KeyForCertExists(cert,&key,wincx);
1107 if (slot) {
1108 if (PK11_ImportCert(slot,cert,key,nickname,PR_FALSE) != SECSuccess) {
1109 PK11_FreeSlot(slot);
1110 slot = NULL;
1112 } else {
1113 PORT_SetError(SEC_ERROR_ADDING_CERT);
1116 return slot;
1119 PK11SlotInfo *
1120 PK11_ImportDERCertForKey(SECItem *derCert, char *nickname,void *wincx) {
1121 CERTCertificate *cert;
1122 PK11SlotInfo *slot = NULL;
1124 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
1125 derCert, NULL, PR_FALSE, PR_TRUE);
1126 if (cert == NULL) return NULL;
1128 slot = PK11_ImportCertForKey(cert, nickname, wincx);
1129 CERT_DestroyCertificate (cert);
1130 return slot;
1133 static CK_OBJECT_HANDLE
1134 pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr,
1135 CK_ATTRIBUTE *searchTemplate, int count, void *wincx) {
1136 PK11SlotList *list;
1137 PK11SlotListElement *le;
1138 CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE;
1139 PK11SlotInfo *slot = NULL;
1140 SECStatus rv;
1142 *slotPtr = NULL;
1144 /* get them all! */
1145 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
1146 if (list == NULL) {
1147 return CK_INVALID_HANDLE;
1151 /* Look for the slot that holds the Key */
1152 for (le = list->head ; le; le = le->next) {
1153 rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
1154 if (rv != SECSuccess) continue;
1156 certHandle = pk11_FindObjectByTemplate(le->slot,searchTemplate,count);
1157 if (certHandle != CK_INVALID_HANDLE) {
1158 slot = PK11_ReferenceSlot(le->slot);
1159 break;
1163 PK11_FreeSlotList(list);
1165 if (slot == NULL) {
1166 return CK_INVALID_HANDLE;
1168 *slotPtr = slot;
1169 return certHandle;
1172 CERTCertificate *
1173 PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo *slot,
1174 CERTIssuerAndSN *issuerSN, void *wincx)
1176 CERTCertificate *rvCert = NULL;
1177 NSSCertificate *cert = NULL;
1178 NSSDER issuer, serial;
1179 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
1180 NSSToken *token = slot->nssToken;
1181 nssSession *session;
1182 nssCryptokiObject *instance = NULL;
1183 nssPKIObject *object = NULL;
1184 SECItem *derSerial;
1185 PRStatus status;
1187 /* Paranoia */
1188 if (token == NULL) {
1189 PORT_SetError(SEC_ERROR_NO_TOKEN);
1190 return NULL;
1194 /* PKCS#11 needs to use DER-encoded serial numbers. Create a
1195 * CERTIssuerAndSN that actually has the encoded value and pass that
1196 * to PKCS#11 (and the crypto context).
1198 derSerial = SEC_ASN1EncodeItem(NULL, NULL,
1199 &issuerSN->serialNumber,
1200 SEC_IntegerTemplate);
1201 if (!derSerial) {
1202 return NULL;
1205 NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
1206 NSSITEM_FROM_SECITEM(&serial, derSerial);
1208 session = nssToken_GetDefaultSession(token);
1209 if (!session) {
1210 goto loser;
1213 instance = nssToken_FindCertificateByIssuerAndSerialNumber(token,session,
1214 &issuer, &serial, nssTokenSearchType_TokenForced, &status);
1216 SECITEM_FreeItem(derSerial, PR_TRUE);
1218 if (!instance) {
1219 goto loser;
1221 object = nssPKIObject_Create(NULL, instance, td, NULL, nssPKIMonitor);
1222 if (!object) {
1223 goto loser;
1225 instance = NULL; /* adopted by the previous call */
1226 cert = nssCertificate_Create(object);
1227 if (!cert) {
1228 goto loser;
1230 object = NULL; /* adopted by the previous call */
1231 nssTrustDomain_AddCertsToCache(td, &cert,1);
1232 /* on failure, cert is freed below */
1233 rvCert = STAN_GetCERTCertificate(cert);
1234 if (!rvCert) {
1235 goto loser;
1237 return rvCert;
1239 loser:
1240 if (instance) {
1241 nssCryptokiObject_Destroy(instance);
1243 if (object) {
1244 nssPKIObject_Destroy(object);
1246 if (cert) {
1247 nssCertificate_Destroy(cert);
1249 return NULL;
1253 * We're looking for a cert which we have the private key for that's on the
1254 * list of recipients. This searches one slot.
1255 * this is the new version for NSS SMIME code
1256 * this stuff should REALLY be in the SMIME code, but some things in here are not public
1257 * (they should be!)
1259 static CERTCertificate *
1260 pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist, int *rlIndex, void *pwarg)
1262 NSSCMSRecipient *ri = NULL;
1263 int i;
1265 for (i=0; (ri = recipientlist[i]) != NULL; i++) {
1266 CERTCertificate *cert = NULL;
1267 if (ri->kind == RLSubjKeyID) {
1268 SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
1269 if (derCert) {
1270 cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg);
1271 SECITEM_FreeItem(derCert, PR_TRUE);
1273 } else {
1274 cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN,
1275 pwarg);
1277 if (cert) {
1278 /* this isn't our cert */
1279 if ((cert->trust == NULL) ||
1280 ((cert->trust->emailFlags & CERTDB_USER) != CERTDB_USER)) {
1281 CERT_DestroyCertificate(cert);
1282 continue;
1284 ri->slot = PK11_ReferenceSlot(slot);
1285 *rlIndex = i;
1286 return cert;
1289 *rlIndex = -1;
1290 return NULL;
1294 * This function is the same as above, but it searches all the slots.
1295 * this is the new version for NSS SMIME code
1296 * this stuff should REALLY be in the SMIME code, but some things in here are not public
1297 * (they should be!)
1299 static CERTCertificate *
1300 pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex)
1302 PK11SlotList *list;
1303 PK11SlotListElement *le;
1304 CERTCertificate *cert = NULL;
1305 SECStatus rv;
1307 /* get them all! */
1308 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
1309 if (list == NULL) {
1310 return CK_INVALID_HANDLE;
1313 /* Look for the slot that holds the Key */
1314 for (le = list->head ; le; le = le->next) {
1315 rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
1316 if (rv != SECSuccess) continue;
1318 cert = pk11_FindCertObjectByRecipientNew(le->slot,
1319 recipientlist, rlIndex, wincx);
1320 if (cert)
1321 break;
1324 PK11_FreeSlotList(list);
1326 return cert;
1330 * We're looking for a cert which we have the private key for that's on the
1331 * list of recipients. This searches one slot.
1333 static CERTCertificate *
1334 pk11_FindCertObjectByRecipient(PK11SlotInfo *slot,
1335 SEC_PKCS7RecipientInfo **recipientArray,
1336 SEC_PKCS7RecipientInfo **rip, void *pwarg)
1338 SEC_PKCS7RecipientInfo *ri = NULL;
1339 int i;
1341 for (i=0; (ri = recipientArray[i]) != NULL; i++) {
1342 CERTCertificate *cert;
1344 cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->issuerAndSN,
1345 pwarg);
1346 if (cert) {
1347 /* this isn't our cert */
1348 if ((cert->trust == NULL) ||
1349 ((cert->trust->emailFlags & CERTDB_USER) != CERTDB_USER)) {
1350 CERT_DestroyCertificate(cert);
1351 continue;
1353 *rip = ri;
1354 return cert;
1358 *rip = NULL;
1359 return NULL;
1363 * This function is the same as above, but it searches all the slots.
1365 static CERTCertificate *
1366 pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr,
1367 SEC_PKCS7RecipientInfo **recipientArray,SEC_PKCS7RecipientInfo **rip,
1368 void *wincx) {
1369 PK11SlotList *list;
1370 PK11SlotListElement *le;
1371 CERTCertificate * cert = NULL;
1372 PK11SlotInfo *slot = NULL;
1373 SECStatus rv;
1375 *slotPtr = NULL;
1377 /* get them all! */
1378 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
1379 if (list == NULL) {
1380 return CK_INVALID_HANDLE;
1383 *rip = NULL;
1385 /* Look for the slot that holds the Key */
1386 for (le = list->head ; le; le = le->next) {
1387 rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
1388 if (rv != SECSuccess) continue;
1390 cert = pk11_FindCertObjectByRecipient(le->slot, recipientArray,
1391 rip, wincx);
1392 if (cert) {
1393 slot = PK11_ReferenceSlot(le->slot);
1394 break;
1398 PK11_FreeSlotList(list);
1400 if (slot == NULL) {
1401 return NULL;
1403 *slotPtr = slot;
1404 PORT_Assert(cert != NULL);
1405 return cert;
1409 * We need to invert the search logic for PKCS 7 because if we search for
1410 * each cert on the list over all the slots, we wind up with lots of spurious
1411 * password prompts. This way we get only one password prompt per slot, at
1412 * the max, and most of the time we can find the cert, and only prompt for
1413 * the key...
1415 CERTCertificate *
1416 PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr,
1417 SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip,
1418 SECKEYPrivateKey**privKey, void *wincx)
1420 CERTCertificate *cert = NULL;
1422 *privKey = NULL;
1423 *slotPtr = NULL;
1424 cert = pk11_AllFindCertObjectByRecipient(slotPtr,array,rip,wincx);
1425 if (!cert) {
1426 return NULL;
1429 *privKey = PK11_FindKeyByAnyCert(cert, wincx);
1430 if (*privKey == NULL) {
1431 goto loser;
1434 return cert;
1435 loser:
1436 if (cert) CERT_DestroyCertificate(cert);
1437 if (*slotPtr) PK11_FreeSlot(*slotPtr);
1438 *slotPtr = NULL;
1439 return NULL;
1442 static PRCallOnceType keyIDHashCallOnce;
1444 static PRStatus PR_CALLBACK
1445 pk11_keyIDHash_populate(void *wincx)
1447 CERTCertList *certList;
1448 CERTCertListNode *node = NULL;
1449 SECItem subjKeyID = {siBuffer, NULL, 0};
1451 certList = PK11_ListCerts(PK11CertListUser, wincx);
1452 if (!certList) {
1453 return PR_FAILURE;
1456 for (node = CERT_LIST_HEAD(certList);
1457 !CERT_LIST_END(node, certList);
1458 node = CERT_LIST_NEXT(node)) {
1459 if (CERT_FindSubjectKeyIDExtension(node->cert,
1460 &subjKeyID) == SECSuccess &&
1461 subjKeyID.data != NULL) {
1462 cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert);
1463 SECITEM_FreeItem(&subjKeyID, PR_FALSE);
1466 CERT_DestroyCertList(certList);
1467 return PR_SUCCESS;
1471 * This is the new version of the above function for NSS SMIME code
1472 * this stuff should REALLY be in the SMIME code, but some things in here are not public
1473 * (they should be!)
1476 PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx)
1478 CERTCertificate *cert;
1479 NSSCMSRecipient *rl;
1480 PRStatus rv;
1481 int rlIndex;
1483 rv = PR_CallOnceWithArg(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx);
1484 if (rv != PR_SUCCESS)
1485 return -1;
1487 cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex);
1488 if (!cert) {
1489 return -1;
1492 rl = recipientlist[rlIndex];
1494 /* at this point, rl->slot is set */
1496 rl->privkey = PK11_FindKeyByAnyCert(cert, wincx);
1497 if (rl->privkey == NULL) {
1498 goto loser;
1501 /* make a cert from the cert handle */
1502 rl->cert = cert;
1503 return rlIndex;
1505 loser:
1506 if (cert) CERT_DestroyCertificate(cert);
1507 if (rl->slot) PK11_FreeSlot(rl->slot);
1508 rl->slot = NULL;
1509 return -1;
1512 CERTCertificate *
1513 PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN,
1514 void *wincx)
1516 CERTCertificate *rvCert = NULL;
1517 NSSCertificate *cert;
1518 NSSDER issuer, serial;
1519 NSSCryptoContext *cc;
1520 SECItem *derSerial;
1522 if (slotPtr) *slotPtr = NULL;
1524 /* PKCS#11 needs to use DER-encoded serial numbers. Create a
1525 * CERTIssuerAndSN that actually has the encoded value and pass that
1526 * to PKCS#11 (and the crypto context).
1528 derSerial = SEC_ASN1EncodeItem(NULL, NULL,
1529 &issuerSN->serialNumber,
1530 SEC_IntegerTemplate);
1531 if (!derSerial) {
1532 return NULL;
1535 NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
1536 NSSITEM_FROM_SECITEM(&serial, derSerial);
1538 cc = STAN_GetDefaultCryptoContext();
1539 cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc,
1540 &issuer,
1541 &serial);
1542 if (cert) {
1543 SECITEM_FreeItem(derSerial, PR_TRUE);
1544 return STAN_GetCERTCertificateOrRelease(cert);
1547 do {
1548 /* free the old cert on retry. Associated slot was not present */
1549 if (rvCert) {
1550 CERT_DestroyCertificate(rvCert);
1551 rvCert = NULL;
1554 cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
1555 STAN_GetDefaultTrustDomain(),
1556 &issuer,
1557 &serial);
1558 if (!cert) {
1559 break;
1562 rvCert = STAN_GetCERTCertificateOrRelease(cert);
1563 if (rvCert == NULL) {
1564 break;
1567 /* Check to see if the cert's token is still there */
1568 } while (!PK11_IsPresent(rvCert->slot));
1570 if (rvCert && slotPtr) *slotPtr = PK11_ReferenceSlot(rvCert->slot);
1572 SECITEM_FreeItem(derSerial, PR_TRUE);
1573 return rvCert;
1576 CK_OBJECT_HANDLE
1577 PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot)
1579 CK_OBJECT_HANDLE certHandle;
1580 CK_ATTRIBUTE searchTemplate = { CKA_VALUE, NULL, 0 };
1582 PK11_SETATTRS(&searchTemplate, CKA_VALUE, cert->derCert.data,
1583 cert->derCert.len);
1585 if (cert->slot) {
1586 certHandle = pk11_getcerthandle(cert->slot,cert,&searchTemplate,1);
1587 if (certHandle != CK_INVALID_HANDLE) {
1588 *pSlot = PK11_ReferenceSlot(cert->slot);
1589 return certHandle;
1593 certHandle = pk11_FindCertObjectByTemplate(pSlot,&searchTemplate,1,wincx);
1594 if (certHandle != CK_INVALID_HANDLE) {
1595 if (cert->slot == NULL) {
1596 cert->slot = PK11_ReferenceSlot(*pSlot);
1597 cert->pkcs11ID = certHandle;
1598 cert->ownSlot = PR_TRUE;
1599 cert->series = cert->slot->series;
1603 return(certHandle);
1606 SECKEYPrivateKey *
1607 PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx)
1609 CK_OBJECT_HANDLE certHandle;
1610 CK_OBJECT_HANDLE keyHandle;
1611 PK11SlotInfo *slot = NULL;
1612 SECKEYPrivateKey *privKey = NULL;
1613 PRBool needLogin;
1614 SECStatus rv;
1615 int err;
1617 certHandle = PK11_FindObjectForCert(cert, wincx, &slot);
1618 if (certHandle == CK_INVALID_HANDLE) {
1619 return NULL;
1622 * prevent a login race condition. If slot is logged in between
1623 * our call to pk11_LoginStillRequired and the
1624 * PK11_MatchItem. The matchItem call will either succeed, or
1625 * we will call it one more time after calling PK11_Authenticate
1626 * (which is a noop on an authenticated token).
1628 needLogin = pk11_LoginStillRequired(slot,wincx);
1629 keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
1630 if ((keyHandle == CK_INVALID_HANDLE) && needLogin &&
1631 (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
1632 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err ) ) {
1633 /* authenticate and try again */
1634 rv = PK11_Authenticate(slot, PR_TRUE, wincx);
1635 if (rv == SECSuccess) {
1636 keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
1639 if (keyHandle != CK_INVALID_HANDLE) {
1640 privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
1642 if (slot) {
1643 PK11_FreeSlot(slot);
1645 return privKey;
1648 CK_OBJECT_HANDLE
1649 pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx)
1651 CK_OBJECT_HANDLE certHandle;
1652 CK_OBJECT_HANDLE keyHandle;
1654 certHandle = PK11_FindObjectForCert(cert, wincx, slot);
1655 if (certHandle == CK_INVALID_HANDLE) {
1656 return CK_INVALID_HANDLE;
1658 keyHandle = PK11_MatchItem(*slot,certHandle,CKO_PUBLIC_KEY);
1659 if (keyHandle == CK_INVALID_HANDLE) {
1660 PK11_FreeSlot(*slot);
1661 return CK_INVALID_HANDLE;
1663 return keyHandle;
1667 * find the number of certs in the slot with the same subject name
1670 PK11_NumberCertsForCertSubject(CERTCertificate *cert)
1672 CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
1673 CK_ATTRIBUTE theTemplate[] = {
1674 { CKA_CLASS, NULL, 0 },
1675 { CKA_SUBJECT, NULL, 0 },
1677 CK_ATTRIBUTE *attr = theTemplate;
1678 int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]);
1680 PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++;
1681 PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len);
1683 if (cert->slot == NULL) {
1684 PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
1685 PR_FALSE,PR_TRUE,NULL);
1686 PK11SlotListElement *le;
1687 int count = 0;
1689 if (!list) {
1690 /* error code is set */
1691 return 0;
1694 /* loop through all the fortezza tokens */
1695 for (le = list->head; le; le = le->next) {
1696 count += PK11_NumberObjectsFor(le->slot,theTemplate,templateSize);
1698 PK11_FreeSlotList(list);
1699 return count;
1702 return PK11_NumberObjectsFor(cert->slot,theTemplate,templateSize);
1706 * Walk all the certs with the same subject
1708 SECStatus
1709 PK11_TraverseCertsForSubject(CERTCertificate *cert,
1710 SECStatus(* callback)(CERTCertificate*, void *), void *arg)
1712 if(!cert) {
1713 return SECFailure;
1715 if (cert->slot == NULL) {
1716 PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
1717 PR_FALSE,PR_TRUE,NULL);
1718 PK11SlotListElement *le;
1720 if (!list) {
1721 /* error code is set */
1722 return SECFailure;
1724 /* loop through all the tokens */
1725 for (le = list->head; le; le = le->next) {
1726 PK11_TraverseCertsForSubjectInSlot(cert,le->slot,callback,arg);
1728 PK11_FreeSlotList(list);
1729 return SECSuccess;
1733 return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg);
1736 SECStatus
1737 PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot,
1738 SECStatus(* callback)(CERTCertificate*, void *), void *arg)
1740 PRStatus nssrv = PR_SUCCESS;
1741 NSSToken *token;
1742 NSSDER subject;
1743 NSSTrustDomain *td;
1744 nssList *subjectList;
1745 nssPKIObjectCollection *collection;
1746 nssCryptokiObject **instances;
1747 NSSCertificate **certs;
1748 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
1749 td = STAN_GetDefaultTrustDomain();
1750 NSSITEM_FROM_SECITEM(&subject, &cert->derSubject);
1751 token = PK11Slot_GetNSSToken(slot);
1752 if (!nssToken_IsPresent(token)) {
1753 return SECSuccess;
1755 collection = nssCertificateCollection_Create(td, NULL);
1756 if (!collection) {
1757 return SECFailure;
1759 subjectList = nssList_Create(NULL, PR_FALSE);
1760 if (!subjectList) {
1761 nssPKIObjectCollection_Destroy(collection);
1762 return SECFailure;
1764 (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject,
1765 subjectList);
1766 transfer_token_certs_to_collection(subjectList, token, collection);
1767 instances = nssToken_FindCertificatesBySubject(token, NULL,
1768 &subject,
1769 tokenOnly, 0, &nssrv);
1770 nssPKIObjectCollection_AddInstances(collection, instances, 0);
1771 nss_ZFreeIf(instances);
1772 nssList_Destroy(subjectList);
1773 certs = nssPKIObjectCollection_GetCertificates(collection,
1774 NULL, 0, NULL);
1775 nssPKIObjectCollection_Destroy(collection);
1776 if (certs) {
1777 CERTCertificate *oldie;
1778 NSSCertificate **cp;
1779 for (cp = certs; *cp; cp++) {
1780 oldie = STAN_GetCERTCertificate(*cp);
1781 if (!oldie) {
1782 continue;
1784 if ((*callback)(oldie, arg) != SECSuccess) {
1785 nssrv = PR_FAILURE;
1786 break;
1789 nssCertificateArray_Destroy(certs);
1791 return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
1794 SECStatus
1795 PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
1796 SECStatus(* callback)(CERTCertificate*, void *), void *arg)
1798 struct nss3_cert_cbstr pk11cb;
1799 PRStatus nssrv = PR_SUCCESS;
1800 NSSToken *token;
1801 NSSTrustDomain *td;
1802 NSSUTF8 *nick;
1803 PRBool created = PR_FALSE;
1804 nssCryptokiObject **instances;
1805 nssPKIObjectCollection *collection = NULL;
1806 NSSCertificate **certs;
1807 nssList *nameList = NULL;
1808 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
1809 pk11cb.callback = callback;
1810 pk11cb.arg = arg;
1811 token = PK11Slot_GetNSSToken(slot);
1812 if (!nssToken_IsPresent(token)) {
1813 return SECSuccess;
1815 if (nickname->data[nickname->len-1] != '\0') {
1816 nick = nssUTF8_Create(NULL, nssStringType_UTF8String,
1817 nickname->data, nickname->len);
1818 created = PR_TRUE;
1819 } else {
1820 nick = (NSSUTF8 *)nickname->data;
1822 td = STAN_GetDefaultTrustDomain();
1823 collection = nssCertificateCollection_Create(td, NULL);
1824 if (!collection) {
1825 goto loser;
1827 nameList = nssList_Create(NULL, PR_FALSE);
1828 if (!nameList) {
1829 goto loser;
1831 (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList);
1832 transfer_token_certs_to_collection(nameList, token, collection);
1833 instances = nssToken_FindCertificatesByNickname(token, NULL,
1834 nick,
1835 tokenOnly, 0, &nssrv);
1836 nssPKIObjectCollection_AddInstances(collection, instances, 0);
1837 nss_ZFreeIf(instances);
1838 nssList_Destroy(nameList);
1839 certs = nssPKIObjectCollection_GetCertificates(collection,
1840 NULL, 0, NULL);
1841 nssPKIObjectCollection_Destroy(collection);
1842 if (certs) {
1843 CERTCertificate *oldie;
1844 NSSCertificate **cp;
1845 for (cp = certs; *cp; cp++) {
1846 oldie = STAN_GetCERTCertificate(*cp);
1847 if (!oldie) {
1848 continue;
1850 if ((*callback)(oldie, arg) != SECSuccess) {
1851 nssrv = PR_FAILURE;
1852 break;
1855 nssCertificateArray_Destroy(certs);
1857 if (created) nss_ZFreeIf(nick);
1858 return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
1859 loser:
1860 if (created) {
1861 nss_ZFreeIf(nick);
1863 if (collection) {
1864 nssPKIObjectCollection_Destroy(collection);
1866 if (nameList) {
1867 nssList_Destroy(nameList);
1869 return SECFailure;
1872 SECStatus
1873 PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
1874 SECStatus(* callback)(CERTCertificate*, void *), void *arg)
1876 PRStatus nssrv;
1877 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
1878 NSSToken *tok;
1879 nssList *certList = NULL;
1880 nssCryptokiObject **instances;
1881 nssPKIObjectCollection *collection;
1882 NSSCertificate **certs;
1883 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
1884 tok = PK11Slot_GetNSSToken(slot);
1885 if (!nssToken_IsPresent(tok)) {
1886 return SECSuccess;
1888 collection = nssCertificateCollection_Create(td, NULL);
1889 if (!collection) {
1890 return SECFailure;
1892 certList = nssList_Create(NULL, PR_FALSE);
1893 if (!certList) {
1894 nssPKIObjectCollection_Destroy(collection);
1895 return SECFailure;
1897 (void *)nssTrustDomain_GetCertsFromCache(td, certList);
1898 transfer_token_certs_to_collection(certList, tok, collection);
1899 instances = nssToken_FindCertificates(tok, NULL,
1900 tokenOnly, 0, &nssrv);
1901 nssPKIObjectCollection_AddInstances(collection, instances, 0);
1902 nss_ZFreeIf(instances);
1903 nssList_Destroy(certList);
1904 certs = nssPKIObjectCollection_GetCertificates(collection,
1905 NULL, 0, NULL);
1906 nssPKIObjectCollection_Destroy(collection);
1907 if (certs) {
1908 CERTCertificate *oldie;
1909 NSSCertificate **cp;
1910 for (cp = certs; *cp; cp++) {
1911 oldie = STAN_GetCERTCertificate(*cp);
1912 if (!oldie) {
1913 continue;
1915 if ((*callback)(oldie, arg) != SECSuccess) {
1916 nssrv = PR_FAILURE;
1917 break;
1920 nssCertificateArray_Destroy(certs);
1922 return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
1926 * return the certificate associated with a derCert
1928 CERTCertificate *
1929 PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
1930 void *wincx)
1932 return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx);
1935 CERTCertificate *
1936 PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, SECItem *inDerCert,
1937 void *wincx)
1940 NSSCertificate *c;
1941 NSSDER derCert;
1942 NSSToken *tok;
1943 NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
1944 SECStatus rv;
1946 tok = PK11Slot_GetNSSToken(slot);
1947 NSSITEM_FROM_SECITEM(&derCert, inDerCert);
1948 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
1949 if (rv != SECSuccess) {
1950 PK11_FreeSlot(slot);
1951 return NULL;
1953 c = NSSTrustDomain_FindCertificateByEncodedCertificate(td, &derCert);
1954 if (c) {
1955 PRBool isToken = PR_FALSE;
1956 NSSToken **tp;
1957 NSSToken **tokens = nssPKIObject_GetTokens(&c->object, NULL);
1958 if (tokens) {
1959 for (tp = tokens; *tp; tp++) {
1960 if (*tp == tok) {
1961 isToken = PR_TRUE;
1962 break;
1965 if (!isToken) {
1966 NSSCertificate_Destroy(c);
1967 c = NULL;
1969 nssTokenArray_Destroy(tokens);
1972 return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
1975 /* mcgreer 3.4 -- nobody uses this, ignoring */
1977 * return the certificate associated with a derCert
1979 CERTCertificate *
1980 PK11_FindCertFromDERSubjectAndNickname(PK11SlotInfo *slot,
1981 CERTCertificate *cert,
1982 char *nickname, void *wincx)
1984 CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
1985 CK_ATTRIBUTE theTemplate[] = {
1986 { CKA_SUBJECT, NULL, 0 },
1987 { CKA_LABEL, NULL, 0 },
1988 { CKA_CLASS, NULL, 0 }
1990 /* if you change the array, change the variable below as well */
1991 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
1992 CK_OBJECT_HANDLE certh;
1993 CK_ATTRIBUTE *attrs = theTemplate;
1994 SECStatus rv;
1996 PK11_SETATTRS(attrs, CKA_SUBJECT, cert->derSubject.data,
1997 cert->derSubject.len); attrs++;
1998 PK11_SETATTRS(attrs, CKA_LABEL, nickname, PORT_Strlen(nickname));
1999 PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
2002 * issue the find
2004 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
2005 if (rv != SECSuccess) return NULL;
2007 certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
2008 if (certh == CK_INVALID_HANDLE) {
2009 return NULL;
2012 return PK11_MakeCertFromHandle(slot, certh, NULL);
2016 * import a cert for a private key we have already generated. Set the label
2017 * on both to be the nickname.
2019 static CK_OBJECT_HANDLE
2020 pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
2021 void *wincx)
2023 SECItem *keyID;
2024 CK_OBJECT_HANDLE key;
2025 SECStatus rv;
2026 PRBool needLogin;
2027 int err;
2029 if((slot == NULL) || (cert == NULL)) {
2030 return CK_INVALID_HANDLE;
2033 keyID = pk11_mkcertKeyID(cert);
2034 if(keyID == NULL) {
2035 return CK_INVALID_HANDLE;
2039 * prevent a login race condition. If slot is logged in between
2040 * our call to pk11_LoginStillRequired and the
2041 * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or
2042 * we will call it one more time after calling PK11_Authenticate
2043 * (which is a noop on an authenticated token).
2045 needLogin = pk11_LoginStillRequired(slot,wincx);
2046 key = pk11_FindPrivateKeyFromCertID(slot, keyID);
2047 if ((key == CK_INVALID_HANDLE) && needLogin &&
2048 (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
2049 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
2050 /* authenticate and try again */
2051 rv = PK11_Authenticate(slot, PR_TRUE, wincx);
2052 if (rv != SECSuccess) goto loser;
2053 key = pk11_FindPrivateKeyFromCertID(slot, keyID);
2056 loser:
2057 SECITEM_ZfreeItem(keyID, PR_TRUE);
2058 return key;
2061 SECKEYPrivateKey *
2062 PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
2063 void *wincx)
2065 CK_OBJECT_HANDLE keyHandle;
2067 if((slot == NULL) || (cert == NULL)) {
2068 return NULL;
2071 keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
2072 if (keyHandle == CK_INVALID_HANDLE) {
2073 return NULL;
2076 return PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,wincx);
2079 SECStatus
2080 PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert,
2081 char *nickname,
2082 PRBool addCertUsage,void *wincx)
2084 CK_OBJECT_HANDLE keyHandle;
2086 if((slot == NULL) || (cert == NULL) || (nickname == NULL)) {
2087 return SECFailure;
2090 keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
2091 if (keyHandle == CK_INVALID_HANDLE) {
2092 return SECFailure;
2095 return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage);
2099 /* remove when the real version comes out */
2100 #define SEC_OID_MISSI_KEA 300 /* until we have v3 stuff merged */
2101 PRBool
2102 KEAPQGCompare(CERTCertificate *server,CERTCertificate *cert) {
2104 if ( SECKEY_KEAParamCompare(server,cert) == SECEqual ) {
2105 return PR_TRUE;
2106 } else {
2107 return PR_FALSE;
2111 PRBool
2112 PK11_FortezzaHasKEA(CERTCertificate *cert) {
2113 /* look at the subject and see if it is a KEA for MISSI key */
2114 SECOidData *oid;
2116 if ((cert->trust == NULL) ||
2117 ((cert->trust->sslFlags & CERTDB_USER) != CERTDB_USER)) {
2118 return PR_FALSE;
2121 oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm);
2122 if (!oid) {
2123 return PR_FALSE;
2126 return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) ||
2127 (oid->offset == SEC_OID_MISSI_KEA_DSS) ||
2128 (oid->offset == SEC_OID_MISSI_KEA)) ;
2132 * Find a kea cert on this slot that matches the domain of it's peer
2134 static CERTCertificate
2135 *pk11_GetKEAMate(PK11SlotInfo *slot,CERTCertificate *peer)
2137 int i;
2138 CERTCertificate *returnedCert = NULL;
2140 for (i=0; i < slot->cert_count; i++) {
2141 CERTCertificate *cert = slot->cert_array[i];
2143 if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer,cert)) {
2144 returnedCert = CERT_DupCertificate(cert);
2145 break;
2148 return returnedCert;
2152 * The following is a FORTEZZA only Certificate request. We call this when we
2153 * are doing a non-client auth SSL connection. We are only interested in the
2154 * fortezza slots, and we are only interested in certs that share the same root
2155 * key as the server.
2157 CERTCertificate *
2158 PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx)
2160 PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE,
2161 PR_FALSE,PR_TRUE,wincx);
2162 PK11SlotListElement *le;
2163 CERTCertificate *returnedCert = NULL;
2164 SECStatus rv;
2166 if (!keaList) {
2167 /* error code is set */
2168 return NULL;
2171 /* loop through all the fortezza tokens */
2172 for (le = keaList->head; le; le = le->next) {
2173 rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
2174 if (rv != SECSuccess) continue;
2175 if (le->slot->session == CK_INVALID_SESSION) {
2176 continue;
2178 returnedCert = pk11_GetKEAMate(le->slot,server);
2179 if (returnedCert) break;
2181 PK11_FreeSlotList(keaList);
2183 return returnedCert;
2187 * find a matched pair of kea certs to key exchange parameters from one
2188 * fortezza card to another as necessary.
2190 SECStatus
2191 PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2,
2192 CERTCertificate **cert1, CERTCertificate **cert2)
2194 CERTCertificate *returnedCert = NULL;
2195 int i;
2197 for (i=0; i < slot1->cert_count; i++) {
2198 CERTCertificate *cert = slot1->cert_array[i];
2200 if (PK11_FortezzaHasKEA(cert)) {
2201 returnedCert = pk11_GetKEAMate(slot2,cert);
2202 if (returnedCert != NULL) {
2203 *cert2 = returnedCert;
2204 *cert1 = CERT_DupCertificate(cert);
2205 return SECSuccess;
2209 return SECFailure;
2213 * return the private key From a given Cert
2215 CK_OBJECT_HANDLE
2216 PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx)
2218 CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
2219 CK_ATTRIBUTE theTemplate[] = {
2220 { CKA_VALUE, NULL, 0 },
2221 { CKA_CLASS, NULL, 0 }
2223 /* if you change the array, change the variable below as well */
2224 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
2225 CK_ATTRIBUTE *attrs = theTemplate;
2226 SECStatus rv;
2228 PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
2229 cert->derCert.len); attrs++;
2230 PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
2233 * issue the find
2235 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
2236 if (rv != SECSuccess) {
2237 return CK_INVALID_HANDLE;
2240 return pk11_getcerthandle(slot,cert,theTemplate,tsize);
2243 SECItem *
2244 PK11_GetKeyIDFromCert(CERTCertificate *cert, void *wincx)
2246 CK_OBJECT_HANDLE handle;
2247 PK11SlotInfo *slot = NULL;
2248 CK_ATTRIBUTE theTemplate[] = {
2249 { CKA_ID, NULL, 0 },
2251 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
2252 SECItem *item = NULL;
2253 CK_RV crv;
2255 handle = PK11_FindObjectForCert(cert,wincx,&slot);
2256 if (handle == CK_INVALID_HANDLE) {
2257 goto loser;
2260 crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize);
2261 if (crv != CKR_OK) {
2262 PORT_SetError( PK11_MapError(crv) );
2263 goto loser;
2266 item = PORT_ZNew(SECItem);
2267 if (item) {
2268 item->data = (unsigned char*) theTemplate[0].pValue;
2269 item->len = theTemplate[0].ulValueLen;
2272 loser:
2273 PK11_FreeSlot(slot);
2274 return item;
2277 struct listCertsStr {
2278 PK11CertListType type;
2279 CERTCertList *certList;
2282 static PRStatus
2283 pk11ListCertCallback(NSSCertificate *c, void *arg)
2285 struct listCertsStr *listCertP = (struct listCertsStr *)arg;
2286 CERTCertificate *newCert = NULL;
2287 PK11CertListType type = listCertP->type;
2288 CERTCertList *certList = listCertP->certList;
2289 PRBool isUnique = PR_FALSE;
2290 PRBool isCA = PR_FALSE;
2291 char *nickname = NULL;
2292 unsigned int certType;
2294 if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique) ||
2295 (type == PK11CertListCAUnique) || (type == PK11CertListUserUnique) ) {
2296 /* only list one instance of each certificate, even if several exist */
2297 isUnique = PR_TRUE;
2299 if ((type == PK11CertListCA) || (type == PK11CertListRootUnique) ||
2300 (type == PK11CertListCAUnique)) {
2301 isCA = PR_TRUE;
2304 /* if we want user certs and we don't have one skip this cert */
2305 if ( ( (type == PK11CertListUser) || (type == PK11CertListUserUnique) ) &&
2306 !NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) {
2307 return PR_SUCCESS;
2310 /* PK11CertListRootUnique means we want CA certs without a private key.
2311 * This is for legacy app support . PK11CertListCAUnique should be used
2312 * instead to get all CA certs, regardless of private key
2314 if ((type == PK11CertListRootUnique) &&
2315 NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) {
2316 return PR_SUCCESS;
2319 /* caller still owns the reference to 'c' */
2320 newCert = STAN_GetCERTCertificate(c);
2321 if (!newCert) {
2322 return PR_SUCCESS;
2324 /* if we want CA certs and it ain't one, skip it */
2325 if( isCA && (!CERT_IsCACert(newCert, &certType)) ) {
2326 return PR_SUCCESS;
2328 if (isUnique) {
2329 CERT_DupCertificate(newCert);
2331 nickname = STAN_GetCERTCertificateName(certList->arena, c);
2333 /* put slot certs at the end */
2334 if (newCert->slot && !PK11_IsInternal(newCert->slot)) {
2335 CERT_AddCertToListTailWithData(certList,newCert,nickname);
2336 } else {
2337 CERT_AddCertToListHeadWithData(certList,newCert,nickname);
2339 } else {
2340 /* add multiple instances to the cert list */
2341 nssCryptokiObject **ip;
2342 nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
2343 if (!instances) {
2344 return PR_SUCCESS;
2346 for (ip = instances; *ip; ip++) {
2347 nssCryptokiObject *instance = *ip;
2348 PK11SlotInfo *slot = instance->token->pk11slot;
2350 /* put the same CERTCertificate in the list for all instances */
2351 CERT_DupCertificate(newCert);
2353 nickname = STAN_GetCERTCertificateNameForInstance(
2354 certList->arena, c, instance);
2356 /* put slot certs at the end */
2357 if (slot && !PK11_IsInternal(slot)) {
2358 CERT_AddCertToListTailWithData(certList,newCert,nickname);
2359 } else {
2360 CERT_AddCertToListHeadWithData(certList,newCert,nickname);
2363 nssCryptokiObjectArray_Destroy(instances);
2365 return PR_SUCCESS;
2369 CERTCertList *
2370 PK11_ListCerts(PK11CertListType type, void *pwarg)
2372 NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
2373 CERTCertList *certList = NULL;
2374 struct listCertsStr listCerts;
2375 certList = CERT_NewCertList();
2376 listCerts.type = type;
2377 listCerts.certList = certList;
2379 /* authenticate to the slots */
2380 (void) pk11_TraverseAllSlots( NULL, NULL, PR_TRUE, pwarg);
2381 NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback,
2382 &listCerts);
2383 return certList;
2386 SECItem *
2387 PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
2388 CERTCertificate *cert, void *wincx)
2390 CK_ATTRIBUTE theTemplate[] = {
2391 { CKA_VALUE, NULL, 0 },
2392 { CKA_CLASS, NULL, 0 }
2394 /* if you change the array, change the variable below as well */
2395 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
2396 CK_OBJECT_HANDLE certHandle;
2397 CK_ATTRIBUTE *attrs = theTemplate;
2398 PK11SlotInfo *slotRef = NULL;
2399 SECItem *item;
2400 SECStatus rv;
2402 if (slot) {
2403 PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
2404 cert->derCert.len); attrs++;
2406 rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
2407 if (rv != SECSuccess) {
2408 return NULL;
2410 certHandle = pk11_getcerthandle(slot,cert,theTemplate,tsize);
2411 } else {
2412 certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef);
2413 if (certHandle == CK_INVALID_HANDLE) {
2414 return pk11_mkcertKeyID(cert);
2416 slot = slotRef;
2419 if (certHandle == CK_INVALID_HANDLE) {
2420 return NULL;
2423 item = pk11_GetLowLevelKeyFromHandle(slot,certHandle);
2424 if (slotRef) PK11_FreeSlot(slotRef);
2425 return item;
2428 /* argument type for listCertsCallback */
2429 typedef struct {
2430 CERTCertList *list;
2431 PK11SlotInfo *slot;
2432 } ListCertsArg;
2434 static SECStatus
2435 listCertsCallback(CERTCertificate* cert, void*arg)
2437 ListCertsArg *cdata = (ListCertsArg*)arg;
2438 char *nickname = NULL;
2439 nssCryptokiObject *instance, **ci;
2440 nssCryptokiObject **instances;
2441 NSSCertificate *c = STAN_GetNSSCertificate(cert);
2443 if (c == NULL) {
2444 return SECFailure;
2446 instances = nssPKIObject_GetInstances(&c->object);
2447 if (!instances) {
2448 return SECFailure;
2450 instance = NULL;
2451 for (ci = instances; *ci; ci++) {
2452 if ((*ci)->token->pk11slot == cdata->slot) {
2453 instance = *ci;
2454 break;
2457 PORT_Assert(instance != NULL);
2458 if (!instance) {
2459 nssCryptokiObjectArray_Destroy(instances);
2460 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2461 return SECFailure;
2463 nickname = STAN_GetCERTCertificateNameForInstance(cdata->list->arena,
2464 c, instance);
2465 nssCryptokiObjectArray_Destroy(instances);
2467 return CERT_AddCertToListTailWithData(cdata->list,
2468 CERT_DupCertificate(cert),nickname);
2471 CERTCertList *
2472 PK11_ListCertsInSlot(PK11SlotInfo *slot)
2474 SECStatus status;
2475 CERTCertList *certs;
2476 ListCertsArg cdata;
2478 certs = CERT_NewCertList();
2479 if(certs == NULL) return NULL;
2480 cdata.list = certs;
2481 cdata.slot = slot;
2483 status = PK11_TraverseCertsInSlot(slot, listCertsCallback,
2484 &cdata);
2486 if( status != SECSuccess ) {
2487 CERT_DestroyCertList(certs);
2488 certs = NULL;
2491 return certs;
2494 PK11SlotList *
2495 PK11_GetAllSlotsForCert(CERTCertificate *cert, void *arg)
2497 NSSCertificate *c = STAN_GetNSSCertificate(cert);
2498 /* add multiple instances to the cert list */
2499 nssCryptokiObject **ip;
2500 nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
2501 PK11SlotList *slotList;
2502 PRBool found = PR_FALSE;
2504 if (!cert) {
2505 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2506 return NULL;
2509 if (!instances) {
2510 PORT_SetError(SEC_ERROR_NO_TOKEN);
2511 return NULL;
2514 slotList = PK11_NewSlotList();
2515 if (!slotList) {
2516 nssCryptokiObjectArray_Destroy(instances);
2517 return NULL;
2520 for (ip = instances; *ip; ip++) {
2521 nssCryptokiObject *instance = *ip;
2522 PK11SlotInfo *slot = instance->token->pk11slot;
2523 if (slot) {
2524 PK11_AddSlotToList(slotList, slot);
2525 found = PR_TRUE;
2528 if (!found) {
2529 PK11_FreeSlotList(slotList);
2530 PORT_SetError(SEC_ERROR_NO_TOKEN);
2531 slotList = NULL;
2534 nssCryptokiObjectArray_Destroy(instances);
2535 return slotList;