security/nss/lib/pk11wrap/pk11cert.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial