diff options
author | nelson%bolyard.com <devnull@localhost> | 2011-01-29 22:17:20 +0000 |
---|---|---|
committer | nelson%bolyard.com <devnull@localhost> | 2011-01-29 22:17:20 +0000 |
commit | 2fe34acf45030f627f502dd5efa003a5bfbb208a (patch) | |
tree | a94d241796d51e62decf9675cbe9d6d764000b54 /security/nss/lib/pk11wrap | |
parent | b1028c9a88ce8c35c891c226d3c89d0f918e8809 (diff) | |
download | nss-hg-2fe34acf45030f627f502dd5efa003a5bfbb208a.tar.gz |
Bug 592489: populate NSS's hash table of SubjectKeyID to token object.
Patch contributed by Kaspar Brand <mozbugzilla@velox.ch>, r=rrelyea
Diffstat (limited to 'security/nss/lib/pk11wrap')
-rw-r--r-- | security/nss/lib/pk11wrap/pk11cert.c | 185 |
1 files changed, 136 insertions, 49 deletions
diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c index 1e7599991..ad3da2a55 100644 --- a/security/nss/lib/pk11wrap/pk11cert.c +++ b/security/nss/lib/pk11wrap/pk11cert.c @@ -1367,6 +1367,69 @@ loser: 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. @@ -1379,11 +1442,77 @@ pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipien { NSSCMSRecipient *ri = NULL; int i; + PRBool tokenRescanDone = PR_FALSE; for (i=0; (ri = recipientlist[i]) != NULL; i++) { CERTCertificate *cert = NULL; if (ri->kind == RLSubjKeyID) { SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID); + if (!derCert && !tokenRescanDone) { + /* + * We didn't find the cert by its key ID. If we have slots + * with removable tokens, a failure from + * cert_FindDERCertBySubjectKeyID doesn't necessarily imply + * that the cert is unavailable - the token might simply + * have been inserted after the initial run of + * pk11_keyIDHash_populate (wrapped by PR_CallOnceWithArg), + * or a different token might have been present in that + * slot, initially. Let's check for new tokens... + */ + PK11SlotList *sl = PK11_GetAllTokens(CKM_INVALID_MECHANISM, + PR_FALSE, PR_FALSE, pwarg); + if (sl) { + PK11SlotListElement *le; + SECItem *slotid = SECITEM_AllocItem(NULL, NULL, + sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID)); + if (!slotid) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + for (le = sl->head; le; le = le->next) { + memcpy(slotid->data, &le->slot->slotID, + sizeof(CK_SLOT_ID)); + memcpy(&slotid->data[sizeof(CK_SLOT_ID)], + &le->slot->module->moduleID, + sizeof(SECMODModuleID)); + /* + * Any changes with the slot since our last check? + * If so, re-read the certs in that specific slot. + */ + if (cert_SubjectKeyIDSlotCheckSeries(slotid) + != PK11_GetSlotSeries(le->slot)) { + CERTCertListNode *node = NULL; + SECItem subjKeyID = {siBuffer, NULL, 0}; + CERTCertList *cl = PK11_ListCertsInSlot(le->slot); + if (!cl) { + continue; + } + for (node = CERT_LIST_HEAD(cl); + !CERT_LIST_END(node, cl); + node = CERT_LIST_NEXT(node)) { + if (CERT_IsUserCert(node->cert) && + CERT_FindSubjectKeyIDExtension(node->cert, + &subjKeyID) == SECSuccess) { + if (subjKeyID.data) { + cert_AddSubjectKeyIDMapping(&subjKeyID, + node->cert); + cert_UpdateSubjectKeyIDSlotCheck(slotid, + PK11_GetSlotSeries(le->slot)); + } + SECITEM_FreeItem(&subjKeyID, PR_FALSE); + } + } + CERT_DestroyCertList(cl); + } + } + PK11_FreeSlotList(sl); + SECITEM_FreeItem(slotid, PR_TRUE); + } + /* only check once per message/recipientlist */ + tokenRescanDone = PR_TRUE; + /* do another lookup (hopefully we found that cert...) */ + derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID); + } if (derCert) { cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg); SECITEM_FreeItem(derCert, PR_TRUE); @@ -1558,34 +1687,6 @@ loser: return NULL; } -static PRCallOnceType keyIDHashCallOnce; - -static PRStatus PR_CALLBACK -pk11_keyIDHash_populate(void *wincx) -{ - CERTCertList *certList; - CERTCertListNode *node = NULL; - SECItem subjKeyID = {siBuffer, NULL, 0}; - - certList = PK11_ListCerts(PK11CertListUser, wincx); - if (!certList) { - return PR_FAILURE; - } - - for (node = CERT_LIST_HEAD(certList); - !CERT_LIST_END(node, certList); - node = CERT_LIST_NEXT(node)) { - if (CERT_FindSubjectKeyIDExtension(node->cert, - &subjKeyID) == SECSuccess && - subjKeyID.data != NULL) { - cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert); - SECITEM_FreeItem(&subjKeyID, PR_FALSE); - } - } - CERT_DestroyCertList(certList); - return PR_SUCCESS; -} - /* * This is the new version of the above function for NSS SMIME code * this stuff should REALLY be in the SMIME code, but some things in here are not public @@ -2064,10 +2165,10 @@ PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, SECItem *inDerCert, void *wincx) { - NSSCertificate *c; NSSDER derCert; NSSToken *tok; NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); + nssCryptokiObject *co = NULL; SECStatus rv; tok = PK11Slot_GetNSSToken(slot); @@ -2077,26 +2178,12 @@ PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, SECItem *inDerCert, PK11_FreeSlot(slot); return NULL; } - c = NSSTrustDomain_FindCertificateByEncodedCertificate(td, &derCert); - if (c) { - PRBool isToken = PR_FALSE; - NSSToken **tp; - NSSToken **tokens = nssPKIObject_GetTokens(&c->object, NULL); - if (tokens) { - for (tp = tokens; *tp; tp++) { - if (*tp == tok) { - isToken = PR_TRUE; - break; - } - } - if (!isToken) { - NSSCertificate_Destroy(c); - c = NULL; - } - nssTokenArray_Destroy(tokens); - } - } - return c ? STAN_GetCERTCertificateOrRelease(c) : NULL; + + co = nssToken_FindCertificateByEncodedCertificate(tok, NULL, &derCert, + nssTokenSearchType_TokenOnly, NULL); + + return co ? PK11_MakeCertFromHandle(slot, co->handle, NULL) : NULL; + } /* |