Index: mozilla/security/nss/lib/softoken/sftkdb.c |
=================================================================== |
--- mozilla/security/nss/lib/softoken/sftkdb.c (revision 191424) |
+++ mozilla/security/nss/lib/softoken/sftkdb.c (working copy) |
@@ -1,2737 +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/. */ |
-/* |
- * The following code handles the storage of PKCS 11 modules used by the |
- * NSS. For the rest of NSS, only one kind of database handle exists: |
- * |
- * SFTKDBHandle |
- * |
- * There is one SFTKDBHandle for the each key database and one for each cert |
- * database. These databases are opened as associated pairs, one pair per |
- * slot. SFTKDBHandles are reference counted objects. |
- * |
- * Each SFTKDBHandle points to a low level database handle (SDB). This handle |
- * represents the underlying physical database. These objects are not |
- * reference counted, an are 'owned' by their respective SFTKDBHandles. |
- * |
- * |
- */ |
-#include "sftkdb.h" |
-#include "sftkdbti.h" |
-#include "pkcs11t.h" |
-#include "pkcs11i.h" |
-#include "sdb.h" |
-#include "prprf.h" |
-#include "pratom.h" |
-#include "lgglue.h" |
-#include "utilpars.h" |
-#include "secerr.h" |
-#include "softoken.h" |
- |
-/* |
- * We want all databases to have the same binary representation independent of |
- * endianness or length of the host architecture. In general PKCS #11 attributes |
- * are endian/length independent except those attributes that pass CK_ULONG. |
- * |
- * The following functions fixes up the CK_ULONG type attributes so that the data |
- * base sees a machine independent view. CK_ULONGs are stored as 4 byte network |
- * byte order values (big endian). |
- */ |
-#define BBP 8 |
- |
-static PRBool |
-sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type) |
-{ |
- switch(type) { |
- case CKA_CERTIFICATE_CATEGORY: |
- case CKA_CERTIFICATE_TYPE: |
- case CKA_CLASS: |
- case CKA_JAVA_MIDP_SECURITY_DOMAIN: |
- case CKA_KEY_GEN_MECHANISM: |
- case CKA_KEY_TYPE: |
- case CKA_MECHANISM_TYPE: |
- case CKA_MODULUS_BITS: |
- case CKA_PRIME_BITS: |
- case CKA_SUBPRIME_BITS: |
- case CKA_VALUE_BITS: |
- case CKA_VALUE_LEN: |
- |
- case CKA_TRUST_DIGITAL_SIGNATURE: |
- case CKA_TRUST_NON_REPUDIATION: |
- case CKA_TRUST_KEY_ENCIPHERMENT: |
- case CKA_TRUST_DATA_ENCIPHERMENT: |
- case CKA_TRUST_KEY_AGREEMENT: |
- case CKA_TRUST_KEY_CERT_SIGN: |
- case CKA_TRUST_CRL_SIGN: |
- |
- case CKA_TRUST_SERVER_AUTH: |
- case CKA_TRUST_CLIENT_AUTH: |
- case CKA_TRUST_CODE_SIGNING: |
- case CKA_TRUST_EMAIL_PROTECTION: |
- case CKA_TRUST_IPSEC_END_SYSTEM: |
- case CKA_TRUST_IPSEC_TUNNEL: |
- case CKA_TRUST_IPSEC_USER: |
- case CKA_TRUST_TIME_STAMPING: |
- case CKA_TRUST_STEP_UP_APPROVED: |
- return PR_TRUE; |
- default: |
- break; |
- } |
- return PR_FALSE; |
- |
-} |
- |
-/* are the attributes private? */ |
-static PRBool |
-sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type) |
-{ |
- switch(type) { |
- case CKA_VALUE: |
- case CKA_PRIVATE_EXPONENT: |
- case CKA_PRIME_1: |
- case CKA_PRIME_2: |
- case CKA_EXPONENT_1: |
- case CKA_EXPONENT_2: |
- case CKA_COEFFICIENT: |
- return PR_TRUE; |
- default: |
- break; |
- } |
- return PR_FALSE; |
-} |
- |
-/* These attributes must be authenticated with an hmac. */ |
-static PRBool |
-sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) |
-{ |
- switch(type) { |
- case CKA_MODULUS: |
- case CKA_PUBLIC_EXPONENT: |
- case CKA_CERT_SHA1_HASH: |
- case CKA_CERT_MD5_HASH: |
- case CKA_TRUST_SERVER_AUTH: |
- case CKA_TRUST_CLIENT_AUTH: |
- case CKA_TRUST_EMAIL_PROTECTION: |
- case CKA_TRUST_CODE_SIGNING: |
- case CKA_TRUST_STEP_UP_APPROVED: |
- case CKA_NSS_OVERRIDE_EXTENSIONS: |
- return PR_TRUE; |
- default: |
- break; |
- } |
- return PR_FALSE; |
-} |
- |
-/* |
- * convert a native ULONG to a database ulong. Database ulong's |
- * are all 4 byte big endian values. |
- */ |
-void |
-sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value) |
-{ |
- int i; |
- |
- for (i=0; i < SDB_ULONG_SIZE; i++) { |
- data[i] = (value >> (SDB_ULONG_SIZE-1-i)*BBP) & 0xff; |
- } |
-} |
- |
-/* |
- * convert a database ulong back to a native ULONG. (reverse of the above |
- * function. |
- */ |
-static CK_ULONG |
-sftk_SDBULong2ULong(unsigned char *data) |
-{ |
- int i; |
- CK_ULONG value = 0; |
- |
- for (i=0; i < SDB_ULONG_SIZE; i++) { |
- value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE-1-i)*BBP); |
- } |
- return value; |
-} |
- |
-/* |
- * fix up the input templates. Our fixed up ints are stored in data and must |
- * be freed by the caller. The new template must also be freed. If there are no |
- * CK_ULONG attributes, the orignal template is passed in as is. |
- */ |
-static CK_ATTRIBUTE * |
-sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, |
- unsigned char **dataOut) |
-{ |
- int i; |
- int ulongCount = 0; |
- unsigned char *data; |
- CK_ATTRIBUTE *ntemplate; |
- |
- *dataOut = NULL; |
- |
- /* first count the number of CK_ULONG attributes */ |
- for (i=0; i < count; i++) { |
- /* Don't 'fixup' NULL values */ |
- if (!template[i].pValue) { |
- continue; |
- } |
- if (template[i].ulValueLen == sizeof (CK_ULONG)) { |
- if ( sftkdb_isULONGAttribute(template[i].type)) { |
- ulongCount++; |
- } |
- } |
- } |
- /* no attributes to fixup, just call on through */ |
- if (ulongCount == 0) { |
- return (CK_ATTRIBUTE *)template; |
- } |
- |
- /* allocate space for new ULONGS */ |
- data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE*ulongCount); |
- if (!data) { |
- return NULL; |
- } |
- |
- /* allocate new template */ |
- ntemplate = PORT_NewArray(CK_ATTRIBUTE,count); |
- if (!ntemplate) { |
- PORT_Free(data); |
- return NULL; |
- } |
- *dataOut = data; |
- /* copy the old template, fixup the actual ulongs */ |
- for (i=0; i < count; i++) { |
- ntemplate[i] = template[i]; |
- /* Don't 'fixup' NULL values */ |
- if (!template[i].pValue) { |
- continue; |
- } |
- if (template[i].ulValueLen == sizeof (CK_ULONG)) { |
- if ( sftkdb_isULONGAttribute(template[i].type) ) { |
- CK_ULONG value = *(CK_ULONG *) template[i].pValue; |
- sftk_ULong2SDBULong(data, value); |
- ntemplate[i].pValue = data; |
- ntemplate[i].ulValueLen = SDB_ULONG_SIZE; |
- data += SDB_ULONG_SIZE; |
- } |
- } |
- } |
- return ntemplate; |
-} |
- |
- |
-static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; |
- |
-/* |
- * return a string describing the database type (key or cert) |
- */ |
-const char * |
-sftkdb_TypeString(SFTKDBHandle *handle) |
-{ |
- return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert"; |
-} |
- |
-/* |
- * Some attributes are signed with an Hmac and a pbe key generated from |
- * the password. This signature is stored indexed by object handle and |
- * attribute type in the meta data table in the key database. |
- * |
- * Signature entries are indexed by the string |
- * sig_[cert/key]_{ObjectID}_{Attribute} |
- * |
- * This function fetches that pkcs5 signature. Caller supplies a SECItem |
- * pre-allocated to the appropriate size if the SECItem is too small the |
- * function will fail with CKR_BUFFER_TOO_SMALL. |
- */ |
-static CK_RV |
-sftkdb_getAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle, |
- CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type, |
- SECItem *signText) |
-{ |
- SDB *db; |
- char id[30]; |
- CK_RV crv; |
- |
- db = SFTK_GET_SDB(keyHandle); |
- |
- sprintf(id, SFTKDB_META_SIG_TEMPLATE, |
- sftkdb_TypeString(handle), |
- (unsigned int)objectID, (unsigned int)type); |
- |
- crv = (*db->sdb_GetMetaData)(db, id, signText, NULL); |
- return crv; |
-} |
- |
-/* |
- * Some attributes are signed with an Hmac and a pbe key generated from |
- * the password. This signature is stored indexed by object handle and |
- * attribute type in the meta data table in the key database. |
- * |
- * Signature entries are indexed by the string |
- * sig_[cert/key]_{ObjectID}_{Attribute} |
- * |
- * This function stores that pkcs5 signature. |
- */ |
-CK_RV |
-sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget, |
- CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type, |
- SECItem *signText) |
-{ |
- char id[30]; |
- CK_RV crv; |
- |
- sprintf(id, SFTKDB_META_SIG_TEMPLATE, |
- sftkdb_TypeString(handle), |
- (unsigned int)objectID, (unsigned int)type); |
- |
- crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL); |
- return crv; |
-} |
- |
-/* |
- * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated |
- * separate data sections for the database ULONG values. |
- */ |
-static CK_RV |
-sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID, |
- CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle) |
-{ |
- int i; |
- CK_RV crv = CKR_OK; |
- SFTKDBHandle *keyHandle; |
- PRBool checkSig = PR_TRUE; |
- PRBool checkEnc = PR_TRUE; |
- |
- PORT_Assert(handle); |
- |
- /* find the key handle */ |
- keyHandle = handle; |
- if (handle->type != SFTK_KEYDB_TYPE) { |
- checkEnc = PR_FALSE; |
- keyHandle = handle->peerDB; |
- } |
- |
- if ((keyHandle == NULL) || |
- ((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0) || |
- (keyHandle->passwordKey.data == NULL)) { |
- checkSig = PR_FALSE; |
- } |
- |
- for (i=0; i < count; i++) { |
- CK_ULONG length = template[i].ulValueLen; |
- template[i].ulValueLen = ntemplate[i].ulValueLen; |
- /* fixup ulongs */ |
- if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) { |
- if (sftkdb_isULONGAttribute(template[i].type)) { |
- if (template[i].pValue) { |
- CK_ULONG value; |
- unsigned char *data; |
- |
- data = (unsigned char *)ntemplate[i].pValue; |
- value = sftk_SDBULong2ULong(ntemplate[i].pValue); |
- if (length < sizeof(CK_ULONG)) { |
- template[i].ulValueLen = -1; |
- crv = CKR_BUFFER_TOO_SMALL; |
- continue; |
- } |
- PORT_Memcpy(template[i].pValue,&value,sizeof(CK_ULONG)); |
- } |
- template[i].ulValueLen = sizeof(CK_ULONG); |
- } |
- } |
- |
- /* if no data was retrieved, no need to process encrypted or signed |
- * attributes */ |
- if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) { |
- continue; |
- } |
- |
- /* fixup private attributes */ |
- if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) { |
- /* we have a private attribute */ |
- /* This code depends on the fact that the cipherText is bigger |
- * than the plain text */ |
- SECItem cipherText; |
- SECItem *plainText; |
- SECStatus rv; |
- |
- cipherText.data = ntemplate[i].pValue; |
- cipherText.len = ntemplate[i].ulValueLen; |
- PZ_Lock(handle->passwordLock); |
- if (handle->passwordKey.data == NULL) { |
- PZ_Unlock(handle->passwordLock); |
- template[i].ulValueLen = -1; |
- crv = CKR_USER_NOT_LOGGED_IN; |
- continue; |
- } |
- rv = sftkdb_DecryptAttribute(&handle->passwordKey, |
- &cipherText, &plainText); |
- PZ_Unlock(handle->passwordLock); |
- if (rv != SECSuccess) { |
- PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); |
- template[i].ulValueLen = -1; |
- crv = CKR_GENERAL_ERROR; |
- continue; |
- } |
- PORT_Assert(template[i].ulValueLen >= plainText->len); |
- if (template[i].ulValueLen < plainText->len) { |
- SECITEM_FreeItem(plainText,PR_TRUE); |
- PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); |
- template[i].ulValueLen = -1; |
- crv = CKR_GENERAL_ERROR; |
- continue; |
- } |
- |
- /* copy the plain text back into the template */ |
- PORT_Memcpy(template[i].pValue, plainText->data, plainText->len); |
- template[i].ulValueLen = plainText->len; |
- SECITEM_FreeItem(plainText,PR_TRUE); |
- } |
- /* make sure signed attributes are valid */ |
- if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) { |
- SECStatus rv; |
- SECItem signText; |
- SECItem plainText; |
- unsigned char signData[SDB_MAX_META_DATA_LEN]; |
- |
- signText.data = signData; |
- signText.len = sizeof(signData); |
- |
- rv = sftkdb_getAttributeSignature(handle, keyHandle, |
- objectID, ntemplate[i].type, &signText); |
- if (rv != SECSuccess) { |
- PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); |
- template[i].ulValueLen = -1; |
- crv = CKR_DATA_INVALID; /* better error code? */ |
- continue; |
- } |
- |
- plainText.data = ntemplate[i].pValue; |
- plainText.len = ntemplate[i].ulValueLen; |
- |
- /* |
- * we do a second check holding the lock just in case the user |
- * loggout while we were trying to get the signature. |
- */ |
- PZ_Lock(keyHandle->passwordLock); |
- if (keyHandle->passwordKey.data == NULL) { |
- /* if we are no longer logged in, no use checking the other |
- * Signatures either. */ |
- checkSig = PR_FALSE; |
- PZ_Unlock(keyHandle->passwordLock); |
- continue; |
- } |
- |
- rv = sftkdb_VerifyAttribute(&keyHandle->passwordKey, |
- objectID, ntemplate[i].type, |
- &plainText, &signText); |
- PZ_Unlock(keyHandle->passwordLock); |
- if (rv != SECSuccess) { |
- PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); |
- template[i].ulValueLen = -1; |
- crv = CKR_SIGNATURE_INVALID; /* better error code? */ |
- } |
- /* This Attribute is fine */ |
- } |
- } |
- return crv; |
-} |
- |
-/* |
- * Some attributes are signed with an HMAC and a pbe key generated from |
- * the password. This signature is stored indexed by object handle and |
- * |
- * Those attributes are: |
- * 1) Trust object hashes and trust values. |
- * 2) public key values. |
- * |
- * Certs themselves are considered properly authenticated by virtue of their |
- * signature, or their matching hash with the trust object. |
- * |
- * These signature is only checked for objects coming from shared databases. |
- * Older dbm style databases have such no signature checks. HMACs are also |
- * only checked when the token is logged in, as it requires a pbe generated |
- * from the password. |
- * |
- * Tokens which have no key database (and therefore no master password) do not |
- * have any stored signature values. Signature values are stored in the key |
- * database, since the signature data is tightly coupled to the key database |
- * password. |
- * |
- * This function takes a template of attributes that were either created or |
- * modified. These attributes are checked to see if the need to be signed. |
- * If they do, then this function signs the attributes and writes them |
- * to the meta data store. |
- * |
- * This function can fail if there are attributes that must be signed, but |
- * the token is not logged in. |
- * |
- * The caller is expected to abort any transaction he was in in the |
- * event of a failure of this function. |
- */ |
-static CK_RV |
-sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle, |
- PRBool mayBeUpdateDB, |
- CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, |
- CK_ULONG count) |
-{ |
- int i; |
- CK_RV crv; |
- SFTKDBHandle *keyHandle = handle; |
- SDB *keyTarget = NULL; |
- PRBool usingPeerDB = PR_FALSE; |
- PRBool inPeerDBTransaction = PR_FALSE; |
- |
- PORT_Assert(handle); |
- |
- if (handle->type != SFTK_KEYDB_TYPE) { |
- keyHandle = handle->peerDB; |
- usingPeerDB = PR_TRUE; |
- } |
- |
- /* no key DB defined? then no need to sign anything */ |
- if (keyHandle == NULL) { |
- crv = CKR_OK; |
- goto loser; |
- } |
- |
- /* When we are in a middle of an update, we have an update database set, |
- * but we want to write to the real database. The bool mayBeUpdateDB is |
- * set to TRUE if it's possible that we want to write an update database |
- * rather than a primary */ |
- keyTarget = (mayBeUpdateDB && keyHandle->update) ? |
- keyHandle->update : keyHandle->db; |
- |
- /* skip the the database does not support meta data */ |
- if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) { |
- crv = CKR_OK; |
- goto loser; |
- } |
- |
- /* If we had to switch databases, we need to initialize a transaction. */ |
- if (usingPeerDB) { |
- crv = (*keyTarget->sdb_Begin)(keyTarget); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- inPeerDBTransaction = PR_TRUE; |
- } |
- |
- for (i=0; i < count; i ++) { |
- if (sftkdb_isAuthenticatedAttribute(template[i].type)) { |
- SECStatus rv; |
- SECItem *signText; |
- SECItem plainText; |
- |
- plainText.data = template[i].pValue; |
- plainText.len = template[i].ulValueLen; |
- PZ_Lock(keyHandle->passwordLock); |
- if (keyHandle->passwordKey.data == NULL) { |
- PZ_Unlock(keyHandle->passwordLock); |
- crv = CKR_USER_NOT_LOGGED_IN; |
- goto loser; |
- } |
- rv = sftkdb_SignAttribute(arena, &keyHandle->passwordKey, |
- objectID, template[i].type, |
- &plainText, &signText); |
- PZ_Unlock(keyHandle->passwordLock); |
- if (rv != SECSuccess) { |
- crv = CKR_GENERAL_ERROR; /* better error code here? */ |
- goto loser; |
- } |
- rv = sftkdb_PutAttributeSignature(handle, keyTarget, |
- objectID, template[i].type, signText); |
- if (rv != SECSuccess) { |
- crv = CKR_GENERAL_ERROR; /* better error code here? */ |
- goto loser; |
- } |
- } |
- } |
- crv = CKR_OK; |
- |
- /* If necessary, commit the transaction */ |
- if (inPeerDBTransaction) { |
- crv = (*keyTarget->sdb_Commit)(keyTarget); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- inPeerDBTransaction = PR_FALSE; |
- } |
- |
-loser: |
- if (inPeerDBTransaction) { |
- /* The transaction must have failed. Abort. */ |
- (*keyTarget->sdb_Abort)(keyTarget); |
- PORT_Assert(crv != CKR_OK); |
- if (crv == CKR_OK) crv = CKR_GENERAL_ERROR; |
- } |
- return crv; |
-} |
- |
-static CK_RV |
-sftkdb_CreateObject(PRArenaPool *arena, SFTKDBHandle *handle, |
- SDB *db, CK_OBJECT_HANDLE *objectID, |
- CK_ATTRIBUTE *template, CK_ULONG count) |
-{ |
- PRBool inTransaction = PR_FALSE; |
- CK_RV crv; |
- |
- inTransaction = PR_TRUE; |
- |
- crv = (*db->sdb_CreateObject)(db, objectID, template, count); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- crv = sftk_signTemplate(arena, handle, (db == handle->update), |
- *objectID, template, count); |
-loser: |
- |
- return crv; |
-} |
- |
- |
-CK_ATTRIBUTE * |
-sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, |
- SFTKDBHandle *handle,CK_ULONG *pcount, |
- CK_RV *crv) |
-{ |
- int count; |
- CK_ATTRIBUTE *template; |
- int i, templateIndex; |
- SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); |
- PRBool doEnc = PR_TRUE; |
- |
- *crv = CKR_OK; |
- |
- if (sessObject == NULL) { |
- *crv = CKR_GENERAL_ERROR; /* internal programming error */ |
- return NULL; |
- } |
- |
- PORT_Assert(handle); |
- /* find the key handle */ |
- if (handle->type != SFTK_KEYDB_TYPE) { |
- doEnc = PR_FALSE; |
- } |
- |
- PZ_Lock(sessObject->attributeLock); |
- count = 0; |
- for (i=0; i < sessObject->hashSize; i++) { |
- SFTKAttribute *attr; |
- for (attr=sessObject->head[i]; attr; attr=attr->next) { |
- count++; |
- } |
- } |
- template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count); |
- if (template == NULL) { |
- PZ_Unlock(sessObject->attributeLock); |
- *crv = CKR_HOST_MEMORY; |
- return NULL; |
- } |
- templateIndex = 0; |
- for (i=0; i < sessObject->hashSize; i++) { |
- SFTKAttribute *attr; |
- for (attr=sessObject->head[i]; attr; attr=attr->next) { |
- CK_ATTRIBUTE *tp = &template[templateIndex++]; |
- /* copy the attribute */ |
- *tp = attr->attrib; |
- |
- /* fixup ULONG s */ |
- if ((tp->ulValueLen == sizeof (CK_ULONG)) && |
- (sftkdb_isULONGAttribute(tp->type)) ) { |
- CK_ULONG value = *(CK_ULONG *) tp->pValue; |
- unsigned char *data; |
- |
- tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE); |
- data = (unsigned char *)tp->pValue; |
- if (data == NULL) { |
- *crv = CKR_HOST_MEMORY; |
- break; |
- } |
- sftk_ULong2SDBULong(data, value); |
- tp->ulValueLen = SDB_ULONG_SIZE; |
- } |
- |
- /* encrypt private attributes */ |
- if (doEnc && sftkdb_isPrivateAttribute(tp->type)) { |
- /* we have a private attribute */ |
- SECItem *cipherText; |
- SECItem plainText; |
- SECStatus rv; |
- |
- plainText.data = tp->pValue; |
- plainText.len = tp->ulValueLen; |
- PZ_Lock(handle->passwordLock); |
- if (handle->passwordKey.data == NULL) { |
- PZ_Unlock(handle->passwordLock); |
- *crv = CKR_USER_NOT_LOGGED_IN; |
- break; |
- } |
- rv = sftkdb_EncryptAttribute(arena, &handle->passwordKey, |
- &plainText, &cipherText); |
- PZ_Unlock(handle->passwordLock); |
- if (rv == SECSuccess) { |
- tp->pValue = cipherText->data; |
- tp->ulValueLen = cipherText->len; |
- } else { |
- *crv = CKR_GENERAL_ERROR; /* better error code here? */ |
- break; |
- } |
- PORT_Memset(plainText.data, 0, plainText.len); |
- } |
- } |
- } |
- PORT_Assert(templateIndex <= count); |
- PZ_Unlock(sessObject->attributeLock); |
- |
- if (*crv != CKR_OK) { |
- return NULL; |
- } |
- if (pcount) { |
- *pcount = count; |
- } |
- return template; |
- |
-} |
- |
-/* |
- * return a pointer to the attribute in the give template. |
- * The return value is not const, as the caller may modify |
- * the given attribute value, but such modifications will |
- * modify the actual value in the template. |
- */ |
-static CK_ATTRIBUTE * |
-sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute, |
- CK_ATTRIBUTE *ptemplate, CK_ULONG len) |
-{ |
- CK_ULONG i; |
- |
- for (i=0; i < len; i++) { |
- if (attribute == ptemplate[i].type) { |
- return &ptemplate[i]; |
- } |
- } |
- return NULL; |
-} |
- |
-static const CK_ATTRIBUTE * |
-sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute, |
- const CK_ATTRIBUTE *ptemplate, CK_ULONG len) |
-{ |
- CK_ULONG i; |
- |
- for (i=0; i < len; i++) { |
- if (attribute == ptemplate[i].type) { |
- return &ptemplate[i]; |
- } |
- } |
- return NULL; |
-} |
- |
- |
-/* |
- * fetch a template which identifies 'unique' entries based on object type |
- */ |
-static CK_RV |
-sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData, |
- CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount, |
- CK_ATTRIBUTE *ptemplate, int len) |
-{ |
- CK_ATTRIBUTE *attr; |
- CK_ULONG count = 1; |
- |
- sftk_ULong2SDBULong(objTypeData, objectType); |
- findTemplate[0].type = CKA_CLASS; |
- findTemplate[0].pValue = objTypeData; |
- findTemplate[0].ulValueLen = SDB_ULONG_SIZE; |
- |
- switch (objectType) { |
- case CKO_CERTIFICATE: |
- case CKO_NSS_TRUST: |
- attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len); |
- if (attr == NULL) { |
- return CKR_TEMPLATE_INCOMPLETE; |
- } |
- findTemplate[1] = *attr; |
- attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER, |
- ptemplate, len); |
- if (attr == NULL) { |
- return CKR_TEMPLATE_INCOMPLETE; |
- } |
- findTemplate[2] = *attr; |
- count = 3; |
- break; |
- |
- case CKO_PRIVATE_KEY: |
- case CKO_PUBLIC_KEY: |
- case CKO_SECRET_KEY: |
- attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len); |
- if (attr == NULL) { |
- return CKR_TEMPLATE_INCOMPLETE; |
- } |
- if (attr->ulValueLen == 0) { |
- /* key is too generic to determine that it's unique, usually |
- * happens in the key gen case */ |
- return CKR_OBJECT_HANDLE_INVALID; |
- } |
- |
- findTemplate[1] = *attr; |
- count = 2; |
- break; |
- |
- case CKO_NSS_CRL: |
- attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len); |
- if (attr == NULL) { |
- return CKR_TEMPLATE_INCOMPLETE; |
- } |
- findTemplate[1] = *attr; |
- count = 2; |
- break; |
- |
- case CKO_NSS_SMIME: |
- attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len); |
- if (attr == NULL) { |
- return CKR_TEMPLATE_INCOMPLETE; |
- } |
- findTemplate[1] = *attr; |
- attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len); |
- if (attr == NULL) { |
- return CKR_TEMPLATE_INCOMPLETE; |
- } |
- findTemplate[2] = *attr; |
- count = 3; |
- break; |
- default: |
- attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len); |
- if (attr == NULL) { |
- return CKR_TEMPLATE_INCOMPLETE; |
- } |
- findTemplate[1] = *attr; |
- count = 2; |
- break; |
- } |
- *findCount = count; |
- |
- return CKR_OK; |
-} |
- |
-/* |
- * look to see if this object already exists and return its object ID if |
- * it does. |
- */ |
-static CK_RV |
-sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType, |
- CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len) |
-{ |
- CK_ATTRIBUTE findTemplate[3]; |
- CK_ULONG count = 1; |
- CK_ULONG objCount = 0; |
- SDBFind *find = NULL; |
- unsigned char objTypeData[SDB_ULONG_SIZE]; |
- CK_RV crv; |
- |
- *id = CK_INVALID_HANDLE; |
- if (objectType == CKO_NSS_CRL) { |
- return CKR_OK; |
- } |
- crv = sftkdb_getFindTemplate(objectType, objTypeData, |
- findTemplate, &count, ptemplate, len); |
- |
- if (crv == CKR_OBJECT_HANDLE_INVALID) { |
- /* key is too generic to determine that it's unique, usually |
- * happens in the key gen case, tell the caller to go ahead |
- * and just create it */ |
- return CKR_OK; |
- } |
- if (crv != CKR_OK) { |
- return crv; |
- } |
- |
- /* use the raw find, so we get the correct database */ |
- crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find); |
- if (crv != CKR_OK) { |
- return crv; |
- } |
- (*db->sdb_FindObjects)(db, find, id, 1, &objCount); |
- (*db->sdb_FindObjectsFinal)(db, find); |
- |
- if (objCount == 0) { |
- *id = CK_INVALID_HANDLE; |
- } |
- return CKR_OK; |
-} |
- |
- |
-/* |
- * check to see if this template conflicts with others in our current database. |
- */ |
-static CK_RV |
-sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType, |
- const CK_ATTRIBUTE *ptemplate, CK_ULONG len, |
- CK_OBJECT_HANDLE sourceID) |
-{ |
- CK_ATTRIBUTE findTemplate[2]; |
- unsigned char objTypeData[SDB_ULONG_SIZE]; |
- /* we may need to allocate some temporaries. Keep track of what was |
- * allocated so we can free it in the end */ |
- unsigned char *temp1 = NULL; |
- unsigned char *temp2 = NULL; |
- CK_ULONG objCount = 0; |
- SDBFind *find = NULL; |
- CK_OBJECT_HANDLE id; |
- const CK_ATTRIBUTE *attr, *attr2; |
- CK_RV crv; |
- CK_ATTRIBUTE subject; |
- |
- /* Currently the only conflict is with nicknames pointing to the same |
- * subject when creating or modifying a certificate. */ |
- /* If the object is not a cert, no problem. */ |
- if (objectType != CKO_CERTIFICATE) { |
- return CKR_OK; |
- } |
- /* if not setting a nickname then there's still no problem */ |
- attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len); |
- if ((attr == NULL) || (attr->ulValueLen == 0)) { |
- return CKR_OK; |
- } |
- /* fetch the subject of the source. For creation and merge, this should |
- * be found in the template */ |
- attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len); |
- if (sourceID == CK_INVALID_HANDLE) { |
- if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) { |
- crv = CKR_TEMPLATE_INCOMPLETE; |
- goto done; |
- } |
- } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) { |
- /* sourceID is set if we are trying to modify an existing entry instead |
- * of creating a new one. In this case the subject may not be (probably |
- * isn't) in the template, we have to read it from the database */ |
- subject.type = CKA_SUBJECT; |
- subject.pValue = NULL; |
- subject.ulValueLen = 0; |
- crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); |
- if (crv != CKR_OK) { |
- goto done; |
- } |
- if ((CK_LONG)subject.ulValueLen < 0) { |
- crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */ |
- goto done; |
- } |
- temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen); |
- if (temp1 == NULL) { |
- crv = CKR_HOST_MEMORY; |
- goto done; |
- } |
- crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); |
- if (crv != CKR_OK) { |
- goto done; |
- } |
- attr2 = &subject; |
- } |
- |
- /* check for another cert in the database with the same nickname */ |
- sftk_ULong2SDBULong(objTypeData, objectType); |
- findTemplate[0].type = CKA_CLASS; |
- findTemplate[0].pValue = objTypeData; |
- findTemplate[0].ulValueLen = SDB_ULONG_SIZE; |
- findTemplate[1] = *attr; |
- |
- crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find); |
- if (crv != CKR_OK) { |
- goto done; |
- } |
- (*db->sdb_FindObjects)(db, find, &id, 1, &objCount); |
- (*db->sdb_FindObjectsFinal)(db, find); |
- |
- /* object count == 0 means no conflicting certs found, |
- * go on with the operation */ |
- if (objCount == 0) { |
- crv = CKR_OK; |
- goto done; |
- } |
- |
- /* There is a least one cert that shares the nickname, make sure it also |
- * matches the subject. */ |
- findTemplate[0] = *attr2; |
- /* we know how big the source subject was. Use that length to create the |
- * space for the target. If it's not enough space, then it means the |
- * source subject is too big, and therefore not a match. GetAttributeValue |
- * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough |
- * space (or enough space to be able to compare the result. */ |
- temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen); |
- if (temp2 == NULL) { |
- crv = CKR_HOST_MEMORY; |
- goto done; |
- } |
- crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1); |
- if (crv != CKR_OK) { |
- if (crv == CKR_BUFFER_TOO_SMALL) { |
- /* if our buffer is too small, then the Subjects clearly do |
- * not match */ |
- crv = CKR_ATTRIBUTE_VALUE_INVALID; |
- goto loser; |
- } |
- /* otherwise we couldn't get the value, just fail */ |
- goto done; |
- } |
- |
- /* Ok, we have both subjects, make sure they are the same. |
- * Compare the subjects */ |
- if ((findTemplate[0].ulValueLen != attr2->ulValueLen) || |
- (attr2->ulValueLen > 0 && |
- PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) |
- != 0)) { |
- crv = CKR_ATTRIBUTE_VALUE_INVALID; |
- goto loser; |
- } |
- crv = CKR_OK; |
- |
-done: |
- /* If we've failed for some other reason than a conflict, make sure we |
- * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID. |
- * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should |
- * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia). |
- */ |
- if (crv == CKR_ATTRIBUTE_VALUE_INVALID) { |
- crv = CKR_GENERAL_ERROR; /* clearly a programming error */ |
- } |
- |
- /* exit point if we found a conflict */ |
-loser: |
- PORT_Free(temp1); |
- PORT_Free(temp2); |
- return crv; |
-} |
- |
-/* |
- * try to update the template to fix any errors. This is only done |
- * during update. |
- * |
- * NOTE: we must update the template or return an error, or the update caller |
- * will loop forever! |
- * |
- * Two copies of the source code for this algorithm exist in NSS. |
- * Changes must be made in both copies. |
- * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c. |
- * |
- */ |
-static CK_RV |
-sftkdb_resolveConflicts(PRArenaPool *arena, CK_OBJECT_CLASS objectType, |
- CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) |
-{ |
- CK_ATTRIBUTE *attr; |
- char *nickname, *newNickname; |
- int end, digit; |
- |
- /* sanity checks. We should never get here with these errors */ |
- if (objectType != CKO_CERTIFICATE) { |
- return CKR_GENERAL_ERROR; /* shouldn't happen */ |
- } |
- attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); |
- if ((attr == NULL) || (attr->ulValueLen == 0)) { |
- return CKR_GENERAL_ERROR; /* shouldn't happen */ |
- } |
- |
- /* update the nickname */ |
- /* is there a number at the end of the nickname already? |
- * if so just increment that number */ |
- nickname = (char *)attr->pValue; |
- |
- /* does nickname end with " #n*" ? */ |
- for (end = attr->ulValueLen - 1; |
- end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0'; |
- end--) /* just scan */ ; |
- if (attr->ulValueLen >= 3 && |
- end < (attr->ulValueLen - 1) /* at least one digit */ && |
- nickname[end] == '#' && |
- nickname[end - 1] == ' ') { |
- /* Already has a suitable suffix string */ |
- } else { |
- /* ... append " #2" to the name */ |
- static const char num2[] = " #2"; |
- newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2)); |
- if (!newNickname) { |
- return CKR_HOST_MEMORY; |
- } |
- PORT_Memcpy(newNickname, nickname, attr->ulValueLen); |
- PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2)); |
- attr->pValue = newNickname; /* modifies ptemplate */ |
- attr->ulValueLen += 3; /* 3 is strlen(num2) */ |
- return CKR_OK; |
- } |
- |
- for (end = attr->ulValueLen - 1; |
- end >= 0 && (digit = nickname[end]) <= '9' && digit >= '0'; |
- end--) { |
- if (digit < '9') { |
- nickname[end]++; |
- return CKR_OK; |
- } |
- nickname[end] = '0'; |
- } |
- |
- /* we overflowed, insert a new '1' for a carry in front of the number */ |
- newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1); |
- if (!newNickname) { |
- return CKR_HOST_MEMORY; |
- } |
- /* PORT_Memcpy should handle len of '0' */ |
- PORT_Memcpy(newNickname, nickname, ++end); |
- newNickname[end] = '1'; |
- PORT_Memset(&newNickname[end+1],'0',attr->ulValueLen - end); |
- attr->pValue = newNickname; |
- attr->ulValueLen++; |
- return CKR_OK; |
-} |
- |
-/* |
- * set an attribute and sign it if necessary |
- */ |
-static CK_RV |
-sftkdb_setAttributeValue(PRArenaPool *arena, SFTKDBHandle *handle, |
- SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, |
- CK_ULONG count) |
-{ |
- CK_RV crv; |
- crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count); |
- if (crv != CKR_OK) { |
- return crv; |
- } |
- crv = sftk_signTemplate(arena, handle, db == handle->update, |
- objectID, template, count); |
- return crv; |
-} |
- |
-/* |
- * write a softoken object out to the database. |
- */ |
-CK_RV |
-sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, |
- CK_OBJECT_HANDLE *objectID) |
-{ |
- CK_ATTRIBUTE *template; |
- PLArenaPool *arena; |
- CK_ULONG count; |
- CK_RV crv; |
- SDB *db; |
- PRBool inTransaction = PR_FALSE; |
- CK_OBJECT_HANDLE id; |
- |
- *objectID = CK_INVALID_HANDLE; |
- |
- if (handle == NULL) { |
- return CKR_TOKEN_WRITE_PROTECTED; |
- } |
- db = SFTK_GET_SDB(handle); |
- |
- /* |
- * we have opened a new database, but we have not yet updated it. We are |
- * still running pointing to the old database (so the application can |
- * still read). We don't want to write to the old database at this point, |
- * however, since it leads to user confusion. So at this point we simply |
- * require a user login. Let NSS know this so it can prompt the user. |
- */ |
- if (db == handle->update) { |
- return CKR_USER_NOT_LOGGED_IN; |
- } |
- |
- arena = PORT_NewArena(256); |
- if (arena == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- template = sftk_ExtractTemplate(arena, object, handle, &count, &crv); |
- if (!template) { |
- goto loser; |
- } |
- |
- crv = (*db->sdb_Begin)(db); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- inTransaction = PR_TRUE; |
- |
- /* |
- * We want to make the base database as free from object specific knowledge |
- * as possible. To maintain compatibility, keep some of the desirable |
- * object specific semantics of the old database. |
- * |
- * These were 2 fold: |
- * 1) there were certain conflicts (like trying to set the same nickname |
- * on two different subjects) that would return an error. |
- * 2) Importing the 'same' object would silently update that object. |
- * |
- * The following 2 functions mimic the desirable effects of these two |
- * semantics without pushing any object knowledge to the underlying database |
- * code. |
- */ |
- |
- /* make sure we don't have attributes that conflict with the existing DB */ |
- crv = sftkdb_checkConflicts(db, object->objclass, template, count, |
- CK_INVALID_HANDLE); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- /* Find any copies that match this particular object */ |
- crv = sftkdb_lookupObject(db, object->objclass, &id, template, count); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- if (id == CK_INVALID_HANDLE) { |
- crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count); |
- } else { |
- /* object already exists, modify it's attributes */ |
- *objectID = id; |
- crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count); |
- } |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- |
- crv = (*db->sdb_Commit)(db); |
- inTransaction = PR_FALSE; |
- |
-loser: |
- if (inTransaction) { |
- (*db->sdb_Abort)(db); |
- /* It is trivial to show the following code cannot |
- * happen unless something is horribly wrong with our compilier or |
- * hardware */ |
- PORT_Assert(crv != CKR_OK); |
- if (crv == CKR_OK) crv = CKR_GENERAL_ERROR; |
- } |
- |
- if (arena) { |
- PORT_FreeArena(arena,PR_FALSE); |
- } |
- if (crv == CKR_OK) { |
- *objectID |= (handle->type | SFTK_TOKEN_TYPE); |
- } |
- return crv; |
-} |
- |
- |
-CK_RV |
-sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template, |
- CK_ULONG count, SDBFind **find) |
-{ |
- unsigned char *data = NULL; |
- CK_ATTRIBUTE *ntemplate = NULL; |
- CK_RV crv; |
- SDB *db; |
- |
- if (handle == NULL) { |
- return CKR_OK; |
- } |
- db = SFTK_GET_SDB(handle); |
- |
- if (count != 0) { |
- ntemplate = sftkdb_fixupTemplateIn(template, count, &data); |
- if (ntemplate == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- } |
- |
- crv = (*db->sdb_FindObjectsInit)(db, ntemplate, |
- count, find); |
- if (data) { |
- PORT_Free(ntemplate); |
- PORT_Free(data); |
- } |
- return crv; |
-} |
- |
-CK_RV |
-sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, |
- CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count) |
-{ |
- CK_RV crv; |
- SDB *db; |
- |
- if (handle == NULL) { |
- *count = 0; |
- return CKR_OK; |
- } |
- db = SFTK_GET_SDB(handle); |
- |
- crv = (*db->sdb_FindObjects)(db, find, ids, |
- arraySize, count); |
- if (crv == CKR_OK) { |
- int i; |
- for (i=0; i < *count; i++) { |
- ids[i] |= (handle->type | SFTK_TOKEN_TYPE); |
- } |
- } |
- return crv; |
-} |
- |
-CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find) |
-{ |
- SDB *db; |
- if (handle == NULL) { |
- return CKR_OK; |
- } |
- db = SFTK_GET_SDB(handle); |
- return (*db->sdb_FindObjectsFinal)(db, find); |
-} |
- |
-CK_RV |
-sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID, |
- CK_ATTRIBUTE *template, CK_ULONG count) |
-{ |
- CK_RV crv,crv2; |
- CK_ATTRIBUTE *ntemplate; |
- unsigned char *data = NULL; |
- SDB *db; |
- |
- if (handle == NULL) { |
- return CKR_GENERAL_ERROR; |
- } |
- |
- /* short circuit common attributes */ |
- if (count == 1 && |
- (template[0].type == CKA_TOKEN || |
- template[0].type == CKA_PRIVATE || |
- template[0].type == CKA_SENSITIVE)) { |
- CK_BBOOL boolVal = CK_TRUE; |
- |
- if (template[0].pValue == NULL) { |
- template[0].ulValueLen = sizeof(CK_BBOOL); |
- return CKR_OK; |
- } |
- if (template[0].ulValueLen < sizeof(CK_BBOOL)) { |
- template[0].ulValueLen = -1; |
- return CKR_BUFFER_TOO_SMALL; |
- } |
- |
- if ((template[0].type == CKA_PRIVATE) && |
- (handle->type != SFTK_KEYDB_TYPE)) { |
- boolVal = CK_FALSE; |
- } |
- if ((template[0].type == CKA_SENSITIVE) && |
- (handle->type != SFTK_KEYDB_TYPE)) { |
- boolVal = CK_FALSE; |
- } |
- *(CK_BBOOL *)template[0].pValue = boolVal; |
- template[0].ulValueLen = sizeof(CK_BBOOL); |
- return CKR_OK; |
- } |
- |
- db = SFTK_GET_SDB(handle); |
- /* nothing to do */ |
- if (count == 0) { |
- return CKR_OK; |
- } |
- ntemplate = sftkdb_fixupTemplateIn(template, count, &data); |
- if (ntemplate == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- objectID &= SFTK_OBJ_ID_MASK; |
- crv = (*db->sdb_GetAttributeValue)(db, objectID, |
- ntemplate, count); |
- crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate, |
- count, handle); |
- if (crv == CKR_OK) crv = crv2; |
- if (data) { |
- PORT_Free(ntemplate); |
- PORT_Free(data); |
- } |
- return crv; |
- |
-} |
- |
-CK_RV |
-sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object, |
- const CK_ATTRIBUTE *template, CK_ULONG count) |
-{ |
- CK_ATTRIBUTE *ntemplate; |
- unsigned char *data = NULL; |
- PLArenaPool *arena = NULL; |
- SDB *db; |
- CK_RV crv = CKR_OK; |
- CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK); |
- PRBool inTransaction = PR_FALSE; |
- |
- if (handle == NULL) { |
- return CKR_TOKEN_WRITE_PROTECTED; |
- } |
- |
- db = SFTK_GET_SDB(handle); |
- /* nothing to do */ |
- if (count == 0) { |
- return CKR_OK; |
- } |
- /* |
- * we have opened a new database, but we have not yet updated it. We are |
- * still running pointing to the old database (so the application can |
- * still read). We don't want to write to the old database at this point, |
- * however, since it leads to user confusion. So at this point we simply |
- * require a user login. Let NSS know this so it can prompt the user. |
- */ |
- if (db == handle->update) { |
- return CKR_USER_NOT_LOGGED_IN; |
- } |
- |
- ntemplate = sftkdb_fixupTemplateIn(template, count, &data); |
- if (ntemplate == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- /* make sure we don't have attributes that conflict with the existing DB */ |
- crv = sftkdb_checkConflicts(db, object->objclass, template, count, objectID); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- |
- arena = PORT_NewArena(256); |
- if (arena == NULL) { |
- crv = CKR_HOST_MEMORY; |
- goto loser; |
- } |
- |
- crv = (*db->sdb_Begin)(db); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- inTransaction = PR_TRUE; |
- crv = sftkdb_setAttributeValue(arena, handle, db, |
- objectID, template, count); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- crv = (*db->sdb_Commit)(db); |
-loser: |
- if (crv != CKR_OK && inTransaction) { |
- (*db->sdb_Abort)(db); |
- } |
- if (data) { |
- PORT_Free(ntemplate); |
- PORT_Free(data); |
- } |
- if (arena) { |
- PORT_FreeArena(arena, PR_FALSE); |
- } |
- return crv; |
-} |
- |
-CK_RV |
-sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID) |
-{ |
- CK_RV crv = CKR_OK; |
- SDB *db; |
- |
- if (handle == NULL) { |
- return CKR_TOKEN_WRITE_PROTECTED; |
- } |
- db = SFTK_GET_SDB(handle); |
- objectID &= SFTK_OBJ_ID_MASK; |
- crv = (*db->sdb_Begin)(db); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- crv = (*db->sdb_DestroyObject)(db, objectID); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- crv = (*db->sdb_Commit)(db); |
-loser: |
- if (crv != CKR_OK) { |
- (*db->sdb_Abort)(db); |
- } |
- return crv; |
-} |
- |
-CK_RV |
-sftkdb_CloseDB(SFTKDBHandle *handle) |
-{ |
-#ifdef NO_FORK_CHECK |
- PRBool parentForkedAfterC_Initialize = PR_FALSE; |
-#endif |
- if (handle == NULL) { |
- return CKR_OK; |
- } |
- if (handle->update) { |
- if (handle->db->sdb_SetForkState) { |
- (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize); |
- } |
- (*handle->update->sdb_Close)(handle->update); |
- } |
- if (handle->db) { |
- if (handle->db->sdb_SetForkState) { |
- (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize); |
- } |
- (*handle->db->sdb_Close)(handle->db); |
- } |
- if (handle->passwordKey.data) { |
- PORT_ZFree(handle->passwordKey.data, handle->passwordKey.len); |
- } |
- if (handle->passwordLock) { |
- SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock)); |
- } |
- if (handle->updatePasswordKey) { |
- SECITEM_FreeItem(handle->updatePasswordKey, PR_TRUE); |
- } |
- if (handle->updateID) { |
- PORT_Free(handle->updateID); |
- } |
- PORT_Free(handle); |
- return CKR_OK; |
-} |
- |
-/* |
- * reset a database to it's uninitialized state. |
- */ |
-static CK_RV |
-sftkdb_ResetDB(SFTKDBHandle *handle) |
-{ |
- CK_RV crv = CKR_OK; |
- SDB *db; |
- if (handle == NULL) { |
- return CKR_TOKEN_WRITE_PROTECTED; |
- } |
- db = SFTK_GET_SDB(handle); |
- crv = (*db->sdb_Begin)(db); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- crv = (*db->sdb_Reset)(db); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- crv = (*db->sdb_Commit)(db); |
-loser: |
- if (crv != CKR_OK) { |
- (*db->sdb_Abort)(db); |
- } |
- return crv; |
-} |
- |
- |
-CK_RV |
-sftkdb_Begin(SFTKDBHandle *handle) |
-{ |
- CK_RV crv = CKR_OK; |
- SDB *db; |
- |
- if (handle == NULL) { |
- return CKR_OK; |
- } |
- db = SFTK_GET_SDB(handle); |
- if (db) { |
- crv = (*db->sdb_Begin)(db); |
- } |
- return crv; |
-} |
- |
-CK_RV |
-sftkdb_Commit(SFTKDBHandle *handle) |
-{ |
- CK_RV crv = CKR_OK; |
- SDB *db; |
- |
- if (handle == NULL) { |
- return CKR_OK; |
- } |
- db = SFTK_GET_SDB(handle); |
- if (db) { |
- (*db->sdb_Commit)(db); |
- } |
- return crv; |
-} |
- |
-CK_RV |
-sftkdb_Abort(SFTKDBHandle *handle) |
-{ |
- CK_RV crv = CKR_OK; |
- SDB *db; |
- |
- if (handle == NULL) { |
- return CKR_OK; |
- } |
- db = SFTK_GET_SDB(handle); |
- if (db) { |
- crv = (db->sdb_Abort)(db); |
- } |
- return crv; |
-} |
- |
- |
-/* |
- * functions to update the database from an old database |
- */ |
- |
-/* |
- * known attributes |
- */ |
-static const CK_ATTRIBUTE_TYPE known_attributes[] = { |
- CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, |
- CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, |
- CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, |
- CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, |
- CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, |
- CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, |
- CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, |
- CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, |
- CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, |
- CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, |
- CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, |
- CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, |
- CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, |
- CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, |
- CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, |
- CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, |
- CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, |
- CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, |
- CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, |
- CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, |
- CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, |
- CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL, |
- CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP, |
- CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES, |
- CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED, |
- CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC, |
- CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, |
- CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, |
- CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, |
- CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, |
- CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, |
- CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, |
- CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, |
- CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS |
-}; |
- |
-static int known_attributes_size= sizeof(known_attributes)/ |
- sizeof(known_attributes[0]); |
- |
-static CK_RV |
-sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id, |
- CK_ATTRIBUTE *ptemplate, CK_ULONG *max) |
-{ |
- int i,j; |
- CK_RV crv; |
- |
- if (*max < known_attributes_size) { |
- *max = known_attributes_size; |
- return CKR_BUFFER_TOO_SMALL; |
- } |
- for (i=0; i < known_attributes_size; i++) { |
- ptemplate[i].type = known_attributes[i]; |
- ptemplate[i].pValue = NULL; |
- ptemplate[i].ulValueLen = 0; |
- } |
- |
- crv = (*source->sdb_GetAttributeValue)(source, id, |
- ptemplate, known_attributes_size); |
- |
- if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { |
- return crv; |
- } |
- |
- for (i=0, j=0; i < known_attributes_size; i++, j++) { |
- while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) { |
- i++; |
- } |
- if (i >= known_attributes_size) { |
- break; |
- } |
- /* cheap optimization */ |
- if (i == j) { |
- continue; |
- } |
- ptemplate[j] = ptemplate[i]; |
- } |
- *max = j; |
- return CKR_OK; |
-} |
- |
-static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s"; |
- |
-/* |
- * check to see if we have already updated this database. |
- * a NULL updateID means we are trying to do an in place |
- * single database update. In that case we have already |
- * determined that an update was necessary. |
- */ |
-static PRBool |
-sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID) |
-{ |
- char *id; |
- CK_RV crv; |
- SECItem dummy = { 0, NULL, 0 }; |
- unsigned char dummyData[SDB_MAX_META_DATA_LEN]; |
- |
- if (!updateID) { |
- return PR_FALSE; |
- } |
- id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID); |
- if (id == NULL) { |
- return PR_FALSE; |
- } |
- dummy.data = dummyData; |
- dummy.len = sizeof(dummyData); |
- |
- crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL); |
- PR_smprintf_free(id); |
- return crv == CKR_OK ? PR_TRUE : PR_FALSE; |
-} |
- |
-/* |
- * we just completed an update, store the update id |
- * so we don't need to do it again. If non was given, |
- * there is nothing to do. |
- */ |
-static CK_RV |
-sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID) |
-{ |
- char *id; |
- CK_RV crv; |
- SECItem dummy = { 0, NULL, 0 }; |
- |
- /* if no id was given, nothing to do */ |
- if (updateID == NULL) { |
- return CKR_OK; |
- } |
- |
- dummy.data = (unsigned char *)updateID; |
- dummy.len = PORT_Strlen(updateID); |
- |
- id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID); |
- if (id == NULL) { |
- return PR_FALSE; |
- } |
- |
- crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL); |
- PR_smprintf_free(id); |
- return crv; |
-} |
- |
-/* |
- * get a ULong attribute from a template: |
- * NOTE: this is a raw templated stored in database order! |
- */ |
-static CK_ULONG |
-sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type, |
- CK_ATTRIBUTE *ptemplate, CK_ULONG len) |
-{ |
- CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type, |
- ptemplate, len); |
- |
- if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) { |
- return sftk_SDBULong2ULong(attr->pValue); |
- } |
- return (CK_ULONG)-1; |
-} |
- |
-/* |
- * we need to find a unique CKA_ID. |
- * The basic idea is to just increment the lowest byte. |
- * This code also handles the following corner cases: |
- * 1) the single byte overflows. On overflow we increment the next byte up |
- * and so forth until we have overflowed the entire CKA_ID. |
- * 2) If we overflow the entire CKA_ID we expand it by one byte. |
- * 3) the CKA_ID is non-existant, we create a new one with one byte. |
- * This means no matter what CKA_ID is passed, the result of this function |
- * is always a new CKA_ID, and this function will never return the same |
- * CKA_ID the it has returned in the passed. |
- */ |
-static CK_RV |
-sftkdb_incrementCKAID(PRArenaPool *arena, CK_ATTRIBUTE *ptemplate) |
-{ |
- unsigned char *buf = ptemplate->pValue; |
- CK_ULONG len = ptemplate->ulValueLen; |
- |
- if (buf == NULL || len == (CK_ULONG)-1) { |
- /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */ |
- len = 0; |
- } else { |
- CK_ULONG i; |
- |
- /* walk from the back to front, incrementing |
- * the CKA_ID until we no longer have a carry, |
- * or have hit the front of the id. */ |
- for (i=len; i != 0; i--) { |
- buf[i-1]++; |
- if (buf[i-1] != 0) { |
- /* no more carries, the increment is complete */ |
- return CKR_OK; |
- } |
- } |
- /* we've now overflowed, fall through and expand the CKA_ID by |
- * one byte */ |
- } |
- buf = PORT_ArenaAlloc(arena, len+1); |
- if (!buf) { |
- return CKR_HOST_MEMORY; |
- } |
- if (len > 0) { |
- PORT_Memcpy(buf, ptemplate->pValue, len); |
- } |
- buf[len] = 0; |
- ptemplate->pValue = buf; |
- ptemplate->ulValueLen = len+1; |
- return CKR_OK; |
-} |
- |
-/* |
- * drop an attribute from a template. |
- */ |
-void |
-sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate, |
- CK_ULONG *plen) |
-{ |
- CK_ULONG count = *plen; |
- CK_ULONG i; |
- |
- for (i=0; i < count; i++) { |
- if (attr->type == ptemplate[i].type) { |
- break; |
- } |
- } |
- |
- if (i == count) { |
- /* attribute not found */ |
- return; |
- } |
- |
- /* copy the remaining attributes up */ |
- for ( i++; i < count; i++) { |
- ptemplate[i-1] = ptemplate[i]; |
- } |
- |
- /* decrement the template size */ |
- *plen = count -1; |
-} |
- |
-/* |
- * create some defines for the following functions to document the meaning |
- * of true/false. (make's it easier to remember what means what. |
- */ |
-typedef enum { |
- SFTKDB_DO_NOTHING = 0, |
- SFTKDB_ADD_OBJECT, |
- SFTKDB_MODIFY_OBJECT, |
- SFTKDB_DROP_ATTRIBUTE |
-} sftkdbUpdateStatus; |
- |
-/* |
- * helper function to reconcile a single trust entry. |
- * Identify which trust entry we want to keep. |
- * If we don't need to do anything (the records are already equal). |
- * return SFTKDB_DO_NOTHING. |
- * If we want to use the source version, |
- * return SFTKDB_MODIFY_OBJECT |
- * If we want to use the target version, |
- * return SFTKDB_DROP_ATTRIBUTE |
- * |
- * In the end the caller will remove any attributes in the source |
- * template when SFTKDB_DROP_ATTRIBUTE is specified, then use do a |
- * set attributes with that template on the target if we received |
- * any SFTKDB_MODIFY_OBJECT returns. |
- */ |
-sftkdbUpdateStatus |
-sftkdb_reconcileTrustEntry(PRArenaPool *arena, CK_ATTRIBUTE *target, |
- CK_ATTRIBUTE *source) |
-{ |
- CK_ULONG targetTrust = sftkdb_getULongFromTemplate(target->type, |
- target, 1); |
- CK_ULONG sourceTrust = sftkdb_getULongFromTemplate(target->type, |
- source, 1); |
- |
- /* |
- * try to pick the best solution between the source and the |
- * target. Update the source template if we want the target value |
- * to win out. Prefer cases where we don't actually update the |
- * trust entry. |
- */ |
- |
- /* they are the same, everything is already kosher */ |
- if (targetTrust == sourceTrust) { |
- return SFTKDB_DO_NOTHING; |
- } |
- |
- /* handle the case where the source Trust attribute may be a bit |
- * flakey */ |
- if (sourceTrust == (CK_ULONG)-1) { |
- /* |
- * The source Trust is invalid. We know that the target Trust |
- * must be valid here, otherwise the above |
- * targetTrust == sourceTrust check would have succeeded. |
- */ |
- return SFTKDB_DROP_ATTRIBUTE; |
- } |
- |
- /* target is invalid, use the source's idea of the trust value */ |
- if (targetTrust == (CK_ULONG)-1) { |
- /* overwriting the target in this case is OK */ |
- return SFTKDB_MODIFY_OBJECT; |
- } |
- |
- /* at this point we know that both attributes exist and have the |
- * appropriate length (SDB_ULONG_SIZE). We no longer need to check |
- * ulValueLen for either attribute. |
- */ |
- if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) { |
- return SFTKDB_DROP_ATTRIBUTE; |
- } |
- |
- /* target has no idea, use the source's idea of the trust value */ |
- if (targetTrust == CKT_NSS_TRUST_UNKNOWN) { |
- /* overwriting the target in this case is OK */ |
- return SFTKDB_MODIFY_OBJECT; |
- } |
- |
- /* so both the target and the source have some idea of what this |
- * trust attribute should be, and neither agree exactly. |
- * At this point, we prefer 'hard' attributes over 'soft' ones. |
- * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and |
- * CKT_NSS_NOT_TRUTED. Soft ones are ones which don't change the |
- * actual trust of the cert (CKT_MUST_VERIFY_TRUST, |
- * CKT_NSS_VALID_DELEGATOR). |
- */ |
- if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) |
- || (sourceTrust == CKT_NSS_VALID_DELEGATOR)) { |
- return SFTKDB_DROP_ATTRIBUTE; |
- } |
- if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST) |
- || (targetTrust == CKT_NSS_VALID_DELEGATOR)) { |
- /* again, overwriting the target in this case is OK */ |
- return SFTKDB_MODIFY_OBJECT; |
- } |
- |
- /* both have hard attributes, we have a conflict, let the target win. */ |
- return SFTKDB_DROP_ATTRIBUTE; |
-} |
- |
-const CK_ATTRIBUTE_TYPE sftkdb_trustList[] = |
- { CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, |
- CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, |
- CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, |
- CKA_TRUST_TIME_STAMPING }; |
- |
-#define SFTK_TRUST_TEMPLATE_COUNT \ |
- (sizeof(sftkdb_trustList)/sizeof(sftkdb_trustList[0])) |
-/* |
- * Run through the list of known trust types, and reconcile each trust |
- * entry one by one. Keep track of we really need to write out the source |
- * trust object (overwriting the existing one). |
- */ |
-static sftkdbUpdateStatus |
-sftkdb_reconcileTrust(PRArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, |
- CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) |
-{ |
- CK_ATTRIBUTE trustTemplate[SFTK_TRUST_TEMPLATE_COUNT]; |
- unsigned char trustData[SFTK_TRUST_TEMPLATE_COUNT*SDB_ULONG_SIZE]; |
- sftkdbUpdateStatus update = SFTKDB_DO_NOTHING; |
- CK_ULONG i; |
- CK_RV crv; |
- |
- |
- for (i=0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) { |
- trustTemplate[i].type = sftkdb_trustList[i]; |
- trustTemplate[i].pValue = &trustData[i*SDB_ULONG_SIZE]; |
- trustTemplate[i].ulValueLen = SDB_ULONG_SIZE; |
- } |
- crv = (*db->sdb_GetAttributeValue)(db, id, |
- trustTemplate, SFTK_TRUST_TEMPLATE_COUNT); |
- if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { |
- /* target trust has some problems, update it */ |
- update = SFTKDB_MODIFY_OBJECT; |
- goto done; |
- } |
- |
- for (i=0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) { |
- CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate( |
- trustTemplate[i].type, ptemplate, *plen); |
- sftkdbUpdateStatus status; |
- |
- |
- /* if target trust value doesn't exist, nothing to merge */ |
- if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) { |
- /* if the source exists, then we want the source entry, |
- * go ahead and update */ |
- if (attr && attr->ulValueLen != (CK_ULONG)-1) { |
- update = SFTKDB_MODIFY_OBJECT; |
- } |
- continue; |
- } |
- |
- /* |
- * the source doesn't have the attribute, go to the next attribute |
- */ |
- if (attr == NULL) { |
- continue; |
- |
- } |
- status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr); |
- if (status == SFTKDB_MODIFY_OBJECT) { |
- update = SFTKDB_MODIFY_OBJECT; |
- } else if (status == SFTKDB_DROP_ATTRIBUTE) { |
- /* drop the source copy of the attribute, we are going with |
- * the target's version */ |
- sftkdb_dropAttribute(attr, ptemplate, plen); |
- } |
- } |
- |
- /* finally manage stepup */ |
- if (update == SFTKDB_MODIFY_OBJECT) { |
- CK_BBOOL stepUpBool = CK_FALSE; |
- /* if we are going to write from the source, make sure we don't |
- * overwrite the stepup bit if it's on*/ |
- trustTemplate[0].type = CKA_TRUST_STEP_UP_APPROVED; |
- trustTemplate[0].pValue = &stepUpBool; |
- trustTemplate[0].ulValueLen = sizeof(stepUpBool); |
- crv = (*db->sdb_GetAttributeValue)(db, id, trustTemplate, 1); |
- if ((crv == CKR_OK) && (stepUpBool == CK_TRUE)) { |
- sftkdb_dropAttribute(trustTemplate, ptemplate, plen); |
- } |
- } else { |
- /* we currently aren't going to update. If the source stepup bit is |
- * on however, do an update so the target gets it as well */ |
- CK_ATTRIBUTE *attr; |
- |
- attr = sftkdb_getAttributeFromTemplate(CKA_TRUST_STEP_UP_APPROVED, |
- ptemplate, *plen); |
- if (attr && (attr->ulValueLen == sizeof(CK_BBOOL)) && |
- (*(CK_BBOOL *)(attr->pValue) == CK_TRUE)) { |
- update = SFTKDB_MODIFY_OBJECT; |
- } |
- } |
- |
-done: |
- return update; |
-} |
- |
-static sftkdbUpdateStatus |
-sftkdb_handleIDAndName(PRArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, |
- CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) |
-{ |
- sftkdbUpdateStatus update = SFTKDB_DO_NOTHING; |
- CK_ATTRIBUTE *attr1, *attr2; |
- CK_ATTRIBUTE ttemplate[2] = { |
- {CKA_ID, NULL, 0}, |
- {CKA_LABEL, NULL, 0} |
- }; |
- CK_RV crv; |
- |
- attr1 = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); |
- attr2 = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen); |
- |
- /* if the source has neither an id nor label, don't bother updating */ |
- if ( (!attr1 || attr1->ulValueLen == 0) && |
- (! attr2 || attr2->ulValueLen == 0) ) { |
- return SFTKDB_DO_NOTHING; |
- } |
- |
- /* the source has either an id or a label, see what the target has */ |
- crv = (*db->sdb_GetAttributeValue)(db, id, ttemplate, 2); |
- |
- /* if the target has neither, update from the source */ |
- if ( ((ttemplate[0].ulValueLen == 0) || |
- (ttemplate[0].ulValueLen == (CK_ULONG)-1)) && |
- ((ttemplate[1].ulValueLen == 0) || |
- (ttemplate[1].ulValueLen == (CK_ULONG)-1)) ) { |
- return SFTKDB_MODIFY_OBJECT; |
- } |
- |
- /* check the CKA_ID */ |
- if ((ttemplate[0].ulValueLen != 0) && |
- (ttemplate[0].ulValueLen != (CK_ULONG)-1)) { |
- /* we have a CKA_ID in the target, don't overwrite |
- * the target with an empty CKA_ID from the source*/ |
- if (attr1 && attr1->ulValueLen == 0) { |
- sftkdb_dropAttribute(attr1, ptemplate, plen); |
- } |
- } else if (attr1 && attr1->ulValueLen != 0) { |
- /* source has a CKA_ID, but the target doesn't, update the target */ |
- update = SFTKDB_MODIFY_OBJECT; |
- } |
- |
- |
- /* check the nickname */ |
- if ((ttemplate[1].ulValueLen != 0) && |
- (ttemplate[1].ulValueLen != (CK_ULONG)-1)) { |
- |
- /* we have a nickname in the target, and we don't have to update |
- * the CKA_ID. We are done. NOTE: if we add addition attributes |
- * in this check, this shortcut can only go on the last of them. */ |
- if (update == SFTKDB_DO_NOTHING) { |
- return update; |
- } |
- /* we have a nickname in the target, don't overwrite |
- * the target with an empty nickname from the source */ |
- if (attr2 && attr2->ulValueLen == 0) { |
- sftkdb_dropAttribute(attr2, ptemplate, plen); |
- } |
- } else if (attr2 && attr2->ulValueLen != 0) { |
- /* source has a nickname, but the target doesn't, update the target */ |
- update = SFTKDB_MODIFY_OBJECT; |
- } |
- |
- return update; |
-} |
- |
- |
- |
-/* |
- * This function updates the template before we write the object out. |
- * |
- * If we are going to skip updating this object, return PR_FALSE. |
- * If it should be updated we return PR_TRUE. |
- * To help readability, these have been defined |
- * as SFTK_DONT_UPDATE and SFTK_UPDATE respectively. |
- */ |
-static PRBool |
-sftkdb_updateObjectTemplate(PRArenaPool *arena, SDB *db, |
- CK_OBJECT_CLASS objectType, |
- CK_ATTRIBUTE *ptemplate, CK_ULONG *plen, |
- CK_OBJECT_HANDLE *targetID) |
-{ |
- PRBool done; /* should we repeat the loop? */ |
- CK_OBJECT_HANDLE id; |
- CK_RV crv = CKR_OK; |
- |
- do { |
- crv = sftkdb_checkConflicts(db, objectType, ptemplate, |
- *plen, CK_INVALID_HANDLE); |
- if (crv != CKR_ATTRIBUTE_VALUE_INVALID) { |
- break; |
- } |
- crv = sftkdb_resolveConflicts(arena, objectType, ptemplate, plen); |
- } while (crv == CKR_OK); |
- |
- if (crv != CKR_OK) { |
- return SFTKDB_DO_NOTHING; |
- } |
- |
- do { |
- done = PR_TRUE; |
- crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen); |
- if (crv != CKR_OK) { |
- return SFTKDB_DO_NOTHING; |
- } |
- |
- /* This object already exists, merge it, don't update */ |
- if (id != CK_INVALID_HANDLE) { |
- CK_ATTRIBUTE *attr = NULL; |
- /* special post processing for attributes */ |
- switch (objectType) { |
- case CKO_CERTIFICATE: |
- case CKO_PUBLIC_KEY: |
- case CKO_PRIVATE_KEY: |
- /* update target's CKA_ID and labels if they don't already |
- * exist */ |
- *targetID = id; |
- return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen); |
- case CKO_NSS_TRUST: |
- /* if we have conflicting trust object types, |
- * we need to reconcile them */ |
- *targetID = id; |
- return sftkdb_reconcileTrust(arena, db, id, ptemplate, plen); |
- case CKO_SECRET_KEY: |
- /* secret keys in the old database are all sdr keys, |
- * unfortunately they all appear to have the same CKA_ID, |
- * even though they are truly different keys, so we always |
- * want to update these keys, but we need to |
- * give them a new CKA_ID */ |
- /* NOTE: this changes ptemplate */ |
- attr = sftkdb_getAttributeFromTemplate(CKA_ID,ptemplate,*plen); |
- crv = attr ? sftkdb_incrementCKAID(arena, attr) |
- : CKR_HOST_MEMORY; |
- /* in the extremely rare event that we needed memory and |
- * couldn't get it, just drop the key */ |
- if (crv != CKR_OK) { |
- return SFTKDB_DO_NOTHING; |
- } |
- done = PR_FALSE; /* repeat this find loop */ |
- break; |
- default: |
- /* for all other objects, if we found the equivalent object, |
- * don't update it */ |
- return SFTKDB_DO_NOTHING; |
- } |
- } |
- } while (!done); |
- |
- /* this object doesn't exist, update it */ |
- return SFTKDB_ADD_OBJECT; |
-} |
- |
- |
-#define MAX_ATTRIBUTES 500 |
-static CK_RV |
-sftkdb_mergeObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, |
- SECItem *key) |
-{ |
- CK_ATTRIBUTE template[MAX_ATTRIBUTES]; |
- CK_ATTRIBUTE *ptemplate; |
- CK_ULONG max_attributes = MAX_ATTRIBUTES; |
- CK_OBJECT_CLASS objectType; |
- SDB *source = handle->update; |
- SDB *target = handle->db; |
- int i; |
- CK_RV crv; |
- PLArenaPool *arena = NULL; |
- |
- arena = PORT_NewArena(256); |
- if (arena == NULL) { |
- return CKR_HOST_MEMORY; |
- } |
- |
- ptemplate = &template[0]; |
- id &= SFTK_OBJ_ID_MASK; |
- crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes); |
- if (crv == CKR_BUFFER_TOO_SMALL) { |
- ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes); |
- if (ptemplate == NULL) { |
- crv = CKR_HOST_MEMORY; |
- } else { |
- crv = sftkdb_GetObjectTemplate(source, id, |
- ptemplate, &max_attributes); |
- } |
- } |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- |
- for (i=0; i < max_attributes; i++) { |
- ptemplate[i].pValue = PORT_ArenaAlloc(arena,ptemplate[i].ulValueLen); |
- if (ptemplate[i].pValue == NULL) { |
- crv = CKR_HOST_MEMORY; |
- goto loser; |
- } |
- } |
- crv = (*source->sdb_GetAttributeValue)(source, id, |
- ptemplate, max_attributes); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- |
- objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate, |
- max_attributes); |
- |
- /* |
- * Update Object updates the object template if necessary then returns |
- * whether or not we need to actually write the object out to our target |
- * database. |
- */ |
- if (!handle->updateID) { |
- crv = sftkdb_CreateObject(arena, handle, target, &id, |
- ptemplate, max_attributes); |
- } else { |
- sftkdbUpdateStatus update_status; |
- update_status = sftkdb_updateObjectTemplate(arena, target, |
- objectType, ptemplate, &max_attributes, &id); |
- switch (update_status) { |
- case SFTKDB_ADD_OBJECT: |
- crv = sftkdb_CreateObject(arena, handle, target, &id, |
- ptemplate, max_attributes); |
- break; |
- case SFTKDB_MODIFY_OBJECT: |
- crv = sftkdb_setAttributeValue(arena, handle, target, |
- id, ptemplate, max_attributes); |
- break; |
- case SFTKDB_DO_NOTHING: |
- case SFTKDB_DROP_ATTRIBUTE: |
- break; |
- } |
- } |
- |
-loser: |
- if (arena) { |
- PORT_FreeArena(arena,PR_TRUE); |
- } |
- return crv; |
-} |
- |
- |
-#define MAX_IDS 10 |
-/* |
- * update a new database from an old one, now that we have the key |
- */ |
-CK_RV |
-sftkdb_Update(SFTKDBHandle *handle, SECItem *key) |
-{ |
- SDBFind *find = NULL; |
- CK_ULONG idCount = MAX_IDS; |
- CK_OBJECT_HANDLE ids[MAX_IDS]; |
- SECItem *updatePasswordKey = NULL; |
- CK_RV crv, crv2; |
- PRBool inTransaction = PR_FALSE; |
- int i; |
- |
- if (handle == NULL) { |
- return CKR_OK; |
- } |
- if (handle->update == NULL) { |
- return CKR_OK; |
- } |
- |
- /* |
- * put the whole update under a transaction. This allows us to handle |
- * any possible race conditions between with the updateID check. |
- */ |
- crv = (*handle->db->sdb_Begin)(handle->db); |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- inTransaction = PR_TRUE; |
- |
- /* some one else has already updated this db */ |
- if (sftkdb_hasUpdate(sftkdb_TypeString(handle), |
- handle->db, handle->updateID)) { |
- crv = CKR_OK; |
- goto done; |
- } |
- |
- updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle); |
- if (updatePasswordKey) { |
- /* pass the source DB key to the legacy code, |
- * so it can decrypt things */ |
- handle->oldKey = updatePasswordKey; |
- } |
- |
- /* find all the objects */ |
- crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find); |
- |
- if (crv != CKR_OK) { |
- goto loser; |
- } |
- while ((crv == CKR_OK) && (idCount == MAX_IDS)) { |
- crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount); |
- for (i=0; (crv == CKR_OK) && (i < idCount); i++) { |
- crv = sftkdb_mergeObject(handle, ids[i], key); |
- } |
- } |
- crv2 = sftkdb_FindObjectsFinal(handle, find); |
- if (crv == CKR_OK) crv = crv2; |
- |
-loser: |
- /* no longer need the old key value */ |
- handle->oldKey = NULL; |
- |
- /* update the password - even if we didn't update objects */ |
- if (handle->type == SFTK_KEYDB_TYPE) { |
- SECItem item1, item2; |
- unsigned char data1[SDB_MAX_META_DATA_LEN]; |
- unsigned char data2[SDB_MAX_META_DATA_LEN]; |
- |
- item1.data = data1; |
- item1.len = sizeof(data1); |
- item2.data = data2; |
- item2.len = sizeof(data2); |
- |
- /* if the target db already has a password, skip this. */ |
- crv = (*handle->db->sdb_GetMetaData)(handle->db, "password", |
- &item1, &item2); |
- if (crv == CKR_OK) { |
- goto done; |
- } |
- |
- |
- /* nope, update it from the source */ |
- crv = (*handle->update->sdb_GetMetaData)(handle->update, "password", |
- &item1, &item2); |
- if (crv != CKR_OK) { |
- goto done; |
- } |
- crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1, |
- &item2); |
- if (crv != CKR_OK) { |
- goto done; |
- } |
- } |
- |
-done: |
- /* finally mark this up to date db up to date */ |
- /* some one else has already updated this db */ |
- if (crv == CKR_OK) { |
- crv = sftkdb_putUpdate(sftkdb_TypeString(handle), |
- handle->db, handle->updateID); |
- } |
- |
- if (inTransaction) { |
- if (crv == CKR_OK) { |
- crv = (*handle->db->sdb_Commit)(handle->db); |
- } else { |
- (*handle->db->sdb_Abort)(handle->db); |
- } |
- } |
- if (handle->update) { |
- (*handle->update->sdb_Close)(handle->update); |
- handle->update = NULL; |
- } |
- if (handle->updateID) { |
- PORT_Free(handle->updateID); |
- handle->updateID = NULL; |
- } |
- sftkdb_FreeUpdatePasswordKey(handle); |
- if (updatePasswordKey) { |
- SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE); |
- } |
- handle->updateDBIsInit = PR_FALSE; |
- return crv; |
-} |
- |
-/****************************************************************** |
- * DB handle managing functions. |
- * |
- * These functions are called by softoken to initialize, acquire, |
- * and release database handles. |
- */ |
- |
-const char * |
-sftkdb_GetUpdateID(SFTKDBHandle *handle) |
-{ |
- return handle->updateID; |
-} |
- |
-/* release a database handle */ |
-void |
-sftk_freeDB(SFTKDBHandle *handle) |
-{ |
- PRInt32 ref; |
- |
- if (!handle) return; |
- ref = PR_ATOMIC_DECREMENT(&handle->ref); |
- if (ref == 0) { |
- sftkdb_CloseDB(handle); |
- } |
- return; |
-} |
- |
- |
-/* |
- * acquire a database handle for a certificate db |
- * (database for public objects) |
- */ |
-SFTKDBHandle * |
-sftk_getCertDB(SFTKSlot *slot) |
-{ |
- SFTKDBHandle *dbHandle; |
- |
- PZ_Lock(slot->slotLock); |
- dbHandle = slot->certDB; |
- if (dbHandle) { |
- PR_ATOMIC_INCREMENT(&dbHandle->ref); |
- } |
- PZ_Unlock(slot->slotLock); |
- return dbHandle; |
-} |
- |
-/* |
- * acquire a database handle for a key database |
- * (database for private objects) |
- */ |
-SFTKDBHandle * |
-sftk_getKeyDB(SFTKSlot *slot) |
-{ |
- SFTKDBHandle *dbHandle; |
- |
- SKIP_AFTER_FORK(PZ_Lock(slot->slotLock)); |
- dbHandle = slot->keyDB; |
- if (dbHandle) { |
- PR_ATOMIC_INCREMENT(&dbHandle->ref); |
- } |
- SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock)); |
- return dbHandle; |
-} |
- |
-/* |
- * acquire the database for a specific object. NOTE: objectID must point |
- * to a Token object! |
- */ |
-SFTKDBHandle * |
-sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID) |
-{ |
- SFTKDBHandle *dbHandle; |
- |
- PZ_Lock(slot->slotLock); |
- dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB; |
- if (dbHandle) { |
- PR_ATOMIC_INCREMENT(&dbHandle->ref); |
- } |
- PZ_Unlock(slot->slotLock); |
- return dbHandle; |
-} |
- |
-/* |
- * initialize a new database handle |
- */ |
-static SFTKDBHandle * |
-sftk_NewDBHandle(SDB *sdb, int type) |
-{ |
- SFTKDBHandle *handle = PORT_New(SFTKDBHandle); |
- handle->ref = 1; |
- handle->db = sdb; |
- handle->update = NULL; |
- handle->peerDB = NULL; |
- handle->newKey = NULL; |
- handle->oldKey = NULL; |
- handle->updatePasswordKey = NULL; |
- handle->updateID = NULL; |
- handle->type = type; |
- handle->passwordKey.data = NULL; |
- handle->passwordKey.len = 0; |
- handle->passwordLock = NULL; |
- if (type == SFTK_KEYDB_TYPE) { |
- handle->passwordLock = PZ_NewLock(nssILockAttribute); |
- } |
- sdb->app_private = handle; |
- return handle; |
-} |
- |
-/* |
- * reset the key database to it's uninitialized state. This call |
- * will clear all the key entried. |
- */ |
-SECStatus |
-sftkdb_ResetKeyDB(SFTKDBHandle *handle) |
-{ |
- CK_RV crv; |
- |
- /* only rest the key db */ |
- if (handle->type != SFTK_KEYDB_TYPE) { |
- return SECFailure; |
- } |
- crv = sftkdb_ResetDB(handle); |
- if (crv != CKR_OK) { |
- /* set error */ |
- return SECFailure; |
- } |
- return SECSuccess; |
-} |
- |
-static PRBool |
-sftk_oldVersionExists(const char *dir, int version) |
-{ |
- int i; |
- PRStatus exists = PR_FAILURE; |
- char *file = NULL; |
- |
- for (i=version; i > 1 ; i--) { |
- file = PR_smprintf("%s%d.db",dir,i); |
- if (file == NULL) { |
- continue; |
- } |
- exists = PR_Access(file, PR_ACCESS_EXISTS); |
- PR_smprintf_free(file); |
- if (exists == PR_SUCCESS) { |
- return PR_TRUE; |
- } |
- } |
- return PR_FALSE; |
-} |
- |
-static PRBool |
-sftk_hasLegacyDB(const char *confdir, const char *certPrefix, |
- const char *keyPrefix, int certVersion, int keyVersion) |
-{ |
- char *dir; |
- PRBool exists; |
- |
- if (certPrefix == NULL) { |
- certPrefix = ""; |
- } |
- |
- if (keyPrefix == NULL) { |
- keyPrefix = ""; |
- } |
- |
- dir= PR_smprintf("%s/%scert", confdir, certPrefix); |
- if (dir == NULL) { |
- return PR_FALSE; |
- } |
- |
- exists = sftk_oldVersionExists(dir, certVersion); |
- PR_smprintf_free(dir); |
- if (exists) { |
- return PR_TRUE; |
- } |
- |
- dir= PR_smprintf("%s/%skey", confdir, keyPrefix); |
- if (dir == NULL) { |
- return PR_FALSE; |
- } |
- |
- exists = sftk_oldVersionExists(dir, keyVersion); |
- PR_smprintf_free(dir); |
- return exists; |
-} |
- |
-/* |
- * initialize certificate and key database handles as a pair. |
- * |
- * This function figures out what type of database we are opening and |
- * calls the appropriate low level function to open the database. |
- * It also figures out whether or not to setup up automatic update. |
- */ |
-CK_RV |
-sftk_DBInit(const char *configdir, const char *certPrefix, |
- const char *keyPrefix, const char *updatedir, |
- const char *updCertPrefix, const char *updKeyPrefix, |
- const char *updateID, PRBool readOnly, PRBool noCertDB, |
- PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS, |
- SFTKDBHandle **certDB, SFTKDBHandle **keyDB) |
-{ |
- const char *confdir; |
- NSSDBType dbType = NSS_DB_TYPE_NONE; |
- char *appName = NULL; |
- SDB *keySDB, *certSDB; |
- CK_RV crv = CKR_OK; |
- int flags = SDB_RDONLY; |
- PRBool newInit = PR_FALSE; |
- PRBool needUpdate = PR_FALSE; |
- |
- if (!readOnly) { |
- flags = SDB_CREATE; |
- } |
- |
- *certDB = NULL; |
- *keyDB = NULL; |
- |
- if (noKeyDB && noCertDB) { |
- return CKR_OK; |
- } |
- confdir = _NSSUTIL_EvaluateConfigDir(configdir, &dbType, &appName); |
- |
- /* |
- * now initialize the appropriate database |
- */ |
- switch (dbType) { |
- case NSS_DB_TYPE_LEGACY: |
- crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, |
- isFIPS, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB); |
- break; |
- case NSS_DB_TYPE_MULTIACCESS: |
- crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags, |
- isFIPS, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB); |
- break; |
- case NSS_DB_TYPE_SQL: |
- case NSS_DB_TYPE_EXTERN: /* SHOULD open a loadable db */ |
- crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags, |
- noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit); |
- |
- /* |
- * if we failed to open the DB's read only, use the old ones if |
- * the exists. |
- */ |
- if (crv != CKR_OK) { |
- if ((flags == SDB_RDONLY) && |
- sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) { |
- /* we have legacy databases, if we failed to open the new format |
- * DB's read only, just use the legacy ones */ |
- crv = sftkdbCall_open(confdir, certPrefix, |
- keyPrefix, 8, 3, flags, isFIPS, |
- noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB); |
- } |
- /* Handle the database merge case. |
- * |
- * For the merge case, we need help from the application. Only |
- * the application knows where the old database is, and what unique |
- * identifier it has associated with it. |
- * |
- * If the client supplies these values, we use them to determine |
- * if we need to update. |
- */ |
- } else if ( |
- /* both update params have been supplied */ |
- updatedir && *updatedir && updateID && *updateID |
- /* old dbs exist? */ |
- && sftk_hasLegacyDB(updatedir, updCertPrefix, updKeyPrefix, 8, 3) |
- /* and they have not yet been updated? */ |
- && ((noKeyDB || !sftkdb_hasUpdate("key", keySDB, updateID)) |
- || (noCertDB || !sftkdb_hasUpdate("cert", certSDB, updateID)))) { |
- /* we need to update */ |
- confdir = updatedir; |
- certPrefix = updCertPrefix; |
- keyPrefix = updKeyPrefix; |
- needUpdate = PR_TRUE; |
- } else if (newInit) { |
- /* if the new format DB was also a newly created DB, and we |
- * succeeded, then need to update that new database with data |
- * from the existing legacy DB */ |
- if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) { |
- needUpdate = PR_TRUE; |
- } |
- } |
- break; |
- default: |
- crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST |
- * return one of the types we already |
- * specified. */ |
- } |
- if (crv != CKR_OK) { |
- goto done; |
- } |
- if (!noCertDB) { |
- *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE); |
- } else { |
- *certDB = NULL; |
- } |
- if (!noKeyDB) { |
- *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE); |
- } else { |
- *keyDB = NULL; |
- } |
- |
- /* link them together */ |
- if (*certDB) { |
- (*certDB)->peerDB = *keyDB; |
- } |
- if (*keyDB) { |
- (*keyDB)->peerDB = *certDB; |
- } |
- |
- /* |
- * if we need to update, open the legacy database and |
- * mark the handle as needing update. |
- */ |
- if (needUpdate) { |
- SDB *updateCert = NULL; |
- SDB *updateKey = NULL; |
- CK_RV crv2; |
- |
- crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, |
- isFIPS, noCertDB ? NULL : &updateCert, |
- noKeyDB ? NULL : &updateKey); |
- if (crv2 == CKR_OK) { |
- if (*certDB) { |
- (*certDB)->update = updateCert; |
- (*certDB)->updateID = updateID && *updateID |
- ? PORT_Strdup(updateID) : NULL; |
- updateCert->app_private = (*certDB); |
- } |
- if (*keyDB) { |
- PRBool tokenRemoved = PR_FALSE; |
- (*keyDB)->update = updateKey; |
- (*keyDB)->updateID = updateID && *updateID ? |
- PORT_Strdup(updateID) : NULL; |
- updateKey->app_private = (*keyDB); |
- (*keyDB)->updateDBIsInit = PR_TRUE; |
- (*keyDB)->updateDBIsInit = |
- (sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ? |
- PR_TRUE : PR_FALSE; |
- /* if the password on the key db is NULL, kick off our update |
- * chain of events */ |
- sftkdb_CheckPassword((*keyDB), "", &tokenRemoved); |
- } else { |
- /* we don't have a key DB, update the certificate DB now */ |
- sftkdb_Update(*certDB, NULL); |
- } |
- } |
- } |
-done: |
- if (appName) { |
- PORT_Free(appName); |
- } |
- return forceOpen ? CKR_OK : crv; |
-} |
- |
-CK_RV |
-sftkdb_Shutdown(void) |
-{ |
- s_shutdown(); |
- sftkdbCall_Shutdown(); |
- return CKR_OK; |
-} |
- |