/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 * Sun Microsystems, Inc. All Rights Reserved. * * Contributor(s): * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */ /* * This file implements the Symkey wrapper and the PKCS context * Interfaces. */ #include "secport.h" #include "seccomon.h" #include "secmod.h" #include "nssilock.h" #include "secmodi.h" #include "pkcs11.h" #include "pk11func.h" #include "cert.h" #include "certi.h" #include "secitem.h" #include "key.h" #include "hasht.h" #include "secoid.h" #include "pkcs7t.h" #include "cmsreclist.h" #include "certdb.h" #include "secerr.h" #include "sslerr.h" #ifndef NSS_3_4_CODE #define NSS_3_4_CODE #endif /* NSS_3_4_CODE */ #include "pki3hack.h" #include "dev3hack.h" #include "devm.h" #include "nsspki.h" #include "pki.h" #include "pkim.h" #include "pkitm.h" #include "pkistore.h" /* to remove temp cert */ #include "devt.h" #define PK11_SEARCH_CHUNKSIZE 10 extern const NSSError NSS_ERROR_NOT_FOUND; CK_OBJECT_HANDLE pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx); struct nss3_cert_cbstr { SECStatus(* callback)(CERTCertificate*, void *); nssList *cached; void *arg; }; /* Translate from NSSCertificate to CERTCertificate, then pass the latter * to a callback. */ static PRStatus convert_cert(NSSCertificate *c, void *arg) { CERTCertificate *nss3cert; SECStatus secrv; struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg; nss3cert = STAN_GetCERTCertificate(c); if (!nss3cert) return PR_FAILURE; secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg); return (secrv) ? PR_FAILURE : PR_SUCCESS; } void PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst) { sl->nssToken = nsst; } NSSToken * PK11Slot_GetNSSToken(PK11SlotInfo *sl) { return sl->nssToken; } /* * build a cert nickname based on the token name and the label of the * certificate If the label in NULL, build a label based on the ID. */ static int toHex(int x) { return (x < 10) ? (x+'0') : (x+'a'-10); } #define MAX_CERT_ID 4 #define DEFAULT_STRING "Cert ID " static char * pk11_buildNickname(PK11SlotInfo *slot,CK_ATTRIBUTE *cert_label, CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id) { int prefixLen = PORT_Strlen(slot->token_name); int suffixLen = 0; char *suffix = NULL; char buildNew[sizeof(DEFAULT_STRING)+MAX_CERT_ID*2]; char *next,*nickname; if (cert_label && (cert_label->ulValueLen)) { suffixLen = cert_label->ulValueLen; suffix = (char*)cert_label->pValue; } else if (key_label && (key_label->ulValueLen)) { suffixLen = key_label->ulValueLen; suffix = (char*)key_label->pValue; } else if (cert_id && cert_id->ulValueLen > 0) { int i,first = cert_id->ulValueLen - MAX_CERT_ID; int offset = sizeof(DEFAULT_STRING); char *idValue = (char *)cert_id->pValue; PORT_Memcpy(buildNew,DEFAULT_STRING,sizeof(DEFAULT_STRING)-1); next = buildNew + offset; if (first < 0) first = 0; for (i=first; i < (int) cert_id->ulValueLen; i++) { *next++ = toHex((idValue[i] >> 4) & 0xf); *next++ = toHex(idValue[i] & 0xf); } *next++ = 0; suffix = buildNew; suffixLen = PORT_Strlen(buildNew); } else { PORT_SetError( SEC_ERROR_LIBRARY_FAILURE ); return NULL; } /* if is internal key slot, add code to skip the prefix!! */ next = nickname = (char *)PORT_Alloc(prefixLen+1+suffixLen+1); if (nickname == NULL) return NULL; PORT_Memcpy(next,slot->token_name,prefixLen); next += prefixLen; *next++ = ':'; PORT_Memcpy(next,suffix,suffixLen); next += suffixLen; *next++ = 0; return nickname; } /* * return the object handle that matches the template */ CK_OBJECT_HANDLE pk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize) { CK_OBJECT_HANDLE object; CK_RV crv; CK_ULONG objectCount; /* * issue the find */ PK11_EnterSlotMonitor(slot); crv=PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, theTemplate, tsize); if (crv != CKR_OK) { PK11_ExitSlotMonitor(slot); PORT_SetError( PK11_MapError(crv) ); return CK_INVALID_HANDLE; } crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount); PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); PK11_ExitSlotMonitor(slot); if ((crv != CKR_OK) || (objectCount < 1)) { /* shouldn't use SSL_ERROR... here */ PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) : SSL_ERROR_NO_CERTIFICATE); return CK_INVALID_HANDLE; } /* blow up if the PKCS #11 module returns us and invalid object handle */ PORT_Assert(object != CK_INVALID_HANDLE); return object; } /* * return all the object handles that matches the template */ CK_OBJECT_HANDLE * pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate,int findCount,int *object_count) { CK_OBJECT_HANDLE *objID = NULL; CK_ULONG returned_count = 0; CK_RV crv; PK11_EnterSlotMonitor(slot); crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, findTemplate, findCount); if (crv != CKR_OK) { PK11_ExitSlotMonitor(slot); PORT_SetError( PK11_MapError(crv) ); *object_count = -1; return NULL; } /* * collect all the Matching Objects */ do { CK_OBJECT_HANDLE *oldObjID = objID; if (objID == NULL) { objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)* (*object_count+ PK11_SEARCH_CHUNKSIZE)); } else { objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID, sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE)); } if (objID == NULL) { if (oldObjID) PORT_Free(oldObjID); break; } crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, &objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); PORT_Free(objID); objID = NULL; break; } *object_count += returned_count; } while (returned_count == PK11_SEARCH_CHUNKSIZE); PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); PK11_ExitSlotMonitor(slot); if (objID && (*object_count == 0)) { PORT_Free(objID); return NULL; } if (objID == NULL) *object_count = -1; return objID; } /* * given a PKCS #11 object, match it's peer based on the KeyID. searchID * is typically a privateKey or a certificate while the peer is the opposite */ CK_OBJECT_HANDLE PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID, CK_OBJECT_CLASS matchclass) { CK_ATTRIBUTE theTemplate[] = { { CKA_ID, NULL, 0 }, { CKA_CLASS, NULL, 0 } }; /* if you change the array, change the variable below as well */ CK_ATTRIBUTE *keyclass = &theTemplate[1]; int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); /* if you change the array, change the variable below as well */ CK_OBJECT_HANDLE peerID; CK_OBJECT_HANDLE parent; PRArenaPool *arena; CK_RV crv; /* now we need to create space for the public key */ arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); if (arena == NULL) return CK_INVALID_HANDLE; crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize); if (crv != CKR_OK) { PORT_FreeArena(arena,PR_FALSE); PORT_SetError( PK11_MapError(crv) ); return CK_INVALID_HANDLE; } if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) { PORT_FreeArena(arena,PR_FALSE); PORT_SetError(SEC_ERROR_BAD_KEY); return CK_INVALID_HANDLE; } /* * issue the find */ parent = *(CK_OBJECT_CLASS *)(keyclass->pValue); *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass; peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize); PORT_FreeArena(arena,PR_FALSE); return peerID; } PRBool PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert, CK_OBJECT_HANDLE certID) { CK_OBJECT_CLASS theClass; if (slot == NULL) return PR_FALSE; if (cert == NULL) return PR_FALSE; theClass = CKO_PRIVATE_KEY; if (!PK11_IsLoggedIn(slot,NULL) && PK11_NeedLogin(slot)) { theClass = CKO_PUBLIC_KEY; } if (PK11_MatchItem(slot, certID , theClass) != CK_INVALID_HANDLE) { return PR_TRUE; } if (theClass == CKO_PUBLIC_KEY) { SECKEYPublicKey *pubKey= CERT_ExtractPublicKey(cert); CK_ATTRIBUTE theTemplate; if (pubKey == NULL) { return PR_FALSE; } PK11_SETATTRS(&theTemplate,0,NULL,0); switch (pubKey->keyType) { case rsaKey: PK11_SETATTRS(&theTemplate,CKA_MODULUS, pubKey->u.rsa.modulus.data, pubKey->u.rsa.modulus.len); break; case dsaKey: PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dsa.publicValue.data, pubKey->u.dsa.publicValue.len); break; case dhKey: PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dh.publicValue.data, pubKey->u.dh.publicValue.len); break; #ifdef NSS_ENABLE_ECC case ecKey: PK11_SETATTRS(&theTemplate,CKA_EC_POINT, pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len); break; #endif /* NSS_ENABLE_ECC */ case keaKey: case fortezzaKey: case nullKey: /* fall through and return false */ break; } if (theTemplate.ulValueLen == 0) { SECKEY_DestroyPublicKey(pubKey); return PR_FALSE; } pk11_SignedToUnsigned(&theTemplate); if (pk11_FindObjectByTemplate(slot,&theTemplate,1) != CK_INVALID_HANDLE) { SECKEY_DestroyPublicKey(pubKey); return PR_TRUE; } SECKEY_DestroyPublicKey(pubKey); } return PR_FALSE; } /* * Check out if a cert has ID of zero. This is a magic ID that tells * NSS that this cert may be an automagically trusted cert. * The Cert has to be self signed as well. That check is done elsewhere. * */ PRBool pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID) { CK_ATTRIBUTE keyID = {CKA_ID, NULL, 0}; PRBool isZero = PR_FALSE; int i; CK_RV crv; crv = PK11_GetAttributes(NULL,slot,certID,&keyID,1); if (crv != CKR_OK) { return isZero; } if (keyID.ulValueLen != 0) { char *value = (char *)keyID.pValue; isZero = PR_TRUE; /* ID exists, may be zero */ for (i=0; i < (int) keyID.ulValueLen; i++) { if (value[i] != 0) { isZero = PR_FALSE; /* nope */ break; } } } PORT_Free(keyID.pValue); return isZero; } /* * Create an NSSCertificate from a slot/certID pair, return it as a * CERTCertificate. */ static CERTCertificate *pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, CK_ATTRIBUTE *privateLabel, char **nickptr) { NSSCertificate *c; nssCryptokiObject *co; nssPKIObject *pkio; NSSToken *token; NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); /* Get the cryptoki object from the handle */ token = PK11Slot_GetNSSToken(slot); co = nssCryptokiObject_Create(token, token->defaultSession, certID); if (!co) { return NULL; } /* Create a PKI object from the cryptoki instance */ pkio = nssPKIObject_Create(NULL, co, td, NULL); if (!pkio) { nssCryptokiObject_Destroy(co); return NULL; } /* Create a certificate */ c = nssCertificate_Create(pkio); if (!c) { nssPKIObject_Destroy(pkio); return NULL; } nssTrustDomain_AddCertsToCache(td, &c, 1); /* Build the old-fashioned nickname */ if ((nickptr) && (co->label)) { CK_ATTRIBUTE label, id; label.type = CKA_LABEL; label.pValue = co->label; label.ulValueLen = PORT_Strlen(co->label); id.type = CKA_ID; id.pValue = c->id.data; id.ulValueLen = c->id.size; *nickptr = pk11_buildNickname(slot, &label, privateLabel, &id); } return STAN_GetCERTCertificate(c); } CK_TRUST pk11_GetTrustField(PK11SlotInfo *slot, PRArenaPool *arena, CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type) { CK_TRUST rv = 0; SECItem item; item.data = NULL; item.len = 0; if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) { PORT_Assert(item.len == sizeof(CK_TRUST)); PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST)); /* Damn, is there an endian problem here? */ return rv; } return 0; } PRBool pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust) { PRArenaPool *arena; CK_ATTRIBUTE tobjTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_CERT_SHA1_HASH, NULL, 0 }, }; CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; CK_OBJECT_HANDLE tobjID; unsigned char sha1_hash[SHA1_LENGTH]; CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth; PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len); PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc)); PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash, SHA1_LENGTH); tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate, sizeof(tobjTemplate)/sizeof(tobjTemplate[0])); if( CK_INVALID_HANDLE == tobjID ) { return PR_FALSE; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if( NULL == arena ) return PR_FALSE; /* Unfortunately, it seems that PK11_GetAttributes doesn't deal * well with nonexistant attributes. I guess we have to check * the trust info fields one at a time. */ /* We could verify CKA_CERT_HASH here */ /* We could verify CKA_EXPIRES here */ /* "Purpose" trust information */ serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH); clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH); codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING); emailProtection = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_EMAIL_PROTECTION); /* Here's where the fun logic happens. We have to map back from the * key usage, extended key usage, purpose, and possibly other trust values * into the old trust-flags bits. */ /* First implementation: keep it simple for testing. We can study what other * mappings would be appropriate and add them later.. fgmr 20000724 */ if ( serverAuth == CKT_NETSCAPE_TRUSTED ) { trust->sslFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; } if ( serverAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; } if ( clientAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { trust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA ; } if ( emailProtection == CKT_NETSCAPE_TRUSTED ) { trust->emailFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; } if ( emailProtection == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; } if( codeSigning == CKT_NETSCAPE_TRUSTED ) { trust->objectSigningFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; } if( codeSigning == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; } /* There's certainly a lot more logic that can go here.. */ PORT_FreeArena(arena, PR_FALSE); return PR_TRUE; } /* * Build an CERTCertificate structure from a PKCS#11 object ID.... certID * Must be a CertObject. This code does not explicitly checks that. */ CERTCertificate * PK11_MakeCertFromHandle(PK11SlotInfo *slot,CK_OBJECT_HANDLE certID, CK_ATTRIBUTE *privateLabel) { char * nickname = NULL; CERTCertificate *cert = NULL; CERTCertTrust *trust; PRBool isFortezzaRootCA = PR_FALSE; PRBool swapNickname = PR_FALSE; cert = pk11_fastCert(slot,certID,privateLabel, &nickname); if (cert == NULL) goto loser; if (nickname) { if (cert->nickname != NULL) { cert->dbnickname = cert->nickname; } cert->nickname = PORT_ArenaStrdup(cert->arena,nickname); PORT_Free(nickname); nickname = NULL; swapNickname = PR_TRUE; } /* remember where this cert came from.... If we have just looked * it up from the database and it already has a slot, don't add a new * one. */ if (cert->slot == NULL) { cert->slot = PK11_ReferenceSlot(slot); cert->pkcs11ID = certID; cert->ownSlot = PR_TRUE; cert->series = slot->series; } trust = (CERTCertTrust*)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust)); if (trust == NULL) goto loser; PORT_Memset(trust,0, sizeof(CERTCertTrust)); cert->trust = trust; if(! pk11_HandleTrustObject(slot, cert, trust) ) { unsigned int type; /* build some cert trust flags */ if (CERT_IsCACert(cert, &type)) { unsigned int trustflags = CERTDB_VALID_CA; /* Allow PKCS #11 modules to give us trusted CA's. We only accept * valid CA's which are self-signed here. They must have an object * ID of '0'. */ if (pk11_isID0(slot,certID) && SECITEM_CompareItem(&cert->derSubject,&cert->derIssuer) == SECEqual) { trustflags |= CERTDB_TRUSTED_CA; /* is the slot a fortezza card? allow the user or * admin to turn on objectSigning, but don't turn * full trust on explicitly */ if (PK11_DoesMechanism(slot,CKM_KEA_KEY_DERIVE)) { trust->objectSigningFlags |= CERTDB_VALID_CA; isFortezzaRootCA = PR_TRUE; } } if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) { trust->sslFlags |= trustflags; } if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) { trust->emailFlags |= trustflags; } if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA) == NS_CERT_TYPE_OBJECT_SIGNING_CA) { trust->objectSigningFlags |= trustflags; } } } if (PK11_IsUserCert(slot,cert,certID)) { trust->sslFlags |= CERTDB_USER; trust->emailFlags |= CERTDB_USER; /* trust->objectSigningFlags |= CERTDB_USER; */ } return cert; loser: if (nickname) PORT_Free(nickname); if (cert) CERT_DestroyCertificate(cert); return NULL; } /* * Build get a certificate from a private key */ CERTCertificate * PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey) { PK11SlotInfo *slot = privKey->pkcs11Slot; CK_OBJECT_HANDLE handle = privKey->pkcs11ID; CK_OBJECT_HANDLE certID = PK11_MatchItem(slot,handle,CKO_CERTIFICATE); CERTCertificate *cert; if (certID == CK_INVALID_HANDLE) { PORT_SetError(SSL_ERROR_NO_CERTIFICATE); return NULL; } cert = PK11_MakeCertFromHandle(slot,certID,NULL); return (cert); } /* * destroy a private key if there are no matching certs. * this function also frees the privKey structure. */ SECStatus PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey, PRBool force) { CERTCertificate *cert=PK11_GetCertFromPrivateKey(privKey); /* found a cert matching the private key?. */ if (!force && cert != NULL) { /* yes, don't delete the key */ CERT_DestroyCertificate(cert); SECKEY_DestroyPrivateKey(privKey); return SECWouldBlock; } /* now, then it's safe for the key to go away */ PK11_DestroyTokenObject(privKey->pkcs11Slot,privKey->pkcs11ID); SECKEY_DestroyPrivateKey(privKey); return SECSuccess; } /* * destroy a private key if there are no matching certs. * this function also frees the privKey structure. */ SECStatus PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey) { /* now, then it's safe for the key to go away */ if (pubKey->pkcs11Slot == NULL) { return SECFailure; } PK11_DestroyTokenObject(pubKey->pkcs11Slot,pubKey->pkcs11ID); SECKEY_DestroyPublicKey(pubKey); return SECSuccess; } /* * delete a cert and it's private key (if no other certs are pointing to the * private key. */ SECStatus PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx) { SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert,wincx); CK_OBJECT_HANDLE pubKey; PK11SlotInfo *slot = NULL; pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx); if (privKey) { #ifdef NSS_CLASSIC PK11_DestroyTokenObject(cert->slot,cert->pkcs11ID); #else /* For 3.4, utilize the generic cert delete function */ SEC_DeletePermCertificate(cert); #endif PK11_DeleteTokenPrivateKey(privKey, PR_FALSE); } if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) { PK11_DestroyTokenObject(slot,pubKey); PK11_FreeSlot(slot); } return SECSuccess; } /* * count the number of objects that match the template. */ int PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, int templateCount) { CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE]; int object_count = 0; CK_ULONG returned_count = 0; CK_RV crv; PK11_EnterSlotMonitor(slot); crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, findTemplate, templateCount); if (crv != CKR_OK) { PK11_ExitSlotMonitor(slot); PORT_SetError( PK11_MapError(crv) ); return 0; } /* * collect all the Matching Objects */ do { crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, objID,PK11_SEARCH_CHUNKSIZE,&returned_count); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); break; } object_count += returned_count; } while (returned_count == PK11_SEARCH_CHUNKSIZE); PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); PK11_ExitSlotMonitor(slot); return object_count; } /* * cert callback structure */ typedef struct pk11DoCertCallbackStr { SECStatus(* callback)(PK11SlotInfo *slot, CERTCertificate*, void *); SECStatus(* noslotcallback)(CERTCertificate*, void *); SECStatus(* itemcallback)(CERTCertificate*, SECItem *, void *); void *callbackArg; } pk11DoCertCallback; #ifdef NSS_CLASSIC /* * callback to map object handles to certificate structures. */ static SECStatus pk11_DoCerts(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, void *arg) { CERTCertificate *cert; pk11DoCertCallback *certcb = (pk11DoCertCallback *) arg; cert = PK11_MakeCertFromHandle(slot, certID, NULL); if (cert == NULL) { return SECFailure; } if (certcb ) { if (certcb->callback) { (*certcb->callback)(slot, cert, certcb->callbackArg); } if (certcb->noslotcallback) { (*certcb->noslotcallback)(cert, certcb->callbackArg); } if (certcb->itemcallback) { (*certcb->itemcallback)(cert, NULL, certcb->callbackArg); } } CERT_DestroyCertificate(cert); return SECSuccess; } #endif static SECStatus pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg) { SECItem derCrl; CERTCrlHeadNode *head = (CERTCrlHeadNode *) arg; CERTCrlNode *new_node = NULL; CK_ATTRIBUTE fetchCrl[3] = { { CKA_VALUE, NULL, 0}, { CKA_NETSCAPE_KRL, NULL, 0}, { CKA_NETSCAPE_URL, NULL, 0}, }; const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]); CK_RV crv; SECStatus rv = SECFailure; crv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize); if (CKR_OK != crv) { PORT_SetError(PK11_MapError(crv)); goto loser; } if (!fetchCrl[1].pValue) { PORT_SetError(SEC_ERROR_CRL_INVALID); goto loser; } new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode)); if (new_node == NULL) { goto loser; } if (*((CK_BBOOL *)fetchCrl[1].pValue)) new_node->type = SEC_KRL_TYPE; else new_node->type = SEC_CRL_TYPE; derCrl.type = siBuffer; derCrl.data = (unsigned char *)fetchCrl[0].pValue; derCrl.len = fetchCrl[0].ulValueLen; new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type); if (new_node->crl == NULL) { goto loser; } if (fetchCrl[2].pValue) { int nnlen = fetchCrl[2].ulValueLen; new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen+1); if ( !new_node->crl->url ) { goto loser; } PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen); new_node->crl->url[nnlen] = 0; } else { new_node->crl->url = NULL; } new_node->next = NULL; if (head->last) { head->last->next = new_node; head->last = new_node; } else { head->first = head->last = new_node; } rv = SECSuccess; loser: return(rv); } /* * key call back structure. */ typedef struct pk11KeyCallbackStr { SECStatus (* callback)(SECKEYPrivateKey *,void *); void *callbackArg; void *wincx; } pk11KeyCallback; /* * callback to map Object Handles to Private Keys; */ SECStatus pk11_DoKeys(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle, void *arg) { SECStatus rv = SECSuccess; SECKEYPrivateKey *privKey; pk11KeyCallback *keycb = (pk11KeyCallback *) arg; privKey = PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,keycb->wincx); if (privKey == NULL) { return SECFailure; } if (keycb && (keycb->callback)) { rv = (*keycb->callback)(privKey,keycb->callbackArg); } SECKEY_DestroyPrivateKey(privKey); return rv; } /* Traverse slots callback */ typedef struct pk11TraverseSlotStr { SECStatus (*callback)(PK11SlotInfo *,CK_OBJECT_HANDLE, void *); void *callbackArg; CK_ATTRIBUTE *findTemplate; int templateCount; } pk11TraverseSlot; /* * Extract all the certs on a card from a slot. */ SECStatus PK11_TraverseSlot(PK11SlotInfo *slot, void *arg) { int i; CK_OBJECT_HANDLE *objID = NULL; int object_count = 0; pk11TraverseSlot *slotcb = (pk11TraverseSlot*) arg; objID = pk11_FindObjectsByTemplate(slot,slotcb->findTemplate, slotcb->templateCount,&object_count); /*Actually this isn't a failure... there just were no objs to be found*/ if (object_count == 0) { return SECSuccess; } if (objID == NULL) { return SECFailure; } for (i=0; i < object_count; i++) { (*slotcb->callback)(slot,objID[i],slotcb->callbackArg); } PORT_Free(objID); return SECSuccess; } typedef struct pk11CertCallbackStr { SECStatus(* callback)(CERTCertificate*,SECItem *,void *); void *callbackArg; } pk11CertCallback; /* * Extract all the certs on a card from a slot. */ SECStatus pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), void *arg,void *wincx) { PK11SlotList *list; PK11SlotListElement *le; SECStatus rv; /* get them all! */ list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,wincx); if (list == NULL) return SECFailure; /* look at each slot and authenticate as necessary */ for (le = list->head ; le; le = le->next) { if (!PK11_IsFriendly(le->slot)) { rv = PK11_Authenticate(le->slot, PR_FALSE, wincx); if (rv != SECSuccess) continue; } if (callback) { (*callback)(le->slot,arg); } } PK11_FreeSlotList(list); return SECSuccess; } struct fake_der_cb_argstr { SECStatus(* callback)(CERTCertificate*, SECItem *, void *); void *arg; }; static SECStatus fake_der_cb(CERTCertificate *c, void *a) { struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a; return (*fda->callback)(c, &c->derCert, fda->arg); } /* * Extract all the certs on a card from a slot. */ SECStatus PK11_TraverseSlotCerts(SECStatus(* callback)(CERTCertificate*,SECItem *,void *), void *arg, void *wincx) { #ifdef NSS_CLASSIC pk11DoCertCallback caller; pk11TraverseSlot creater; CK_ATTRIBUTE theTemplate; CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; PK11_SETATTRS(&theTemplate, CKA_CLASS, &certClass, sizeof(certClass)); caller.callback = NULL; caller.noslotcallback = NULL; caller.itemcallback = callback; caller.callbackArg = arg; creater.callback = pk11_DoCerts; creater.callbackArg = (void *) & caller; creater.findTemplate = &theTemplate; creater.templateCount = 1; return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, wincx); #else NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); struct fake_der_cb_argstr fda; struct nss3_cert_cbstr pk11cb; /* authenticate to the tokens first */ (void) pk11_TraverseAllSlots( NULL, NULL, wincx); fda.callback = callback; fda.arg = arg; pk11cb.callback = fake_der_cb; pk11cb.arg = &fda; NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb); return SECSuccess; #endif } /* * Extract all the certs on a card from a slot. */ SECStatus PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) { pk11TraverseSlot creater; CK_ATTRIBUTE theTemplate[2]; CK_ATTRIBUTE *attrs; CK_OBJECT_CLASS certClass = CKO_NETSCAPE_CRL; attrs = theTemplate; PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++; if (type != -1) { CK_BBOOL isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE); PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++; } creater.callback = pk11_CollectCrls; creater.callbackArg = (void *) nodes; creater.findTemplate = theTemplate; creater.templateCount = (attrs - theTemplate); return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, wincx); } /*********************************************************************** * PK11_TraversePrivateKeysInSlot * * Traverses all the private keys on a slot. * * INPUTS * slot * The PKCS #11 slot whose private keys you want to traverse. * callback * A callback function that will be called for each key. * arg * An argument that will be passed to the callback function. */ SECStatus PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot, SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg) { pk11KeyCallback perKeyCB; pk11TraverseSlot perObjectCB; CK_OBJECT_CLASS privkClass = CKO_PRIVATE_KEY; CK_BBOOL ckTrue = CK_TRUE; CK_ATTRIBUTE theTemplate[2]; int templateSize = 2; theTemplate[0].type = CKA_CLASS; theTemplate[0].pValue = &privkClass; theTemplate[0].ulValueLen = sizeof(privkClass); theTemplate[1].type = CKA_TOKEN; theTemplate[1].pValue = &ckTrue; theTemplate[1].ulValueLen = sizeof(ckTrue); if(slot==NULL) { return SECSuccess; } perObjectCB.callback = pk11_DoKeys; perObjectCB.callbackArg = &perKeyCB; perObjectCB.findTemplate = theTemplate; perObjectCB.templateCount = templateSize; perKeyCB.callback = callback; perKeyCB.callbackArg = arg; perKeyCB.wincx = NULL; return PK11_TraverseSlot(slot, &perObjectCB); } CK_OBJECT_HANDLE * PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr, CK_OBJECT_CLASS objclass, int *returnCount, void *wincx) { char *tokenName; char *delimit; PK11SlotInfo *slot; CK_OBJECT_HANDLE *objID; CK_ATTRIBUTE findTemplate[] = { { CKA_LABEL, NULL, 0}, { CKA_CLASS, NULL, 0}, }; int findCount = sizeof(findTemplate)/sizeof(findTemplate[0]); SECStatus rv; PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass)); *slotptr = slot = NULL; *returnCount = 0; /* first find the slot associated with this nickname */ if ((delimit = PORT_Strchr(nickname,':')) != NULL) { int len = delimit - nickname; tokenName = (char*)PORT_Alloc(len+1); PORT_Memcpy(tokenName,nickname,len); tokenName[len] = 0; slot = *slotptr = PK11_FindSlotByName(tokenName); PORT_Free(tokenName); /* if we couldn't find a slot, assume the nickname is an internal cert * with no proceding slot name */ if (slot == NULL) { slot = *slotptr = PK11_GetInternalKeySlot(); } else { nickname = delimit+1; } } else { *slotptr = slot = PK11_GetInternalKeySlot(); } if (slot == NULL) { return CK_INVALID_HANDLE; } if (!PK11_IsFriendly(slot)) { rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) { PK11_FreeSlot(slot); *slotptr = NULL; return CK_INVALID_HANDLE; } } findTemplate[0].pValue = nickname; findTemplate[0].ulValueLen = PORT_Strlen(nickname); objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,returnCount); if (objID == NULL) { /* PKCS #11 isn't clear on whether or not the NULL is * stored in the template.... try the find again with the * full null terminated string. */ findTemplate[0].ulValueLen += 1; objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount, returnCount); if (objID == NULL) { /* Well that's the best we can do. It's just not here */ /* what about faked nicknames? */ PK11_FreeSlot(slot); *slotptr = NULL; *returnCount = 0; } } return objID; } static void transfer_token_certs_to_collection(nssList *certList, NSSToken *token, nssPKIObjectCollection *collection) { NSSCertificate **certs; PRUint32 i, count; NSSToken **tokens, **tp; count = nssList_Count(certList); if (count == 0) { return; } certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count); if (!certs) { return; } nssList_GetArray(certList, (void **)certs, count); for (i=0; iobject, NULL); if (tokens) { for (tp = tokens; *tp; tp++) { if (*tp == token) { nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)certs[i]); } } nssTokenArray_Destroy(tokens); } /* *must* be a valid CERTCertificate, came from cache */ CERT_DestroyCertificate(STAN_GetCERTCertificate(certs[i])); } nss_ZFreeIf(certs); } CERTCertificate * PK11_FindCertFromNickname(char *nickname, void *wincx) { #ifdef NSS_CLASSIC PK11SlotInfo *slot; int count=0; CK_OBJECT_HANDLE *certID = PK11_FindObjectsFromNickname(nickname,&slot, CKO_CERTIFICATE, &count, wincx); CERTCertificate *cert; if (certID == CK_INVALID_HANDLE) return NULL; cert = PK11_MakeCertFromHandle(slot,certID[0],NULL); PK11_FreeSlot(slot); PORT_Free(certID); return cert; #else PRStatus status; CERTCertificate *rvCert = NULL; NSSCertificate *cert = NULL; NSSCertificate **certs = NULL; NSSUsage usage; NSSToken *token; PK11SlotInfo *slot = NULL; char *nickCopy; char *delimit = NULL; char *tokenName; NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); usage.anyUsage = PR_TRUE; nickCopy = PORT_Strdup(nickname); if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) { tokenName = nickCopy; nickname = delimit + 1; *delimit = '\0'; /* find token by name */ token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName); if (token) { slot = PK11_ReferenceSlot(token->pk11slot); } *delimit = ':'; } else { slot = PK11_GetInternalKeySlot(); token = PK11Slot_GetNSSToken(slot); } if (token) { nssList *certList; nssCryptokiObject **instances; nssPKIObjectCollection *collection; nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; if (!PK11_IsPresent(slot)) { goto loser; } if (!PK11_IsFriendly(slot)) { if (PK11_Authenticate(slot, PR_TRUE, wincx) != SECSuccess) { goto loser; } } collection = nssCertificateCollection_Create(defaultTD, NULL); if (!collection) { goto loser; } certList = nssList_Create(NULL, PR_FALSE); if (!certList) { nssPKIObjectCollection_Destroy(collection); goto loser; } (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, nickname, certList); transfer_token_certs_to_collection(certList, token, collection); instances = nssToken_FindCertificatesByNickname(token, NULL, nickname, tokenOnly, 0, &status); nssPKIObjectCollection_AddInstances(collection, instances, 0); nss_ZFreeIf(instances); /* if it wasn't found, repeat the process for email address */ if (nssPKIObjectCollection_Count(collection) == 0 && PORT_Strchr(nickname, '@') != NULL) { char* lowercaseName = CERT_FixupEmailAddr(nickname); if (lowercaseName) { (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD, lowercaseName, certList); transfer_token_certs_to_collection(certList, token, collection); instances = nssToken_FindCertificatesByEmail(token, NULL, lowercaseName, tokenOnly, 0, &status); nssPKIObjectCollection_AddInstances(collection, instances, 0); nss_ZFreeIf(instances); PORT_Free(lowercaseName); } } certs = nssPKIObjectCollection_GetCertificates(collection, NULL, 0, NULL); nssPKIObjectCollection_Destroy(collection); if (certs) { cert = nssCertificateArray_FindBestCertificate(certs, NULL, &usage, NULL); if (cert) { rvCert = STAN_GetCERTCertificate(cert); } nssCertificateArray_Destroy(certs); } nssList_Destroy(certList); } if (slot) { PK11_FreeSlot(slot); } if (nickCopy) PORT_Free(nickCopy); return rvCert; loser: if (slot) { PK11_FreeSlot(slot); } if (nickCopy) PORT_Free(nickCopy); return NULL; #endif } CERTCertList * PK11_FindCertsFromNickname(char *nickname, void *wincx) { #ifdef NSS_CLASSIC PK11SlotInfo *slot; int i,count = 0; CK_OBJECT_HANDLE *certID = PK11_FindObjectsFromNickname(nickname,&slot, CKO_CERTIFICATE, &count, wincx); CERTCertList *certList = NULL; if (certID == NULL) return NULL; certList= CERT_NewCertList(); for (i=0; i < count; i++) { CERTCertificate *cert = PK11_MakeCertFromHandle(slot,certID[i],NULL); if (cert) CERT_AddCertToListTail(certList,cert); } if (CERT_LIST_HEAD(certList) == NULL) { CERT_DestroyCertList(certList); certList = NULL; } PK11_FreeSlot(slot); PORT_Free(certID); return certList; #else char *nickCopy; char *delimit = NULL; char *tokenName; int i; CERTCertList *certList = NULL; nssPKIObjectCollection *collection = NULL; NSSCertificate **foundCerts = NULL; NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); NSSCertificate *c; NSSToken *token; PK11SlotInfo *slot; nickCopy = PORT_Strdup(nickname); if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) { tokenName = nickCopy; nickname = delimit + 1; *delimit = '\0'; /* find token by name */ token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName); if (token) { slot = PK11_ReferenceSlot(token->pk11slot); } else { slot = NULL; } *delimit = ':'; } else { slot = PK11_GetInternalKeySlot(); token = PK11Slot_GetNSSToken(slot); } if (token) { PRStatus status; nssList *nameList; nssCryptokiObject **instances; nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; if (!PK11_IsFriendly(slot)) { if (PK11_Authenticate(slot, PR_TRUE, wincx) != SECSuccess) { PK11_FreeSlot(slot); if (nickCopy) PORT_Free(nickCopy); return NULL; } } collection = nssCertificateCollection_Create(defaultTD, NULL); if (!collection) { PK11_FreeSlot(slot); if (nickCopy) PORT_Free(nickCopy); return NULL; } nameList = nssList_Create(NULL, PR_FALSE); if (!nameList) { PK11_FreeSlot(slot); if (nickCopy) PORT_Free(nickCopy); return NULL; } (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD, nickname, nameList); transfer_token_certs_to_collection(nameList, token, collection); instances = nssToken_FindCertificatesByNickname(token, NULL, nickname, tokenOnly, 0, &status); nssPKIObjectCollection_AddInstances(collection, instances, 0); nss_ZFreeIf(instances); nssList_Destroy(nameList); foundCerts = nssPKIObjectCollection_GetCertificates(collection, NULL, 0, NULL); nssPKIObjectCollection_Destroy(collection); } if (slot) { PK11_FreeSlot(slot); } if (nickCopy) PORT_Free(nickCopy); if (foundCerts) { PRTime now = PR_Now(); certList = CERT_NewCertList(); for (i=0, c = *foundCerts; c; c = foundCerts[++i]) { CERTCertificate *certCert = STAN_GetCERTCertificate(c); if (certCert) { CERT_AddCertToListSorted(certList, certCert, CERT_SortCBValidity, &now); } } if (CERT_LIST_HEAD(certList) == NULL) { CERT_DestroyCertList(certList); certList = NULL; } nss_ZFreeIf(foundCerts); } return certList; #endif } /* * extract a key ID for a certificate... * NOTE: We call this function from PKCS11.c If we ever use * pkcs11 to extract the public key (we currently do not), this will break. */ SECItem * PK11_GetPubIndexKeyID(CERTCertificate *cert) { SECKEYPublicKey *pubk; SECItem *newItem = NULL; pubk = CERT_ExtractPublicKey(cert); if (pubk == NULL) return NULL; switch (pubk->keyType) { case rsaKey: newItem = SECITEM_DupItem(&pubk->u.rsa.modulus); break; case dsaKey: newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue); break; case dhKey: newItem = SECITEM_DupItem(&pubk->u.dh.publicValue); break; case ecKey: #ifdef NSS_ENABLE_ECC newItem = SECITEM_DupItem(&pubk->u.ec.publicValue); #endif /* NSS_ENABLE_ECC */ break; case fortezzaKey: default: newItem = NULL; /* Fortezza Fix later... */ } SECKEY_DestroyPublicKey(pubk); /* make hash of it */ return newItem; } /* * generate a CKA_ID from a certificate. */ SECItem * pk11_mkcertKeyID(CERTCertificate *cert) { SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert) ; SECItem *certCKA_ID; if (pubKeyData == NULL) return NULL; certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData); SECITEM_FreeItem(pubKeyData,PR_TRUE); return certCKA_ID; } /* * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make * smart cards happy. */ SECItem * PK11_MakeIDFromPubKey(SECItem *pubKeyData) { PK11Context *context; SECItem *certCKA_ID; SECStatus rv; context = PK11_CreateDigestContext(SEC_OID_SHA1); if (context == NULL) { return NULL; } rv = PK11_DigestBegin(context); if (rv == SECSuccess) { rv = PK11_DigestOp(context,pubKeyData->data,pubKeyData->len); } if (rv != SECSuccess) { PK11_DestroyContext(context,PR_TRUE); return NULL; } certCKA_ID = (SECItem *)PORT_Alloc(sizeof(SECItem)); if (certCKA_ID == NULL) { PK11_DestroyContext(context,PR_TRUE); return NULL; } certCKA_ID->len = SHA1_LENGTH; certCKA_ID->data = (unsigned char*)PORT_Alloc(certCKA_ID->len); if (certCKA_ID->data == NULL) { PORT_Free(certCKA_ID); PK11_DestroyContext(context,PR_TRUE); return NULL; } rv = PK11_DigestFinal(context,certCKA_ID->data,&certCKA_ID->len, SHA1_LENGTH); PK11_DestroyContext(context,PR_TRUE); if (rv != SECSuccess) { SECITEM_FreeItem(certCKA_ID,PR_TRUE); return NULL; } return certCKA_ID; } extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; /* * Write the cert into the token. */ SECStatus PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) { #ifdef NSS_CLASSIC int len = 0; SECItem *keyID = pk11_mkcertKeyID(cert); CK_ATTRIBUTE keyAttrs[] = { { CKA_LABEL, NULL, 0}, { CKA_SUBJECT, NULL, 0}, }; CK_OBJECT_CLASS certc = CKO_CERTIFICATE; CK_CERTIFICATE_TYPE certType = CKC_X_509; CK_OBJECT_HANDLE certID; CK_SESSION_HANDLE rwsession; CK_BBOOL cktrue = CK_TRUE; SECStatus rv = SECFailure; CK_ATTRIBUTE certAttrs[] = { { CKA_ID, NULL, 0 }, { CKA_LABEL, NULL, 0}, { CKA_CLASS, NULL, 0}, { CKA_TOKEN, NULL, 0}, { CKA_CERTIFICATE_TYPE, NULL, 0}, { CKA_SUBJECT, NULL, 0}, { CKA_ISSUER, NULL, 0}, { CKA_SERIAL_NUMBER, NULL, 0}, { CKA_VALUE, NULL, 0}, { CKA_NETSCAPE_TRUST, NULL, 0}, { CKA_NETSCAPE_EMAIL, NULL, 0}, }; int certCount = sizeof(certAttrs)/sizeof(certAttrs[0]), keyCount = 2; int realCount = 0; CK_ATTRIBUTE *attrs; CK_RV crv; SECCertUsage *certUsage = NULL; SECItem derSerial = { 0 }; NSSToken *token; if (keyID == NULL) { PORT_SetError(SEC_ERROR_ADDING_CERT); return rv; } len = ((nickname) ? PORT_Strlen(nickname) : 0); attrs = certAttrs; PK11_SETATTRS(attrs,CKA_ID, keyID->data, keyID->len); attrs++; if (nickname) { PK11_SETATTRS(attrs,CKA_LABEL, nickname, len ); attrs++; } PK11_SETATTRS(attrs,CKA_CLASS, &certc, sizeof(certc) ); attrs++; PK11_SETATTRS(attrs,CKA_TOKEN, &cktrue, sizeof(cktrue) ); attrs++; PK11_SETATTRS(attrs,CKA_CERTIFICATE_TYPE, &certType, sizeof(certType)); attrs++; PK11_SETATTRS(attrs,CKA_SUBJECT, cert->derSubject.data, cert->derSubject.len ); attrs++; PK11_SETATTRS(attrs,CKA_ISSUER, cert->derIssuer.data, cert->derIssuer.len ); attrs++; if (PR_TRUE) { /* CERTCertificate stores serial numbers decoded. I need the DER * here. sigh. */ CERT_SerialNumberFromDERCert(&cert->derCert, &derSerial); PK11_SETATTRS(attrs,CKA_SERIAL_NUMBER, derSerial.data, derSerial.len); attrs++; } PK11_SETATTRS(attrs,CKA_VALUE, cert->derCert.data, cert->derCert.len); attrs++; if (includeTrust && PK11_IsInternal(slot)) { certUsage = (SECCertUsage*)PORT_Alloc(sizeof(SECCertUsage)); if(!certUsage) { SECITEM_FreeItem(keyID,PR_TRUE); PORT_SetError(SEC_ERROR_NO_MEMORY); return rv; } *certUsage = certUsageUserCertImport; PK11_SETATTRS(attrs,CKA_NETSCAPE_TRUST, certUsage, sizeof(SECCertUsage)); attrs++; if (cert->emailAddr) { PK11_SETATTRS(attrs,CKA_NETSCAPE_EMAIL, cert->emailAddr, PORT_Strlen(cert->emailAddr); attrs++; } } realCount = attrs - certAttrs; PORT_Assert(realCount <= certCount); attrs = keyAttrs; if(nickname) { PK11_SETATTRS(attrs,CKA_LABEL, nickname, len ); attrs++; } PK11_SETATTRS(attrs,CKA_SUBJECT, cert->derSubject.data, cert->derSubject.len ); if(!nickname) { certCount--; keyCount--; } rwsession = PK11_GetRWSession(slot); if (key != CK_INVALID_HANDLE) { crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession,key,keyAttrs, keyCount); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); goto done; } } crv = PK11_GETTAB(slot)-> C_CreateObject(rwsession,certAttrs,realCount,&certID); if (crv == CKR_OK) { rv = SECSuccess; } else { PORT_SetError( PK11_MapError(crv) ); } if (!cert->nickname && nickname) { cert->nickname = PORT_ArenaStrdup(cert->arena, nickname); } cert->pkcs11ID = certID; cert->dbhandle = STAN_GetDefaultTrustDomain(); if (cert->slot == NULL) { cert->slot = PK11_ReferenceSlot(slot); cert->series = slot->series; cert->ownSlot = PR_TRUE; if (cert->nssCertificate) { nssCryptokiInstance *instance; NSSCertificate *c = cert->nssCertificate; instance = nss_ZNEW(c->object.arena, nssCryptokiInstance); instance->token = slot->nssToken; instance->handle = cert->pkcs11ID; instance->isTokenObject = PR_TRUE; nssPKIObject_AddInstance(&c->object, instance); } else { cert->nssCertificate = STAN_GetNSSCertificate(cert); } } cert->trust = nssTrust_GetCERTCertTrustForCert(cert->nssCertificate, cert); token = PK11Slot_GetNSSToken(slot); done: if (derSerial.data) PORT_Free(derSerial.data); SECITEM_FreeItem(keyID,PR_TRUE); PK11_RestoreROSession(slot,rwsession); if(certUsage) { PORT_Free(certUsage); } return rv; #else PRStatus status; NSSCertificate *c; nssCryptokiObject *keyobj, *certobj; NSSToken *token = PK11Slot_GetNSSToken(slot); SECItem *keyID = pk11_mkcertKeyID(cert); char *emailAddr = NULL; if (keyID == NULL) { goto loser; } if (PK11_IsInternal(slot) && cert->emailAddr) { emailAddr = cert->emailAddr; } /* need to get the cert as a stan cert */ if (cert->nssCertificate) { c = cert->nssCertificate; } else { c = STAN_GetNSSCertificate(cert); } if (c->object.cryptoContext) { /* Delete the temp instance */ NSSCryptoContext *cc = c->object.cryptoContext; nssCertificateStore_Lock(cc->certStore); nssCertificateStore_RemoveCertLOCKED(cc->certStore, c); nssCertificateStore_Unlock(cc->certStore); c->object.cryptoContext = NULL; cert->istemp = PR_FALSE; cert->isperm = PR_TRUE; } /* set the id for the cert */ nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data); if (!c->id.data) { goto loser; } if (key != CK_INVALID_HANDLE) { /* create an object for the key, ... */ keyobj = nss_ZNEW(NULL, nssCryptokiObject); if (!keyobj) { goto loser; } keyobj->token = nssToken_AddRef(token); keyobj->handle = key; keyobj->isTokenObject = PR_TRUE; /* ... in order to set matching attributes for the key */ status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname, &c->id, &c->subject); nssCryptokiObject_Destroy(keyobj); if (status != PR_SUCCESS) { goto loser; } } /* do the token import */ certobj = nssToken_ImportCertificate(token, NULL, NSSCertificateType_PKIX, &c->id, nickname, &c->encoding, &c->issuer, &c->subject, &c->serial, emailAddr, PR_TRUE); if (!certobj) { if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) { PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL); SECITEM_FreeItem(keyID,PR_TRUE); return SECFailure; } goto loser; } /* add the new instance to the cert, force an update of the * CERTCertificate, and finish */ nssPKIObject_AddInstance(&c->object, certobj); nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1); (void)STAN_ForceCERTCertificateUpdate(c); SECITEM_FreeItem(keyID,PR_TRUE); return SECSuccess; loser: SECITEM_FreeItem(keyID,PR_TRUE); PORT_SetError(SEC_ERROR_ADDING_CERT); return SECFailure; #endif } SECStatus PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert, CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) { CERTCertificate *cert; SECStatus rv; cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), derCert, NULL, PR_FALSE, PR_TRUE); if (cert == NULL) return SECFailure; rv = PK11_ImportCert(slot, cert, key, nickname, includeTrust); CERT_DestroyCertificate (cert); return rv; } /* * get a certificate handle, look at the cached handle first.. */ CK_OBJECT_HANDLE pk11_getcerthandle(PK11SlotInfo *slot, CERTCertificate *cert, CK_ATTRIBUTE *theTemplate,int tsize) { CK_OBJECT_HANDLE certh; if (cert->slot == slot) { certh = cert->pkcs11ID; if ((certh == CK_INVALID_HANDLE) || (cert->series != slot->series)) { certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize); cert->pkcs11ID = certh; cert->series = slot->series; } } else { certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize); } return certh; } /* * return the private key From a given Cert */ SECKEYPrivateKey * PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx) { CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_ATTRIBUTE theTemplate[] = { { CKA_VALUE, NULL, 0 }, { CKA_CLASS, NULL, 0 } }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_OBJECT_HANDLE certh; CK_OBJECT_HANDLE keyh; CK_ATTRIBUTE *attrs = theTemplate; SECStatus rv; PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, cert->derCert.len); attrs++; PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); /* * issue the find */ rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) { return NULL; } certh = pk11_getcerthandle(slot,cert,theTemplate,tsize); if (certh == CK_INVALID_HANDLE) { return NULL; } keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY); if (keyh == CK_INVALID_HANDLE) { return NULL; } return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx); } /* * return the private key with the given ID */ static CK_OBJECT_HANDLE pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, SECItem *keyID) { CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY; CK_ATTRIBUTE theTemplate[] = { { CKA_ID, NULL, 0 }, { CKA_CLASS, NULL, 0 }, }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_ATTRIBUTE *attrs = theTemplate; PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len ); attrs++; PK11_SETATTRS(attrs, CKA_CLASS, &privKey, sizeof(privKey)); return pk11_FindObjectByTemplate(slot,theTemplate,tsize); } /* * import a cert for a private key we have already generated. Set the label * on both to be the nickname. This is for the Key Gen, orphaned key case. */ PK11SlotInfo * PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr, void *wincx) { PK11SlotList *list; PK11SlotListElement *le; SECItem *keyID; CK_OBJECT_HANDLE key; PK11SlotInfo *slot = NULL; SECStatus rv; keyID = pk11_mkcertKeyID(cert); /* get them all! */ list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx); if ((keyID == NULL) || (list == NULL)) { if (keyID) SECITEM_FreeItem(keyID,PR_TRUE); if (list) PK11_FreeSlotList(list); return NULL; } /* Look for the slot that holds the Key */ for (le = list->head ; le; le = le->next) { rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); if (rv != SECSuccess) continue; key = pk11_FindPrivateKeyFromCertID(le->slot,keyID); if (key != CK_INVALID_HANDLE) { slot = PK11_ReferenceSlot(le->slot); if (keyPtr) *keyPtr = key; break; } } SECITEM_FreeItem(keyID,PR_TRUE); PK11_FreeSlotList(list); return slot; } /* * import a cert for a private key we have already generated. Set the label * on both to be the nickname. This is for the Key Gen, orphaned key case. */ PK11SlotInfo * PK11_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr, void *wincx) { CERTCertificate *cert; PK11SlotInfo *slot = NULL; /* letting this use go -- the only thing that the cert is used for is * to get the ID attribute. */ cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); if (cert == NULL) return NULL; slot = PK11_KeyForCertExists(cert, keyPtr, wincx); CERT_DestroyCertificate (cert); return slot; } PK11SlotInfo * PK11_ImportCertForKey(CERTCertificate *cert, char *nickname,void *wincx) { PK11SlotInfo *slot = NULL; CK_OBJECT_HANDLE key; slot = PK11_KeyForCertExists(cert,&key,wincx); if (slot) { if (PK11_ImportCert(slot,cert,key,nickname,PR_FALSE) != SECSuccess) { PK11_FreeSlot(slot); slot = NULL; } } else { PORT_SetError(SEC_ERROR_ADDING_CERT); } return slot; } PK11SlotInfo * PK11_ImportDERCertForKey(SECItem *derCert, char *nickname,void *wincx) { CERTCertificate *cert; PK11SlotInfo *slot = NULL; cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), derCert, NULL, PR_FALSE, PR_TRUE); if (cert == NULL) return NULL; slot = PK11_ImportCertForKey(cert, nickname, wincx); CERT_DestroyCertificate (cert); return slot; } static CK_OBJECT_HANDLE pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr, CK_ATTRIBUTE *searchTemplate, int count, void *wincx) { PK11SlotList *list; PK11SlotListElement *le; CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE; PK11SlotInfo *slot = NULL; SECStatus rv; *slotPtr = NULL; /* get them all! */ list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx); if (list == NULL) { if (list) PK11_FreeSlotList(list); return CK_INVALID_HANDLE; } /* Look for the slot that holds the Key */ for (le = list->head ; le; le = le->next) { if (!PK11_IsFriendly(le->slot)) { rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); if (rv != SECSuccess) continue; } certHandle = pk11_FindObjectByTemplate(le->slot,searchTemplate,count); if (certHandle != CK_INVALID_HANDLE) { slot = PK11_ReferenceSlot(le->slot); break; } } PK11_FreeSlotList(list); if (slot == NULL) { return CK_INVALID_HANDLE; } *slotPtr = slot; return certHandle; } CERTCertificate * PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo *slot, CERTIssuerAndSN *issuerSN, void *wincx) { CERTCertificate *rvCert = NULL; NSSCertificate *cert = NULL; NSSDER issuer, serial; NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); NSSToken *token = slot->nssToken; nssSession *session; nssCryptokiObject *instance = NULL; nssPKIObject *object = NULL; SECItem *derSerial; PRStatus status; /* Paranoia */ if (token == NULL) { PORT_SetError(SEC_ERROR_NO_TOKEN); return NULL; } /* PKCS#11 needs to use DER-encoded serial numbers. Create a * CERTIssuerAndSN that actually has the encoded value and pass that * to PKCS#11 (and the crypto context). */ derSerial = SEC_ASN1EncodeItem(NULL, NULL, &issuerSN->serialNumber, SEC_IntegerTemplate); if (!derSerial) { return NULL; } NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer); NSSITEM_FROM_SECITEM(&serial, derSerial); session = nssToken_GetDefaultSession(token); if (!session) { goto loser; } instance = nssToken_FindCertificateByIssuerAndSerialNumber(token,session, &issuer, &serial, nssTokenSearchType_TokenForced, &status); SECITEM_FreeItem(derSerial, PR_TRUE); if (!instance) { goto loser; } object = nssPKIObject_Create(NULL, instance, td, NULL); if (!object) { goto loser; } instance = NULL; /* adopted by the previous call */ cert = nssCertificate_Create(object); if (!cert) { goto loser; } object = NULL; /* adopted by the previous call */ nssTrustDomain_AddCertsToCache(td, &cert,1); rvCert = STAN_GetCERTCertificate(cert); if (!rvCert) { goto loser; } return rvCert; loser: if (instance) { nssCryptokiObject_Destroy(instance); } if (object) { nssPKIObject_Destroy(object); } if (cert) { nssCertificate_Destroy(cert); } return NULL; } /* * We're looking for a cert which we have the private key for that's on the * list of recipients. This searches one slot. * this is the new version for NSS SMIME code * this stuff should REALLY be in the SMIME code, but some things in here are not public * (they should be!) */ static CERTCertificate * pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist, int *rlIndex, void *pwarg) { NSSCMSRecipient *ri = NULL; int i; for (i=0; (ri = recipientlist[i]) != NULL; i++) { CERTCertificate *cert = NULL; if (ri->kind == RLSubjKeyID) { SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID); if (derCert) { cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg); SECITEM_FreeItem(derCert, PR_TRUE); } } else { cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN, pwarg); } if (cert) { /* this isn't our cert */ if ((cert->trust == NULL) || ((cert->trust->emailFlags & CERTDB_USER) != CERTDB_USER)) { CERT_DestroyCertificate(cert); continue; } ri->slot = PK11_ReferenceSlot(slot); *rlIndex = i; return cert; } } *rlIndex = -1; return NULL; } /* * This function is the same as above, but it searches all the slots. * this is the new version for NSS SMIME code * this stuff should REALLY be in the SMIME code, but some things in here are not public * (they should be!) */ static CERTCertificate * pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex) { PK11SlotList *list; PK11SlotListElement *le; CERTCertificate *cert = NULL; SECStatus rv; /* get them all! */ list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx); if (list == NULL) { if (list) PK11_FreeSlotList(list); return CK_INVALID_HANDLE; } /* Look for the slot that holds the Key */ for (le = list->head ; le; le = le->next) { if ( !PK11_IsFriendly(le->slot)) { rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); if (rv != SECSuccess) continue; } cert = pk11_FindCertObjectByRecipientNew(le->slot, recipientlist, rlIndex, wincx); if (cert) break; } PK11_FreeSlotList(list); return cert; } /* * We're looking for a cert which we have the private key for that's on the * list of recipients. This searches one slot. */ static CERTCertificate * pk11_FindCertObjectByRecipient(PK11SlotInfo *slot, SEC_PKCS7RecipientInfo **recipientArray, SEC_PKCS7RecipientInfo **rip, void *pwarg) { SEC_PKCS7RecipientInfo *ri = NULL; int i; for (i=0; (ri = recipientArray[i]) != NULL; i++) { CERTCertificate *cert; cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->issuerAndSN, pwarg); if (cert) { /* this isn't our cert */ if ((cert->trust == NULL) || ((cert->trust->emailFlags & CERTDB_USER) != CERTDB_USER)) { CERT_DestroyCertificate(cert); continue; } *rip = ri; return cert; } } *rip = NULL; return NULL; } /* * This function is the same as above, but it searches all the slots. */ static CERTCertificate * pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr, SEC_PKCS7RecipientInfo **recipientArray,SEC_PKCS7RecipientInfo **rip, void *wincx) { PK11SlotList *list; PK11SlotListElement *le; CERTCertificate * cert = NULL; PK11SlotInfo *slot = NULL; SECStatus rv; *slotPtr = NULL; /* get them all! */ list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx); if (list == NULL) { if (list) PK11_FreeSlotList(list); return CK_INVALID_HANDLE; } *rip = NULL; /* Look for the slot that holds the Key */ for (le = list->head ; le; le = le->next) { if ( !PK11_IsFriendly(le->slot)) { rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); if (rv != SECSuccess) continue; } cert = pk11_FindCertObjectByRecipient(le->slot, recipientArray, rip, wincx); if (cert) { slot = PK11_ReferenceSlot(le->slot); break; } } PK11_FreeSlotList(list); if (slot == NULL) { return NULL; } *slotPtr = slot; PORT_Assert(cert != NULL); return cert; } /* * We need to invert the search logic for PKCS 7 because if we search for * each cert on the list over all the slots, we wind up with lots of spurious * password prompts. This way we get only one password prompt per slot, at * the max, and most of the time we can find the cert, and only prompt for * the key... */ CERTCertificate * PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr, SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip, SECKEYPrivateKey**privKey, void *wincx) { CERTCertificate *cert = NULL; SECStatus rv; *privKey = NULL; *slotPtr = NULL; cert = pk11_AllFindCertObjectByRecipient(slotPtr,array,rip,wincx); if (!cert) { return NULL; } rv = PK11_Authenticate(*slotPtr,PR_TRUE,wincx); if (rv != SECSuccess) { goto loser; } *privKey = PK11_FindKeyByAnyCert(cert, wincx); if (*privKey == NULL) { goto loser; } return cert; loser: if (cert) CERT_DestroyCertificate(cert); if (*slotPtr) PK11_FreeSlot(*slotPtr); *slotPtr = NULL; return NULL; } static PRCallOnceType keyIDHashCallOnce; static PRStatus PR_CALLBACK pk11_keyIDHash_populate(void *wincx) { CERTCertList *certList; CERTCertListNode *node = NULL; SECItem subjKeyID = {siBuffer, NULL, 0}; certList = PK11_ListCerts(PK11CertListUser, wincx); if (!certList) { return PR_FAILURE; } for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) { if (CERT_FindSubjectKeyIDExtension(node->cert, &subjKeyID) == SECSuccess && subjKeyID.data != NULL) { cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert); SECITEM_FreeItem(&subjKeyID, PR_FALSE); } } CERT_DestroyCertList(certList); return PR_SUCCESS; } /* * This is the new version of the above function for NSS SMIME code * this stuff should REALLY be in the SMIME code, but some things in here are not public * (they should be!) */ int PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx) { CERTCertificate *cert; NSSCMSRecipient *rl; PRStatus rv; int rlIndex; rv = PR_CallOnceWithArg(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx); if (rv != PR_SUCCESS) return -1; cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex); if (!cert) { return -1; } rl = recipientlist[rlIndex]; /* at this point, rl->slot is set */ /* authenticate to the token */ if (PK11_Authenticate(rl->slot, PR_TRUE, wincx) != SECSuccess) { goto loser; } rl->privkey = PK11_FindKeyByAnyCert(cert, wincx); if (rl->privkey == NULL) { goto loser; } /* make a cert from the cert handle */ rl->cert = cert; return rlIndex; loser: if (cert) CERT_DestroyCertificate(cert); if (rl->slot) PK11_FreeSlot(rl->slot); rl->slot = NULL; return -1; } CERTCertificate * PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN, void *wincx) { #ifdef NSS_CLASSIC CK_OBJECT_HANDLE certHandle; CERTCertificate *cert = NULL; CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_ATTRIBUTE searchTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_ISSUER, NULL, 0 }, { CKA_SERIAL_NUMBER, NULL, 0} }; int count = sizeof(searchTemplate)/sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE *attrs = searchTemplate; PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++; PK11_SETATTRS(attrs, CKA_ISSUER, issuerSN->derIssuer.data, issuerSN->derIssuer.len); attrs++; PK11_SETATTRS(attrs, CKA_SERIAL_NUMBER, issuerSN->serialNumber.data, issuerSN->serialNumber.len); certHandle = pk11_FindCertObjectByTemplate (slotPtr,searchTemplate,count,wincx); if (certHandle == CK_INVALID_HANDLE) { return NULL; } cert = PK11_MakeCertFromHandle(*slotPtr,certHandle,NULL); if (cert == NULL) { PK11_FreeSlot(*slotPtr); return NULL; } return cert; #else CERTCertificate *rvCert = NULL; NSSCertificate *cert; NSSDER issuer, serial; NSSCryptoContext *cc; SECItem *derSerial; if (slotPtr) *slotPtr = NULL; /* PKCS#11 needs to use DER-encoded serial numbers. Create a * CERTIssuerAndSN that actually has the encoded value and pass that * to PKCS#11 (and the crypto context). */ derSerial = SEC_ASN1EncodeItem(NULL, NULL, &issuerSN->serialNumber, SEC_IntegerTemplate); if (!derSerial) { return NULL; } NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer); NSSITEM_FROM_SECITEM(&serial, derSerial); cc = STAN_GetDefaultCryptoContext(); cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc, &issuer, &serial); if (cert) { SECITEM_FreeItem(derSerial, PR_TRUE); return STAN_GetCERTCertificate(cert); } retry: cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber( STAN_GetDefaultTrustDomain(), &issuer, &serial); if (cert) { rvCert = STAN_GetCERTCertificate(cert); /* Check to see if the cert's token is still there */ if (!PK11_IsPresent(rvCert->slot)) { CERT_DestroyCertificate(rvCert); goto retry; } if (slotPtr) *slotPtr = PK11_ReferenceSlot(rvCert->slot); } SECITEM_FreeItem(derSerial, PR_TRUE); return rvCert; #endif } CK_OBJECT_HANDLE PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot) { CK_OBJECT_HANDLE certHandle; CK_ATTRIBUTE searchTemplate = { CKA_VALUE, NULL, 0 }; PK11_SETATTRS(&searchTemplate, CKA_VALUE, cert->derCert.data, cert->derCert.len); if (cert->slot) { certHandle = pk11_getcerthandle(cert->slot,cert,&searchTemplate,1); if (certHandle != CK_INVALID_HANDLE) { *pSlot = PK11_ReferenceSlot(cert->slot); return certHandle; } } certHandle = pk11_FindCertObjectByTemplate(pSlot,&searchTemplate,1,wincx); if (certHandle != CK_INVALID_HANDLE) { if (cert->slot == NULL) { cert->slot = PK11_ReferenceSlot(*pSlot); cert->pkcs11ID = certHandle; cert->ownSlot = PR_TRUE; cert->series = cert->slot->series; } } return(certHandle); } SECKEYPrivateKey * PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx) { CK_OBJECT_HANDLE certHandle; CK_OBJECT_HANDLE keyHandle; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privKey; SECStatus rv; certHandle = PK11_FindObjectForCert(cert, wincx, &slot); if (certHandle == CK_INVALID_HANDLE) { return NULL; } rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) { PK11_FreeSlot(slot); return NULL; } keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY); if (keyHandle == CK_INVALID_HANDLE) { PK11_FreeSlot(slot); return NULL; } privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); PK11_FreeSlot(slot); return privKey; } CK_OBJECT_HANDLE pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx) { CK_OBJECT_HANDLE certHandle; CK_OBJECT_HANDLE keyHandle; certHandle = PK11_FindObjectForCert(cert, wincx, slot); if (certHandle == CK_INVALID_HANDLE) { return CK_INVALID_HANDLE; } keyHandle = PK11_MatchItem(*slot,certHandle,CKO_PUBLIC_KEY); if (keyHandle == CK_INVALID_HANDLE) { PK11_FreeSlot(*slot); return CK_INVALID_HANDLE; } return keyHandle; } SECKEYPrivateKey * PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, void *wincx) { CK_OBJECT_HANDLE keyHandle; SECKEYPrivateKey *privKey; keyHandle = pk11_FindPrivateKeyFromCertID(slot, keyID); if (keyHandle == CK_INVALID_HANDLE) { return NULL; } privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); return privKey; } /* * find the number of certs in the slot with the same subject name */ int PK11_NumberCertsForCertSubject(CERTCertificate *cert) { CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_ATTRIBUTE theTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_SUBJECT, NULL, 0 }, }; CK_ATTRIBUTE *attr = theTemplate; int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]); PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++; PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len); if (cert->slot == NULL) { PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE,PR_TRUE,NULL); PK11SlotListElement *le; int count = 0; /* loop through all the fortezza tokens */ for (le = list->head; le; le = le->next) { count += PK11_NumberObjectsFor(le->slot,theTemplate,templateSize); } PK11_FreeSlotList(list); return count; } return PK11_NumberObjectsFor(cert->slot,theTemplate,templateSize); } /* * Walk all the certs with the same subject */ SECStatus PK11_TraverseCertsForSubject(CERTCertificate *cert, SECStatus(* callback)(CERTCertificate*, void *), void *arg) { if(!cert) { return SECFailure; } if (cert->slot == NULL) { PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE,PR_TRUE,NULL); PK11SlotListElement *le; /* loop through all the fortezza tokens */ for (le = list->head; le; le = le->next) { PK11_TraverseCertsForSubjectInSlot(cert,le->slot,callback,arg); } PK11_FreeSlotList(list); return SECSuccess; } return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg); } SECStatus PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot, SECStatus(* callback)(CERTCertificate*, void *), void *arg) { #ifdef NSS_CLASSIC pk11DoCertCallback caller; pk11TraverseSlot callarg; CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_ATTRIBUTE theTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_SUBJECT, NULL, 0 }, }; CK_ATTRIBUTE *attr = theTemplate; int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]); PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++; PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len); if (slot == NULL) { return SECSuccess; } caller.noslotcallback = callback; caller.callback = NULL; caller.itemcallback = NULL; caller.callbackArg = arg; callarg.callback = pk11_DoCerts; callarg.callbackArg = (void *) & caller; callarg.findTemplate = theTemplate; callarg.templateCount = templateSize; return PK11_TraverseSlot(slot, &callarg); #else PRStatus nssrv = PR_SUCCESS; NSSToken *token; NSSDER subject; NSSTrustDomain *td; nssList *subjectList; nssPKIObjectCollection *collection; nssCryptokiObject **instances; NSSCertificate **certs; nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; td = STAN_GetDefaultTrustDomain(); NSSITEM_FROM_SECITEM(&subject, &cert->derSubject); token = PK11Slot_GetNSSToken(slot); if (!nssToken_IsPresent(token)) { return SECSuccess; } collection = nssCertificateCollection_Create(td, NULL); if (!collection) { return SECFailure; } subjectList = nssList_Create(NULL, PR_FALSE); if (!subjectList) { nssPKIObjectCollection_Destroy(collection); return SECFailure; } (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject, subjectList); transfer_token_certs_to_collection(subjectList, token, collection); instances = nssToken_FindCertificatesBySubject(token, NULL, &subject, tokenOnly, 0, &nssrv); nssPKIObjectCollection_AddInstances(collection, instances, 0); nss_ZFreeIf(instances); nssList_Destroy(subjectList); certs = nssPKIObjectCollection_GetCertificates(collection, NULL, 0, NULL); nssPKIObjectCollection_Destroy(collection); if (certs) { CERTCertificate *oldie; NSSCertificate **cp; for (cp = certs; *cp; cp++) { oldie = STAN_GetCERTCertificate(*cp); if ((*callback)(oldie, arg) != SECSuccess) { nssrv = PR_FAILURE; break; } } nssCertificateArray_Destroy(certs); } return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; #endif } SECStatus PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot, SECStatus(* callback)(CERTCertificate*, void *), void *arg) { #ifdef NSS_CLASSIC pk11DoCertCallback caller; pk11TraverseSlot callarg; CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_ATTRIBUTE theTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_LABEL, NULL, 0 }, }; CK_ATTRIBUTE *attr = theTemplate; int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]); if(!nickname) { return SECSuccess; } PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++; PK11_SETATTRS(attr,CKA_LABEL,nickname->data,nickname->len); if (slot == NULL) { return SECSuccess; } caller.noslotcallback = callback; caller.callback = NULL; caller.itemcallback = NULL; caller.callbackArg = arg; callarg.callback = pk11_DoCerts; callarg.callbackArg = (void *) & caller; callarg.findTemplate = theTemplate; callarg.templateCount = templateSize; return PK11_TraverseSlot(slot, &callarg); #else struct nss3_cert_cbstr pk11cb; PRStatus nssrv = PR_SUCCESS; NSSToken *token; NSSTrustDomain *td; NSSUTF8 *nick; PRBool created = PR_FALSE; nssCryptokiObject **instances; nssPKIObjectCollection *collection = NULL; NSSCertificate **certs; nssList *nameList = NULL; nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; pk11cb.callback = callback; pk11cb.arg = arg; token = PK11Slot_GetNSSToken(slot); if (!nssToken_IsPresent(token)) { return SECSuccess; } if (nickname->data[nickname->len-1] != '\0') { nick = nssUTF8_Create(NULL, nssStringType_UTF8String, nickname->data, nickname->len); created = PR_TRUE; } else { nick = (NSSUTF8 *)nickname->data; } td = STAN_GetDefaultTrustDomain(); collection = nssCertificateCollection_Create(td, NULL); if (!collection) { goto loser; } nameList = nssList_Create(NULL, PR_FALSE); if (!nameList) { goto loser; } (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList); transfer_token_certs_to_collection(nameList, token, collection); instances = nssToken_FindCertificatesByNickname(token, NULL, nick, tokenOnly, 0, &nssrv); nssPKIObjectCollection_AddInstances(collection, instances, 0); nss_ZFreeIf(instances); nssList_Destroy(nameList); certs = nssPKIObjectCollection_GetCertificates(collection, NULL, 0, NULL); nssPKIObjectCollection_Destroy(collection); if (certs) { CERTCertificate *oldie; NSSCertificate **cp; for (cp = certs; *cp; cp++) { oldie = STAN_GetCERTCertificate(*cp); if ((*callback)(oldie, arg) != SECSuccess) { nssrv = PR_FAILURE; break; } } nssCertificateArray_Destroy(certs); } if (created) nss_ZFreeIf(nick); return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; loser: if (created) { nss_ZFreeIf(nick); } if (collection) { nssPKIObjectCollection_Destroy(collection); } if (nameList) { nssList_Destroy(nameList); } return SECFailure; #endif } SECStatus PK11_TraverseCertsInSlot(PK11SlotInfo *slot, SECStatus(* callback)(CERTCertificate*, void *), void *arg) { #ifdef NSS_CLASSIC pk11DoCertCallback caller; pk11TraverseSlot callarg; CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_ATTRIBUTE theTemplate[] = { { CKA_CLASS, NULL, 0 }, }; CK_ATTRIBUTE *attr = theTemplate; int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]); PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++; if (slot == NULL) { return SECSuccess; } caller.noslotcallback = callback; caller.callback = NULL; caller.itemcallback = NULL; caller.callbackArg = arg; callarg.callback = pk11_DoCerts; callarg.callbackArg = (void *) & caller; callarg.findTemplate = theTemplate; callarg.templateCount = templateSize; return PK11_TraverseSlot(slot, &callarg); #else PRStatus nssrv; NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); NSSToken *tok; nssList *certList = NULL; nssCryptokiObject **instances; nssPKIObjectCollection *collection; NSSCertificate **certs; nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; tok = PK11Slot_GetNSSToken(slot); if (!nssToken_IsPresent(tok)) { return SECSuccess; } collection = nssCertificateCollection_Create(td, NULL); if (!collection) { return SECFailure; } certList = nssList_Create(NULL, PR_FALSE); if (!certList) { nssPKIObjectCollection_Destroy(collection); return SECFailure; } (void *)nssTrustDomain_GetCertsFromCache(td, certList); transfer_token_certs_to_collection(certList, tok, collection); instances = nssToken_FindCertificates(tok, NULL, tokenOnly, 0, &nssrv); nssPKIObjectCollection_AddInstances(collection, instances, 0); nss_ZFreeIf(instances); nssList_Destroy(certList); certs = nssPKIObjectCollection_GetCertificates(collection, NULL, 0, NULL); nssPKIObjectCollection_Destroy(collection); if (certs) { CERTCertificate *oldie; NSSCertificate **cp; for (cp = certs; *cp; cp++) { oldie = STAN_GetCERTCertificate(*cp); if ((*callback)(oldie, arg) != SECSuccess) { nssrv = PR_FAILURE; break; } } nssCertificateArray_Destroy(certs); } return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; #endif } /* * return the certificate associated with a derCert */ CERTCertificate * PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx) { return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx); } CERTCertificate * PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, SECItem *inDerCert, void *wincx) { CERTCertificate *rvCert = NULL; NSSCertificate *c; NSSDER derCert; NSSToken *tok; NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); tok = PK11Slot_GetNSSToken(slot); NSSITEM_FROM_SECITEM(&derCert, inDerCert); if (!PK11_IsFriendly(slot)) { if (PK11_Authenticate(slot, PR_TRUE, wincx) != SECSuccess) { PK11_FreeSlot(slot); return NULL; } } c = NSSTrustDomain_FindCertificateByEncodedCertificate(td, &derCert); if (c) { PRBool isToken = PR_FALSE; NSSToken **tp; NSSToken **tokens = nssPKIObject_GetTokens(&c->object, NULL); if (tokens) { for (tp = tokens; *tp; tp++) { if (*tp == tok) { isToken = PR_TRUE; break; } } if (!isToken) { NSSCertificate_Destroy(c); c = NULL; } nssTokenArray_Destroy(tokens); } } if (c) { rvCert = STAN_GetCERTCertificate(c); } return rvCert; } /* mcgreer 3.4 -- nobody uses this, ignoring */ /* * return the certificate associated with a derCert */ CERTCertificate * PK11_FindCertFromDERSubjectAndNickname(PK11SlotInfo *slot, CERTCertificate *cert, char *nickname, void *wincx) { CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_ATTRIBUTE theTemplate[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_LABEL, NULL, 0 }, { CKA_CLASS, NULL, 0 } }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_OBJECT_HANDLE certh; CK_ATTRIBUTE *attrs = theTemplate; SECStatus rv; PK11_SETATTRS(attrs, CKA_SUBJECT, cert->derSubject.data, cert->derSubject.len); attrs++; PK11_SETATTRS(attrs, CKA_LABEL, nickname, PORT_Strlen(nickname)); PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); /* * issue the find */ if ( !PK11_IsFriendly(slot)) { rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) return NULL; } certh = pk11_getcerthandle(slot,cert,theTemplate,tsize); if (certh == CK_INVALID_HANDLE) { return NULL; } return PK11_MakeCertFromHandle(slot, certh, NULL); } /* * import a cert for a private key we have already generated. Set the label * on both to be the nickname. */ static CK_OBJECT_HANDLE pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx) { SECItem *keyID; CK_OBJECT_HANDLE key; SECStatus rv; if((slot == NULL) || (cert == NULL)) { return CK_INVALID_HANDLE; } keyID = pk11_mkcertKeyID(cert); if(keyID == NULL) { return CK_INVALID_HANDLE; } key = CK_INVALID_HANDLE; rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) goto loser; key = pk11_FindPrivateKeyFromCertID(slot, keyID); loser: SECITEM_ZfreeItem(keyID, PR_TRUE); return key; } SECKEYPrivateKey * PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx) { CK_OBJECT_HANDLE keyHandle; if((slot == NULL) || (cert == NULL)) { return NULL; } keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx); if (keyHandle == CK_INVALID_HANDLE) { return NULL; } return PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,wincx); } SECStatus PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert, char *nickname, PRBool addCertUsage,void *wincx) { CK_OBJECT_HANDLE keyHandle; if((slot == NULL) || (cert == NULL) || (nickname == NULL)) { return SECFailure; } keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx); if (keyHandle == CK_INVALID_HANDLE) { return SECFailure; } return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage); } /* remove when the real version comes out */ #define SEC_OID_MISSI_KEA 300 /* until we have v3 stuff merged */ PRBool KEAPQGCompare(CERTCertificate *server,CERTCertificate *cert) { if ( SECKEY_KEAParamCompare(server,cert) == SECEqual ) { return PR_TRUE; } else { return PR_FALSE; } } PRBool PK11_FortezzaHasKEA(CERTCertificate *cert) { /* look at the subject and see if it is a KEA for MISSI key */ SECOidData *oid; if ((cert->trust == NULL) || ((cert->trust->sslFlags & CERTDB_USER) != CERTDB_USER)) { return PR_FALSE; } oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm); return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) || (oid->offset == SEC_OID_MISSI_KEA_DSS) || (oid->offset == SEC_OID_MISSI_KEA)) ; } /* * Find a kea cert on this slot that matches the domain of it's peer */ static CERTCertificate *pk11_GetKEAMate(PK11SlotInfo *slot,CERTCertificate *peer) { int i; CERTCertificate *returnedCert = NULL; for (i=0; i < slot->cert_count; i++) { CERTCertificate *cert = slot->cert_array[i]; if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer,cert)) { returnedCert = CERT_DupCertificate(cert); break; } } return returnedCert; } /* * The following is a FORTEZZA only Certificate request. We call this when we * are doing a non-client auth SSL connection. We are only interested in the * fortezza slots, and we are only interested in certs that share the same root * key as the server. */ CERTCertificate * PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx) { PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE, PR_FALSE,PR_TRUE,wincx); PK11SlotListElement *le; CERTCertificate *returnedCert = NULL; SECStatus rv; /* loop through all the fortezza tokens */ for (le = keaList->head; le; le = le->next) { rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); if (rv != SECSuccess) continue; if (le->slot->session == CK_INVALID_SESSION) { continue; } returnedCert = pk11_GetKEAMate(le->slot,server); if (returnedCert) break; } PK11_FreeSlotList(keaList); return returnedCert; } /* * find a matched pair of kea certs to key exchange parameters from one * fortezza card to another as necessary. */ SECStatus PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2, CERTCertificate **cert1, CERTCertificate **cert2) { CERTCertificate *returnedCert = NULL; int i; for (i=0; i < slot1->cert_count; i++) { CERTCertificate *cert = slot1->cert_array[i]; if (PK11_FortezzaHasKEA(cert)) { returnedCert = pk11_GetKEAMate(slot2,cert); if (returnedCert != NULL) { *cert2 = returnedCert; *cert1 = CERT_DupCertificate(cert); return SECSuccess; } } } return SECFailure; } SECOidTag PK11_FortezzaMapSig(SECOidTag algTag) { switch (algTag) { case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_DSS: case SEC_OID_MISSI_DSS_OLD: case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: return SEC_OID_ANSIX9_DSA_SIGNATURE; default: break; } return algTag; } /* * return the private key From a given Cert */ CK_OBJECT_HANDLE PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx) { CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; CK_ATTRIBUTE theTemplate[] = { { CKA_VALUE, NULL, 0 }, { CKA_CLASS, NULL, 0 } }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_ATTRIBUTE *attrs = theTemplate; SECStatus rv; PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, cert->derCert.len); attrs++; PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); /* * issue the find */ rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) { return CK_INVALID_HANDLE; } return pk11_getcerthandle(slot,cert,theTemplate,tsize); } SECItem * PK11_GetKeyIDFromCert(CERTCertificate *cert, void *wincx) { CK_OBJECT_HANDLE handle; PK11SlotInfo *slot = NULL; CK_ATTRIBUTE theTemplate[] = { { CKA_ID, NULL, 0 }, }; int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); SECItem *item = NULL; CK_RV crv; handle = PK11_FindObjectForCert(cert,wincx,&slot); if (handle == CK_INVALID_HANDLE) { goto loser; } crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); goto loser; } item = PORT_ZNew(SECItem); if (item) { item->data = (unsigned char*) theTemplate[0].pValue; item->len = theTemplate[0].ulValueLen; } loser: PK11_FreeSlot(slot); return item; } SECItem * PK11_GetKeyIDFromPrivateKey(SECKEYPrivateKey *key, void *wincx) { CK_ATTRIBUTE theTemplate[] = { { CKA_ID, NULL, 0 }, }; int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); SECItem *item = NULL; CK_RV crv; crv = PK11_GetAttributes(NULL,key->pkcs11Slot,key->pkcs11ID, theTemplate,tsize); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); goto loser; } item = PORT_ZNew(SECItem); if (item) { item->data = (unsigned char*) theTemplate[0].pValue; item->len = theTemplate[0].ulValueLen; } loser: return item; } struct listCertsStr { PK11CertListType type; CERTCertList *certList; }; static PRStatus pk11ListCertCallback(NSSCertificate *c, void *arg) { struct listCertsStr *listCertP = (struct listCertsStr *)arg; CERTCertificate *newCert = NULL; PK11CertListType type = listCertP->type; CERTCertList *certList = listCertP->certList; PRBool isUnique = PR_FALSE; PRBool isCA = PR_FALSE; char *nickname = NULL; unsigned int certType; if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique) || (type == PK11CertListCAUnique) || (type == PK11CertListUserUnique) ) { /* only list one instance of each certificate, even if several exist */ isUnique = PR_TRUE; } if ((type == PK11CertListCA) || (type == PK11CertListRootUnique) || (type == PK11CertListCAUnique)) { isCA = PR_TRUE; } /* if we want user certs and we don't have one skip this cert */ if ( ( (type == PK11CertListUser) || (type == PK11CertListUserUnique) ) && !NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) { return PR_SUCCESS; } /* PK11CertListRootUnique means we want CA certs without a private key. * This is for legacy app support . PK11CertListCAUnique should be used * instead to get all CA certs, regardless of private key */ if ((type == PK11CertListRootUnique) && NSSCertificate_IsPrivateKeyAvailable(c, NULL,NULL)) { return PR_SUCCESS; } newCert = STAN_GetCERTCertificate(c); if (!newCert) { return PR_SUCCESS; } /* if we want CA certs and it ain't one, skip it */ if( isCA && (!CERT_IsCACert(newCert, &certType)) ) { return PR_SUCCESS; } if (isUnique) { CERT_DupCertificate(newCert); nickname = STAN_GetCERTCertificateName(certList->arena, c); /* put slot certs at the end */ if (newCert->slot && !PK11_IsInternal(newCert->slot)) { CERT_AddCertToListTailWithData(certList,newCert,nickname); } else { CERT_AddCertToListHeadWithData(certList,newCert,nickname); } } else { /* add multiple instances to the cert list */ nssCryptokiObject **ip; nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object); if (!instances) { return PR_SUCCESS; } for (ip = instances; *ip; ip++) { nssCryptokiObject *instance = *ip; PK11SlotInfo *slot = instance->token->pk11slot; /* put the same CERTCertificate in the list for all instances */ CERT_DupCertificate(newCert); nickname = STAN_GetCERTCertificateNameForInstance( certList->arena, c, instance); /* put slot certs at the end */ if (slot && !PK11_IsInternal(slot)) { CERT_AddCertToListTailWithData(certList,newCert,nickname); } else { CERT_AddCertToListHeadWithData(certList,newCert,nickname); } } nssCryptokiObjectArray_Destroy(instances); } return PR_SUCCESS; } CERTCertList * PK11_ListCerts(PK11CertListType type, void *pwarg) { #ifdef NSS_CLASSIC CERTCertList *certList = NULL; struct listCertsStr listCerts; certList= CERT_NewCertList(); listCerts.type = type; listCerts.certList = certList; PK11_TraverseSlotCerts(pk11ListCertCallback,&listCerts,pwarg); if (CERT_LIST_HEAD(certList) == NULL) { CERT_DestroyCertList(certList); certList = NULL; } return certList; #else NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); CERTCertList *certList = NULL; struct listCertsStr listCerts; certList = CERT_NewCertList(); listCerts.type = type; listCerts.certList = certList; /* authenticate to the slots */ (void) pk11_TraverseAllSlots( NULL, NULL, pwarg); NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback, &listCerts); return certList; #endif } static SECItem * pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) { CK_ATTRIBUTE theTemplate[] = { { CKA_ID, NULL, 0 }, }; int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_RV crv; SECItem *item; item = SECITEM_AllocItem(NULL, NULL, 0); if (item == NULL) { return NULL; } crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize); if (crv != CKR_OK) { SECITEM_FreeItem(item,PR_TRUE); PORT_SetError( PK11_MapError(crv) ); return NULL; } item->data = (unsigned char*) theTemplate[0].pValue; item->len =theTemplate[0].ulValueLen; return item; } SECItem * PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx) { CK_ATTRIBUTE theTemplate[] = { { CKA_VALUE, NULL, 0 }, { CKA_CLASS, NULL, 0 } }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_OBJECT_HANDLE certHandle; CK_ATTRIBUTE *attrs = theTemplate; PK11SlotInfo *slotRef = NULL; SECItem *item; SECStatus rv; if (slot) { PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, cert->derCert.len); attrs++; rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) { return NULL; } certHandle = pk11_getcerthandle(slot,cert,theTemplate,tsize); } else { certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef); if (certHandle == CK_INVALID_HANDLE) { return pk11_mkcertKeyID(cert); } slot = slotRef; } if (certHandle == CK_INVALID_HANDLE) { return NULL; } item = pk11_GetLowLevelKeyFromHandle(slot,certHandle); if (slotRef) PK11_FreeSlot(slotRef); return item; } SECItem * PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *privKey) { return pk11_GetLowLevelKeyFromHandle(privKey->pkcs11Slot,privKey->pkcs11ID); } static SECStatus listCertsCallback(CERTCertificate* cert, void*arg) { CERTCertList *list = (CERTCertList*)arg; char *nickname = NULL; if (cert->nickname) { nickname = PORT_ArenaStrdup(list->arena,cert->nickname); } return CERT_AddCertToListTailWithData(list, CERT_DupCertificate(cert),nickname); } CERTCertList * PK11_ListCertsInSlot(PK11SlotInfo *slot) { SECStatus status; CERTCertList *certs; certs = CERT_NewCertList(); if(certs == NULL) return NULL; status = PK11_TraverseCertsInSlot(slot, listCertsCallback, (void*)certs); if( status != SECSuccess ) { CERT_DestroyCertList(certs); certs = NULL; } return certs; } static SECStatus privateKeyListCallback(SECKEYPrivateKey *key, void *arg) { SECKEYPrivateKeyList *list = (SECKEYPrivateKeyList*)arg; return SECKEY_AddPrivateKeyToListTail(list, SECKEY_CopyPrivateKey(key)); } SECKEYPrivateKeyList* PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot) { SECStatus status; SECKEYPrivateKeyList *keys; keys = SECKEY_NewPrivateKeyList(); if(keys == NULL) return NULL; status = PK11_TraversePrivateKeysInSlot(slot, privateKeyListCallback, (void*)keys); if( status != SECSuccess ) { SECKEY_DestroyPrivateKeyList(keys); keys = NULL; } return keys; } SECKEYPublicKeyList* PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname) { CK_ATTRIBUTE findTemp[4]; CK_ATTRIBUTE *attrs; CK_BBOOL ckTrue = CK_TRUE; CK_OBJECT_CLASS keyclass = CKO_PUBLIC_KEY; int tsize = 0; int objCount = 0; CK_OBJECT_HANDLE *key_ids; SECKEYPublicKeyList *keys; int i,len; attrs = findTemp; PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; if (nickname) { len = PORT_Strlen(nickname)-1; PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; } tsize = attrs - findTemp; PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); if (key_ids == NULL) { return NULL; } keys = SECKEY_NewPublicKeyList(); if (keys == NULL) { PORT_Free(key_ids); } for (i=0; i < objCount ; i++) { SECKEYPublicKey *pubKey = PK11_ExtractPublicKey(slot,nullKey,key_ids[i]); if (pubKey) { SECKEY_AddPublicKeyToListTail(keys, pubKey); } } PORT_Free(key_ids); return keys; } SECKEYPrivateKeyList* PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx) { CK_ATTRIBUTE findTemp[4]; CK_ATTRIBUTE *attrs; CK_BBOOL ckTrue = CK_TRUE; CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY; int tsize = 0; int objCount = 0; CK_OBJECT_HANDLE *key_ids; SECKEYPrivateKeyList *keys; int i,len; attrs = findTemp; PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; if (nickname) { len = PORT_Strlen(nickname)-1; PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; } tsize = attrs - findTemp; PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); if (key_ids == NULL) { return NULL; } keys = SECKEY_NewPrivateKeyList(); if (keys == NULL) { PORT_Free(key_ids); } for (i=0; i < objCount ; i++) { SECKEYPrivateKey *privKey = PK11_MakePrivKey(slot,nullKey,PR_TRUE,key_ids[i],wincx); SECKEY_AddPrivateKeyToListTail(keys, privKey); } PORT_Free(key_ids); return keys; } /* * return the certificate associated with a derCert */ SECItem * PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle, SECItem *name, int type, char **url) { #ifdef NSS_CLASSIC CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL; CK_ATTRIBUTE theTemplate[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_CLASS, NULL, 0 }, { CKA_NETSCAPE_KRL, NULL, 0 }, }; CK_ATTRIBUTE crlData[] = { { CKA_VALUE, NULL, 0 }, { CKA_NETSCAPE_URL, NULL, 0 }, }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_FALSE; CK_OBJECT_HANDLE crlh = CK_INVALID_HANDLE; CK_ATTRIBUTE *attrs = theTemplate; CK_RV crv; SECItem *derCrl = NULL; PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++; PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, (type == SEC_CRL_TYPE) ? &ck_false : &ck_true, sizeof (CK_BBOOL)); attrs++; if (*slot) { crlh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); } else { PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE,PR_TRUE,NULL); PK11SlotListElement *le; /* loop through all the fortezza tokens */ for (le = list->head; le; le = le->next) { crlh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); if (crlh != CK_INVALID_HANDLE) { *slot = PK11_ReferenceSlot(le->slot); break; } } PK11_FreeSlotList(list); } if (crlh == CK_INVALID_HANDLE) { PORT_SetError(SEC_ERROR_NO_KRL); return NULL; } crv = PK11_GetAttributes(NULL,*slot,crlh,crlData,2); if (crv != CKR_OK) { PORT_SetError(PK11_MapError (crv)); goto loser; } derCrl = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); if (derCrl == NULL) { goto loser; } derCrl->data = crlData[0].pValue; derCrl->len = crlData[0].ulValueLen; if (crlHandle) { *crlHandle = crlh; } if ((url) && crlData[1].ulValueLen != 0) { /* make sure it's a null terminated string */ *url = PORT_ZAlloc (crlData[1].ulValueLen+1); if (*url) { PORT_Memcpy(*url,crlData[1].pValue,crlData[1].ulValueLen); } } loser: if (!derCrl) { if (crlData[0].pValue) PORT_Free(crlData[0].pValue); } if (crlData[1].pValue) PORT_Free(crlData[1].pValue); return derCrl; #else NSSCRL **crls, **crlp, *crl; NSSDER subject; SECItem *rvItem; NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); NSSITEM_FROM_SECITEM(&subject, name); if (*slot) { nssCryptokiObject **instances; nssPKIObjectCollection *collection; nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; NSSToken *token = PK11Slot_GetNSSToken(*slot); collection = nssCRLCollection_Create(td, NULL); if (!collection) { return NULL; } instances = nssToken_FindCRLsBySubject(token, NULL, &subject, tokenOnly, 0, NULL); nssPKIObjectCollection_AddInstances(collection, instances, 0); nss_ZFreeIf(instances); crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL); nssPKIObjectCollection_Destroy(collection); } else { crls = nssTrustDomain_FindCRLsBySubject(td, &subject); } if ((!crls) || (*crls == NULL)) { if (crls) { nssCRLArray_Destroy(crls); } if (NSS_GetError() == NSS_ERROR_NOT_FOUND) { PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); } return NULL; } crl = NULL; for (crlp = crls; *crlp; crlp++) { if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) || ((*crlp)->isKRL && type != SEC_CRL_TYPE)) { crl = nssCRL_AddRef(*crlp); break; } } nssCRLArray_Destroy(crls); if (!crl) { /* CRL collection was found, but no interesting CRL's were on it. * Not an error */ PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); return NULL; } if (crl->url) { *url = PORT_Strdup(crl->url); if (!*url) { nssCRL_Destroy(crl); return NULL; } } else { *url = NULL; } rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size); if (!rvItem) { PORT_Free(*url); nssCRL_Destroy(crl); return NULL; } memcpy(rvItem->data, crl->encoding.data, crl->encoding.size); *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot); *crlHandle = crl->object.instances[0]->handle; nssCRL_Destroy(crl); return rvItem; #endif } CK_OBJECT_HANDLE PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name, char *url, int type) { #ifdef NSS_CLASSIC CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL; CK_ATTRIBUTE theTemplate[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_CLASS, NULL, 0 }, { CKA_NETSCAPE_KRL, NULL, 0 }, { CKA_NETSCAPE_URL, NULL, 0 }, { CKA_VALUE, NULL, 0 }, { CKA_TOKEN, NULL, 0 } }; /* if you change the array, change the variable below as well */ int tsize; CK_BBOOL ck_true = CK_TRUE; CK_BBOOL ck_false = CK_FALSE; CK_OBJECT_HANDLE crlh = CK_INVALID_HANDLE; CK_ATTRIBUTE *attrs = theTemplate; CK_SESSION_HANDLE rwsession; CK_RV crv; PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++; PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, (type == SEC_CRL_TYPE) ? &ck_false : &ck_true, sizeof (CK_BBOOL)); attrs++; if (url) { PK11_SETATTRS(attrs, CKA_NETSCAPE_URL, url, PORT_Strlen(url)+1); attrs++; } PK11_SETATTRS(attrs, CKA_VALUE,crl->data,crl->len); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true,sizeof(CK_BBOOL)); attrs++; tsize = attrs - &theTemplate[0]; PORT_Assert(tsize <= sizeof(theTemplate)/sizeof(theTemplate[0])); rwsession = PK11_GetRWSession(slot); if (rwsession == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_READ_ONLY); return crlh; } crv = PK11_GETTAB(slot)-> C_CreateObject(rwsession,theTemplate,tsize,&crlh); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); } PK11_RestoreROSession(slot,rwsession); return crlh; #else NSSItem derCRL, derSubject; NSSToken *token = PK11Slot_GetNSSToken(slot); nssCryptokiObject *object; PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE; CK_OBJECT_HANDLE rvH; NSSITEM_FROM_SECITEM(&derSubject, name); NSSITEM_FROM_SECITEM(&derCRL, crl); object = nssToken_ImportCRL(token, NULL, &derSubject, &derCRL, isKRL, url, PR_TRUE); if (object) { rvH = object->handle; nssCryptokiObject_Destroy(object); } else { rvH = CK_INVALID_HANDLE; } return rvH; #endif } /* * delete a crl. */ SECStatus SEC_DeletePermCRL(CERTSignedCrl *crl) { #ifdef NSS_CLASSIC PK11SlotInfo *slot = crl->slot; CK_RV crv; if (slot == NULL) { /* shouldn't happen */ PORT_SetError( SEC_ERROR_CRL_INVALID); return SECFailure; } crv = PK11_DestroyTokenObject(slot,crl->pkcs11ID); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); return SECFailure; } crl->slot = NULL; PK11_FreeSlot(slot); return SECSuccess; #else PRStatus status; NSSToken *token; nssCryptokiObject *object; PK11SlotInfo *slot = crl->slot; if (slot == NULL) { PORT_Assert(slot); /* shouldn't happen */ PORT_SetError( SEC_ERROR_CRL_INVALID); return SECFailure; } token = PK11Slot_GetNSSToken(slot); object = nss_ZNEW(NULL, nssCryptokiObject); object->token = nssToken_AddRef(token); object->handle = crl->pkcs11ID; object->isTokenObject = PR_TRUE; status = nssToken_DeleteStoredObject(object); nssCryptokiObject_Destroy(object); return (status == PR_SUCCESS) ? SECSuccess : SECFailure; #endif } /* * return the certificate associated with a derCert */ SECItem * PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr, SECItem *name, SECItem **profileTime) { CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; CK_ATTRIBUTE theTemplate[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_CLASS, NULL, 0 }, { CKA_NETSCAPE_EMAIL, NULL, 0 }, }; CK_ATTRIBUTE smimeData[] = { { CKA_SUBJECT, NULL, 0 }, { CKA_VALUE, NULL, 0 }, }; /* if you change the array, change the variable below as well */ int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; CK_ATTRIBUTE *attrs = theTemplate; CK_RV crv; SECItem *emailProfile = NULL; PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr)); attrs++; if (*slot) { smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); } else { PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE,PR_TRUE,NULL); PK11SlotListElement *le; /* loop through all the fortezza tokens */ for (le = list->head; le; le = le->next) { smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); if (smimeh != CK_INVALID_HANDLE) { *slot = PK11_ReferenceSlot(le->slot); break; } } PK11_FreeSlotList(list); } if (smimeh == CK_INVALID_HANDLE) { PORT_SetError(SEC_ERROR_NO_KRL); return NULL; } if (profileTime) { PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0); } crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2); if (crv != CKR_OK) { PORT_SetError(PK11_MapError (crv)); goto loser; } if (!profileTime) { SECItem profileSubject; profileSubject.data = (unsigned char*) smimeData[0].pValue; profileSubject.len = smimeData[0].ulValueLen; if (!SECITEM_ItemsAreEqual(&profileSubject,name)) { goto loser; } } emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); if (emailProfile == NULL) { goto loser; } emailProfile->data = (unsigned char*) smimeData[1].pValue; emailProfile->len = smimeData[1].ulValueLen; if (profileTime) { *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); if (*profileTime) { (*profileTime)->data = (unsigned char*) smimeData[0].pValue; (*profileTime)->len = smimeData[0].ulValueLen; } } loser: if (emailProfile == NULL) { if (smimeData[1].pValue) { PORT_Free(smimeData[1].pValue); } } if (profileTime == NULL || *profileTime == NULL) { if (smimeData[0].pValue) { PORT_Free(smimeData[0].pValue); } } return emailProfile; } SECStatus PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj, SECItem *emailProfile, SECItem *profileTime) { CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; CK_BBOOL ck_true = CK_TRUE; CK_ATTRIBUTE theTemplate[] = { { CKA_CLASS, NULL, 0 }, { CKA_TOKEN, NULL, 0 }, { CKA_SUBJECT, NULL, 0 }, { CKA_NETSCAPE_EMAIL, NULL, 0 }, { CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 }, { CKA_VALUE, NULL, 0 } }; /* if you change the array, change the variable below as well */ int realSize = 0; CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; CK_ATTRIBUTE *attrs = theTemplate; CK_SESSION_HANDLE rwsession; PK11SlotInfo *free_slot = NULL; CK_RV crv; #ifdef DEBUG int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); #endif PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++; PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++; PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, PORT_Strlen(emailAddr)+1); attrs++; if (profileTime) { PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data, profileTime->len); attrs++; PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data, emailProfile->len); attrs++; } realSize = attrs - theTemplate; PORT_Assert (realSize <= tsize); if (slot == NULL) { free_slot = slot = PK11_GetInternalKeySlot(); /* we need to free the key slot in the end!!! */ } rwsession = PK11_GetRWSession(slot); if (rwsession == CK_INVALID_SESSION) { PORT_SetError(SEC_ERROR_READ_ONLY); if (free_slot) { PK11_FreeSlot(free_slot); } return SECFailure; } crv = PK11_GETTAB(slot)-> C_CreateObject(rwsession,theTemplate,realSize,&smimeh); if (crv != CKR_OK) { PORT_SetError( PK11_MapError(crv) ); } PK11_RestoreROSession(slot,rwsession); if (free_slot) { PK11_FreeSlot(free_slot); } return SECSuccess; } CERTSignedCrl * crl_storeCRL (PK11SlotInfo *slot,char *url, CERTSignedCrl *newCrl, SECItem *derCrl, int type); /* import the CRL into the token */ CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url, int type, void *wincx, PRInt32 importOptions, PRArenaPool* arena, PRInt32 decodeoptions) { CERTSignedCrl *newCrl, *crl; SECStatus rv; newCrl = crl = NULL; do { newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type, decodeoptions); if (newCrl == NULL) { if (type == SEC_CRL_TYPE) { /* only promote error when the error code is too generic */ if (PORT_GetError () == SEC_ERROR_BAD_DER) PORT_SetError(SEC_ERROR_CRL_INVALID); } else { PORT_SetError(SEC_ERROR_KRL_INVALID); } break; } if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){ CERTCertificate *caCert; CERTCertDBHandle* handle = CERT_GetDefaultCertDB(); PR_ASSERT(handle != NULL); caCert = CERT_FindCertByName (handle, &newCrl->crl.derName); if (caCert == NULL) { PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); break; } /* If caCert is a v3 certificate, make sure that it can be used for crl signing purpose */ rv = CERT_CheckCertUsage (caCert, KU_CRL_SIGN); if (rv != SECSuccess) { break; } rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert, PR_Now(), wincx); if (rv != SECSuccess) { if (type == SEC_CRL_TYPE) { PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE); } else { PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE); } break; } } crl = crl_storeCRL(slot, url, newCrl, derCRL, type); } while (0); if (crl == NULL) { SEC_DestroyCrl (newCrl); } return (crl); }