| Index: mozilla/security/nss/lib/pk11wrap/pk11cert.c
|
| ===================================================================
|
| --- mozilla/security/nss/lib/pk11wrap/pk11cert.c (revision 191424)
|
| +++ mozilla/security/nss/lib/pk11wrap/pk11cert.c (working copy)
|
| @@ -1,2684 +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));
|
| -
|
| - 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; */
|
| - }
|
| - CERT_LockCertTrust(cert);
|
| - cert->trust = trust;
|
| - CERT_UnlockCertTrust(cert);
|
| -
|
| - 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;
|
| - CERTCertTrust trust;
|
| -
|
| - 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_GetCertTrust(cert, &trust) != SECSuccess ||
|
| - ((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;
|
| - CERTCertTrust trust;
|
| - 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_GetCertTrust(cert, &trust) != SECSuccess ||
|
| - ((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;
|
| - CERTCertTrust trust;
|
| -
|
| - if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
|
| - ((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;
|
| -}
|
|
|