diff options
Diffstat (limited to 'security/nss/lib/certdb/certdb.c')
-rw-r--r-- | security/nss/lib/certdb/certdb.c | 160 |
1 files changed, 158 insertions, 2 deletions
diff --git a/security/nss/lib/certdb/certdb.c b/security/nss/lib/certdb/certdb.c index 8bfe1a58c..4362630cc 100644 --- a/security/nss/lib/certdb/certdb.c +++ b/security/nss/lib/certdb/certdb.c @@ -670,7 +670,7 @@ cert_GetKeyID(CERTCertificate *cert) cert->subjectKeyID.len = 0; /* see of the cert has a key identifier extension */ - rv = CERT_FindSubjectKeyIDExten(cert, &tmpitem); + rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem); if ( rv == SECSuccess ) { cert->subjectKeyID.data = (unsigned char*) PORT_ArenaAlloc(cert->arena, tmpitem.len); if ( cert->subjectKeyID.data != NULL ) { @@ -747,7 +747,7 @@ cert_IsRootCert(CERTCertificate *cert) /* authority key identifier is present */ if (cert->authKeyID->keyID.len > 0) { /* the keyIdentifier field is set, look for subjectKeyID */ - rv = CERT_FindSubjectKeyIDExten(cert, &tmpitem); + rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem); if (rv == SECSuccess) { PRBool match; /* also present, they MUST match for it to be a root */ @@ -2737,3 +2737,159 @@ CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig) PORT_Assert(handle->statusConfig == NULL); handle->statusConfig = statusConfig; } + +/* + * Code for dealing with subjKeyID to cert mappings. + */ + +static PLHashTable *gSubjKeyIDHash = NULL; +static PRLock *gSubjKeyIDLock = NULL; + +static void *cert_AllocTable(void *pool, PRSize size) +{ + return PORT_Alloc(size); +} + +static void cert_FreeTable(void *pool, void *item) +{ + PORT_Free(item); +} + +static PLHashEntry* cert_AllocEntry(void *pool, const void *key) +{ + return PORT_New(PLHashEntry); +} + +static void cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag) +{ + SECITEM_FreeItem((SECItem*)(he->value), PR_TRUE); + if (flag == HT_FREE_ENTRY) { + SECITEM_FreeItem((SECItem*)(he->key), PR_TRUE); + PORT_Free(he); + } +} + +static PLHashAllocOps cert_AllocOps = { + cert_AllocTable, cert_FreeTable, cert_AllocEntry, cert_FreeEntry +}; + +SECStatus +cert_CreateSubjectKeyIDHashTable(void) +{ + gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, + SECITEM_HashCompare, + &cert_AllocOps, NULL); + if (!gSubjKeyIDHash) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + gSubjKeyIDLock = PR_NewLock(); + if (!gSubjKeyIDLock) { + PL_HashTableDestroy(gSubjKeyIDHash); + gSubjKeyIDHash = NULL; + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + return SECSuccess; + +} + +SECStatus +cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert) +{ + SECItem *newKeyID, *oldVal, *newVal; + SECStatus rv = SECFailure; + + if (!gSubjKeyIDLock) { + /* If one is created, then both are there. So only check for one. */ + return SECFailure; + } + + newVal = SECITEM_DupItem(&cert->derCert); + if (!newVal) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + goto done; + } + newKeyID = SECITEM_DupItem(subjKeyID); + if (!newKeyID) { + SECITEM_FreeItem(newVal, PR_TRUE); + PORT_SetError(SEC_ERROR_NO_MEMORY); + goto done; + } + + PR_Lock(gSubjKeyIDLock); + /* The hash table implementation does not free up the memory + * associated with the key of an already existing entry if we add a + * duplicate, so we would wind up leaking the previously allocated + * key if we don't remove before adding. + */ + oldVal = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID); + if (oldVal) { + PL_HashTableRemove(gSubjKeyIDHash, subjKeyID); + } + + rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess : + SECFailure; + PR_Unlock(gSubjKeyIDLock); +done: + return rv; +} + +SECStatus +cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID) +{ + SECStatus rv; + if (!gSubjKeyIDLock) + return SECFailure; + + PR_Lock(gSubjKeyIDLock); + rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess : + SECFailure; + PR_Unlock(gSubjKeyIDLock); + return rv; +} + +SECStatus +cert_DestroySubjectKeyIDHashTable(void) +{ + if (gSubjKeyIDHash) { + PR_Lock(gSubjKeyIDLock); + PL_HashTableDestroy(gSubjKeyIDHash); + gSubjKeyIDHash = NULL; + PR_Unlock(gSubjKeyIDLock); + PR_DestroyLock(gSubjKeyIDLock); + gSubjKeyIDLock = NULL; + } + return SECSuccess; +} + +SECItem* +cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID) +{ + SECItem *val; + + if (!gSubjKeyIDLock) + return NULL; + + PR_Lock(gSubjKeyIDLock); + val = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID); + if (val) { + val = SECITEM_DupItem(val); + } + PR_Unlock(gSubjKeyIDLock); + return val; +} + +CERTCertificate* +CERT_FindCertBySubjectKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID) +{ + CERTCertificate *cert = NULL; + SECItem *derCert; + + derCert = cert_FindDERCertBySubjectKeyID(subjKeyID); + if (derCert) { + cert = CERT_FindCertByDERCert(handle, derCert); + SECITEM_FreeItem(derCert, PR_TRUE); + } + return cert; +} |