/* 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.
*/
/* 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.
*/ staticint
toHex(int x)
{ return (x < 10) ? (x + '0') : (x + 'a' - 10);
} #define MAX_CERT_ID 4 #define DEFAULT_STRING "Cert ID " staticchar *
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;
} elseif (key_label && (key_label->ulValueLen)) {
suffixLen = key_label->ulValueLen;
suffix = (char *)key_label->pValue;
} elseif (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;
PK11_SETATTRS(&theTemplate, 0, NULL, 0); switch (pubKey->keyType) { case rsaKey: case rsaPssKey: case rsaOaepKey:
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: case edKey: case ecMontKey:
PK11_SETATTRS(&theTemplate, CKA_EC_POINT,
pubKey->u.ec.publicValue.data,
pubKey->u.ec.publicValue.len); break; case keaKey: case fortezzaKey: case kyberKey: case nullKey: /* fall through and return false */ break;
}
/* * 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;
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;
NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
/* Get the cryptoki object from the handle */
NSSToken *token = PK11Slot_GetNSSToken(slot); if (!token || !token->defaultSession) {
(void)nssToken_Destroy(token); /* null token is ok */
PORT_SetError(SEC_ERROR_NO_TOKEN); return NULL;
}
co = nssCryptokiObject_Create(token, token->defaultSession, certID);
(void)nssToken_Destroy(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;
/* 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. :)
*/
(void)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;
/* 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;
}
if (!pk11_HandleTrustObject(slot, cert, trust)) { unsignedint type;
/* build some cert trust flags */ if (CERT_IsCACert(cert, &type)) { unsignedint 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;
}
} 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;
}
}
}
CERTCertList *
PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey *privKey)
{ if (!privKey) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL;
}
CERTCertList *certs = CERT_NewCertList(); if (!certs) {
PORT_SetError(SEC_ERROR_NO_MEMORY); return NULL;
}
PK11SlotInfo *slot = privKey->pkcs11Slot;
CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
CK_OBJECT_HANDLE certID = PK11_MatchItem(slot, handle, CKO_CERTIFICATE); /* If we can't get a matching certID, there are no matching certificates,
* which is not an error. */ if (certID == CK_INVALID_HANDLE) { return certs;
} int certHandleCount = 0;
CK_OBJECT_HANDLE *certHandles = PK11_FindCertHandlesForKeyHandle(slot, handle, &certHandleCount); if (!certHandles) { /* If certHandleCount is 0, there are no matching certificates, which is
* not an error. */ if (certHandleCount == 0) { return certs;
}
CERT_DestroyCertList(certs); return NULL;
} int i; for (i = 0; i < certHandleCount; i++) {
CERTCertificate *cert = PK11_MakeCertFromHandle(slot, certHandles[i], NULL); /* If PK11_MakeCertFromHandle fails for one handle, optimistically
assume other handles may succeed (i.e. this is best-effort). */ if (!cert) { continue;
} if (CERT_AddCertToListTail(certs, cert) != SECSuccess) {
CERT_DestroyCertificate(cert);
}
}
PORT_Free(certHandles); return certs;
}
/* * 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;
}
count = nssList_Count(certList); if (count == 0) { return;
}
certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count); if (!certs) { return;
}
id = PK11URI_GetPathAttributeItem(uri, PK11URI_PATTR_ID);
nssList_GetArray(certList, (void **)certs, count); for (i = 0; i < count; i++) { /* * Filter the subject matched certs based on the * CKA_ID from the URI
*/ if (id && (id->len != certs[i]->id.size ||
memcmp(id, certs[i]->id.data, certs[i]->id.size))) continue;
tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL); if (tokens) { for (tp = tokens; *tp; tp++) { constchar *value;
slot = (*tp)->pk11slot;
value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TOKEN); if (value &&
!pk11_MatchString(value,
(char *)slot->tokenInfo.label, sizeof(slot->tokenInfo.label))) { continue;
}
value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MANUFACTURER); if (value &&
!pk11_MatchString(value,
(char *)slot->tokenInfo.manufacturerID, sizeof(slot->tokenInfo.manufacturerID))) { continue;
}
value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MODEL); if (value &&
!pk11_MatchString(value,
(char *)slot->tokenInfo.model, sizeof(slot->tokenInfo.model))) { continue;
}
value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_SERIAL); if (value &&
!pk11_MatchString(value,
(char *)slot->tokenInfo.serialNumber, sizeof(slot->tokenInfo.serialNumber))) { continue;
}
uri = PK11URI_ParseURI(uriString); if (uri == NULL) { goto loser;
}
collection = nssCertificateCollection_Create(defaultTD, NULL); if (!collection) { goto loser;
}
certList = nssList_Create(NULL, PR_FALSE); if (!certList) { goto loser;
}
/* if the "type" attribute is specified its value must be "cert" */
type = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TYPE); if (type && strcmp(type, "cert")) { goto loser;
}
foundCerts = find_certs_from_uri(uri, wincx); 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;
}
/* 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(constchar *email, void *wincx)
{
FindCertsEmailArg cbparam;
SECStatus rv;
foundCerts = find_certs_from_nickname(nickname, wincx); 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);
}
} /* 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: case edKey: case ecMontKey:
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;
/* need to get the cert as a stan cert */
CERT_LockCertTempPerm(cert);
NSSCertificate *nssCert = cert->nssCertificate;
CERT_UnlockCertTempPerm(cert); if (nssCert) {
c = nssCert;
} 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;
}
/* add the new instance to the cert, force an update of the * CERTCertificate, and finish
*/
nssPKIObject_AddInstance(&c->object, certobj); /* nssTrustDomain_AddCertsToCache may release a reference to 'c' and * replace 'c' with a different value. So we add a reference to 'c' to
* prevent 'c' from being destroyed. */
nssCertificate_AddRef(c);
nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
(void)STAN_ForceCERTCertificateUpdate(c);
nssCertificate_Destroy(c);
SECITEM_FreeItem(keyID, PR_TRUE);
(void)nssToken_Destroy(token); return SECSuccess;
loser: if (token) {
(void)nssToken_Destroy(token);
}
CERT_MapStanError();
SECITEM_FreeItem(keyID, PR_TRUE); if (PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
PORT_SetError(SEC_ERROR_ADDING_CERT);
} return SECFailure;
}
/* * return the private key From a given Cert
*/
SECKEYPrivateKey *
PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx)
{ int err;
CK_OBJECT_HANDLE certh;
CK_OBJECT_HANDLE keyh;
PRBool needLogin;
SECStatus rv;
certh = PK11_FindCertInSlot(slot, cert, wincx); 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;
/* 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;
/* 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) {
(void)nssToken_Destroy(token); return NULL;
}
/* * 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) {
SECITEM_FreeItem(slotid, PR_TRUE);
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);
PK11_FreeSlotList(sl); 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;
/* * 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;
/* * 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;
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;
/* 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.