security/nss/lib/pk11wrap/pk11cert.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/pk11wrap/pk11cert.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2691 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +/*
     1.8 + * This file manages PKCS #11 instances of certificates.
     1.9 + */
    1.10 +
    1.11 +#include "secport.h"
    1.12 +#include "seccomon.h"
    1.13 +#include "secmod.h"
    1.14 +#include "secmodi.h"
    1.15 +#include "secmodti.h"
    1.16 +#include "pkcs11.h"
    1.17 +#include "pk11func.h"
    1.18 +#include "cert.h"
    1.19 +#include "certi.h"
    1.20 +#include "secitem.h"
    1.21 +#include "key.h" 
    1.22 +#include "secoid.h"
    1.23 +#include "pkcs7t.h"
    1.24 +#include "cmsreclist.h"
    1.25 +
    1.26 +#include "certdb.h"
    1.27 +#include "secerr.h"
    1.28 +#include "sslerr.h"
    1.29 +
    1.30 +#include "pki3hack.h"
    1.31 +#include "dev3hack.h"
    1.32 +
    1.33 +#include "devm.h" 
    1.34 +#include "nsspki.h"
    1.35 +#include "pki.h"
    1.36 +#include "pkim.h"
    1.37 +#include "pkitm.h"
    1.38 +#include "pkistore.h" /* to remove temp cert */
    1.39 +#include "devt.h"
    1.40 +
    1.41 +extern const NSSError NSS_ERROR_NOT_FOUND;
    1.42 +extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
    1.43 +
    1.44 +struct nss3_cert_cbstr {
    1.45 +    SECStatus(* callback)(CERTCertificate*, void *);
    1.46 +    nssList *cached;
    1.47 +    void *arg;
    1.48 +};
    1.49 +
    1.50 +/* Translate from NSSCertificate to CERTCertificate, then pass the latter
    1.51 + * to a callback.
    1.52 + */
    1.53 +static PRStatus convert_cert(NSSCertificate *c, void *arg)
    1.54 +{
    1.55 +    CERTCertificate *nss3cert;
    1.56 +    SECStatus secrv;
    1.57 +    struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg;
    1.58 +    /* 'c' is not adopted. caller will free it */
    1.59 +    nss3cert = STAN_GetCERTCertificate(c);
    1.60 +    if (!nss3cert) return PR_FAILURE;
    1.61 +    secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg);
    1.62 +    return (secrv) ? PR_FAILURE : PR_SUCCESS;
    1.63 +}
    1.64 +
    1.65 +/*
    1.66 + * build a cert nickname based on the token name and the label of the 
    1.67 + * certificate If the label in NULL, build a label based on the ID.
    1.68 + */
    1.69 +static int toHex(int x) { return (x < 10) ? (x+'0') : (x+'a'-10); }
    1.70 +#define MAX_CERT_ID 4
    1.71 +#define DEFAULT_STRING "Cert ID "
    1.72 +static char *
    1.73 +pk11_buildNickname(PK11SlotInfo *slot,CK_ATTRIBUTE *cert_label,
    1.74 +			CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id)
    1.75 +{
    1.76 +    int prefixLen = PORT_Strlen(slot->token_name);
    1.77 +    int suffixLen = 0;
    1.78 +    char *suffix = NULL;
    1.79 +    char buildNew[sizeof(DEFAULT_STRING)+MAX_CERT_ID*2];
    1.80 +    char *next,*nickname;
    1.81 +
    1.82 +    if (cert_label && (cert_label->ulValueLen)) {
    1.83 +	suffixLen = cert_label->ulValueLen;
    1.84 +	suffix = (char*)cert_label->pValue;
    1.85 +    } else if (key_label && (key_label->ulValueLen)) {
    1.86 +	suffixLen = key_label->ulValueLen;
    1.87 +	suffix = (char*)key_label->pValue;
    1.88 +    } else if (cert_id && cert_id->ulValueLen > 0) {
    1.89 +	int i,first = cert_id->ulValueLen - MAX_CERT_ID;
    1.90 +	int offset = sizeof(DEFAULT_STRING);
    1.91 +	char *idValue = (char *)cert_id->pValue;
    1.92 +
    1.93 +	PORT_Memcpy(buildNew,DEFAULT_STRING,sizeof(DEFAULT_STRING)-1);
    1.94 +	next = buildNew + offset;
    1.95 +	if (first < 0) first = 0;
    1.96 +	for (i=first; i < (int) cert_id->ulValueLen; i++) {
    1.97 +		*next++ = toHex((idValue[i] >> 4) & 0xf);
    1.98 +		*next++ = toHex(idValue[i] & 0xf);
    1.99 +	}
   1.100 +	*next++ = 0;
   1.101 +	suffix = buildNew;
   1.102 +	suffixLen = PORT_Strlen(buildNew);
   1.103 +    } else {
   1.104 +	PORT_SetError( SEC_ERROR_LIBRARY_FAILURE );
   1.105 +	return NULL;
   1.106 +    }
   1.107 +
   1.108 +    /* if is internal key slot, add code to skip the prefix!! */
   1.109 +    next = nickname = (char *)PORT_Alloc(prefixLen+1+suffixLen+1);
   1.110 +    if (nickname == NULL) return NULL;
   1.111 +
   1.112 +    PORT_Memcpy(next,slot->token_name,prefixLen);
   1.113 +    next += prefixLen;
   1.114 +    *next++ = ':';
   1.115 +    PORT_Memcpy(next,suffix,suffixLen);
   1.116 +    next += suffixLen;
   1.117 +    *next++ = 0;
   1.118 +    return nickname;
   1.119 +}
   1.120 +
   1.121 +PRBool
   1.122 +PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert,
   1.123 +						CK_OBJECT_HANDLE certID)
   1.124 +{
   1.125 +    CK_OBJECT_CLASS theClass;
   1.126 +
   1.127 +    if (slot == NULL) return PR_FALSE;
   1.128 +    if (cert == NULL) return PR_FALSE;
   1.129 +
   1.130 +    theClass = CKO_PRIVATE_KEY;
   1.131 +    if (pk11_LoginStillRequired(slot,NULL)) {
   1.132 +	theClass = CKO_PUBLIC_KEY;
   1.133 +    }
   1.134 +    if (PK11_MatchItem(slot, certID , theClass) != CK_INVALID_HANDLE) {
   1.135 +	return PR_TRUE;
   1.136 +    }
   1.137 +
   1.138 +   if (theClass == CKO_PUBLIC_KEY) {
   1.139 +	SECKEYPublicKey *pubKey= CERT_ExtractPublicKey(cert);
   1.140 +	CK_ATTRIBUTE theTemplate;
   1.141 +
   1.142 +	if (pubKey == NULL) {
   1.143 +	   return PR_FALSE;
   1.144 +	}
   1.145 +
   1.146 +	PK11_SETATTRS(&theTemplate,0,NULL,0);
   1.147 +	switch (pubKey->keyType) {
   1.148 +	case rsaKey:
   1.149 +	    PK11_SETATTRS(&theTemplate,CKA_MODULUS, pubKey->u.rsa.modulus.data,
   1.150 +						pubKey->u.rsa.modulus.len);
   1.151 +	    break;
   1.152 +	case dsaKey:
   1.153 +	    PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dsa.publicValue.data,
   1.154 +						pubKey->u.dsa.publicValue.len);
   1.155 +	    break;
   1.156 +	case dhKey:
   1.157 +	    PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dh.publicValue.data,
   1.158 +						pubKey->u.dh.publicValue.len);
   1.159 +	    break;
   1.160 +	case ecKey:
   1.161 +	    PK11_SETATTRS(&theTemplate,CKA_EC_POINT, 
   1.162 +			  pubKey->u.ec.publicValue.data,
   1.163 +			  pubKey->u.ec.publicValue.len);
   1.164 +	    break;
   1.165 +	case keaKey:
   1.166 +	case fortezzaKey:
   1.167 +	case nullKey:
   1.168 +	    /* fall through and return false */
   1.169 +	    break;
   1.170 +	}
   1.171 +
   1.172 +	if (theTemplate.ulValueLen == 0) {
   1.173 +	    SECKEY_DestroyPublicKey(pubKey);
   1.174 +	    return PR_FALSE;
   1.175 +	}
   1.176 +	pk11_SignedToUnsigned(&theTemplate);
   1.177 +	if (pk11_FindObjectByTemplate(slot,&theTemplate,1) != CK_INVALID_HANDLE) {
   1.178 +	    SECKEY_DestroyPublicKey(pubKey);
   1.179 +	    return PR_TRUE;
   1.180 +	}
   1.181 +	SECKEY_DestroyPublicKey(pubKey);
   1.182 +    }
   1.183 +    return PR_FALSE;
   1.184 +}
   1.185 +
   1.186 +/*
   1.187 + * Check out if a cert has ID of zero. This is a magic ID that tells
   1.188 + * NSS that this cert may be an automagically trusted cert.
   1.189 + * The Cert has to be self signed as well. That check is done elsewhere.
   1.190 + *  
   1.191 + */
   1.192 +PRBool
   1.193 +pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID)
   1.194 +{
   1.195 +    CK_ATTRIBUTE keyID = {CKA_ID, NULL, 0};
   1.196 +    PRBool isZero = PR_FALSE;
   1.197 +    int i;
   1.198 +    CK_RV crv;
   1.199 +
   1.200 +
   1.201 +    crv = PK11_GetAttributes(NULL,slot,certID,&keyID,1);
   1.202 +    if (crv != CKR_OK) {
   1.203 +	return isZero;
   1.204 +    }
   1.205 +
   1.206 +    if (keyID.ulValueLen != 0) {
   1.207 +	char *value = (char *)keyID.pValue;
   1.208 +	isZero = PR_TRUE; /* ID exists, may be zero */
   1.209 +	for (i=0; i < (int) keyID.ulValueLen; i++) {
   1.210 +	    if (value[i] != 0) {
   1.211 +		isZero = PR_FALSE; /* nope */
   1.212 +		break;
   1.213 +	    }
   1.214 +	}
   1.215 +    }
   1.216 +    PORT_Free(keyID.pValue);
   1.217 +    return isZero;
   1.218 +
   1.219 +}
   1.220 +
   1.221 +/*
   1.222 + * Create an NSSCertificate from a slot/certID pair, return it as a
   1.223 + * CERTCertificate.  Optionally, output the nickname string.
   1.224 + */
   1.225 +static CERTCertificate *
   1.226 +pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, 
   1.227 +	      CK_ATTRIBUTE *privateLabel, char **nickptr)
   1.228 +{
   1.229 +    NSSCertificate *c;
   1.230 +    nssCryptokiObject *co = NULL;
   1.231 +    nssPKIObject *pkio;
   1.232 +    NSSToken *token;
   1.233 +    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
   1.234 +    PRStatus status;
   1.235 +
   1.236 +    /* Get the cryptoki object from the handle */
   1.237 +    token = PK11Slot_GetNSSToken(slot);
   1.238 +    if (token->defaultSession) {
   1.239 +	co = nssCryptokiObject_Create(token, token->defaultSession, certID);
   1.240 +    } else {
   1.241 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
   1.242 +    }
   1.243 +    if (!co) {
   1.244 +	return NULL;
   1.245 +    }
   1.246 +
   1.247 +    /* Create a PKI object from the cryptoki instance */
   1.248 +    pkio = nssPKIObject_Create(NULL, co, td, NULL, nssPKIMonitor);
   1.249 +    if (!pkio) {
   1.250 +	nssCryptokiObject_Destroy(co);
   1.251 +	return NULL;
   1.252 +    }
   1.253 +
   1.254 +    /* Create a certificate */
   1.255 +    c = nssCertificate_Create(pkio);
   1.256 +    if (!c) {
   1.257 +	nssPKIObject_Destroy(pkio);
   1.258 +	return NULL;
   1.259 +    }
   1.260 +
   1.261 +    /* Build and output a nickname, if desired. 
   1.262 +     * This must be done before calling nssTrustDomain_AddCertsToCache
   1.263 +     * because that function may destroy c, pkio and co!
   1.264 +     */
   1.265 +    if ((nickptr) && (co->label)) {
   1.266 +	CK_ATTRIBUTE label, id;
   1.267 +
   1.268 +	label.type = CKA_LABEL;
   1.269 +	label.pValue = co->label;
   1.270 +	label.ulValueLen = PORT_Strlen(co->label);
   1.271 +
   1.272 +	id.type = CKA_ID;
   1.273 +	id.pValue = c->id.data;
   1.274 +	id.ulValueLen = c->id.size;
   1.275 +
   1.276 +	*nickptr = pk11_buildNickname(slot, &label, privateLabel, &id);
   1.277 +    }
   1.278 +
   1.279 +    /* This function may destroy the cert in "c" and all its subordinate
   1.280 +     * structures, and replace the value in "c" with the address of a 
   1.281 +     * different NSSCertificate that it found in the cache.
   1.282 +     * Presumably, the nickname which we just output above remains valid. :)
   1.283 +     */
   1.284 +    status = nssTrustDomain_AddCertsToCache(td, &c, 1);
   1.285 +    return STAN_GetCERTCertificateOrRelease(c);
   1.286 +}
   1.287 +
   1.288 +/*
   1.289 + * Build an CERTCertificate structure from a PKCS#11 object ID.... certID
   1.290 + * Must be a CertObject. This code does not explicitly checks that.
   1.291 + */
   1.292 +CERTCertificate *
   1.293 +PK11_MakeCertFromHandle(PK11SlotInfo *slot,CK_OBJECT_HANDLE certID,
   1.294 +						CK_ATTRIBUTE *privateLabel)
   1.295 +{
   1.296 +    char * nickname = NULL;
   1.297 +    CERTCertificate *cert = NULL;
   1.298 +    CERTCertTrust *trust;
   1.299 +    PRBool isFortezzaRootCA = PR_FALSE;
   1.300 +    PRBool swapNickname = PR_FALSE;
   1.301 +
   1.302 +    cert = pk11_fastCert(slot,certID,privateLabel, &nickname);
   1.303 +    if (cert == NULL) 
   1.304 +    	goto loser;
   1.305 +	
   1.306 +    if (nickname) {
   1.307 +	if (cert->nickname != NULL) {
   1.308 +	    cert->dbnickname = cert->nickname;
   1.309 +	} 
   1.310 +	cert->nickname = PORT_ArenaStrdup(cert->arena,nickname);
   1.311 +	PORT_Free(nickname);
   1.312 +	nickname = NULL;
   1.313 +	swapNickname = PR_TRUE;
   1.314 +    }
   1.315 +
   1.316 +    /* remember where this cert came from.... If we have just looked
   1.317 +     * it up from the database and it already has a slot, don't add a new
   1.318 +     * one. */
   1.319 +    if (cert->slot == NULL) {
   1.320 +	cert->slot = PK11_ReferenceSlot(slot);
   1.321 +	cert->pkcs11ID = certID;
   1.322 +	cert->ownSlot = PR_TRUE;
   1.323 +	cert->series = slot->series;
   1.324 +    }
   1.325 +
   1.326 +    trust = (CERTCertTrust*)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust));
   1.327 +    if (trust == NULL) 
   1.328 +    	goto loser;
   1.329 +    PORT_Memset(trust,0, sizeof(CERTCertTrust));
   1.330 +
   1.331 +    if(! pk11_HandleTrustObject(slot, cert, trust) ) {
   1.332 +	unsigned int type;
   1.333 +
   1.334 +	/* build some cert trust flags */
   1.335 +	if (CERT_IsCACert(cert, &type)) {
   1.336 +	    unsigned int trustflags = CERTDB_VALID_CA;
   1.337 +	   
   1.338 +	    /* Allow PKCS #11 modules to give us trusted CA's. We only accept
   1.339 +	     * valid CA's which are self-signed here. They must have an object
   1.340 +	     * ID of '0'.  */ 
   1.341 +	    if (pk11_isID0(slot,certID) && 
   1.342 +		cert->isRoot) {
   1.343 +		trustflags |= CERTDB_TRUSTED_CA;
   1.344 +		/* is the slot a fortezza card? allow the user or
   1.345 +		 * admin to turn on objectSigning, but don't turn
   1.346 +		 * full trust on explicitly */
   1.347 +		if (PK11_DoesMechanism(slot,CKM_KEA_KEY_DERIVE)) {
   1.348 +		    trust->objectSigningFlags |= CERTDB_VALID_CA;
   1.349 +		    isFortezzaRootCA = PR_TRUE;
   1.350 +		}
   1.351 +	    }
   1.352 +	    if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
   1.353 +		trust->sslFlags |= trustflags;
   1.354 +	    }
   1.355 +	    if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) {
   1.356 +		trust->emailFlags |= trustflags;
   1.357 +	    }
   1.358 +	    if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA) 
   1.359 +					== NS_CERT_TYPE_OBJECT_SIGNING_CA) {
   1.360 +		trust->objectSigningFlags |= trustflags;
   1.361 +	    }
   1.362 +	}
   1.363 +    }
   1.364 +
   1.365 +    if (PK11_IsUserCert(slot,cert,certID)) {
   1.366 +	trust->sslFlags |= CERTDB_USER;
   1.367 +	trust->emailFlags |= CERTDB_USER;
   1.368 +	/*    trust->objectSigningFlags |= CERTDB_USER; */
   1.369 +    }
   1.370 +    CERT_LockCertTrust(cert);
   1.371 +    cert->trust = trust;
   1.372 +    CERT_UnlockCertTrust(cert);
   1.373 +
   1.374 +    return cert;
   1.375 +
   1.376 +loser:
   1.377 +    if (nickname) 
   1.378 +    	PORT_Free(nickname);
   1.379 +    if (cert) 
   1.380 +    	CERT_DestroyCertificate(cert);
   1.381 +    return NULL;
   1.382 +}
   1.383 +
   1.384 +	
   1.385 +/*
   1.386 + * Build get a certificate from a private key
   1.387 + */
   1.388 +CERTCertificate *
   1.389 +PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey)
   1.390 +{
   1.391 +    PK11SlotInfo *slot = privKey->pkcs11Slot;
   1.392 +    CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
   1.393 +    CK_OBJECT_HANDLE certID = 
   1.394 +		PK11_MatchItem(slot,handle,CKO_CERTIFICATE);
   1.395 +    CERTCertificate *cert;
   1.396 +
   1.397 +    if (certID == CK_INVALID_HANDLE) {
   1.398 +	PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
   1.399 +	return NULL;
   1.400 +    }
   1.401 +    cert = PK11_MakeCertFromHandle(slot,certID,NULL);
   1.402 +    return (cert);
   1.403 +
   1.404 +}
   1.405 +
   1.406 +/*
   1.407 + * delete a cert and it's private key (if no other certs are pointing to the
   1.408 + * private key.
   1.409 + */
   1.410 +SECStatus
   1.411 +PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx)
   1.412 +{
   1.413 +    SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert,wincx);
   1.414 +    CK_OBJECT_HANDLE pubKey;
   1.415 +    PK11SlotInfo *slot = NULL;
   1.416 +
   1.417 +    pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx);
   1.418 +    if (privKey) {
   1.419 +	/* For 3.4, utilize the generic cert delete function */
   1.420 +	SEC_DeletePermCertificate(cert);
   1.421 +	PK11_DeleteTokenPrivateKey(privKey, PR_FALSE);
   1.422 +    }
   1.423 +    if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) { 
   1.424 +    	PK11_DestroyTokenObject(slot,pubKey);
   1.425 +        PK11_FreeSlot(slot);
   1.426 +    }
   1.427 +    return SECSuccess;
   1.428 +}
   1.429 +
   1.430 +/*
   1.431 + * cert callback structure
   1.432 + */
   1.433 +typedef struct pk11DoCertCallbackStr {
   1.434 +	SECStatus(* callback)(PK11SlotInfo *slot, CERTCertificate*, void *);
   1.435 +	SECStatus(* noslotcallback)(CERTCertificate*, void *);
   1.436 +	SECStatus(* itemcallback)(CERTCertificate*, SECItem *, void *);
   1.437 +	void *callbackArg;
   1.438 +} pk11DoCertCallback;
   1.439 +
   1.440 +
   1.441 +typedef struct pk11CertCallbackStr {
   1.442 +	SECStatus(* callback)(CERTCertificate*,SECItem *,void *);
   1.443 +	void *callbackArg;
   1.444 +} pk11CertCallback;
   1.445 +
   1.446 +struct fake_der_cb_argstr
   1.447 +{
   1.448 +    SECStatus(* callback)(CERTCertificate*, SECItem *, void *);
   1.449 +    void *arg;
   1.450 +};
   1.451 +
   1.452 +static SECStatus fake_der_cb(CERTCertificate *c, void *a)
   1.453 +{
   1.454 +    struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a;
   1.455 +    return (*fda->callback)(c, &c->derCert, fda->arg);
   1.456 +}
   1.457 +
   1.458 +/*
   1.459 + * Extract all the certs on a card from a slot.
   1.460 + */
   1.461 +SECStatus
   1.462 +PK11_TraverseSlotCerts(SECStatus(* callback)(CERTCertificate*,SECItem *,void *),
   1.463 +						void *arg, void *wincx) 
   1.464 +{
   1.465 +    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
   1.466 +    struct fake_der_cb_argstr fda;
   1.467 +    struct nss3_cert_cbstr pk11cb;
   1.468 +
   1.469 +    /* authenticate to the tokens first */
   1.470 +    (void) pk11_TraverseAllSlots( NULL, NULL, PR_TRUE, wincx);
   1.471 +
   1.472 +    fda.callback = callback;
   1.473 +    fda.arg = arg;
   1.474 +    pk11cb.callback = fake_der_cb;
   1.475 +    pk11cb.arg = &fda;
   1.476 +    NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
   1.477 +    return SECSuccess;
   1.478 +}
   1.479 +
   1.480 +static void
   1.481 +transfer_token_certs_to_collection(nssList *certList, NSSToken *token, 
   1.482 +                                   nssPKIObjectCollection *collection)
   1.483 +{
   1.484 +    NSSCertificate **certs;
   1.485 +    PRUint32 i, count;
   1.486 +    NSSToken **tokens, **tp;
   1.487 +    count = nssList_Count(certList);
   1.488 +    if (count == 0) {
   1.489 +	return;
   1.490 +    }
   1.491 +    certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
   1.492 +    if (!certs) {
   1.493 +	return;
   1.494 +    }
   1.495 +    nssList_GetArray(certList, (void **)certs, count);
   1.496 +    for (i=0; i<count; i++) {
   1.497 +	tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
   1.498 +	if (tokens) {
   1.499 +	    for (tp = tokens; *tp; tp++) {
   1.500 +		if (*tp == token) {
   1.501 +		    nssPKIObjectCollection_AddObject(collection, 
   1.502 +		                                     (nssPKIObject *)certs[i]);
   1.503 +		}
   1.504 +	    }
   1.505 +	    nssTokenArray_Destroy(tokens);
   1.506 +	}
   1.507 +	CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i]));
   1.508 +    }
   1.509 +    nss_ZFreeIf(certs);
   1.510 +}
   1.511 +
   1.512 +CERTCertificate *
   1.513 +PK11_FindCertFromNickname(const char *nickname, void *wincx) 
   1.514 +{
   1.515 +    PRStatus status;
   1.516 +    CERTCertificate *rvCert = NULL;
   1.517 +    NSSCertificate *cert = NULL;
   1.518 +    NSSCertificate **certs = NULL;
   1.519 +    static const NSSUsage usage = {PR_TRUE /* ... */ };
   1.520 +    NSSToken *token;
   1.521 +    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
   1.522 +    PK11SlotInfo *slot = NULL;
   1.523 +    SECStatus rv;
   1.524 +    char *nickCopy;
   1.525 +    char *delimit = NULL;
   1.526 +    char *tokenName;
   1.527 +
   1.528 +    nickCopy = PORT_Strdup(nickname);
   1.529 +    if (!nickCopy) {
   1.530 +        /* error code is set */
   1.531 +        return NULL;
   1.532 +    }
   1.533 +    if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
   1.534 +	tokenName = nickCopy;
   1.535 +	nickname = delimit + 1;
   1.536 +	*delimit = '\0';
   1.537 +	/* find token by name */
   1.538 +	token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
   1.539 +	if (token) {
   1.540 +	    slot = PK11_ReferenceSlot(token->pk11slot);
   1.541 +	} else {
   1.542 +	    PORT_SetError(SEC_ERROR_NO_TOKEN);
   1.543 +	}
   1.544 +	*delimit = ':';
   1.545 +    } else {
   1.546 +	slot = PK11_GetInternalKeySlot();
   1.547 +	token = PK11Slot_GetNSSToken(slot);
   1.548 +    }
   1.549 +    if (token) {
   1.550 +	nssList *certList;
   1.551 +	nssCryptokiObject **instances;
   1.552 +	nssPKIObjectCollection *collection;
   1.553 +	nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
   1.554 +	if (!PK11_IsPresent(slot)) {
   1.555 +	    goto loser;
   1.556 +	}
   1.557 +   	rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
   1.558 +	if (rv != SECSuccess) {
   1.559 +	    goto loser;
   1.560 +	}
   1.561 +	collection = nssCertificateCollection_Create(defaultTD, NULL);
   1.562 +	if (!collection) {
   1.563 +	    goto loser;
   1.564 +	}
   1.565 +	certList = nssList_Create(NULL, PR_FALSE);
   1.566 +	if (!certList) {
   1.567 +	    nssPKIObjectCollection_Destroy(collection);
   1.568 +	    goto loser;
   1.569 +	}
   1.570 +	(void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, 
   1.571 +	                                                  nickname, 
   1.572 +	                                                  certList);
   1.573 +	transfer_token_certs_to_collection(certList, token, collection);
   1.574 +	instances = nssToken_FindCertificatesByNickname(token,
   1.575 +	                                                NULL,
   1.576 +	                                                nickname,
   1.577 +	                                                tokenOnly,
   1.578 +	                                                0,
   1.579 +	                                                &status);
   1.580 +	nssPKIObjectCollection_AddInstances(collection, instances, 0);
   1.581 +	nss_ZFreeIf(instances);
   1.582 +	/* if it wasn't found, repeat the process for email address */
   1.583 +	if (nssPKIObjectCollection_Count(collection) == 0 &&
   1.584 +	    PORT_Strchr(nickname, '@') != NULL) 
   1.585 +	{
   1.586 +	    char* lowercaseName = CERT_FixupEmailAddr(nickname);
   1.587 +	    if (lowercaseName) {
   1.588 +		(void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD, 
   1.589 +								      lowercaseName, 
   1.590 +								      certList);
   1.591 +		transfer_token_certs_to_collection(certList, token, collection);
   1.592 +		instances = nssToken_FindCertificatesByEmail(token,
   1.593 +							     NULL,
   1.594 +							     lowercaseName,
   1.595 +							     tokenOnly,
   1.596 +							     0,
   1.597 +							     &status);
   1.598 +		nssPKIObjectCollection_AddInstances(collection, instances, 0);
   1.599 +		nss_ZFreeIf(instances);
   1.600 +		PORT_Free(lowercaseName);
   1.601 +	    }
   1.602 +	}
   1.603 +	certs = nssPKIObjectCollection_GetCertificates(collection, 
   1.604 +	                                               NULL, 0, NULL);
   1.605 +	nssPKIObjectCollection_Destroy(collection);
   1.606 +	if (certs) {
   1.607 +	    cert = nssCertificateArray_FindBestCertificate(certs, NULL, 
   1.608 +	                                                   &usage, NULL);
   1.609 +	    if (cert) {
   1.610 +		rvCert = STAN_GetCERTCertificateOrRelease(cert);
   1.611 +	    }
   1.612 +	    nssCertificateArray_Destroy(certs);
   1.613 +	}
   1.614 +	nssList_Destroy(certList);
   1.615 +    }
   1.616 +    if (slot) {
   1.617 +	PK11_FreeSlot(slot);
   1.618 +    }
   1.619 +    if (nickCopy) PORT_Free(nickCopy);
   1.620 +    return rvCert;
   1.621 +loser:
   1.622 +    if (slot) {
   1.623 +	PK11_FreeSlot(slot);
   1.624 +    }
   1.625 +    if (nickCopy) PORT_Free(nickCopy);
   1.626 +    return NULL;
   1.627 +}
   1.628 +
   1.629 +/* Traverse slots callback */
   1.630 +typedef struct FindCertsEmailArgStr {
   1.631 +    char         *email;
   1.632 +    CERTCertList *certList;
   1.633 +} FindCertsEmailArg;
   1.634 +
   1.635 +SECStatus 
   1.636 +FindCertsEmailCallback(CERTCertificate *cert, SECItem *item, void *arg)
   1.637 +{
   1.638 +    FindCertsEmailArg *cbparam = (FindCertsEmailArg *) arg;	
   1.639 +    const char *cert_email = CERT_GetFirstEmailAddress(cert);
   1.640 +    PRBool found = PR_FALSE;
   1.641 +
   1.642 +    /* Email address present in certificate? */
   1.643 +    if (cert_email == NULL){
   1.644 +	return SECSuccess;
   1.645 +    }
   1.646 + 
   1.647 +    /* Parameter correctly set? */
   1.648 +    if (cbparam->email == NULL) {
   1.649 +	return SECFailure;
   1.650 +    }
   1.651 +
   1.652 +    /* Loop over all email addresses */
   1.653 +    do {
   1.654 +	if (!strcmp(cert_email, cbparam->email)) {
   1.655 +	    /* found one matching email address */
   1.656 +	    PRTime now = PR_Now();
   1.657 +	    found = PR_TRUE;
   1.658 +	    CERT_AddCertToListSorted(cbparam->certList, 
   1.659 +	                             CERT_DupCertificate(cert),
   1.660 +			             CERT_SortCBValidity, &now);
   1.661 +	}
   1.662 +	cert_email = CERT_GetNextEmailAddress(cert, cert_email);
   1.663 +    } while (cert_email && !found);   
   1.664 +
   1.665 +    return SECSuccess;
   1.666 +}
   1.667 +
   1.668 +/* Find all certificates with matching email address */
   1.669 +CERTCertList *
   1.670 +PK11_FindCertsFromEmailAddress(const char *email, void *wincx) 
   1.671 +{
   1.672 +    FindCertsEmailArg cbparam;
   1.673 +    SECStatus rv;
   1.674 +
   1.675 +    cbparam.certList = CERT_NewCertList();
   1.676 +    if (cbparam.certList == NULL) {
   1.677 +	return NULL;
   1.678 +    }
   1.679 +
   1.680 +    cbparam.email = CERT_FixupEmailAddr(email);
   1.681 +    if (cbparam.email == NULL) {
   1.682 +	CERT_DestroyCertList(cbparam.certList);
   1.683 +	return NULL;
   1.684 +    }
   1.685 +
   1.686 +    rv = PK11_TraverseSlotCerts(FindCertsEmailCallback, &cbparam, NULL); 	
   1.687 +    if (rv != SECSuccess) {
   1.688 +	CERT_DestroyCertList(cbparam.certList);
   1.689 +	PORT_Free(cbparam.email);
   1.690 +	return NULL;
   1.691 +    }
   1.692 +
   1.693 +    /* empty list? */
   1.694 +    if (CERT_LIST_HEAD(cbparam.certList) == NULL || 
   1.695 +        CERT_LIST_END(CERT_LIST_HEAD(cbparam.certList), cbparam.certList)) {
   1.696 +	CERT_DestroyCertList(cbparam.certList);
   1.697 +	cbparam.certList = NULL;
   1.698 +    }
   1.699 +
   1.700 +    PORT_Free(cbparam.email);
   1.701 +    return cbparam.certList;
   1.702 +}
   1.703 +
   1.704 +
   1.705 +CERTCertList *
   1.706 +PK11_FindCertsFromNickname(const char *nickname, void *wincx) 
   1.707 +{
   1.708 +    char *nickCopy;
   1.709 +    char *delimit = NULL;
   1.710 +    char *tokenName;
   1.711 +    int i;
   1.712 +    CERTCertList *certList = NULL;
   1.713 +    nssPKIObjectCollection *collection = NULL;
   1.714 +    NSSCertificate **foundCerts = NULL;
   1.715 +    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
   1.716 +    NSSCertificate *c;
   1.717 +    NSSToken *token;
   1.718 +    PK11SlotInfo *slot;
   1.719 +    SECStatus rv;
   1.720 +
   1.721 +    nickCopy = PORT_Strdup(nickname);
   1.722 +    if (!nickCopy) {
   1.723 +        /* error code is set */
   1.724 +        return NULL;
   1.725 +    }
   1.726 +    if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
   1.727 +	tokenName = nickCopy;
   1.728 +	nickname = delimit + 1;
   1.729 +	*delimit = '\0';
   1.730 +	/* find token by name */
   1.731 +	token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
   1.732 +	if (token) {
   1.733 +	    slot = PK11_ReferenceSlot(token->pk11slot);
   1.734 +	} else {
   1.735 +	    PORT_SetError(SEC_ERROR_NO_TOKEN);
   1.736 +	    slot = NULL;
   1.737 +	}
   1.738 +	*delimit = ':';
   1.739 +    } else {
   1.740 +	slot = PK11_GetInternalKeySlot();
   1.741 +	token = PK11Slot_GetNSSToken(slot);
   1.742 +    }
   1.743 +    if (token) {
   1.744 +	PRStatus status;
   1.745 +	nssList *nameList;
   1.746 +	nssCryptokiObject **instances;
   1.747 +	nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
   1.748 +   	rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
   1.749 +	if (rv != SECSuccess) {
   1.750 +	    PK11_FreeSlot(slot);
   1.751 +    	    if (nickCopy) PORT_Free(nickCopy);
   1.752 +	    return NULL;
   1.753 +	}
   1.754 +	collection = nssCertificateCollection_Create(defaultTD, NULL);
   1.755 +	if (!collection) {
   1.756 +	    PK11_FreeSlot(slot);
   1.757 +	    if (nickCopy) PORT_Free(nickCopy);
   1.758 +	    return NULL;
   1.759 +	}
   1.760 +	nameList = nssList_Create(NULL, PR_FALSE);
   1.761 +	if (!nameList) {
   1.762 +	    PK11_FreeSlot(slot);
   1.763 +	    if (nickCopy) PORT_Free(nickCopy);
   1.764 +	    return NULL;
   1.765 +	}
   1.766 +	(void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
   1.767 +	                                                  nickname, 
   1.768 +	                                                  nameList);
   1.769 +	transfer_token_certs_to_collection(nameList, token, collection);
   1.770 +	instances = nssToken_FindCertificatesByNickname(token,
   1.771 +	                                                NULL,
   1.772 +	                                                nickname,
   1.773 +	                                                tokenOnly,
   1.774 +	                                                0,
   1.775 +	                                                &status);
   1.776 +	nssPKIObjectCollection_AddInstances(collection, instances, 0);
   1.777 +	nss_ZFreeIf(instances);
   1.778 +
   1.779 +        /* if it wasn't found, repeat the process for email address */
   1.780 +        if (nssPKIObjectCollection_Count(collection) == 0 &&
   1.781 +            PORT_Strchr(nickname, '@') != NULL) 
   1.782 +        {
   1.783 +            char* lowercaseName = CERT_FixupEmailAddr(nickname);
   1.784 +            if (lowercaseName) {
   1.785 +                (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD, 
   1.786 +                                                                      lowercaseName, 
   1.787 +                                                                      nameList);
   1.788 +                transfer_token_certs_to_collection(nameList, token, collection);
   1.789 +                instances = nssToken_FindCertificatesByEmail(token,
   1.790 +                                                             NULL,
   1.791 +                                                             lowercaseName,
   1.792 +                                                             tokenOnly,
   1.793 +                                                             0,
   1.794 +                                                             &status);
   1.795 +                nssPKIObjectCollection_AddInstances(collection, instances, 0);
   1.796 +                nss_ZFreeIf(instances);
   1.797 +                PORT_Free(lowercaseName);
   1.798 +            }
   1.799 +        }
   1.800 +
   1.801 +        nssList_Destroy(nameList);
   1.802 +	foundCerts = nssPKIObjectCollection_GetCertificates(collection,
   1.803 +	                                                    NULL, 0, NULL);
   1.804 +	nssPKIObjectCollection_Destroy(collection);
   1.805 +    }
   1.806 +    if (slot) {
   1.807 +	PK11_FreeSlot(slot);
   1.808 +    }
   1.809 +    if (nickCopy) PORT_Free(nickCopy);
   1.810 +    if (foundCerts) {
   1.811 +	PRTime now = PR_Now();
   1.812 +	certList = CERT_NewCertList();
   1.813 +	for (i=0, c = *foundCerts; c; c = foundCerts[++i]) {
   1.814 +	    if (certList) {
   1.815 +	 	CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c);
   1.816 +		/* c may be invalid after this, don't reference it */
   1.817 +		if (certCert) {
   1.818 +		    /* CERT_AddCertToListSorted adopts certCert  */
   1.819 +		    CERT_AddCertToListSorted(certList, certCert,
   1.820 +				CERT_SortCBValidity, &now);
   1.821 +		}
   1.822 +	    } else {
   1.823 +		nssCertificate_Destroy(c);
   1.824 +	    }
   1.825 +	}
   1.826 +	if (certList && CERT_LIST_HEAD(certList) == NULL) {
   1.827 +	    CERT_DestroyCertList(certList);
   1.828 +	    certList = NULL;
   1.829 +	}
   1.830 +	/* all the certs have been adopted or freed, free the  raw array */
   1.831 +	nss_ZFreeIf(foundCerts);
   1.832 +    }
   1.833 +    return certList;
   1.834 +}
   1.835 +
   1.836 +/*
   1.837 + * extract a key ID for a certificate...
   1.838 + * NOTE: We call this function from PKCS11.c If we ever use
   1.839 + * pkcs11 to extract the public key (we currently do not), this will break.
   1.840 + */
   1.841 +SECItem *
   1.842 +PK11_GetPubIndexKeyID(CERTCertificate *cert) 
   1.843 +{
   1.844 +    SECKEYPublicKey *pubk;
   1.845 +    SECItem *newItem = NULL;
   1.846 +
   1.847 +    pubk = CERT_ExtractPublicKey(cert);
   1.848 +    if (pubk == NULL) return NULL;
   1.849 +
   1.850 +    switch (pubk->keyType) {
   1.851 +    case rsaKey:
   1.852 +	newItem = SECITEM_DupItem(&pubk->u.rsa.modulus);
   1.853 +	break;
   1.854 +    case dsaKey:
   1.855 +        newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue);
   1.856 +	break;
   1.857 +    case dhKey:
   1.858 +        newItem = SECITEM_DupItem(&pubk->u.dh.publicValue);
   1.859 +	break;
   1.860 +    case ecKey:
   1.861 +        newItem = SECITEM_DupItem(&pubk->u.ec.publicValue);
   1.862 +	break;
   1.863 +    case fortezzaKey:
   1.864 +    default:
   1.865 +	newItem = NULL; /* Fortezza Fix later... */
   1.866 +    }
   1.867 +    SECKEY_DestroyPublicKey(pubk);
   1.868 +    /* make hash of it */
   1.869 +    return newItem;
   1.870 +}
   1.871 +
   1.872 +/*
   1.873 + * generate a CKA_ID from a certificate.
   1.874 + */
   1.875 +SECItem *
   1.876 +pk11_mkcertKeyID(CERTCertificate *cert) 
   1.877 +{
   1.878 +    SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert) ;
   1.879 +    SECItem *certCKA_ID;
   1.880 +
   1.881 +    if (pubKeyData == NULL) return NULL;
   1.882 +    
   1.883 +    certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData);
   1.884 +    SECITEM_FreeItem(pubKeyData,PR_TRUE);
   1.885 +    return certCKA_ID;
   1.886 +}
   1.887 +
   1.888 +/*
   1.889 + * Write the cert into the token.
   1.890 + */
   1.891 +SECStatus
   1.892 +PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, 
   1.893 +		CK_OBJECT_HANDLE key, const char *nickname, 
   1.894 +                PRBool includeTrust) 
   1.895 +{
   1.896 +    PRStatus status;
   1.897 +    NSSCertificate *c;
   1.898 +    nssCryptokiObject *keyobj, *certobj;
   1.899 +    NSSToken *token = PK11Slot_GetNSSToken(slot);
   1.900 +    SECItem *keyID = pk11_mkcertKeyID(cert);
   1.901 +    char *emailAddr = NULL;
   1.902 +    nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
   1.903 +    nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
   1.904 +
   1.905 +    if (keyID == NULL) {
   1.906 +	goto loser; /* error code should be set already */
   1.907 +    }
   1.908 +    if (!token) {
   1.909 +    	PORT_SetError(SEC_ERROR_NO_TOKEN);
   1.910 +	goto loser;
   1.911 +    }
   1.912 +
   1.913 +    if (PK11_IsInternal(slot) && cert->emailAddr && cert->emailAddr[0]) {
   1.914 +	emailAddr = cert->emailAddr;
   1.915 +    }
   1.916 +
   1.917 +    /* need to get the cert as a stan cert */
   1.918 +    if (cert->nssCertificate) {
   1.919 +	c = cert->nssCertificate;
   1.920 +    } else {
   1.921 +	c = STAN_GetNSSCertificate(cert);
   1.922 +	if (c == NULL) {
   1.923 +	    goto loser;
   1.924 +	}
   1.925 +    }
   1.926 +
   1.927 +    /* set the id for the cert */
   1.928 +    nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
   1.929 +    if (!c->id.data) {
   1.930 +	goto loser;
   1.931 +    }
   1.932 +
   1.933 +    if (key != CK_INVALID_HANDLE) {
   1.934 +	/* create an object for the key, ... */
   1.935 +	keyobj = nss_ZNEW(NULL, nssCryptokiObject);
   1.936 +	if (!keyobj) {
   1.937 +	    goto loser;
   1.938 +	}
   1.939 +	keyobj->token = nssToken_AddRef(token);
   1.940 +	keyobj->handle = key;
   1.941 +	keyobj->isTokenObject = PR_TRUE;
   1.942 +
   1.943 +	/* ... in order to set matching attributes for the key */
   1.944 +	status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname, 
   1.945 +	                                              &c->id, &c->subject);
   1.946 +	nssCryptokiObject_Destroy(keyobj);
   1.947 +	if (status != PR_SUCCESS) {
   1.948 +	    goto loser;
   1.949 +	}
   1.950 +    }
   1.951 +
   1.952 +    /* do the token import */
   1.953 +    certobj = nssToken_ImportCertificate(token, NULL,
   1.954 +                                         NSSCertificateType_PKIX,
   1.955 +                                         &c->id,
   1.956 +                                         nickname,
   1.957 +                                         &c->encoding,
   1.958 +                                         &c->issuer,
   1.959 +                                         &c->subject,
   1.960 +                                         &c->serial,
   1.961 +					 emailAddr,
   1.962 +                                         PR_TRUE);
   1.963 +    if (!certobj) {
   1.964 +	if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
   1.965 +	    PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
   1.966 +	    SECITEM_FreeItem(keyID,PR_TRUE);
   1.967 +	    return SECFailure;
   1.968 +	}
   1.969 +	goto loser;
   1.970 +    }
   1.971 +
   1.972 +    if (c->object.cryptoContext) {
   1.973 +	/* Delete the temp instance */
   1.974 +	NSSCryptoContext *cc = c->object.cryptoContext;
   1.975 +	nssCertificateStore_Lock(cc->certStore, &lockTrace);
   1.976 +	nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
   1.977 +	nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace);
   1.978 +	c->object.cryptoContext = NULL;
   1.979 +	cert->istemp = PR_FALSE;
   1.980 +	cert->isperm = PR_TRUE;
   1.981 +    }
   1.982 +
   1.983 +    /* add the new instance to the cert, force an update of the
   1.984 +     * CERTCertificate, and finish
   1.985 +     */
   1.986 +    nssPKIObject_AddInstance(&c->object, certobj);
   1.987 +    /* nssTrustDomain_AddCertsToCache may release a reference to 'c' and
   1.988 +     * replace 'c' by a different value. So we add a reference to 'c' to
   1.989 +     * prevent 'c' from being destroyed. */
   1.990 +    nssCertificate_AddRef(c);
   1.991 +    nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
   1.992 +    /* XXX should we pass the original value of 'c' to
   1.993 +     * STAN_ForceCERTCertificateUpdate? */
   1.994 +    (void)STAN_ForceCERTCertificateUpdate(c);
   1.995 +    nssCertificate_Destroy(c);
   1.996 +    SECITEM_FreeItem(keyID,PR_TRUE);
   1.997 +    return SECSuccess;
   1.998 +loser:
   1.999 +    CERT_MapStanError();
  1.1000 +    SECITEM_FreeItem(keyID,PR_TRUE);
  1.1001 +    if (PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
  1.1002 +	PORT_SetError(SEC_ERROR_ADDING_CERT);
  1.1003 +    }
  1.1004 +    return SECFailure;
  1.1005 +}
  1.1006 +
  1.1007 +SECStatus
  1.1008 +PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert,
  1.1009 +		CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) 
  1.1010 +{
  1.1011 +    CERTCertificate *cert;
  1.1012 +    SECStatus rv;
  1.1013 +
  1.1014 +    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  1.1015 +                                   derCert, NULL, PR_FALSE, PR_TRUE);
  1.1016 +    if (cert == NULL) return SECFailure;
  1.1017 +
  1.1018 +    rv = PK11_ImportCert(slot, cert, key, nickname, includeTrust);
  1.1019 +    CERT_DestroyCertificate (cert);
  1.1020 +    return rv;
  1.1021 +}
  1.1022 +
  1.1023 +/*
  1.1024 + * get a certificate handle, look at the cached handle first..
  1.1025 + */
  1.1026 +CK_OBJECT_HANDLE
  1.1027 +pk11_getcerthandle(PK11SlotInfo *slot, CERTCertificate *cert, 
  1.1028 +					CK_ATTRIBUTE *theTemplate,int tsize)
  1.1029 +{
  1.1030 +    CK_OBJECT_HANDLE certh;
  1.1031 +
  1.1032 +    if (cert->slot == slot) {
  1.1033 +	certh = cert->pkcs11ID;
  1.1034 +	if ((certh == CK_INVALID_HANDLE) ||
  1.1035 +			(cert->series != slot->series)) {
  1.1036 +    	     certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
  1.1037 +	     cert->pkcs11ID = certh;
  1.1038 +	     cert->series = slot->series;
  1.1039 +	}
  1.1040 +    } else {
  1.1041 +    	certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
  1.1042 +    }
  1.1043 +    return certh;
  1.1044 +}
  1.1045 +
  1.1046 +/*
  1.1047 + * return the private key From a given Cert
  1.1048 + */
  1.1049 +SECKEYPrivateKey *
  1.1050 +PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert,
  1.1051 +								 void *wincx) 
  1.1052 +{
  1.1053 +    int err;
  1.1054 +    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
  1.1055 +    CK_ATTRIBUTE theTemplate[] = {
  1.1056 +	{ CKA_VALUE, NULL, 0 },
  1.1057 +	{ CKA_CLASS, NULL, 0 }
  1.1058 +    };
  1.1059 +    /* if you change the array, change the variable below as well */
  1.1060 +    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
  1.1061 +    CK_OBJECT_HANDLE certh;
  1.1062 +    CK_OBJECT_HANDLE keyh;
  1.1063 +    CK_ATTRIBUTE *attrs = theTemplate;
  1.1064 +    PRBool needLogin;
  1.1065 +    SECStatus rv;
  1.1066 +
  1.1067 +    PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, 
  1.1068 +						cert->derCert.len); attrs++;
  1.1069 +    PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
  1.1070 +
  1.1071 +    /*
  1.1072 +     * issue the find
  1.1073 +     */
  1.1074 +    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
  1.1075 +    if (rv != SECSuccess) {
  1.1076 +	return NULL;
  1.1077 +    }
  1.1078 +
  1.1079 +    certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
  1.1080 +    if (certh == CK_INVALID_HANDLE) {
  1.1081 +	return NULL;
  1.1082 +    }
  1.1083 +    /*
  1.1084 +     * prevent a login race condition. If slot is logged in between
  1.1085 +     * our call to pk11_LoginStillRequired and the 
  1.1086 +     * PK11_MatchItem. The matchItem call will either succeed, or
  1.1087 +     * we will call it one more time after calling PK11_Authenticate 
  1.1088 +     * (which is a noop on an authenticated token).
  1.1089 +     */
  1.1090 +    needLogin = pk11_LoginStillRequired(slot,wincx);
  1.1091 +    keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
  1.1092 +    if ((keyh == CK_INVALID_HANDLE) && needLogin &&
  1.1093 +                        (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
  1.1094 +			 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
  1.1095 +	/* try it again authenticated */
  1.1096 +	rv = PK11_Authenticate(slot, PR_TRUE, wincx);
  1.1097 +	if (rv != SECSuccess) {
  1.1098 +	    return NULL;
  1.1099 +	}
  1.1100 +	keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
  1.1101 +    }
  1.1102 +    if (keyh == CK_INVALID_HANDLE) { 
  1.1103 +	return NULL; 
  1.1104 +    }
  1.1105 +    return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx);
  1.1106 +} 
  1.1107 +
  1.1108 +/*
  1.1109 + * import a cert for a private key we have already generated. Set the label
  1.1110 + * on both to be the nickname. This is for the Key Gen, orphaned key case.
  1.1111 + */
  1.1112 +PK11SlotInfo *
  1.1113 +PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr, 
  1.1114 +								void *wincx) 
  1.1115 +{
  1.1116 +    PK11SlotList *list;
  1.1117 +    PK11SlotListElement *le;
  1.1118 +    SECItem *keyID;
  1.1119 +    CK_OBJECT_HANDLE key;
  1.1120 +    PK11SlotInfo *slot = NULL;
  1.1121 +    SECStatus rv;
  1.1122 +    int err;
  1.1123 +
  1.1124 +    keyID = pk11_mkcertKeyID(cert);
  1.1125 +    /* get them all! */
  1.1126 +    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
  1.1127 +    if ((keyID == NULL) || (list == NULL)) {
  1.1128 +	if (keyID) SECITEM_FreeItem(keyID,PR_TRUE);
  1.1129 +	if (list) PK11_FreeSlotList(list);
  1.1130 +    	return NULL;
  1.1131 +    }
  1.1132 +
  1.1133 +    /* Look for the slot that holds the Key */
  1.1134 +    for (le = list->head ; le; le = le->next) {
  1.1135 +	/*
  1.1136 +	 * prevent a login race condition. If le->slot is logged in between
  1.1137 +	 * our call to pk11_LoginStillRequired and the 
  1.1138 +	 * pk11_FindPrivateKeyFromCertID, the find will either succeed, or
  1.1139 +	 * we will call it one more time after calling PK11_Authenticate 
  1.1140 +	 * (which is a noop on an authenticated token).
  1.1141 +	 */
  1.1142 +	PRBool needLogin = pk11_LoginStillRequired(le->slot,wincx);
  1.1143 +	key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
  1.1144 +	if ((key == CK_INVALID_HANDLE) && needLogin &&
  1.1145 +            		(SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
  1.1146 +			 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
  1.1147 +	    /* authenticate and try again */
  1.1148 +	    rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
  1.1149 +	    if (rv != SECSuccess) continue;
  1.1150 +	    key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
  1.1151 +	}
  1.1152 +	if (key != CK_INVALID_HANDLE) {
  1.1153 +	    slot = PK11_ReferenceSlot(le->slot);
  1.1154 +	    if (keyPtr) *keyPtr = key;
  1.1155 +	    break;
  1.1156 +	}
  1.1157 +    }
  1.1158 +
  1.1159 +    SECITEM_FreeItem(keyID,PR_TRUE);
  1.1160 +    PK11_FreeSlotList(list);
  1.1161 +    return slot;
  1.1162 +
  1.1163 +}
  1.1164 +/*
  1.1165 + * import a cert for a private key we have already generated. Set the label
  1.1166 + * on both to be the nickname. This is for the Key Gen, orphaned key case.
  1.1167 + */
  1.1168 +PK11SlotInfo *
  1.1169 +PK11_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr, 
  1.1170 +								void *wincx) 
  1.1171 +{
  1.1172 +    CERTCertificate *cert;
  1.1173 +    PK11SlotInfo *slot = NULL;
  1.1174 +
  1.1175 +    /* letting this use go -- the only thing that the cert is used for is
  1.1176 +     * to get the ID attribute.
  1.1177 +     */
  1.1178 +    cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
  1.1179 +    if (cert == NULL) return NULL;
  1.1180 +
  1.1181 +    slot = PK11_KeyForCertExists(cert, keyPtr, wincx);
  1.1182 +    CERT_DestroyCertificate (cert);
  1.1183 +    return slot;
  1.1184 +}
  1.1185 +
  1.1186 +PK11SlotInfo *
  1.1187 +PK11_ImportCertForKey(CERTCertificate *cert, const char *nickname,
  1.1188 +                      void *wincx) 
  1.1189 +{
  1.1190 +    PK11SlotInfo *slot = NULL;
  1.1191 +    CK_OBJECT_HANDLE key;
  1.1192 +
  1.1193 +    slot = PK11_KeyForCertExists(cert,&key,wincx);
  1.1194 +
  1.1195 +    if (slot) {
  1.1196 +	if (PK11_ImportCert(slot,cert,key,nickname,PR_FALSE) != SECSuccess) {
  1.1197 +	    PK11_FreeSlot(slot);
  1.1198 +	    slot = NULL;
  1.1199 +	}
  1.1200 +    } else {
  1.1201 +	PORT_SetError(SEC_ERROR_ADDING_CERT);
  1.1202 +    }
  1.1203 +
  1.1204 +    return slot;
  1.1205 +}
  1.1206 +
  1.1207 +PK11SlotInfo *
  1.1208 +PK11_ImportDERCertForKey(SECItem *derCert, char *nickname,void *wincx) 
  1.1209 +{
  1.1210 +    CERTCertificate *cert;
  1.1211 +    PK11SlotInfo *slot = NULL;
  1.1212 +
  1.1213 +    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  1.1214 +                                   derCert, NULL, PR_FALSE, PR_TRUE);
  1.1215 +    if (cert == NULL) return NULL;
  1.1216 +
  1.1217 +    slot = PK11_ImportCertForKey(cert, nickname, wincx);
  1.1218 +    CERT_DestroyCertificate (cert);
  1.1219 +    return slot;
  1.1220 +}
  1.1221 +
  1.1222 +static CK_OBJECT_HANDLE
  1.1223 +pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr, 
  1.1224 +		CK_ATTRIBUTE *searchTemplate, int count, void *wincx) 
  1.1225 +{
  1.1226 +    PK11SlotList *list;
  1.1227 +    PK11SlotListElement *le;
  1.1228 +    CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE;
  1.1229 +    PK11SlotInfo *slot = NULL;
  1.1230 +    SECStatus rv;
  1.1231 +
  1.1232 +    *slotPtr = NULL;
  1.1233 +
  1.1234 +    /* get them all! */
  1.1235 +    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
  1.1236 +    if (list == NULL) {
  1.1237 +    	return CK_INVALID_HANDLE;
  1.1238 +    }
  1.1239 +
  1.1240 +
  1.1241 +    /* Look for the slot that holds the Key */
  1.1242 +    for (le = list->head ; le; le = le->next) {
  1.1243 +	rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
  1.1244 +	if (rv != SECSuccess) continue;
  1.1245 +
  1.1246 +	certHandle = pk11_FindObjectByTemplate(le->slot,searchTemplate,count);
  1.1247 +	if (certHandle != CK_INVALID_HANDLE) {
  1.1248 +	    slot = PK11_ReferenceSlot(le->slot);
  1.1249 +	    break;
  1.1250 +	}
  1.1251 +    }
  1.1252 +
  1.1253 +    PK11_FreeSlotList(list);
  1.1254 +
  1.1255 +    if (slot == NULL) {
  1.1256 +	return CK_INVALID_HANDLE;
  1.1257 +    }
  1.1258 +    *slotPtr = slot;
  1.1259 +    return certHandle;
  1.1260 +}
  1.1261 +
  1.1262 +CERTCertificate *
  1.1263 +PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo *slot, 
  1.1264 +				CERTIssuerAndSN *issuerSN, void *wincx)
  1.1265 +{
  1.1266 +    CERTCertificate *rvCert = NULL;
  1.1267 +    NSSCertificate *cert = NULL;
  1.1268 +    NSSDER issuer, serial;
  1.1269 +    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
  1.1270 +    NSSToken *token = slot->nssToken;
  1.1271 +    nssSession *session;
  1.1272 +    nssCryptokiObject *instance = NULL;
  1.1273 +    nssPKIObject *object = NULL;
  1.1274 +    SECItem *derSerial;
  1.1275 +    PRStatus status;
  1.1276 +
  1.1277 +    if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
  1.1278 +        !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || 
  1.1279 +	issuerSN->derIssuer.len    > CERT_MAX_DN_BYTES ||
  1.1280 +	issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES ) {
  1.1281 +    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1282 +	return NULL;
  1.1283 +    }
  1.1284 +
  1.1285 +    /* Paranoia */
  1.1286 +    if (token == NULL) {
  1.1287 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.1288 +	return NULL;
  1.1289 +    }
  1.1290 +
  1.1291 +
  1.1292 +    /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
  1.1293 +     * CERTIssuerAndSN that actually has the encoded value and pass that
  1.1294 +     * to PKCS#11 (and the crypto context).
  1.1295 +     */
  1.1296 +    derSerial = SEC_ASN1EncodeItem(NULL, NULL,
  1.1297 +                                   &issuerSN->serialNumber,
  1.1298 +                                   SEC_ASN1_GET(SEC_IntegerTemplate));
  1.1299 +    if (!derSerial) {
  1.1300 +	return NULL;
  1.1301 +    }
  1.1302 +
  1.1303 +    NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
  1.1304 +    NSSITEM_FROM_SECITEM(&serial, derSerial);
  1.1305 +
  1.1306 +    session = nssToken_GetDefaultSession(token);
  1.1307 +    if (!session) {
  1.1308 +	goto loser;
  1.1309 +    }
  1.1310 +
  1.1311 +    instance = nssToken_FindCertificateByIssuerAndSerialNumber(token,session,
  1.1312 +		&issuer, &serial, nssTokenSearchType_TokenForced, &status);
  1.1313 +
  1.1314 +    SECITEM_FreeItem(derSerial, PR_TRUE);
  1.1315 +
  1.1316 +    if (!instance) {
  1.1317 +	goto loser;
  1.1318 +    }
  1.1319 +    object = nssPKIObject_Create(NULL, instance, td, NULL, nssPKIMonitor);
  1.1320 +    if (!object) {
  1.1321 +	goto loser;
  1.1322 +    }
  1.1323 +    instance = NULL; /* adopted by the previous call */
  1.1324 +    cert = nssCertificate_Create(object);
  1.1325 +    if (!cert) {
  1.1326 +	goto loser;
  1.1327 +    }
  1.1328 +    object = NULL; /* adopted by the previous call */
  1.1329 +    nssTrustDomain_AddCertsToCache(td, &cert,1);
  1.1330 +    /* on failure, cert is freed below */
  1.1331 +    rvCert = STAN_GetCERTCertificate(cert);
  1.1332 +    if (!rvCert) {
  1.1333 +	goto loser;
  1.1334 +    }
  1.1335 +    return rvCert;
  1.1336 +
  1.1337 +loser:
  1.1338 +    if (instance) {
  1.1339 +	nssCryptokiObject_Destroy(instance);
  1.1340 +    }
  1.1341 +    if (object) {
  1.1342 +	nssPKIObject_Destroy(object);
  1.1343 +    }
  1.1344 +    if (cert) {
  1.1345 +	nssCertificate_Destroy(cert);
  1.1346 +    }
  1.1347 +    return NULL;
  1.1348 +}
  1.1349 +
  1.1350 +static PRCallOnceType keyIDHashCallOnce;
  1.1351 +
  1.1352 +static PRStatus PR_CALLBACK
  1.1353 +pk11_keyIDHash_populate(void *wincx)
  1.1354 +{
  1.1355 +    CERTCertList     *certList;
  1.1356 +    CERTCertListNode *node = NULL;
  1.1357 +    SECItem           subjKeyID = {siBuffer, NULL, 0};
  1.1358 +    SECItem          *slotid = NULL;
  1.1359 +    SECMODModuleList *modules, *mlp;
  1.1360 +    SECMODListLock   *moduleLock;
  1.1361 +    int               i;
  1.1362 +
  1.1363 +    certList = PK11_ListCerts(PK11CertListUser, wincx);
  1.1364 +    if (!certList) {
  1.1365 +	return PR_FAILURE;
  1.1366 +    }
  1.1367 +
  1.1368 +    for (node = CERT_LIST_HEAD(certList);
  1.1369 +         !CERT_LIST_END(node, certList);
  1.1370 +         node = CERT_LIST_NEXT(node)) {
  1.1371 +	if (CERT_FindSubjectKeyIDExtension(node->cert, 
  1.1372 +	                                   &subjKeyID) == SECSuccess && 
  1.1373 +	    subjKeyID.data != NULL) {
  1.1374 +	    cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert);
  1.1375 +	    SECITEM_FreeItem(&subjKeyID, PR_FALSE);
  1.1376 +	}
  1.1377 +    }
  1.1378 +    CERT_DestroyCertList(certList);
  1.1379 +
  1.1380 +    /*
  1.1381 +     * Record the state of each slot in a hash. The concatenation of slotID
  1.1382 +     * and moduleID is used as its key, with the slot series as its value.
  1.1383 +     */
  1.1384 +    slotid = SECITEM_AllocItem(NULL, NULL,
  1.1385 +                               sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID));
  1.1386 +    if (!slotid) {
  1.1387 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1.1388 +	return PR_FAILURE;
  1.1389 +    }
  1.1390 +    moduleLock = SECMOD_GetDefaultModuleListLock();
  1.1391 +    if (!moduleLock) {
  1.1392 +	PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
  1.1393 +	return PR_FAILURE;
  1.1394 +    }
  1.1395 +    SECMOD_GetReadLock(moduleLock);
  1.1396 +    modules = SECMOD_GetDefaultModuleList();
  1.1397 +    for (mlp = modules; mlp; mlp = mlp->next) {
  1.1398 +	for (i = 0; i < mlp->module->slotCount; i++) {
  1.1399 +	    memcpy(slotid->data, &mlp->module->slots[i]->slotID,
  1.1400 +	           sizeof(CK_SLOT_ID));
  1.1401 +	    memcpy(&slotid->data[sizeof(CK_SLOT_ID)], &mlp->module->moduleID,
  1.1402 +	           sizeof(SECMODModuleID));
  1.1403 +	    cert_UpdateSubjectKeyIDSlotCheck(slotid,
  1.1404 +	                                     mlp->module->slots[i]->series);
  1.1405 +	}
  1.1406 +    }
  1.1407 +    SECMOD_ReleaseReadLock(moduleLock);
  1.1408 +    SECITEM_FreeItem(slotid, PR_TRUE);
  1.1409 +
  1.1410 +    return PR_SUCCESS;
  1.1411 +}
  1.1412 +
  1.1413 +/*
  1.1414 + * We're looking for a cert which we have the private key for that's on the
  1.1415 + * list of recipients. This searches one slot.
  1.1416 + * this is the new version for NSS SMIME code
  1.1417 + * this stuff should REALLY be in the SMIME code, but some things in here are not public
  1.1418 + * (they should be!)
  1.1419 + */
  1.1420 +static CERTCertificate *
  1.1421 +pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist, int *rlIndex, void *pwarg)
  1.1422 +{
  1.1423 +    NSSCMSRecipient *ri = NULL;
  1.1424 +    int i;
  1.1425 +    PRBool tokenRescanDone = PR_FALSE;
  1.1426 +    CERTCertTrust trust;
  1.1427 +
  1.1428 +    for (i=0; (ri = recipientlist[i]) != NULL; i++) {
  1.1429 +	CERTCertificate *cert = NULL;
  1.1430 +	if (ri->kind == RLSubjKeyID) {
  1.1431 +	    SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
  1.1432 +	    if (!derCert && !tokenRescanDone) {
  1.1433 +		/*
  1.1434 +		 * We didn't find the cert by its key ID. If we have slots
  1.1435 +		 * with removable tokens, a failure from
  1.1436 +		 * cert_FindDERCertBySubjectKeyID doesn't necessarily imply
  1.1437 +		 * that the cert is unavailable - the token might simply
  1.1438 +		 * have been inserted after the initial run of
  1.1439 +		 * pk11_keyIDHash_populate (wrapped by PR_CallOnceWithArg),
  1.1440 +		 * or a different token might have been present in that
  1.1441 +		 * slot, initially. Let's check for new tokens...
  1.1442 +		 */
  1.1443 +		PK11SlotList *sl = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
  1.1444 +		                                     PR_FALSE, PR_FALSE, pwarg);
  1.1445 +		if (sl) {
  1.1446 +		    PK11SlotListElement *le;
  1.1447 +		    SECItem *slotid = SECITEM_AllocItem(NULL, NULL,
  1.1448 +		                   sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID));
  1.1449 +		    if (!slotid) {
  1.1450 +			PORT_SetError(SEC_ERROR_NO_MEMORY);
  1.1451 +			return NULL;
  1.1452 +		    }
  1.1453 +		    for (le = sl->head; le; le = le->next) {
  1.1454 +			memcpy(slotid->data, &le->slot->slotID,
  1.1455 +			       sizeof(CK_SLOT_ID));
  1.1456 +			memcpy(&slotid->data[sizeof(CK_SLOT_ID)],
  1.1457 +			       &le->slot->module->moduleID,
  1.1458 +			       sizeof(SECMODModuleID));
  1.1459 +			/*
  1.1460 +			 * Any changes with the slot since our last check?
  1.1461 +			 * If so, re-read the certs in that specific slot.
  1.1462 +			 */
  1.1463 +			if (cert_SubjectKeyIDSlotCheckSeries(slotid)
  1.1464 +			    != PK11_GetSlotSeries(le->slot)) {
  1.1465 +			    CERTCertListNode *node = NULL;
  1.1466 +			    SECItem subjKeyID = {siBuffer, NULL, 0};
  1.1467 +			    CERTCertList *cl = PK11_ListCertsInSlot(le->slot);
  1.1468 +			    if (!cl) {
  1.1469 +				continue;
  1.1470 +			    }
  1.1471 +			    for (node = CERT_LIST_HEAD(cl);
  1.1472 +			         !CERT_LIST_END(node, cl);
  1.1473 +			         node = CERT_LIST_NEXT(node)) {
  1.1474 +				if (CERT_IsUserCert(node->cert) &&
  1.1475 +				    CERT_FindSubjectKeyIDExtension(node->cert,
  1.1476 +				                   &subjKeyID) == SECSuccess) {
  1.1477 +				    if (subjKeyID.data) {
  1.1478 +					cert_AddSubjectKeyIDMapping(&subjKeyID,
  1.1479 +					                            node->cert);
  1.1480 +					cert_UpdateSubjectKeyIDSlotCheck(slotid,
  1.1481 +					          PK11_GetSlotSeries(le->slot));
  1.1482 +				    }
  1.1483 +				    SECITEM_FreeItem(&subjKeyID, PR_FALSE);
  1.1484 +				}
  1.1485 +			    }
  1.1486 +			    CERT_DestroyCertList(cl);
  1.1487 +			}
  1.1488 +		    }
  1.1489 +		    PK11_FreeSlotList(sl);
  1.1490 +		    SECITEM_FreeItem(slotid, PR_TRUE);
  1.1491 +		}
  1.1492 +		/* only check once per message/recipientlist */
  1.1493 +		tokenRescanDone = PR_TRUE;
  1.1494 +		/* do another lookup (hopefully we found that cert...) */
  1.1495 +		derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
  1.1496 +	    }
  1.1497 +	    if (derCert) {
  1.1498 +		cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg);
  1.1499 +		SECITEM_FreeItem(derCert, PR_TRUE);
  1.1500 +	    }
  1.1501 +	} else {
  1.1502 +	    cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN, 
  1.1503 +						     pwarg);
  1.1504 +	}
  1.1505 +	if (cert) {
  1.1506 +	    /* this isn't our cert */
  1.1507 +	    if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
  1.1508 +       		((trust.emailFlags & CERTDB_USER) != CERTDB_USER)) {
  1.1509 +		 CERT_DestroyCertificate(cert);
  1.1510 +		continue;
  1.1511 +	    }
  1.1512 +	    ri->slot = PK11_ReferenceSlot(slot);
  1.1513 +	    *rlIndex = i;
  1.1514 +	    return cert;
  1.1515 +	}
  1.1516 +    }
  1.1517 +    *rlIndex = -1;
  1.1518 +    return NULL;
  1.1519 +}
  1.1520 +
  1.1521 +/*
  1.1522 + * This function is the same as above, but it searches all the slots.
  1.1523 + * this is the new version for NSS SMIME code
  1.1524 + * this stuff should REALLY be in the SMIME code, but some things in here are not public
  1.1525 + * (they should be!)
  1.1526 + */
  1.1527 +static CERTCertificate *
  1.1528 +pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex)
  1.1529 +{
  1.1530 +    PK11SlotList *list;
  1.1531 +    PK11SlotListElement *le;
  1.1532 +    CERTCertificate *cert = NULL;
  1.1533 +    SECStatus rv;
  1.1534 +
  1.1535 +    /* get them all! */
  1.1536 +    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
  1.1537 +    if (list == NULL) {
  1.1538 +    	return CK_INVALID_HANDLE;
  1.1539 +    }
  1.1540 +
  1.1541 +    /* Look for the slot that holds the Key */
  1.1542 +    for (le = list->head ; le; le = le->next) {
  1.1543 +	rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
  1.1544 +	if (rv != SECSuccess) continue;
  1.1545 +
  1.1546 +	cert = pk11_FindCertObjectByRecipientNew(le->slot, 
  1.1547 +					recipientlist, rlIndex, wincx);
  1.1548 +	if (cert)
  1.1549 +	    break;
  1.1550 +    }
  1.1551 +
  1.1552 +    PK11_FreeSlotList(list);
  1.1553 +
  1.1554 +    return cert;
  1.1555 +}
  1.1556 +
  1.1557 +/*
  1.1558 + * We're looking for a cert which we have the private key for that's on the
  1.1559 + * list of recipients. This searches one slot.
  1.1560 + */
  1.1561 +static CERTCertificate *
  1.1562 +pk11_FindCertObjectByRecipient(PK11SlotInfo *slot, 
  1.1563 +	SEC_PKCS7RecipientInfo **recipientArray,
  1.1564 +	SEC_PKCS7RecipientInfo **rip, void *pwarg)
  1.1565 +{
  1.1566 +    SEC_PKCS7RecipientInfo *ri = NULL;
  1.1567 +    CERTCertTrust trust;
  1.1568 +    int i;
  1.1569 +
  1.1570 +    for (i=0; (ri = recipientArray[i]) != NULL; i++) {
  1.1571 +	CERTCertificate *cert;
  1.1572 +
  1.1573 +	cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->issuerAndSN, 
  1.1574 +								pwarg);
  1.1575 +        if (cert) {
  1.1576 +	    /* this isn't our cert */
  1.1577 +	    if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
  1.1578 +       		((trust.emailFlags & CERTDB_USER) != CERTDB_USER)) {
  1.1579 +		 CERT_DestroyCertificate(cert);
  1.1580 +		continue;
  1.1581 +	    }
  1.1582 +	    *rip = ri;
  1.1583 +	    return cert;
  1.1584 +	}
  1.1585 +
  1.1586 +    }
  1.1587 +    *rip = NULL;
  1.1588 +    return NULL;
  1.1589 +}
  1.1590 +
  1.1591 +/*
  1.1592 + * This function is the same as above, but it searches all the slots.
  1.1593 + */
  1.1594 +static CERTCertificate *
  1.1595 +pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr, 
  1.1596 +	SEC_PKCS7RecipientInfo **recipientArray,SEC_PKCS7RecipientInfo **rip,
  1.1597 +							void *wincx) 
  1.1598 +{
  1.1599 +    PK11SlotList *list;
  1.1600 +    PK11SlotListElement *le;
  1.1601 +    CERTCertificate * cert = NULL;
  1.1602 +    PK11SlotInfo *slot = NULL;
  1.1603 +    SECStatus rv;
  1.1604 +
  1.1605 +    *slotPtr = NULL;
  1.1606 +
  1.1607 +    /* get them all! */
  1.1608 +    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
  1.1609 +    if (list == NULL) {
  1.1610 +    	return CK_INVALID_HANDLE;
  1.1611 +    }
  1.1612 +
  1.1613 +    *rip = NULL;
  1.1614 +
  1.1615 +    /* Look for the slot that holds the Key */
  1.1616 +    for (le = list->head ; le; le = le->next) {
  1.1617 +	rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
  1.1618 +	if (rv != SECSuccess) continue;
  1.1619 +
  1.1620 +	cert = pk11_FindCertObjectByRecipient(le->slot, recipientArray, 
  1.1621 +							rip, wincx);
  1.1622 +	if (cert) {
  1.1623 +	    slot = PK11_ReferenceSlot(le->slot);
  1.1624 +	    break;
  1.1625 +	}
  1.1626 +    }
  1.1627 +
  1.1628 +    PK11_FreeSlotList(list);
  1.1629 +
  1.1630 +    if (slot == NULL) {
  1.1631 +	return NULL;
  1.1632 +    }
  1.1633 +    *slotPtr = slot;
  1.1634 +    PORT_Assert(cert != NULL);
  1.1635 +    return cert;
  1.1636 +}
  1.1637 +
  1.1638 +/*
  1.1639 + * We need to invert the search logic for PKCS 7 because if we search for
  1.1640 + * each cert on the list over all the slots, we wind up with lots of spurious
  1.1641 + * password prompts. This way we get only one password prompt per slot, at
  1.1642 + * the max, and most of the time we can find the cert, and only prompt for
  1.1643 + * the key...
  1.1644 + */
  1.1645 +CERTCertificate *
  1.1646 +PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr, 
  1.1647 +	SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip,
  1.1648 +				SECKEYPrivateKey**privKey, void *wincx)
  1.1649 +{
  1.1650 +    CERTCertificate *cert = NULL;
  1.1651 +
  1.1652 +    *privKey = NULL;
  1.1653 +    *slotPtr = NULL;
  1.1654 +    cert = pk11_AllFindCertObjectByRecipient(slotPtr,array,rip,wincx);
  1.1655 +    if (!cert) {
  1.1656 +	return NULL;
  1.1657 +    }
  1.1658 +
  1.1659 +    *privKey = PK11_FindKeyByAnyCert(cert, wincx);
  1.1660 +    if (*privKey == NULL) {
  1.1661 +	goto loser;
  1.1662 +    }
  1.1663 +
  1.1664 +    return cert;
  1.1665 +loser:
  1.1666 +    if (cert) CERT_DestroyCertificate(cert);
  1.1667 +    if (*slotPtr) PK11_FreeSlot(*slotPtr);
  1.1668 +    *slotPtr = NULL;
  1.1669 +    return NULL;
  1.1670 +}
  1.1671 +
  1.1672 +/*
  1.1673 + * This is the new version of the above function for NSS SMIME code
  1.1674 + * this stuff should REALLY be in the SMIME code, but some things in here are not public
  1.1675 + * (they should be!)
  1.1676 + */
  1.1677 +int
  1.1678 +PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx)
  1.1679 +{
  1.1680 +    CERTCertificate *cert;
  1.1681 +    NSSCMSRecipient *rl;
  1.1682 +    PRStatus rv;
  1.1683 +    int rlIndex;
  1.1684 +
  1.1685 +    rv = PR_CallOnceWithArg(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx);
  1.1686 +    if (rv != PR_SUCCESS)
  1.1687 +	return -1;
  1.1688 +
  1.1689 +    cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex);
  1.1690 +    if (!cert) {
  1.1691 +	return -1;
  1.1692 +    }
  1.1693 +
  1.1694 +    rl = recipientlist[rlIndex];
  1.1695 +
  1.1696 +    /* at this point, rl->slot is set */
  1.1697 +
  1.1698 +    rl->privkey = PK11_FindKeyByAnyCert(cert, wincx);
  1.1699 +    if (rl->privkey == NULL) {
  1.1700 +	goto loser;
  1.1701 +    }
  1.1702 +
  1.1703 +    /* make a cert from the cert handle */
  1.1704 +    rl->cert = cert;
  1.1705 +    return rlIndex;
  1.1706 +
  1.1707 +loser:
  1.1708 +    if (cert) CERT_DestroyCertificate(cert);
  1.1709 +    if (rl->slot) PK11_FreeSlot(rl->slot);
  1.1710 +    rl->slot = NULL;
  1.1711 +    return -1;
  1.1712 +}
  1.1713 +
  1.1714 +CERTCertificate *
  1.1715 +PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN,
  1.1716 +							 void *wincx)
  1.1717 +{
  1.1718 +    CERTCertificate *rvCert = NULL;
  1.1719 +    NSSCertificate *cert;
  1.1720 +    NSSDER issuer, serial;
  1.1721 +    NSSCryptoContext *cc;
  1.1722 +    SECItem *derSerial;
  1.1723 +
  1.1724 +    if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
  1.1725 +        !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || 
  1.1726 +	issuerSN->derIssuer.len    > CERT_MAX_DN_BYTES ||
  1.1727 +	issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES ) {
  1.1728 +    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1729 +	return NULL;
  1.1730 +    }
  1.1731 +
  1.1732 +    if (slotPtr) *slotPtr = NULL;
  1.1733 +
  1.1734 +    /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
  1.1735 +     * CERTIssuerAndSN that actually has the encoded value and pass that
  1.1736 +     * to PKCS#11 (and the crypto context).
  1.1737 +     */
  1.1738 +    derSerial = SEC_ASN1EncodeItem(NULL, NULL,
  1.1739 +                                   &issuerSN->serialNumber,
  1.1740 +                                   SEC_ASN1_GET(SEC_IntegerTemplate));
  1.1741 +    if (!derSerial) {
  1.1742 +	return NULL;
  1.1743 +    }
  1.1744 +
  1.1745 +    NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
  1.1746 +    NSSITEM_FROM_SECITEM(&serial, derSerial);
  1.1747 +
  1.1748 +    cc = STAN_GetDefaultCryptoContext();
  1.1749 +    cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc, 
  1.1750 +                                                                &issuer, 
  1.1751 +                                                                &serial);
  1.1752 +    if (cert) {
  1.1753 +	SECITEM_FreeItem(derSerial, PR_TRUE);
  1.1754 +	return STAN_GetCERTCertificateOrRelease(cert);
  1.1755 +    }
  1.1756 +
  1.1757 +    do {
  1.1758 +	/* free the old cert on retry. Associated slot was not present */
  1.1759 +	if (rvCert) {
  1.1760 +	    CERT_DestroyCertificate(rvCert);
  1.1761 +	    rvCert = NULL;
  1.1762 + 	}
  1.1763 +
  1.1764 +	cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
  1.1765 +                                                  STAN_GetDefaultTrustDomain(),
  1.1766 +                                                  &issuer,
  1.1767 +                                                  &serial);
  1.1768 +	if (!cert) {
  1.1769 +	    break;
  1.1770 +	}
  1.1771 +
  1.1772 +	rvCert = STAN_GetCERTCertificateOrRelease(cert);
  1.1773 +	if (rvCert == NULL) {
  1.1774 +	   break;
  1.1775 +	}
  1.1776 +
  1.1777 +	/* Check to see if the cert's token is still there */
  1.1778 +    } while (!PK11_IsPresent(rvCert->slot));
  1.1779 +
  1.1780 +    if (rvCert && slotPtr) *slotPtr = PK11_ReferenceSlot(rvCert->slot);
  1.1781 +
  1.1782 +    SECITEM_FreeItem(derSerial, PR_TRUE);
  1.1783 +    return rvCert;
  1.1784 +}
  1.1785 +
  1.1786 +CK_OBJECT_HANDLE
  1.1787 +PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot)
  1.1788 +{
  1.1789 +    CK_OBJECT_HANDLE certHandle;
  1.1790 +    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
  1.1791 +    CK_ATTRIBUTE *attr;
  1.1792 +    CK_ATTRIBUTE searchTemplate[]= {
  1.1793 +	{ CKA_CLASS, NULL, 0 },
  1.1794 +	{ CKA_VALUE, NULL, 0 },
  1.1795 +    };
  1.1796 +    int templateSize = sizeof(searchTemplate)/sizeof(searchTemplate[0]);
  1.1797 +
  1.1798 +    attr = searchTemplate;
  1.1799 +    PK11_SETATTRS(attr, CKA_CLASS, &certClass, sizeof(certClass)); attr++;
  1.1800 +    PK11_SETATTRS(attr, CKA_VALUE, cert->derCert.data, cert->derCert.len);
  1.1801 +
  1.1802 +    if (cert->slot) {
  1.1803 +	certHandle = pk11_getcerthandle(cert->slot, cert, searchTemplate,
  1.1804 +	                                templateSize);
  1.1805 +	if (certHandle != CK_INVALID_HANDLE) {
  1.1806 +	    *pSlot = PK11_ReferenceSlot(cert->slot);
  1.1807 +	    return certHandle;
  1.1808 +	}
  1.1809 +    }
  1.1810 +
  1.1811 +    certHandle = pk11_FindCertObjectByTemplate(pSlot, searchTemplate,
  1.1812 +                                               templateSize, wincx);
  1.1813 +    if (certHandle != CK_INVALID_HANDLE) {
  1.1814 +	if (cert->slot == NULL) {
  1.1815 +	    cert->slot = PK11_ReferenceSlot(*pSlot);
  1.1816 +	    cert->pkcs11ID = certHandle;
  1.1817 +	    cert->ownSlot = PR_TRUE;
  1.1818 +	    cert->series = cert->slot->series;
  1.1819 +	}
  1.1820 +    }
  1.1821 +
  1.1822 +    return(certHandle);
  1.1823 +}
  1.1824 +
  1.1825 +SECKEYPrivateKey *
  1.1826 +PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx)
  1.1827 +{
  1.1828 +    CK_OBJECT_HANDLE certHandle;
  1.1829 +    CK_OBJECT_HANDLE keyHandle;
  1.1830 +    PK11SlotInfo *slot = NULL;
  1.1831 +    SECKEYPrivateKey *privKey = NULL;
  1.1832 +    PRBool needLogin;
  1.1833 +    SECStatus rv;
  1.1834 +    int err;
  1.1835 +
  1.1836 +    certHandle = PK11_FindObjectForCert(cert, wincx, &slot);
  1.1837 +    if (certHandle == CK_INVALID_HANDLE) {
  1.1838 +	 return NULL;
  1.1839 +    }
  1.1840 +    /*
  1.1841 +     * prevent a login race condition. If slot is logged in between
  1.1842 +     * our call to pk11_LoginStillRequired and the 
  1.1843 +     * PK11_MatchItem. The matchItem call will either succeed, or
  1.1844 +     * we will call it one more time after calling PK11_Authenticate 
  1.1845 +     * (which is a noop on an authenticated token).
  1.1846 +     */
  1.1847 +    needLogin = pk11_LoginStillRequired(slot,wincx);
  1.1848 +    keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
  1.1849 +    if ((keyHandle == CK_INVALID_HANDLE) &&  needLogin &&
  1.1850 +			(SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
  1.1851 +			 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err ) ) {
  1.1852 +	/* authenticate and try again */
  1.1853 +	rv = PK11_Authenticate(slot, PR_TRUE, wincx);
  1.1854 +	if (rv == SECSuccess) {
  1.1855 +            keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
  1.1856 +	}
  1.1857 +    }
  1.1858 +    if (keyHandle != CK_INVALID_HANDLE) { 
  1.1859 +        privKey =  PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
  1.1860 +    }
  1.1861 +    if (slot) {
  1.1862 +	PK11_FreeSlot(slot);
  1.1863 +    }
  1.1864 +    return privKey;
  1.1865 +}
  1.1866 +
  1.1867 +CK_OBJECT_HANDLE
  1.1868 +pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx)
  1.1869 +{
  1.1870 +    CK_OBJECT_HANDLE certHandle;
  1.1871 +    CK_OBJECT_HANDLE keyHandle;
  1.1872 +
  1.1873 +    certHandle = PK11_FindObjectForCert(cert, wincx, slot);
  1.1874 +    if (certHandle == CK_INVALID_HANDLE) {
  1.1875 +	 return CK_INVALID_HANDLE;
  1.1876 +    }
  1.1877 +    keyHandle = PK11_MatchItem(*slot,certHandle,CKO_PUBLIC_KEY);
  1.1878 +    if (keyHandle == CK_INVALID_HANDLE) { 
  1.1879 +	PK11_FreeSlot(*slot);
  1.1880 +	return CK_INVALID_HANDLE;
  1.1881 +    }
  1.1882 +    return keyHandle;
  1.1883 +}
  1.1884 +
  1.1885 +/*
  1.1886 + * find the number of certs in the slot with the same subject name
  1.1887 + */
  1.1888 +int
  1.1889 +PK11_NumberCertsForCertSubject(CERTCertificate *cert)
  1.1890 +{
  1.1891 +    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
  1.1892 +    CK_ATTRIBUTE theTemplate[] = {
  1.1893 +	{ CKA_CLASS, NULL, 0 },
  1.1894 +	{ CKA_SUBJECT, NULL, 0 },
  1.1895 +    };
  1.1896 +    CK_ATTRIBUTE *attr = theTemplate;
  1.1897 +   int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]);
  1.1898 +
  1.1899 +    PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++;
  1.1900 +    PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len);
  1.1901 +
  1.1902 +    if (cert->slot == NULL) {
  1.1903 +	PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
  1.1904 +							PR_FALSE,PR_TRUE,NULL);
  1.1905 +	PK11SlotListElement *le;
  1.1906 +	int count = 0;
  1.1907 +
  1.1908 +	if (!list) {
  1.1909 +            /* error code is set */
  1.1910 +            return 0;
  1.1911 +	}
  1.1912 +
  1.1913 +	/* loop through all the fortezza tokens */
  1.1914 +	for (le = list->head; le; le = le->next) {
  1.1915 +	    count += PK11_NumberObjectsFor(le->slot,theTemplate,templateSize);
  1.1916 +	}
  1.1917 +	PK11_FreeSlotList(list);
  1.1918 +	return count;
  1.1919 +    }
  1.1920 +
  1.1921 +    return PK11_NumberObjectsFor(cert->slot,theTemplate,templateSize);
  1.1922 +}
  1.1923 +
  1.1924 +/*
  1.1925 + *  Walk all the certs with the same subject
  1.1926 + */
  1.1927 +SECStatus
  1.1928 +PK11_TraverseCertsForSubject(CERTCertificate *cert,
  1.1929 +        SECStatus(* callback)(CERTCertificate*, void *), void *arg)
  1.1930 +{
  1.1931 +    if(!cert) {
  1.1932 +	return SECFailure;
  1.1933 +    }
  1.1934 +    if (cert->slot == NULL) {
  1.1935 +	PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
  1.1936 +							PR_FALSE,PR_TRUE,NULL);
  1.1937 +	PK11SlotListElement *le;
  1.1938 +
  1.1939 +	if (!list) {
  1.1940 +            /* error code is set */
  1.1941 +            return SECFailure;
  1.1942 +	}
  1.1943 +	/* loop through all the tokens */
  1.1944 +	for (le = list->head; le; le = le->next) {
  1.1945 +	    PK11_TraverseCertsForSubjectInSlot(cert,le->slot,callback,arg);
  1.1946 +	}
  1.1947 +	PK11_FreeSlotList(list);
  1.1948 +	return SECSuccess;
  1.1949 +
  1.1950 +    }
  1.1951 +
  1.1952 +    return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg);
  1.1953 +}
  1.1954 +
  1.1955 +SECStatus
  1.1956 +PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot,
  1.1957 +	SECStatus(* callback)(CERTCertificate*, void *), void *arg)
  1.1958 +{
  1.1959 +    PRStatus nssrv = PR_SUCCESS;
  1.1960 +    NSSToken *token;
  1.1961 +    NSSDER subject;
  1.1962 +    NSSTrustDomain *td;
  1.1963 +    nssList *subjectList;
  1.1964 +    nssPKIObjectCollection *collection;
  1.1965 +    nssCryptokiObject **instances;
  1.1966 +    NSSCertificate **certs;
  1.1967 +    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
  1.1968 +    td = STAN_GetDefaultTrustDomain();
  1.1969 +    NSSITEM_FROM_SECITEM(&subject, &cert->derSubject);
  1.1970 +    token = PK11Slot_GetNSSToken(slot);
  1.1971 +    if (!nssToken_IsPresent(token)) {
  1.1972 +	return SECSuccess;
  1.1973 +    }
  1.1974 +    collection = nssCertificateCollection_Create(td, NULL);
  1.1975 +    if (!collection) {
  1.1976 +	return SECFailure;
  1.1977 +    }
  1.1978 +    subjectList = nssList_Create(NULL, PR_FALSE);
  1.1979 +    if (!subjectList) {
  1.1980 +	nssPKIObjectCollection_Destroy(collection);
  1.1981 +	return SECFailure;
  1.1982 +    }
  1.1983 +    (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject, 
  1.1984 +                                                     subjectList);
  1.1985 +    transfer_token_certs_to_collection(subjectList, token, collection);
  1.1986 +    instances = nssToken_FindCertificatesBySubject(token, NULL,
  1.1987 +	                                           &subject, 
  1.1988 +	                                           tokenOnly, 0, &nssrv);
  1.1989 +    nssPKIObjectCollection_AddInstances(collection, instances, 0);
  1.1990 +    nss_ZFreeIf(instances);
  1.1991 +    nssList_Destroy(subjectList);
  1.1992 +    certs = nssPKIObjectCollection_GetCertificates(collection,
  1.1993 +                                                   NULL, 0, NULL);
  1.1994 +    nssPKIObjectCollection_Destroy(collection);
  1.1995 +    if (certs) {
  1.1996 +	CERTCertificate *oldie;
  1.1997 +	NSSCertificate **cp;
  1.1998 +	for (cp = certs; *cp; cp++) {
  1.1999 +	    oldie = STAN_GetCERTCertificate(*cp);
  1.2000 +	    if (!oldie) {
  1.2001 +		continue;
  1.2002 +	    }
  1.2003 +	    if ((*callback)(oldie, arg) != SECSuccess) {
  1.2004 +		nssrv = PR_FAILURE;
  1.2005 +		break;
  1.2006 +	    }
  1.2007 +	}
  1.2008 +	nssCertificateArray_Destroy(certs);
  1.2009 +    }
  1.2010 +    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
  1.2011 +}
  1.2012 +
  1.2013 +SECStatus
  1.2014 +PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
  1.2015 +	SECStatus(* callback)(CERTCertificate*, void *), void *arg)
  1.2016 +{
  1.2017 +    struct nss3_cert_cbstr pk11cb;
  1.2018 +    PRStatus nssrv = PR_SUCCESS;
  1.2019 +    NSSToken *token;
  1.2020 +    NSSTrustDomain *td;
  1.2021 +    NSSUTF8 *nick;
  1.2022 +    PRBool created = PR_FALSE;
  1.2023 +    nssCryptokiObject **instances;
  1.2024 +    nssPKIObjectCollection *collection = NULL;
  1.2025 +    NSSCertificate **certs;
  1.2026 +    nssList *nameList = NULL;
  1.2027 +    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
  1.2028 +    pk11cb.callback = callback;
  1.2029 +    pk11cb.arg = arg;
  1.2030 +    token = PK11Slot_GetNSSToken(slot);
  1.2031 +    if (!nssToken_IsPresent(token)) {
  1.2032 +	return SECSuccess;
  1.2033 +    }
  1.2034 +    if (nickname->data[nickname->len-1] != '\0') {
  1.2035 +	nick = nssUTF8_Create(NULL, nssStringType_UTF8String, 
  1.2036 +	                      nickname->data, nickname->len);
  1.2037 +	created = PR_TRUE;
  1.2038 +    } else {
  1.2039 +	nick = (NSSUTF8 *)nickname->data;
  1.2040 +    }
  1.2041 +    td = STAN_GetDefaultTrustDomain();
  1.2042 +    collection = nssCertificateCollection_Create(td, NULL);
  1.2043 +    if (!collection) {
  1.2044 +	goto loser;
  1.2045 +    }
  1.2046 +    nameList = nssList_Create(NULL, PR_FALSE);
  1.2047 +    if (!nameList) {
  1.2048 +	goto loser;
  1.2049 +    }
  1.2050 +    (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList);
  1.2051 +    transfer_token_certs_to_collection(nameList, token, collection);
  1.2052 +    instances = nssToken_FindCertificatesByNickname(token, NULL,
  1.2053 +	                                            nick,
  1.2054 +	                                            tokenOnly, 0, &nssrv);
  1.2055 +    nssPKIObjectCollection_AddInstances(collection, instances, 0);
  1.2056 +    nss_ZFreeIf(instances);
  1.2057 +    nssList_Destroy(nameList);
  1.2058 +    certs = nssPKIObjectCollection_GetCertificates(collection,
  1.2059 +                                                   NULL, 0, NULL);
  1.2060 +    nssPKIObjectCollection_Destroy(collection);
  1.2061 +    if (certs) {
  1.2062 +	CERTCertificate *oldie;
  1.2063 +	NSSCertificate **cp;
  1.2064 +	for (cp = certs; *cp; cp++) {
  1.2065 +	    oldie = STAN_GetCERTCertificate(*cp);
  1.2066 +	    if (!oldie) {
  1.2067 +		continue;
  1.2068 +	    }
  1.2069 +	    if ((*callback)(oldie, arg) != SECSuccess) {
  1.2070 +		nssrv = PR_FAILURE;
  1.2071 +		break;
  1.2072 +	    }
  1.2073 +	}
  1.2074 +	nssCertificateArray_Destroy(certs);
  1.2075 +    }
  1.2076 +    if (created) nss_ZFreeIf(nick);
  1.2077 +    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
  1.2078 +loser:
  1.2079 +    if (created) {
  1.2080 +	nss_ZFreeIf(nick);
  1.2081 +    }
  1.2082 +    if (collection) {
  1.2083 +	nssPKIObjectCollection_Destroy(collection);
  1.2084 +    }
  1.2085 +    if (nameList) {
  1.2086 +	nssList_Destroy(nameList);
  1.2087 +    }
  1.2088 +    return SECFailure;
  1.2089 +}
  1.2090 +
  1.2091 +SECStatus
  1.2092 +PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
  1.2093 +	SECStatus(* callback)(CERTCertificate*, void *), void *arg)
  1.2094 +{
  1.2095 +    PRStatus nssrv;
  1.2096 +    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
  1.2097 +    NSSToken *tok;
  1.2098 +    nssList *certList = NULL;
  1.2099 +    nssCryptokiObject **instances;
  1.2100 +    nssPKIObjectCollection *collection;
  1.2101 +    NSSCertificate **certs;
  1.2102 +    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
  1.2103 +    tok = PK11Slot_GetNSSToken(slot);
  1.2104 +    if (!nssToken_IsPresent(tok)) {
  1.2105 +	return SECSuccess;
  1.2106 +    }
  1.2107 +    collection = nssCertificateCollection_Create(td, NULL);
  1.2108 +    if (!collection) {
  1.2109 +	return SECFailure;
  1.2110 +    }
  1.2111 +    certList = nssList_Create(NULL, PR_FALSE);
  1.2112 +    if (!certList) {
  1.2113 +	nssPKIObjectCollection_Destroy(collection);
  1.2114 +	return SECFailure;
  1.2115 +    }
  1.2116 +    (void)nssTrustDomain_GetCertsFromCache(td, certList);
  1.2117 +    transfer_token_certs_to_collection(certList, tok, collection);
  1.2118 +    instances = nssToken_FindObjects(tok, NULL, CKO_CERTIFICATE,
  1.2119 +                                     tokenOnly, 0, &nssrv);
  1.2120 +    nssPKIObjectCollection_AddInstances(collection, instances, 0);
  1.2121 +    nss_ZFreeIf(instances);
  1.2122 +    nssList_Destroy(certList);
  1.2123 +    certs = nssPKIObjectCollection_GetCertificates(collection,
  1.2124 +                                                   NULL, 0, NULL);
  1.2125 +    nssPKIObjectCollection_Destroy(collection);
  1.2126 +    if (certs) {
  1.2127 +	CERTCertificate *oldie;
  1.2128 +	NSSCertificate **cp;
  1.2129 +	for (cp = certs; *cp; cp++) {
  1.2130 +	    oldie = STAN_GetCERTCertificate(*cp);
  1.2131 +	    if (!oldie) {
  1.2132 +		continue;
  1.2133 +	    }
  1.2134 +	    if ((*callback)(oldie, arg) != SECSuccess) {
  1.2135 +		nssrv = PR_FAILURE;
  1.2136 +		break;
  1.2137 +	    }
  1.2138 +	}
  1.2139 +	nssCertificateArray_Destroy(certs);
  1.2140 +    }
  1.2141 +    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
  1.2142 +}
  1.2143 +
  1.2144 +/*
  1.2145 + * return the certificate associated with a derCert 
  1.2146 + */
  1.2147 +CERTCertificate *
  1.2148 +PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
  1.2149 +								 void *wincx)
  1.2150 +{
  1.2151 +    return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx);
  1.2152 +}
  1.2153 +
  1.2154 +CERTCertificate *
  1.2155 +PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, const SECItem *inDerCert,
  1.2156 +								 void *wincx)
  1.2157 +
  1.2158 +{
  1.2159 +    NSSDER derCert;
  1.2160 +    NSSToken *tok;
  1.2161 +    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
  1.2162 +    nssCryptokiObject *co = NULL;
  1.2163 +    SECStatus rv;
  1.2164 +
  1.2165 +    tok = PK11Slot_GetNSSToken(slot);
  1.2166 +    NSSITEM_FROM_SECITEM(&derCert, inDerCert);
  1.2167 +    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
  1.2168 +    if (rv != SECSuccess) {
  1.2169 +	PK11_FreeSlot(slot);
  1.2170 +	return NULL;
  1.2171 +    }
  1.2172 +
  1.2173 +    co = nssToken_FindCertificateByEncodedCertificate(tok, NULL, &derCert,
  1.2174 +                                          nssTokenSearchType_TokenOnly, NULL);
  1.2175 +
  1.2176 +    return co ? PK11_MakeCertFromHandle(slot, co->handle, NULL) : NULL;
  1.2177 +
  1.2178 +} 
  1.2179 +
  1.2180 +/*
  1.2181 + * import a cert for a private key we have already generated. Set the label
  1.2182 + * on both to be the nickname.
  1.2183 + */
  1.2184 +static CK_OBJECT_HANDLE 
  1.2185 +pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 
  1.2186 +								void *wincx)
  1.2187 +{
  1.2188 +    SECItem *keyID;
  1.2189 +    CK_OBJECT_HANDLE key;
  1.2190 +    SECStatus rv;
  1.2191 +    PRBool needLogin;
  1.2192 +    int err;
  1.2193 +
  1.2194 +    if((slot == NULL) || (cert == NULL)) {
  1.2195 +	return CK_INVALID_HANDLE;
  1.2196 +    }
  1.2197 +
  1.2198 +    keyID = pk11_mkcertKeyID(cert);
  1.2199 +    if(keyID == NULL) {
  1.2200 +	return CK_INVALID_HANDLE;
  1.2201 +    }
  1.2202 +
  1.2203 +    /*
  1.2204 +     * prevent a login race condition. If slot is logged in between
  1.2205 +     * our call to pk11_LoginStillRequired and the 
  1.2206 +     * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or
  1.2207 +     * we will call it one more time after calling PK11_Authenticate 
  1.2208 +     * (which is a noop on an authenticated token).
  1.2209 +     */
  1.2210 +    needLogin = pk11_LoginStillRequired(slot,wincx);
  1.2211 +    key = pk11_FindPrivateKeyFromCertID(slot, keyID);
  1.2212 +    if ((key == CK_INVALID_HANDLE) && needLogin &&
  1.2213 +			(SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
  1.2214 +			 SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) {
  1.2215 +	/* authenticate and try again */
  1.2216 +	rv = PK11_Authenticate(slot, PR_TRUE, wincx);
  1.2217 +	if (rv != SECSuccess) goto loser;
  1.2218 +	key = pk11_FindPrivateKeyFromCertID(slot, keyID);
  1.2219 +   }
  1.2220 +
  1.2221 +loser:
  1.2222 +    SECITEM_ZfreeItem(keyID, PR_TRUE);
  1.2223 +    return key;
  1.2224 +}
  1.2225 +
  1.2226 +SECKEYPrivateKey *
  1.2227 +PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 
  1.2228 +								void *wincx)
  1.2229 +{
  1.2230 +    CK_OBJECT_HANDLE keyHandle;
  1.2231 +
  1.2232 +    if((slot == NULL) || (cert == NULL)) {
  1.2233 +	return NULL;
  1.2234 +    }
  1.2235 +
  1.2236 +    keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
  1.2237 +    if (keyHandle == CK_INVALID_HANDLE) {
  1.2238 +	return NULL;
  1.2239 +    }
  1.2240 +
  1.2241 +    return PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,wincx);
  1.2242 +}
  1.2243 +
  1.2244 +SECStatus
  1.2245 +PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert, 
  1.2246 +						char *nickname, 
  1.2247 +						PRBool addCertUsage,void *wincx)
  1.2248 +{
  1.2249 +    CK_OBJECT_HANDLE keyHandle;
  1.2250 +
  1.2251 +    if((slot == NULL) || (cert == NULL) || (nickname == NULL)) {
  1.2252 +	return SECFailure;
  1.2253 +    }
  1.2254 +
  1.2255 +    keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
  1.2256 +    if (keyHandle == CK_INVALID_HANDLE) {
  1.2257 +	return SECFailure;
  1.2258 +    }
  1.2259 +
  1.2260 +    return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage);
  1.2261 +}   
  1.2262 +
  1.2263 +
  1.2264 +/* remove when the real version comes out */
  1.2265 +#define SEC_OID_MISSI_KEA 300  /* until we have v3 stuff merged */
  1.2266 +PRBool
  1.2267 +KEAPQGCompare(CERTCertificate *server,CERTCertificate *cert) {
  1.2268 +
  1.2269 +    /* not implemented */
  1.2270 +    return PR_FALSE;
  1.2271 +}
  1.2272 +
  1.2273 +PRBool
  1.2274 +PK11_FortezzaHasKEA(CERTCertificate *cert) 
  1.2275 +{
  1.2276 +   /* look at the subject and see if it is a KEA for MISSI key */
  1.2277 +   SECOidData *oid;
  1.2278 +   CERTCertTrust trust;
  1.2279 +
  1.2280 +   if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
  1.2281 +       ((trust.sslFlags & CERTDB_USER) != CERTDB_USER)) {
  1.2282 +       return PR_FALSE;
  1.2283 +   }
  1.2284 +
  1.2285 +   oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm);
  1.2286 +   if (!oid) {
  1.2287 +       return PR_FALSE;
  1.2288 +   }
  1.2289 +
  1.2290 +   return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) || 
  1.2291 +		(oid->offset == SEC_OID_MISSI_KEA_DSS) ||
  1.2292 +				(oid->offset == SEC_OID_MISSI_KEA)) ;
  1.2293 +}
  1.2294 +
  1.2295 +/*
  1.2296 + * Find a kea cert on this slot that matches the domain of it's peer
  1.2297 + */
  1.2298 +static CERTCertificate
  1.2299 +*pk11_GetKEAMate(PK11SlotInfo *slot,CERTCertificate *peer)
  1.2300 +{
  1.2301 +    int i;
  1.2302 +    CERTCertificate *returnedCert = NULL;
  1.2303 +
  1.2304 +    for (i=0; i < slot->cert_count; i++) {
  1.2305 +	CERTCertificate *cert = slot->cert_array[i];
  1.2306 +
  1.2307 +	if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer,cert)) {
  1.2308 +		returnedCert = CERT_DupCertificate(cert);
  1.2309 +		break;
  1.2310 +	}
  1.2311 +    }
  1.2312 +    return returnedCert;
  1.2313 +}
  1.2314 +
  1.2315 +/*
  1.2316 + * The following is a FORTEZZA only Certificate request. We call this when we
  1.2317 + * are doing a non-client auth SSL connection. We are only interested in the
  1.2318 + * fortezza slots, and we are only interested in certs that share the same root
  1.2319 + * key as the server.
  1.2320 + */
  1.2321 +CERTCertificate *
  1.2322 +PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx)
  1.2323 +{
  1.2324 +    PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE,
  1.2325 +							PR_FALSE,PR_TRUE,wincx);
  1.2326 +    PK11SlotListElement *le;
  1.2327 +    CERTCertificate *returnedCert = NULL;
  1.2328 +    SECStatus rv;
  1.2329 +
  1.2330 +    if (!keaList) {
  1.2331 +        /* error code is set */
  1.2332 +        return NULL;
  1.2333 +    }
  1.2334 +
  1.2335 +    /* loop through all the fortezza tokens */
  1.2336 +    for (le = keaList->head; le; le = le->next) {
  1.2337 +        rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
  1.2338 +        if (rv != SECSuccess) continue;
  1.2339 +	if (le->slot->session == CK_INVALID_SESSION) {
  1.2340 +	    continue;
  1.2341 +	}
  1.2342 +	returnedCert = pk11_GetKEAMate(le->slot,server);
  1.2343 +	if (returnedCert) break;
  1.2344 +    }
  1.2345 +    PK11_FreeSlotList(keaList);
  1.2346 +
  1.2347 +    return returnedCert;
  1.2348 +}
  1.2349 +
  1.2350 +/*
  1.2351 + * find a matched pair of kea certs to key exchange parameters from one 
  1.2352 + * fortezza card to another as necessary.
  1.2353 + */
  1.2354 +SECStatus
  1.2355 +PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2,
  1.2356 +	CERTCertificate **cert1, CERTCertificate **cert2)
  1.2357 +{
  1.2358 +    CERTCertificate *returnedCert = NULL;
  1.2359 +    int i;
  1.2360 +
  1.2361 +    for (i=0; i < slot1->cert_count; i++) {
  1.2362 +	CERTCertificate *cert = slot1->cert_array[i];
  1.2363 +
  1.2364 +	if (PK11_FortezzaHasKEA(cert)) {
  1.2365 +	    returnedCert = pk11_GetKEAMate(slot2,cert);
  1.2366 +	    if (returnedCert != NULL) {
  1.2367 +		*cert2 = returnedCert;
  1.2368 +		*cert1 = CERT_DupCertificate(cert);
  1.2369 +		return SECSuccess;
  1.2370 +	    }
  1.2371 +	}
  1.2372 +    }
  1.2373 +    return SECFailure;
  1.2374 +}
  1.2375 +
  1.2376 +/*
  1.2377 + * return the private key From a given Cert
  1.2378 + */
  1.2379 +CK_OBJECT_HANDLE
  1.2380 +PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx)
  1.2381 +{
  1.2382 +    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
  1.2383 +    CK_ATTRIBUTE theTemplate[] = {
  1.2384 +	{ CKA_VALUE, NULL, 0 },
  1.2385 +	{ CKA_CLASS, NULL, 0 }
  1.2386 +    };
  1.2387 +    /* if you change the array, change the variable below as well */
  1.2388 +    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
  1.2389 +    CK_ATTRIBUTE *attrs = theTemplate;
  1.2390 +    SECStatus rv;
  1.2391 +
  1.2392 +    PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
  1.2393 +						cert->derCert.len); attrs++;
  1.2394 +    PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
  1.2395 +
  1.2396 +    /*
  1.2397 +     * issue the find
  1.2398 +     */
  1.2399 +    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
  1.2400 +    if (rv != SECSuccess) {
  1.2401 +	return CK_INVALID_HANDLE;
  1.2402 +    }
  1.2403 +
  1.2404 +    return pk11_getcerthandle(slot,cert,theTemplate,tsize);
  1.2405 +}
  1.2406 +
  1.2407 +/* Looking for PK11_GetKeyIDFromCert?  
  1.2408 + * Use PK11_GetLowLevelKeyIDForCert instead.
  1.2409 + */
  1.2410 +
  1.2411 +
  1.2412 +struct listCertsStr {
  1.2413 +    PK11CertListType type;
  1.2414 +    CERTCertList *certList;
  1.2415 +};
  1.2416 +
  1.2417 +static PRStatus
  1.2418 +pk11ListCertCallback(NSSCertificate *c, void *arg)
  1.2419 +{
  1.2420 +    struct listCertsStr *listCertP = (struct listCertsStr *)arg;
  1.2421 +    CERTCertificate *newCert = NULL;
  1.2422 +    PK11CertListType type = listCertP->type;
  1.2423 +    CERTCertList *certList = listCertP->certList;
  1.2424 +    PRBool isUnique = PR_FALSE;
  1.2425 +    PRBool isCA = PR_FALSE;
  1.2426 +    char *nickname = NULL;
  1.2427 +    unsigned int certType;
  1.2428 +    SECStatus rv;
  1.2429 +
  1.2430 +    if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique) ||
  1.2431 +        (type == PK11CertListCAUnique) || (type == PK11CertListUserUnique) ) {
  1.2432 +        /* only list one instance of each certificate, even if several exist */
  1.2433 +	isUnique = PR_TRUE;
  1.2434 +    }
  1.2435 +    if ((type == PK11CertListCA) || (type == PK11CertListRootUnique) ||
  1.2436 +        (type == PK11CertListCAUnique)) {
  1.2437 +	isCA = PR_TRUE;
  1.2438 +    }
  1.2439 +
  1.2440 +    /* if we want user certs and we don't have one skip this cert */
  1.2441 +    if ( ( (type == PK11CertListUser) || (type == PK11CertListUserUnique) ) && 
  1.2442 +		!NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) {
  1.2443 +	return PR_SUCCESS;
  1.2444 +    }
  1.2445 +
  1.2446 +    /* PK11CertListRootUnique means we want CA certs without a private key.
  1.2447 +     * This is for legacy app support . PK11CertListCAUnique should be used
  1.2448 +     * instead to get all CA certs, regardless of private key
  1.2449 +     */
  1.2450 +    if ((type == PK11CertListRootUnique) && 
  1.2451 +		NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) {
  1.2452 +	return PR_SUCCESS;
  1.2453 +    }
  1.2454 +
  1.2455 +    /* caller still owns the reference to 'c' */
  1.2456 +    newCert = STAN_GetCERTCertificate(c);
  1.2457 +    if (!newCert) {
  1.2458 +	return PR_SUCCESS;
  1.2459 +    }
  1.2460 +    /* if we want CA certs and it ain't one, skip it */
  1.2461 +    if( isCA  && (!CERT_IsCACert(newCert, &certType)) ) {
  1.2462 +	return PR_SUCCESS;
  1.2463 +    }
  1.2464 +    if (isUnique) {
  1.2465 +	CERT_DupCertificate(newCert);
  1.2466 +
  1.2467 +	nickname = STAN_GetCERTCertificateName(certList->arena, c);
  1.2468 +
  1.2469 +	/* put slot certs at the end */
  1.2470 +	if (newCert->slot && !PK11_IsInternal(newCert->slot)) {
  1.2471 +	    rv = CERT_AddCertToListTailWithData(certList,newCert,nickname);
  1.2472 +	} else {
  1.2473 +	    rv = CERT_AddCertToListHeadWithData(certList,newCert,nickname);
  1.2474 +	}
  1.2475 +	/* if we didn't add the cert to the list, don't leak it */
  1.2476 +	if (rv != SECSuccess) {
  1.2477 +	    CERT_DestroyCertificate(newCert);
  1.2478 +	}
  1.2479 +    } else {
  1.2480 +	/* add multiple instances to the cert list */
  1.2481 +	nssCryptokiObject **ip;
  1.2482 +	nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
  1.2483 +	if (!instances) {
  1.2484 +	    return PR_SUCCESS;
  1.2485 +	}
  1.2486 +	for (ip = instances; *ip; ip++) {
  1.2487 +	    nssCryptokiObject *instance = *ip;
  1.2488 +	    PK11SlotInfo *slot = instance->token->pk11slot;
  1.2489 +
  1.2490 +	    /* put the same CERTCertificate in the list for all instances */
  1.2491 +	    CERT_DupCertificate(newCert);
  1.2492 +
  1.2493 +	    nickname = STAN_GetCERTCertificateNameForInstance(
  1.2494 +			certList->arena, c, instance);
  1.2495 +
  1.2496 +	    /* put slot certs at the end */
  1.2497 +	    if (slot && !PK11_IsInternal(slot)) {
  1.2498 +		rv = CERT_AddCertToListTailWithData(certList,newCert,nickname);
  1.2499 +	    } else {
  1.2500 +		rv = CERT_AddCertToListHeadWithData(certList,newCert,nickname);
  1.2501 +	    }
  1.2502 +	    /* if we didn't add the cert to the list, don't leak it */
  1.2503 +	    if (rv != SECSuccess) {
  1.2504 +		CERT_DestroyCertificate(newCert);
  1.2505 +	    }
  1.2506 +	}
  1.2507 +	nssCryptokiObjectArray_Destroy(instances);
  1.2508 +    }
  1.2509 +    return PR_SUCCESS;
  1.2510 +}
  1.2511 +
  1.2512 +
  1.2513 +CERTCertList *
  1.2514 +PK11_ListCerts(PK11CertListType type, void *pwarg)
  1.2515 +{
  1.2516 +    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
  1.2517 +    CERTCertList *certList = NULL;
  1.2518 +    struct listCertsStr listCerts;
  1.2519 +    certList = CERT_NewCertList();
  1.2520 +    listCerts.type = type;
  1.2521 +    listCerts.certList = certList;
  1.2522 +
  1.2523 +    /* authenticate to the slots */
  1.2524 +    (void) pk11_TraverseAllSlots( NULL, NULL, PR_TRUE, pwarg);
  1.2525 +    NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback,
  1.2526 +								 &listCerts);
  1.2527 +    return certList;
  1.2528 +}
  1.2529 +    
  1.2530 +SECItem *
  1.2531 +PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
  1.2532 +					CERTCertificate *cert, void *wincx)
  1.2533 +{
  1.2534 +    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
  1.2535 +    CK_ATTRIBUTE theTemplate[] = {
  1.2536 +	{ CKA_VALUE, NULL, 0 },
  1.2537 +	{ CKA_CLASS, NULL, 0 }
  1.2538 +    };
  1.2539 +    /* if you change the array, change the variable below as well */
  1.2540 +    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
  1.2541 +    CK_OBJECT_HANDLE certHandle;
  1.2542 +    CK_ATTRIBUTE *attrs = theTemplate;
  1.2543 +    PK11SlotInfo *slotRef = NULL;
  1.2544 +    SECItem *item;
  1.2545 +    SECStatus rv;
  1.2546 +
  1.2547 +    if (slot) {
  1.2548 +	PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, 
  1.2549 +						cert->derCert.len); attrs++;
  1.2550 +	PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
  1.2551 + 
  1.2552 +	rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
  1.2553 +	if (rv != SECSuccess) {
  1.2554 +	    return NULL;
  1.2555 +	}
  1.2556 +        certHandle = pk11_getcerthandle(slot,cert,theTemplate,tsize);
  1.2557 +    } else {
  1.2558 +    	certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef);
  1.2559 +	if (certHandle == CK_INVALID_HANDLE) {
  1.2560 +	   return pk11_mkcertKeyID(cert);
  1.2561 +	}
  1.2562 +	slot = slotRef;
  1.2563 +    }
  1.2564 +
  1.2565 +    if (certHandle == CK_INVALID_HANDLE) {
  1.2566 +	 return NULL;
  1.2567 +    }
  1.2568 +
  1.2569 +    item = pk11_GetLowLevelKeyFromHandle(slot,certHandle);
  1.2570 +    if (slotRef) PK11_FreeSlot(slotRef);
  1.2571 +    return item;
  1.2572 +}
  1.2573 +
  1.2574 +/* argument type for listCertsCallback */
  1.2575 +typedef struct {
  1.2576 +    CERTCertList *list;
  1.2577 +    PK11SlotInfo *slot;
  1.2578 +} ListCertsArg;
  1.2579 +
  1.2580 +static SECStatus
  1.2581 +listCertsCallback(CERTCertificate* cert, void*arg)
  1.2582 +{
  1.2583 +    ListCertsArg *cdata = (ListCertsArg*)arg;
  1.2584 +    char *nickname = NULL;
  1.2585 +    nssCryptokiObject *instance, **ci;
  1.2586 +    nssCryptokiObject **instances;
  1.2587 +    NSSCertificate *c = STAN_GetNSSCertificate(cert);
  1.2588 +    SECStatus rv;
  1.2589 +
  1.2590 +    if (c == NULL) {
  1.2591 +        return SECFailure;
  1.2592 +    }
  1.2593 +    instances = nssPKIObject_GetInstances(&c->object);
  1.2594 +    if (!instances) {
  1.2595 +        return SECFailure;
  1.2596 +    }
  1.2597 +    instance = NULL;
  1.2598 +    for (ci = instances; *ci; ci++) {
  1.2599 +	if ((*ci)->token->pk11slot == cdata->slot) {
  1.2600 +	    instance = *ci;
  1.2601 +	    break;
  1.2602 +	}
  1.2603 +    }
  1.2604 +    PORT_Assert(instance != NULL);
  1.2605 +    if (!instance) {
  1.2606 +	nssCryptokiObjectArray_Destroy(instances);
  1.2607 +	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2608 +	return SECFailure;
  1.2609 +    }
  1.2610 +    nickname = STAN_GetCERTCertificateNameForInstance(cdata->list->arena,
  1.2611 +						      c, instance);
  1.2612 +    nssCryptokiObjectArray_Destroy(instances);
  1.2613 +
  1.2614 +    CERT_DupCertificate(cert);
  1.2615 +    rv = CERT_AddCertToListTailWithData(cdata->list, cert, nickname);
  1.2616 +    if (rv != SECSuccess) {
  1.2617 +	CERT_DestroyCertificate(cert);
  1.2618 +    }
  1.2619 +    return rv;
  1.2620 +}
  1.2621 +
  1.2622 +CERTCertList *
  1.2623 +PK11_ListCertsInSlot(PK11SlotInfo *slot)
  1.2624 +{
  1.2625 +    SECStatus status;
  1.2626 +    CERTCertList *certs;
  1.2627 +    ListCertsArg cdata;
  1.2628 +
  1.2629 +    certs = CERT_NewCertList();
  1.2630 +    if(certs == NULL) return NULL;
  1.2631 +    cdata.list = certs;
  1.2632 +    cdata.slot = slot;
  1.2633 +
  1.2634 +    status = PK11_TraverseCertsInSlot(slot, listCertsCallback,
  1.2635 +		&cdata);
  1.2636 +
  1.2637 +    if( status != SECSuccess ) {
  1.2638 +	CERT_DestroyCertList(certs);
  1.2639 +	certs = NULL;
  1.2640 +    }
  1.2641 +
  1.2642 +    return certs;
  1.2643 +}
  1.2644 +
  1.2645 +PK11SlotList *
  1.2646 +PK11_GetAllSlotsForCert(CERTCertificate *cert, void *arg)
  1.2647 +{
  1.2648 +    nssCryptokiObject **ip;
  1.2649 +    PK11SlotList *slotList;
  1.2650 +    NSSCertificate *c;
  1.2651 +    nssCryptokiObject **instances;
  1.2652 +    PRBool found = PR_FALSE;
  1.2653 +
  1.2654 +    if (!cert) {
  1.2655 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2656 +	return NULL;
  1.2657 +    }
  1.2658 +
  1.2659 +    c = STAN_GetNSSCertificate(cert);
  1.2660 +    if (!c) {
  1.2661 +	CERT_MapStanError();
  1.2662 +	return NULL;
  1.2663 +    }
  1.2664 +
  1.2665 +    /* add multiple instances to the cert list */
  1.2666 +    instances = nssPKIObject_GetInstances(&c->object);
  1.2667 +    if (!instances) {
  1.2668 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.2669 +	return NULL;
  1.2670 +    }
  1.2671 +
  1.2672 +    slotList = PK11_NewSlotList();
  1.2673 +    if (!slotList) {
  1.2674 +	nssCryptokiObjectArray_Destroy(instances);
  1.2675 +	return NULL;
  1.2676 +    }
  1.2677 +
  1.2678 +    for (ip = instances; *ip; ip++) {
  1.2679 +	nssCryptokiObject *instance = *ip;
  1.2680 +	PK11SlotInfo *slot = instance->token->pk11slot;
  1.2681 +	if (slot) {
  1.2682 +	    PK11_AddSlotToList(slotList, slot, PR_TRUE);
  1.2683 +	    found = PR_TRUE;
  1.2684 +	}
  1.2685 +    }
  1.2686 +    if (!found) {
  1.2687 +	PK11_FreeSlotList(slotList);
  1.2688 +	PORT_SetError(SEC_ERROR_NO_TOKEN);
  1.2689 +	slotList = NULL;
  1.2690 +    }
  1.2691 +
  1.2692 +    nssCryptokiObjectArray_Destroy(instances);
  1.2693 +    return slotList;
  1.2694 +}

mercurial