diff options
Diffstat (limited to 'security/nss/lib/pk11wrap/pk11cert.c')
-rw-r--r-- | security/nss/lib/pk11wrap/pk11cert.c | 2678 |
1 files changed, 0 insertions, 2678 deletions
diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c deleted file mode 100644 index b2c91b2f1..000000000 --- a/security/nss/lib/pk11wrap/pk11cert.c +++ /dev/null @@ -1,2678 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* - * This file manages PKCS #11 instances of certificates. - */ - -#include "secport.h" -#include "seccomon.h" -#include "secmod.h" -#include "secmodi.h" -#include "secmodti.h" -#include "pkcs11.h" -#include "pk11func.h" -#include "cert.h" -#include "certi.h" -#include "secitem.h" -#include "key.h" -#include "secoid.h" -#include "pkcs7t.h" -#include "cmsreclist.h" - -#include "certdb.h" -#include "secerr.h" -#include "sslerr.h" - -#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" - -extern const NSSError NSS_ERROR_NOT_FOUND; -extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; - -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; - /* 'c' is not adopted. caller will free it */ - nss3cert = STAN_GetCERTCertificate(c); - if (!nss3cert) return PR_FAILURE; - secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg); - return (secrv) ? PR_FAILURE : PR_SUCCESS; -} - -/* - * 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; -} - -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_LoginStillRequired(slot,NULL)) { - 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; - case ecKey: - PK11_SETATTRS(&theTemplate,CKA_EC_POINT, - pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len); - break; - 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. Optionally, output the nickname string. - */ -static CERTCertificate * -pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, - CK_ATTRIBUTE *privateLabel, char **nickptr) -{ - NSSCertificate *c; - nssCryptokiObject *co = NULL; - nssPKIObject *pkio; - NSSToken *token; - NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); - PRStatus status; - - /* Get the cryptoki object from the handle */ - token = PK11Slot_GetNSSToken(slot); - if (token->defaultSession) { - co = nssCryptokiObject_Create(token, token->defaultSession, certID); - } else { - PORT_SetError(SEC_ERROR_NO_TOKEN); - } - if (!co) { - return NULL; - } - - /* Create a PKI object from the cryptoki instance */ - pkio = nssPKIObject_Create(NULL, co, td, NULL, nssPKIMonitor); - if (!pkio) { - nssCryptokiObject_Destroy(co); - return NULL; - } - - /* Create a certificate */ - c = nssCertificate_Create(pkio); - if (!c) { - nssPKIObject_Destroy(pkio); - return NULL; - } - - /* Build and output a nickname, if desired. - * This must be done before calling nssTrustDomain_AddCertsToCache - * because that function may destroy c, pkio and co! - */ - 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); - } - - /* This function may destroy the cert in "c" and all its subordinate - * structures, and replace the value in "c" with the address of a - * different NSSCertificate that it found in the cache. - * Presumably, the nickname which we just output above remains valid. :) - */ - status = nssTrustDomain_AddCertsToCache(td, &c, 1); - return STAN_GetCERTCertificateOrRelease(c); -} - -/* - * 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) && - cert->isRoot) { - 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); - -} - -/* - * 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) { - /* For 3.4, utilize the generic cert delete function */ - SEC_DeletePermCertificate(cert); - PK11_DeleteTokenPrivateKey(privKey, PR_FALSE); - } - if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) { - PK11_DestroyTokenObject(slot,pubKey); - PK11_FreeSlot(slot); - } - return SECSuccess; -} - -/* - * cert callback structure - */ -typedef struct pk11DoCertCallbackStr { - SECStatus(* callback)(PK11SlotInfo *slot, CERTCertificate*, void *); - SECStatus(* noslotcallback)(CERTCertificate*, void *); - SECStatus(* itemcallback)(CERTCertificate*, SECItem *, void *); - void *callbackArg; -} pk11DoCertCallback; - - -typedef struct pk11CertCallbackStr { - SECStatus(* callback)(CERTCertificate*,SECItem *,void *); - void *callbackArg; -} pk11CertCallback; - -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) -{ - 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, PR_TRUE, wincx); - - fda.callback = callback; - fda.arg = arg; - pk11cb.callback = fake_der_cb; - pk11cb.arg = &fda; - NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb); - return SECSuccess; -} - -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; i<count; i++) { - tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL); - if (tokens) { - for (tp = tokens; *tp; tp++) { - if (*tp == token) { - nssPKIObjectCollection_AddObject(collection, - (nssPKIObject *)certs[i]); - } - } - nssTokenArray_Destroy(tokens); - } - CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i])); - } - nss_ZFreeIf(certs); -} - -CERTCertificate * -PK11_FindCertFromNickname(const char *nickname, void *wincx) -{ - PRStatus status; - CERTCertificate *rvCert = NULL; - NSSCertificate *cert = NULL; - NSSCertificate **certs = NULL; - static const NSSUsage usage = {PR_TRUE /* ... */ }; - NSSToken *token; - NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain(); - PK11SlotInfo *slot = NULL; - SECStatus rv; - char *nickCopy; - char *delimit = NULL; - char *tokenName; - - nickCopy = PORT_Strdup(nickname); - if (!nickCopy) { - /* error code is set */ - return NULL; - } - 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 { - PORT_SetError(SEC_ERROR_NO_TOKEN); - } - *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; - } - rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); - if (rv != 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_GetCERTCertificateOrRelease(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; -} - -/* Traverse slots callback */ -typedef struct FindCertsEmailArgStr { - char *email; - CERTCertList *certList; -} FindCertsEmailArg; - -SECStatus -FindCertsEmailCallback(CERTCertificate *cert, SECItem *item, void *arg) -{ - FindCertsEmailArg *cbparam = (FindCertsEmailArg *) arg; - const char *cert_email = CERT_GetFirstEmailAddress(cert); - PRBool found = PR_FALSE; - - /* Email address present in certificate? */ - if (cert_email == NULL){ - return SECSuccess; - } - - /* Parameter correctly set? */ - if (cbparam->email == NULL) { - return SECFailure; - } - - /* Loop over all email addresses */ - do { - if (!strcmp(cert_email, cbparam->email)) { - /* found one matching email address */ - PRTime now = PR_Now(); - found = PR_TRUE; - CERT_AddCertToListSorted(cbparam->certList, - CERT_DupCertificate(cert), - CERT_SortCBValidity, &now); - } - cert_email = CERT_GetNextEmailAddress(cert, cert_email); - } while (cert_email && !found); - - return SECSuccess; -} - -/* Find all certificates with matching email address */ -CERTCertList * -PK11_FindCertsFromEmailAddress(const char *email, void *wincx) -{ - FindCertsEmailArg cbparam; - SECStatus rv; - - cbparam.certList = CERT_NewCertList(); - if (cbparam.certList == NULL) { - return NULL; - } - - cbparam.email = CERT_FixupEmailAddr(email); - if (cbparam.email == NULL) { - CERT_DestroyCertList(cbparam.certList); - return NULL; - } - - rv = PK11_TraverseSlotCerts(FindCertsEmailCallback, &cbparam, NULL); - if (rv != SECSuccess) { - CERT_DestroyCertList(cbparam.certList); - PORT_Free(cbparam.email); - return NULL; - } - - /* empty list? */ - if (CERT_LIST_HEAD(cbparam.certList) == NULL || - CERT_LIST_END(CERT_LIST_HEAD(cbparam.certList), cbparam.certList)) { - CERT_DestroyCertList(cbparam.certList); - cbparam.certList = NULL; - } - - PORT_Free(cbparam.email); - return cbparam.certList; -} - - -CERTCertList * -PK11_FindCertsFromNickname(const char *nickname, void *wincx) -{ - 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; - SECStatus rv; - - nickCopy = PORT_Strdup(nickname); - if (!nickCopy) { - /* error code is set */ - return NULL; - } - 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 { - PORT_SetError(SEC_ERROR_NO_TOKEN); - slot = NULL; - } - *delimit = ':'; - } else { - slot = PK11_GetInternalKeySlot(); - token = PK11Slot_GetNSSToken(slot); - } - if (token) { - PRStatus status; - nssList *nameList; - nssCryptokiObject **instances; - nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; - rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); - if (rv != 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); - - /* 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, - nameList); - transfer_token_certs_to_collection(nameList, token, collection); - instances = nssToken_FindCertificatesByEmail(token, - NULL, - lowercaseName, - tokenOnly, - 0, - &status); - nssPKIObjectCollection_AddInstances(collection, instances, 0); - nss_ZFreeIf(instances); - PORT_Free(lowercaseName); - } - } - - 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]) { - if (certList) { - CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c); - /* c may be invalid after this, don't reference it */ - if (certCert) { - /* CERT_AddCertToListSorted adopts certCert */ - CERT_AddCertToListSorted(certList, certCert, - CERT_SortCBValidity, &now); - } - } else { - nssCertificate_Destroy(c); - } - } - if (certList && CERT_LIST_HEAD(certList) == NULL) { - CERT_DestroyCertList(certList); - certList = NULL; - } - /* all the certs have been adopted or freed, free the raw array */ - nss_ZFreeIf(foundCerts); - } - return certList; -} - -/* - * 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: - newItem = SECITEM_DupItem(&pubk->u.ec.publicValue); - 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; -} - -/* - * Write the cert into the token. - */ -SECStatus -PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, - CK_OBJECT_HANDLE key, const char *nickname, - PRBool includeTrust) -{ - PRStatus status; - NSSCertificate *c; - nssCryptokiObject *keyobj, *certobj; - NSSToken *token = PK11Slot_GetNSSToken(slot); - SECItem *keyID = pk11_mkcertKeyID(cert); - char *emailAddr = NULL; - nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; - nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; - - if (keyID == NULL) { - goto loser; /* error code should be set already */ - } - if (!token) { - PORT_SetError(SEC_ERROR_NO_TOKEN); - goto loser; - } - - if (PK11_IsInternal(slot) && cert->emailAddr && cert->emailAddr[0]) { - 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 == NULL) { - goto loser; - } - } - - /* 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; - } - - if (c->object.cryptoContext) { - /* Delete the temp instance */ - NSSCryptoContext *cc = c->object.cryptoContext; - nssCertificateStore_Lock(cc->certStore, &lockTrace); - nssCertificateStore_RemoveCertLOCKED(cc->certStore, c); - nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace); - c->object.cryptoContext = NULL; - cert->istemp = PR_FALSE; - cert->isperm = PR_TRUE; - } - - /* 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: - CERT_MapStanError(); - SECITEM_FreeItem(keyID,PR_TRUE); - if (PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) { - PORT_SetError(SEC_ERROR_ADDING_CERT); - } - return SECFailure; -} - -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) -{ - int err; - 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; - PRBool needLogin; - 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_AuthenticateUnfriendly(slot, PR_TRUE, wincx); - if (rv != SECSuccess) { - return NULL; - } - - certh = pk11_getcerthandle(slot,cert,theTemplate,tsize); - if (certh == CK_INVALID_HANDLE) { - return NULL; - } - /* - * prevent a login race condition. If slot is logged in between - * our call to pk11_LoginStillRequired and the - * PK11_MatchItem. The matchItem call will either succeed, or - * we will call it one more time after calling PK11_Authenticate - * (which is a noop on an authenticated token). - */ - needLogin = pk11_LoginStillRequired(slot,wincx); - keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY); - if ((keyh == CK_INVALID_HANDLE) && needLogin && - (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) || - SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) { - /* try it again authenticated */ - rv = PK11_Authenticate(slot, PR_TRUE, wincx); - if (rv != SECSuccess) { - 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); -} - -/* - * 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; - int err; - - 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) { - /* - * prevent a login race condition. If le->slot is logged in between - * our call to pk11_LoginStillRequired and the - * pk11_FindPrivateKeyFromCertID, the find will either succeed, or - * we will call it one more time after calling PK11_Authenticate - * (which is a noop on an authenticated token). - */ - PRBool needLogin = pk11_LoginStillRequired(le->slot,wincx); - key = pk11_FindPrivateKeyFromCertID(le->slot,keyID); - if ((key == CK_INVALID_HANDLE) && needLogin && - (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) || - SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) { - /* authenticate and try again */ - 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, const 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) { - return CK_INVALID_HANDLE; - } - - - /* Look for the slot that holds the Key */ - for (le = list->head ; le; le = le->next) { - rv = pk11_AuthenticateUnfriendly(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; - - if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len || - !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || - issuerSN->derIssuer.len > CERT_MAX_DN_BYTES || - issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES ) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return NULL; - } - - /* 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_ASN1_GET(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, nssPKIMonitor); - 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); - /* on failure, cert is freed below */ - 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; -} - -static PRCallOnceType keyIDHashCallOnce; - -static PRStatus PR_CALLBACK -pk11_keyIDHash_populate(void *wincx) -{ - CERTCertList *certList; - CERTCertListNode *node = NULL; - SECItem subjKeyID = {siBuffer, NULL, 0}; - SECItem *slotid = NULL; - SECMODModuleList *modules, *mlp; - SECMODListLock *moduleLock; - int i; - - 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); - - /* - * Record the state of each slot in a hash. The concatenation of slotID - * and moduleID is used as its key, with the slot series as its value. - */ - slotid = SECITEM_AllocItem(NULL, NULL, - sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID)); - if (!slotid) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return PR_FAILURE; - } - moduleLock = SECMOD_GetDefaultModuleListLock(); - if (!moduleLock) { - PORT_SetError(SEC_ERROR_NOT_INITIALIZED); - return PR_FAILURE; - } - SECMOD_GetReadLock(moduleLock); - modules = SECMOD_GetDefaultModuleList(); - for (mlp = modules; mlp; mlp = mlp->next) { - for (i = 0; i < mlp->module->slotCount; i++) { - memcpy(slotid->data, &mlp->module->slots[i]->slotID, - sizeof(CK_SLOT_ID)); - memcpy(&slotid->data[sizeof(CK_SLOT_ID)], &mlp->module->moduleID, - sizeof(SECMODModuleID)); - cert_UpdateSubjectKeyIDSlotCheck(slotid, - mlp->module->slots[i]->series); - } - } - SECMOD_ReleaseReadLock(moduleLock); - SECITEM_FreeItem(slotid, PR_TRUE); - - return PR_SUCCESS; -} - -/* - * 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; - PRBool tokenRescanDone = PR_FALSE; - - for (i=0; (ri = recipientlist[i]) != NULL; i++) { - CERTCertificate *cert = NULL; - if (ri->kind == RLSubjKeyID) { - SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID); - if (!derCert && !tokenRescanDone) { - /* - * We didn't find the cert by its key ID. If we have slots - * with removable tokens, a failure from - * cert_FindDERCertBySubjectKeyID doesn't necessarily imply - * that the cert is unavailable - the token might simply - * have been inserted after the initial run of - * pk11_keyIDHash_populate (wrapped by PR_CallOnceWithArg), - * or a different token might have been present in that - * slot, initially. Let's check for new tokens... - */ - PK11SlotList *sl = PK11_GetAllTokens(CKM_INVALID_MECHANISM, - PR_FALSE, PR_FALSE, pwarg); - if (sl) { - PK11SlotListElement *le; - SECItem *slotid = SECITEM_AllocItem(NULL, NULL, - sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID)); - if (!slotid) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return NULL; - } - for (le = sl->head; le; le = le->next) { - memcpy(slotid->data, &le->slot->slotID, - sizeof(CK_SLOT_ID)); - memcpy(&slotid->data[sizeof(CK_SLOT_ID)], - &le->slot->module->moduleID, - sizeof(SECMODModuleID)); - /* - * Any changes with the slot since our last check? - * If so, re-read the certs in that specific slot. - */ - if (cert_SubjectKeyIDSlotCheckSeries(slotid) - != PK11_GetSlotSeries(le->slot)) { - CERTCertListNode *node = NULL; - SECItem subjKeyID = {siBuffer, NULL, 0}; - CERTCertList *cl = PK11_ListCertsInSlot(le->slot); - if (!cl) { - continue; - } - for (node = CERT_LIST_HEAD(cl); - !CERT_LIST_END(node, cl); - node = CERT_LIST_NEXT(node)) { - if (CERT_IsUserCert(node->cert) && - CERT_FindSubjectKeyIDExtension(node->cert, - &subjKeyID) == SECSuccess) { - if (subjKeyID.data) { - cert_AddSubjectKeyIDMapping(&subjKeyID, - node->cert); - cert_UpdateSubjectKeyIDSlotCheck(slotid, - PK11_GetSlotSeries(le->slot)); - } - SECITEM_FreeItem(&subjKeyID, PR_FALSE); - } - } - CERT_DestroyCertList(cl); - } - } - PK11_FreeSlotList(sl); - SECITEM_FreeItem(slotid, PR_TRUE); - } - /* only check once per message/recipientlist */ - tokenRescanDone = PR_TRUE; - /* do another lookup (hopefully we found that cert...) */ - 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) { - return CK_INVALID_HANDLE; - } - - /* Look for the slot that holds the Key */ - for (le = list->head ; le; le = le->next) { - rv = pk11_AuthenticateUnfriendly(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) { - return CK_INVALID_HANDLE; - } - - *rip = NULL; - - /* Look for the slot that holds the Key */ - for (le = list->head ; le; le = le->next) { - rv = pk11_AuthenticateUnfriendly(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; - - *privKey = NULL; - *slotPtr = NULL; - cert = pk11_AllFindCertObjectByRecipient(slotPtr,array,rip,wincx); - if (!cert) { - return NULL; - } - - *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; -} - -/* - * 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 */ - - 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) -{ - CERTCertificate *rvCert = NULL; - NSSCertificate *cert; - NSSDER issuer, serial; - NSSCryptoContext *cc; - SECItem *derSerial; - - if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len || - !issuerSN->serialNumber.data || !issuerSN->serialNumber.len || - issuerSN->derIssuer.len > CERT_MAX_DN_BYTES || - issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES ) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return NULL; - } - - 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_ASN1_GET(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_GetCERTCertificateOrRelease(cert); - } - - do { - /* free the old cert on retry. Associated slot was not present */ - if (rvCert) { - CERT_DestroyCertificate(rvCert); - rvCert = NULL; - } - - cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber( - STAN_GetDefaultTrustDomain(), - &issuer, - &serial); - if (!cert) { - break; - } - - rvCert = STAN_GetCERTCertificateOrRelease(cert); - if (rvCert == NULL) { - break; - } - - /* Check to see if the cert's token is still there */ - } while (!PK11_IsPresent(rvCert->slot)); - - if (rvCert && slotPtr) *slotPtr = PK11_ReferenceSlot(rvCert->slot); - - SECITEM_FreeItem(derSerial, PR_TRUE); - return rvCert; -} - -CK_OBJECT_HANDLE -PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot) -{ - CK_OBJECT_HANDLE certHandle; - CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; - CK_ATTRIBUTE *attr; - CK_ATTRIBUTE searchTemplate[]= { - { CKA_CLASS, NULL, 0 }, - { CKA_VALUE, NULL, 0 }, - }; - int templateSize = sizeof(searchTemplate)/sizeof(searchTemplate[0]); - - attr = searchTemplate; - PK11_SETATTRS(attr, CKA_CLASS, &certClass, sizeof(certClass)); attr++; - PK11_SETATTRS(attr, CKA_VALUE, cert->derCert.data, cert->derCert.len); - - if (cert->slot) { - certHandle = pk11_getcerthandle(cert->slot, cert, searchTemplate, - templateSize); - if (certHandle != CK_INVALID_HANDLE) { - *pSlot = PK11_ReferenceSlot(cert->slot); - return certHandle; - } - } - - certHandle = pk11_FindCertObjectByTemplate(pSlot, searchTemplate, - templateSize, 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 = NULL; - PRBool needLogin; - SECStatus rv; - int err; - - certHandle = PK11_FindObjectForCert(cert, wincx, &slot); - if (certHandle == CK_INVALID_HANDLE) { - return NULL; - } - /* - * prevent a login race condition. If slot is logged in between - * our call to pk11_LoginStillRequired and the - * PK11_MatchItem. The matchItem call will either succeed, or - * we will call it one more time after calling PK11_Authenticate - * (which is a noop on an authenticated token). - */ - needLogin = pk11_LoginStillRequired(slot,wincx); - keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY); - if ((keyHandle == CK_INVALID_HANDLE) && needLogin && - (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) || - SEC_ERROR_TOKEN_NOT_LOGGED_IN == err ) ) { - /* authenticate and try again */ - rv = PK11_Authenticate(slot, PR_TRUE, wincx); - if (rv == SECSuccess) { - keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY); - } - } - if (keyHandle != CK_INVALID_HANDLE) { - privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); - } - if (slot) { - 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; -} - -/* - * 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; - - if (!list) { - /* error code is set */ - return 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; - - if (!list) { - /* error code is set */ - return SECFailure; - } - /* loop through all the 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) -{ - 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 (!oldie) { - continue; - } - if ((*callback)(oldie, arg) != SECSuccess) { - nssrv = PR_FAILURE; - break; - } - } - nssCertificateArray_Destroy(certs); - } - return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; -} - -SECStatus -PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot, - SECStatus(* callback)(CERTCertificate*, void *), void *arg) -{ - 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 (!oldie) { - continue; - } - 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; -} - -SECStatus -PK11_TraverseCertsInSlot(PK11SlotInfo *slot, - SECStatus(* callback)(CERTCertificate*, void *), void *arg) -{ - 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_FindObjects(tok, NULL, CKO_CERTIFICATE, - 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 (!oldie) { - continue; - } - if ((*callback)(oldie, arg) != SECSuccess) { - nssrv = PR_FAILURE; - break; - } - } - nssCertificateArray_Destroy(certs); - } - return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure; -} - -/* - * 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, const SECItem *inDerCert, - void *wincx) - -{ - NSSDER derCert; - NSSToken *tok; - NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); - nssCryptokiObject *co = NULL; - SECStatus rv; - - tok = PK11Slot_GetNSSToken(slot); - NSSITEM_FROM_SECITEM(&derCert, inDerCert); - rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); - if (rv != SECSuccess) { - PK11_FreeSlot(slot); - return NULL; - } - - co = nssToken_FindCertificateByEncodedCertificate(tok, NULL, &derCert, - nssTokenSearchType_TokenOnly, NULL); - - return co ? PK11_MakeCertFromHandle(slot, co->handle, NULL) : 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; - PRBool needLogin; - int err; - - if((slot == NULL) || (cert == NULL)) { - return CK_INVALID_HANDLE; - } - - keyID = pk11_mkcertKeyID(cert); - if(keyID == NULL) { - return CK_INVALID_HANDLE; - } - - /* - * prevent a login race condition. If slot is logged in between - * our call to pk11_LoginStillRequired and the - * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or - * we will call it one more time after calling PK11_Authenticate - * (which is a noop on an authenticated token). - */ - needLogin = pk11_LoginStillRequired(slot,wincx); - key = pk11_FindPrivateKeyFromCertID(slot, keyID); - if ((key == CK_INVALID_HANDLE) && needLogin && - (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) || - SEC_ERROR_TOKEN_NOT_LOGGED_IN == err )) { - /* authenticate and try again */ - 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) { - - /* not implemented */ - 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); - if (!oid) { - return PR_FALSE; - } - - 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; - - if (!keaList) { - /* error code is set */ - return NULL; - } - - /* 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; -} - -/* - * 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_AuthenticateUnfriendly(slot, PR_TRUE, wincx); - if (rv != SECSuccess) { - return CK_INVALID_HANDLE; - } - - return pk11_getcerthandle(slot,cert,theTemplate,tsize); -} - -/* Looking for PK11_GetKeyIDFromCert? - * Use PK11_GetLowLevelKeyIDForCert instead. - */ - - -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; - SECStatus rv; - - 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; - } - - /* caller still owns the reference to 'c' */ - 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)) { - rv = CERT_AddCertToListTailWithData(certList,newCert,nickname); - } else { - rv = CERT_AddCertToListHeadWithData(certList,newCert,nickname); - } - /* if we didn't add the cert to the list, don't leak it */ - if (rv != SECSuccess) { - CERT_DestroyCertificate(newCert); - } - } 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)) { - rv = CERT_AddCertToListTailWithData(certList,newCert,nickname); - } else { - rv = CERT_AddCertToListHeadWithData(certList,newCert,nickname); - } - /* if we didn't add the cert to the list, don't leak it */ - if (rv != SECSuccess) { - CERT_DestroyCertificate(newCert); - } - } - nssCryptokiObjectArray_Destroy(instances); - } - return PR_SUCCESS; -} - - -CERTCertList * -PK11_ListCerts(PK11CertListType type, void *pwarg) -{ - 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, PR_TRUE, pwarg); - NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback, - &listCerts); - return certList; -} - -SECItem * -PK11_GetLowLevelKeyIDForCert(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 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++; - PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); - - rv = pk11_AuthenticateUnfriendly(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; -} - -/* argument type for listCertsCallback */ -typedef struct { - CERTCertList *list; - PK11SlotInfo *slot; -} ListCertsArg; - -static SECStatus -listCertsCallback(CERTCertificate* cert, void*arg) -{ - ListCertsArg *cdata = (ListCertsArg*)arg; - char *nickname = NULL; - nssCryptokiObject *instance, **ci; - nssCryptokiObject **instances; - NSSCertificate *c = STAN_GetNSSCertificate(cert); - SECStatus rv; - - if (c == NULL) { - return SECFailure; - } - instances = nssPKIObject_GetInstances(&c->object); - if (!instances) { - return SECFailure; - } - instance = NULL; - for (ci = instances; *ci; ci++) { - if ((*ci)->token->pk11slot == cdata->slot) { - instance = *ci; - break; - } - } - PORT_Assert(instance != NULL); - if (!instance) { - nssCryptokiObjectArray_Destroy(instances); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - nickname = STAN_GetCERTCertificateNameForInstance(cdata->list->arena, - c, instance); - nssCryptokiObjectArray_Destroy(instances); - - CERT_DupCertificate(cert); - rv = CERT_AddCertToListTailWithData(cdata->list, cert, nickname); - if (rv != SECSuccess) { - CERT_DestroyCertificate(cert); - } - return rv; -} - -CERTCertList * -PK11_ListCertsInSlot(PK11SlotInfo *slot) -{ - SECStatus status; - CERTCertList *certs; - ListCertsArg cdata; - - certs = CERT_NewCertList(); - if(certs == NULL) return NULL; - cdata.list = certs; - cdata.slot = slot; - - status = PK11_TraverseCertsInSlot(slot, listCertsCallback, - &cdata); - - if( status != SECSuccess ) { - CERT_DestroyCertList(certs); - certs = NULL; - } - - return certs; -} - -PK11SlotList * -PK11_GetAllSlotsForCert(CERTCertificate *cert, void *arg) -{ - nssCryptokiObject **ip; - PK11SlotList *slotList; - NSSCertificate *c; - nssCryptokiObject **instances; - PRBool found = PR_FALSE; - - if (!cert) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return NULL; - } - - c = STAN_GetNSSCertificate(cert); - if (!c) { - CERT_MapStanError(); - return NULL; - } - - /* add multiple instances to the cert list */ - instances = nssPKIObject_GetInstances(&c->object); - if (!instances) { - PORT_SetError(SEC_ERROR_NO_TOKEN); - return NULL; - } - - slotList = PK11_NewSlotList(); - if (!slotList) { - nssCryptokiObjectArray_Destroy(instances); - return NULL; - } - - for (ip = instances; *ip; ip++) { - nssCryptokiObject *instance = *ip; - PK11SlotInfo *slot = instance->token->pk11slot; - if (slot) { - PK11_AddSlotToList(slotList, slot, PR_TRUE); - found = PR_TRUE; - } - } - if (!found) { - PK11_FreeSlotList(slotList); - PORT_SetError(SEC_ERROR_NO_TOKEN); - slotList = NULL; - } - - nssCryptokiObjectArray_Destroy(instances); - return slotList; -} |