/security/nss/lib/softoken/sftkdb.c
C | 2713 lines | 1906 code | 270 blank | 537 comment | 561 complexity | ebd446c454642045d84a75cdd2765876 MD5 | raw file
Possible License(s): LGPL-3.0, MIT, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1994-2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
- /*
- * 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 "secmodt.h"
- #include "pratom.h"
- #include "lgglue.h"
- #include "sftkpars.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;
- SFTKDBHandle *keyHandle = handle;
- SDB *keyTarget = NULL;
- PORT_Assert(handle);
- if (handle->type != SFTK_KEYDB_TYPE) {
- keyHandle = handle->peerDB;
- }
- /* no key DB defined? then no need to sign anything */
- if (keyHandle == NULL) {
- return CKR_OK;
- }
- /* 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) {
- return CKR_OK;
- }
- 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);
- return CKR_USER_NOT_LOGGED_IN;
- }
- rv = sftkdb_SignAttribute(arena, &keyHandle->passwordKey,
- objectID, template[i].type,
- &plainText, &signText);
- PZ_Unlock(keyHandle->passwordLock);
- if (rv != SECSuccess) {
- return CKR_GENERAL_ERROR; /* better error code here? */
- }
- rv = sftkdb_PutAttributeSignature(handle, keyTarget,
- objectID, template[i].type, signText);
- if (rv != SECSuccess) {
- return CKR_GENERAL_ERROR; /* better error code here? */
- }
- }
- }
- return CKR_OK;
- }
- 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;
- }
- 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 it's 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_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_RV crv = CKR_OK;
- CK_ATTRIBUTE *ntemplate;
- unsigned char *data = NULL;
- PLArenaPool *arena = NULL;
- CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK);
- SDB *db;
- 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) {
- return crv;
- }
- arena = PORT_NewArena(256);
- if (arena == NULL) {
- return CKR_HOST_MEMORY;
- }
- crv = (*db->sdb_Begin)(db);
- if (crv != CKR_OK) {
- goto loser;
- }
- 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) {
- (*db->sdb_Abort)(db);
- }
- if (data) {
- PORT_Free(ntemplate);
- PORT_Free(data);
- }
- 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->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 mea…
Large files files are truncated, but you can click here to view the full file