diff options
Diffstat (limited to 'security/nss/lib/pki/pkistore.c')
-rw-r--r-- | security/nss/lib/pki/pkistore.c | 412 |
1 files changed, 360 insertions, 52 deletions
diff --git a/security/nss/lib/pki/pkistore.c b/security/nss/lib/pki/pkistore.c index a9a43870e..1550fedc5 100644 --- a/security/nss/lib/pki/pkistore.c +++ b/security/nss/lib/pki/pkistore.c @@ -700,6 +700,8 @@ struct nssTokenObjectStoreStr PRBool isFriendly; PZLock *lock; /* protects everything below */ NSSCert **certs; /* token certs */ + NSSPublicKey **bkeys; /* token public keys */ + NSSPrivateKey **vkeys; /* token private keys */ PRBool wasLoggedIn; /* token was authenticated last time * we accessed it */ @@ -715,12 +717,109 @@ struct nssTokenStoreStr { NSSTrustDomain *td; nssCertStore *certs; + NSSPublicKey **bkeys; + NSSPrivateKey **vkeys; + NSSSymKey **mkeys; PZLock *lock; /* protects the arena, array, and counter */ NSSArena *arena; nssTokenObjectStore **tokens; PRUint32 numTokens; }; +static PRStatus +add_pubkey_to_store(nssTokenStore *store, NSSPublicKey *bk) +{ + PRIntn count; + PZ_Lock(store->lock); + if (!store->bkeys) { + store->bkeys = nss_ZNEWARRAY(NULL, NSSPublicKey *, 5); + count = 0; + } else { + count = nssObjectArray_Count((void **)store->bkeys); + if (count > 0 && count % 4 == 0) { + NSSPublicKey **test; + test = nss_ZREALLOCARRAY(store->bkeys, NSSPublicKey *, count + 5); + if (!test) { + PZ_Unlock(store->lock); + return PR_FAILURE; + } + store->bkeys = test; + } + } + store->bkeys[count] = nssPublicKey_AddRef(bk); + PZ_Unlock(store->lock); + return PR_SUCCESS; +} + +static PRStatus +add_privkey_to_store(nssTokenStore *store, NSSPrivateKey *vk) +{ + PRIntn count; + PZ_Lock(store->lock); + if (!store->vkeys) { + store->vkeys = nss_ZNEWARRAY(NULL, NSSPrivateKey *, 5); + count = 0; + } else { + count = nssObjectArray_Count((void **)store->bkeys); + if (count > 0 && count % 4 == 0) { + NSSPrivateKey **test; + test = nss_ZREALLOCARRAY(store->vkeys, NSSPrivateKey *, count + 5); + if (!test) { + PZ_Unlock(store->lock); + return PR_FAILURE; + } + store->vkeys = test; + } + } + store->vkeys[count] = nssPrivateKey_AddRef(vk); + PZ_Unlock(store->lock); + return PR_SUCCESS; +} + +static void +remove_pubkey_from_store(nssTokenStore *store, NSSPublicKey *bk) +{ + PRBool foundIt = PR_FALSE; + NSSPublicKey **bkp; + PZ_Lock(store->lock); + for (bkp = store->bkeys; bkp && *bkp; bkp++) { + if (*bkp == bk) { + nssPublicKey_Destroy(*bkp); + foundIt = PR_TRUE; + break; + } + } + if (foundIt) { + NSSPublicKey **removed = bkp; + for (; bkp[1]; bkp++); + *removed = *bkp; + *bkp = NULL; + } + PZ_Unlock(store->lock); +} + +static void +remove_privkey_from_store(nssTokenStore *store, NSSPrivateKey *vk) +{ + PRBool foundIt = PR_FALSE; + NSSPrivateKey **vkp; + PZ_Lock(store->lock); + for (vkp = store->vkeys; vkp && *vkp; vkp++) { + if (*vkp == vk) { + nssPrivateKey_Destroy(*vkp); + foundIt = PR_TRUE; + break; + } + } + if (foundIt) { + NSSPrivateKey **removed = vkp; + for (; vkp[1]; vkp++); + *removed = *vkp; + *vkp = NULL; + } + PZ_Unlock(store->lock); +} + static void unload_token_certs(nssTokenObjectStore *objectStore, nssTokenStore *store) { @@ -758,7 +857,7 @@ load_token_certs(nssTokenObjectStore *objectStore, nssTokenStore *store) * on the token */ tokenCerts = nssToken_FindCerts(objectStore->token, objectStore->session, - nssTokenSearchType_TokenOnly, 0, &status); + 0, &status); if (status == PR_FAILURE) { return PR_FAILURE; } @@ -767,7 +866,7 @@ load_token_certs(nssTokenObjectStore *objectStore, nssTokenStore *store) store->td, NULL, NULL); if (!objectStore->certs) { - nssCryptokiObjectArray_Destroy(tokenCerts); + /* XXX nssCryptokiObjectArray_Destroy(tokenCerts); */ return PR_FAILURE; } nss_ZFreeIf(tokenCerts); @@ -781,6 +880,130 @@ load_token_certs(nssTokenObjectStore *objectStore, nssTokenStore *store) return PR_SUCCESS; } +static void +unload_token_bkeys(nssTokenObjectStore *objectStore, nssTokenStore *store) +{ + NSSPublicKey **bkp; + if (objectStore->bkeys) { + /* notify the objects that the token is removed */ + for (bkp = objectStore->bkeys; *bkp; bkp++) { + nssPublicKey_RemoveInstanceForToken(*bkp, objectStore->token); + if (nssPublicKey_CountInstances(*bkp) == 0) { + /* the key now has no token instances, remove it from + * the token store + */ + remove_pubkey_from_store(store, *bkp); + } + } + /* clear the array of token certs */ + nssPublicKeyArray_Destroy(objectStore->bkeys); + objectStore->bkeys = NULL; + } +} + +static PRStatus +load_token_bkeys(nssTokenObjectStore *objectStore, nssTokenStore *store) +{ + PRStatus status; + nssCryptokiObject **tokenBKeys; + NSSPublicKey **bkp; + + if (objectStore->bkeys) { + /* clear the existing array of token bkeys */ + nssPublicKeyArray_Destroy(objectStore->bkeys); + objectStore->bkeys = NULL; + } + /* find all peristent cert instances (PKCS #11 "token objects") + * on the token + */ + tokenBKeys = nssToken_FindPublicKeys(objectStore->token, + objectStore->session, + 0, &status); + if (status == PR_FAILURE) { + return PR_FAILURE; + } + if (tokenBKeys) { + objectStore->bkeys = nssPublicKeyArray_CreateFromInstances(tokenBKeys, + store->td, + NULL, NULL); + if (!objectStore->bkeys) { + /* XXX nssCryptokiObjectArray_Destroy(tokenBKeys); */ + return PR_FAILURE; + } + for (bkp = objectStore->bkeys; *bkp; bkp++) { + status = add_pubkey_to_store(store, *bkp); + if (status == PR_FAILURE) { + unload_token_bkeys(objectStore, store); + } + } + } + return PR_SUCCESS; +} + +static void +unload_token_vkeys(nssTokenObjectStore *objectStore, nssTokenStore *store) +{ + NSSPrivateKey **vkp; + if (objectStore->vkeys) { + /* notify the objects that the token is removed */ + for (vkp = objectStore->vkeys; *vkp; vkp++) { + nssPrivateKey_RemoveInstanceForToken(*vkp, objectStore->token); + if (nssPrivateKey_CountInstances(*vkp) == 0) { + /* the key now has no token instances, remove it from + * the token store + */ + remove_privkey_from_store(store, *vkp); + } + } + /* clear the array of token certs */ + nssPrivateKeyArray_Destroy(objectStore->vkeys); + objectStore->vkeys = NULL; + } +} + +static PRStatus +load_token_vkeys(nssTokenObjectStore *objectStore, nssTokenStore *store) +{ + PRStatus status; + nssCryptokiObject **tokenVKeys; + NSSPrivateKey **vkp; + + if (objectStore->vkeys) { + /* clear the existing array of token bkeys */ + nssPrivateKeyArray_Destroy(objectStore->vkeys); + objectStore->vkeys = NULL; + } + /* find all peristent cert instances (PKCS #11 "token objects") + * on the token + */ + tokenVKeys = nssToken_FindPrivateKeys(objectStore->token, + objectStore->session, + 0, &status); + if (status == PR_FAILURE) { + return PR_FAILURE; + } + if (tokenVKeys) { + objectStore->vkeys = nssPrivateKeyArray_CreateFromInstances(tokenVKeys, + store->td, + NULL, NULL); + if (!objectStore->vkeys) { + /* XXX nssCryptokiObjectArray_Destroy(tokenVKeys); */ + return PR_FAILURE; + } + for (vkp = objectStore->vkeys; *vkp; vkp++) { + status = add_privkey_to_store(store, *vkp); + if (status == PR_FAILURE) { + unload_token_vkeys(objectStore, store); + } + } + } + return PR_SUCCESS; +} + +static void +refresh_token_object_store(nssTokenObjectStore *objectStore, + nssTokenStore *store); + static nssTokenObjectStore * create_token_object_store(nssTokenStore *store, NSSToken *token) { @@ -803,18 +1026,9 @@ create_token_object_store(nssTokenStore *store, NSSToken *token) rvObjectStore->token = nssToken_AddRef(token); rvObjectStore->slot = nssToken_GetSlot(token); rvObjectStore->isFriendly = nssSlot_IsFriendly(rvObjectStore->slot); - if (load_token_certs(rvObjectStore, store) == PR_SUCCESS) { - rvObjectStore->wasPresent = PR_TRUE; - } else { - NSSError e = NSS_GetError(); - if (e == NSS_ERROR_DEVICE_REMOVED) { - rvObjectStore->wasPresent = PR_FALSE; - } else if (e == NSS_ERROR_LOGIN_REQUIRED) { - rvObjectStore->wasLoggedIn = PR_FALSE; - } else { - rvObjectStore->error = e; - } - } + rvObjectStore->wasPresent = PR_FALSE; + rvObjectStore->wasLoggedIn = PR_FALSE; + refresh_token_object_store(rvObjectStore, store); return rvObjectStore; } @@ -847,6 +1061,8 @@ refresh_token_object_store(nssTokenObjectStore *objectStore, if (objectStore->wasPresent) { /* token has been removed since the last search */ unload_token_certs(objectStore, store); + unload_token_bkeys(objectStore, store); + unload_token_vkeys(objectStore, store); } /* else it wasn't present before, so do nothing */ } else if (!objectStore->wasPresent) { /* token has been inserted since the last search */ @@ -855,18 +1071,30 @@ refresh_token_object_store(nssTokenObjectStore *objectStore, * be available */ status = load_token_certs(objectStore, store); + status = load_token_bkeys(objectStore, store); + if (isLoggedIn) { + status = load_token_vkeys(objectStore, store); + } } } else if (!isLoggedIn) { /* token is present but not authenticated */ - if (!objectStore->isFriendly && objectStore->wasLoggedIn) { - /* it is not friendly, and was previously authenticated, so + if (objectStore->wasLoggedIn) { + /* it was previously authenticated, so * we have private objects that need to be unloaded */ - unload_token_certs(objectStore, store); + unload_token_vkeys(objectStore, store); + if (!objectStore->isFriendly) { + unload_token_certs(objectStore, store); + unload_token_bkeys(objectStore, store); + } } /* else it wasn't authenticated before, so do nothing */ - } else if (!objectStore->isFriendly && !objectStore->wasLoggedIn) { - /* token is present and authenticated, load private objects */ - status = load_token_certs(objectStore, store); + } else if (!objectStore->wasLoggedIn) { + /* token is present and (now) authenticated, load private objects */ + status = load_token_vkeys(objectStore, store); + if (!objectStore->isFriendly) { + status = load_token_certs(objectStore, store); + status = load_token_bkeys(objectStore, store); + } } if (status == PR_FAILURE) { e = NSS_GetError(); @@ -876,6 +1104,8 @@ refresh_token_object_store(nssTokenObjectStore *objectStore, * move on. */ unload_token_certs(objectStore, store); + unload_token_bkeys(objectStore, store); + unload_token_vkeys(objectStore, store); e = NSS_ERROR_NO_ERROR; /* override the error */ } } @@ -919,38 +1149,6 @@ find_store_for_token(nssTokenStore *store, NSSToken *token) return objectStore; } -NSS_IMPLEMENT PRStatus -nssTokenStore_AddToken ( - nssTokenStore *store, - NSSToken *token -) -{ - PRStatus status = PR_SUCCESS; - PZ_Lock(store->lock); - if (store->numTokens == 0) { - store->tokens = nss_ZNEWARRAY(NULL, - nssTokenObjectStore *, - store->numTokens + 1); - } else { - store->tokens = nss_ZREALLOCARRAY(store->tokens, - nssTokenObjectStore *, - store->numTokens + 1); - } - if (store->tokens) { - store->tokens[store->numTokens] = create_token_object_store(store, - token); - if (!store->tokens[store->numTokens]) { - status = PR_FAILURE; - } else { - store->numTokens++; - } - } else { - status = PR_FAILURE; - } - PZ_Unlock(store->lock); - return status; -} - NSS_IMPLEMENT nssTokenStore * nssTokenStore_Create ( NSSTrustDomain *td, @@ -1024,6 +1222,38 @@ nssTokenStore_Destroy ( } NSS_IMPLEMENT PRStatus +nssTokenStore_AddToken ( + nssTokenStore *store, + NSSToken *token +) +{ + PRStatus status = PR_SUCCESS; + PZ_Lock(store->lock); + if (store->numTokens == 0) { + store->tokens = nss_ZNEWARRAY(NULL, + nssTokenObjectStore *, + store->numTokens + 1); + } else { + store->tokens = nss_ZREALLOCARRAY(store->tokens, + nssTokenObjectStore *, + store->numTokens + 1); + } + if (store->tokens) { + store->tokens[store->numTokens] = create_token_object_store(store, + token); + if (!store->tokens[store->numTokens]) { + status = PR_FAILURE; + } else { + store->numTokens++; + } + } else { + status = PR_FAILURE; + } + PZ_Unlock(store->lock); + return status; +} + +NSS_IMPLEMENT PRStatus nssTokenStore_EnableToken ( nssTokenStore *store, NSSToken *token @@ -1103,6 +1333,7 @@ nssTokenStore_ImportCert ( return PR_SUCCESS; } /* copy it onto the token and add it to the store */ + /* XXX use session */ status = nssCert_CopyToToken(cert, destination, nicknameOpt); if (status == PR_SUCCESS) { status = nssCertStore_AddCert(store->certs, cert); @@ -1130,6 +1361,7 @@ nssTokenStore_RemoveCert ( NSSCert *cert ) { + /* XXX destroy session objects */ (void)nssCertStore_RemoveCert(store->certs, cert); } @@ -1222,3 +1454,79 @@ nssTokenStore_TraverseCerts ( return nssCertStore_TraverseCerts(store->certs, callback, arg); } +NSS_IMPLEMENT NSSPublicKey * +nssTokenStore_FindPublicKeyByID ( + nssTokenStore *store, + NSSItem *id +) +{ + NSSPublicKey **bkp; + NSSPublicKey *rvBK = NULL; + NSSItem *bkID; + + nssTokenStore_Refresh(store); + PZ_Lock(store->lock); + for (bkp = store->bkeys; bkp && *bkp; bkp++) { + bkID = nssPublicKey_GetID(*bkp); + if (nssItem_Equal(bkID, id, NULL)) { + rvBK = nssPublicKey_AddRef(*bkp); + break; + } + } + PZ_Unlock(store->lock); + return rvBK; +} + +NSS_IMPLEMENT NSSPrivateKey * +nssTokenStore_FindPrivateKeyByID ( + nssTokenStore *store, + NSSItem *id +) +{ + NSSPrivateKey **vkp; + NSSPrivateKey *rvVK = NULL; + NSSItem *vkID; + + nssTokenStore_Refresh(store); + PZ_Lock(store->lock); + for (vkp = store->vkeys; vkp && *vkp; vkp++) { + vkID = nssPrivateKey_GetID(*vkp); + if (nssItem_Equal(vkID, id, NULL)) { + rvVK = nssPrivateKey_AddRef(*vkp); + break; + } + } + PZ_Unlock(store->lock); + return rvVK; +} + +NSS_IMPLEMENT PRStatus * +nssTokenStore_TraversePrivateKeys ( + nssTokenStore *store, + PRStatus (*callback)(NSSPrivateKey *vk, void *arg), + void *arg +) +{ + NSSPrivateKey **vkp; + NSSPrivateKey **vkeys; + PRUint32 count; + + nssTokenStore_Refresh(store); + /* XXX ugly */ + PZ_Lock(store->lock); + for (vkp = store->vkeys, count = 0; vkp && *vkp; vkp++, count++); + if (count > 0) { + vkeys = nss_ZNEWARRAY(NULL, NSSPrivateKey *, count + 1); + if (vkeys) { + for (vkp = store->vkeys, count = 0; *vkp; vkp++, count++) + vkeys[count++] = nssPrivateKey_AddRef(*vkp); + } + } + PZ_Unlock(store->lock); + for (vkp = vkeys; vkp && *vkp; vkp++) { + (*callback)(*vkp, arg); + } + nssPrivateKeyArray_Destroy(vkeys); + return NULL; +} + |