From f2f4f32c0c92b8051dd4e8e2a62a8f5b160f6207 Mon Sep 17 00:00:00 2001 From: "relyea%netscape.com" Date: Wed, 28 Sep 2005 17:12:17 +0000 Subject: bug 305697: open additional database on the fly in softoken. part1: softoken changes. r=julien --- security/nss/lib/softoken/cdbhdl.h | 4 + security/nss/lib/softoken/dbinit.c | 49 +- security/nss/lib/softoken/keydb.c | 279 +++++++----- security/nss/lib/softoken/keydbi.h | 2 + security/nss/lib/softoken/lowcert.c | 1 + security/nss/lib/softoken/manifest.mn | 1 + security/nss/lib/softoken/pcertdb.c | 19 +- security/nss/lib/softoken/pk11db.c | 6 +- security/nss/lib/softoken/pk11pars.h | 13 +- security/nss/lib/softoken/pkcs11.c | 818 +++++++++++++++++++++++----------- security/nss/lib/softoken/pkcs11i.h | 108 +++-- security/nss/lib/softoken/pkcs11n.h | 10 + security/nss/lib/softoken/pkcs11u.c | 345 ++++++++++---- 13 files changed, 1166 insertions(+), 489 deletions(-) (limited to 'security/nss/lib') diff --git a/security/nss/lib/softoken/cdbhdl.h b/security/nss/lib/softoken/cdbhdl.h index a53aacea3..238a48669 100644 --- a/security/nss/lib/softoken/cdbhdl.h +++ b/security/nss/lib/softoken/cdbhdl.h @@ -45,6 +45,7 @@ #include "nspr.h" #include "mcom_db.h" #include "pcertt.h" +#include "prtypes.h" /* * Handle structure for open certificate databases @@ -53,8 +54,11 @@ struct NSSLOWCERTCertDBHandleStr { DB *permCertDB; PZMonitor *dbMon; PRBool dbVerify; + PRInt32 ref; /* reference count */ }; +#define nsslowcert_reference(x) (PR_AtomicIncrement(&(x)->ref) , (x)) + #ifdef DBM_USING_NSPR #define NO_RDONLY PR_RDONLY #define NO_RDWR PR_RDWR diff --git a/security/nss/lib/softoken/dbinit.c b/security/nss/lib/softoken/dbinit.c index 110419dac..2b7f81a73 100644 --- a/security/nss/lib/softoken/dbinit.c +++ b/security/nss/lib/softoken/dbinit.c @@ -43,10 +43,12 @@ #include "prinit.h" #include "prprf.h" #include "prmem.h" +#include "pratom.h" #include "pcertt.h" #include "lowkeyi.h" #include "pcert.h" #include "cdbhdl.h" +#include "keydbi.h" #include "pkcs11i.h" static char * @@ -164,6 +166,7 @@ sftk_OpenCertDB(const char * configdir, const char *prefix, PRBool readOnly, if (certdb == NULL) goto loser; + certdb->ref = 1; /* fix when we get the DB in */ rv = nsslowcert_OpenCertDB(certdb, readOnly, appName, prefix, sftk_certdb_name_cb, (void *)name, PR_FALSE); @@ -254,20 +257,52 @@ loser: return crv; } - -void -sftk_DBShutdown(NSSLOWCERTCertDBHandle *certHandle, - NSSLOWKEYDBHandle *keyHandle) +NSSLOWCERTCertDBHandle * +sftk_getCertDB(SFTKSlot *slot) { + NSSLOWCERTCertDBHandle *certHandle; + + PZ_Lock(slot->slotLock); + certHandle = slot->certDB; if (certHandle) { - nsslowcert_ClosePermCertDB(certHandle); - PORT_Free(certHandle); + PR_AtomicIncrement(&certHandle->ref); } + PZ_Unlock(slot->slotLock); + return certHandle; +} +NSSLOWKEYDBHandle * +sftk_getKeyDB(SFTKSlot *slot) +{ + NSSLOWKEYDBHandle *keyHandle; + + PZ_Lock(slot->slotLock); + keyHandle = slot->keyDB; if (keyHandle) { - nsslowkey_CloseKeyDB(keyHandle); + PR_AtomicIncrement(&keyHandle->ref); } + PZ_Unlock(slot->slotLock); + return keyHandle; +} + +void +sftk_freeCertDB(NSSLOWCERTCertDBHandle *certHandle) +{ + PRInt32 ref = PR_AtomicDecrement(&certHandle->ref); + if (ref == 0) { + nsslowcert_ClosePermCertDB(certHandle); + } +} + +void +sftk_freeKeyDB(NSSLOWKEYDBHandle *keyHandle) +{ + PRInt32 ref = PR_AtomicDecrement(&keyHandle->ref); + if (ref == 0) { + nsslowkey_CloseKeyDB(keyHandle); + } } + static int rdbmapflags(int flags); static rdbfunc sftk_rdbfunc = NULL; diff --git a/security/nss/lib/softoken/keydb.c b/security/nss/lib/softoken/keydb.c index 8ab56ec5b..2f685a5a6 100644 --- a/security/nss/lib/softoken/keydb.c +++ b/security/nss/lib/softoken/keydb.c @@ -161,20 +161,21 @@ free_dbt(DBT *dbt) return; } -static int keydb_Get(DB *db, DBT *key, DBT *data, unsigned int flags); -static int keydb_Put(DB *db, DBT *key, DBT *data, unsigned int flags); -static int keydb_Sync(DB *db, unsigned int flags); -static int keydb_Del(DB *db, DBT *key, unsigned int flags); -static int keydb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags); -static void keydb_Close(DB *db); - -static PZLock *kdbLock = NULL; +static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, + unsigned int flags); +static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, + unsigned int flags); +static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags); +static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags); +static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, + unsigned int flags); +static void keydb_Close(NSSLOWKEYDBHandle *db); static void keydb_InitLocks(NSSLOWKEYDBHandle *handle) { - if (kdbLock == NULL) { - nss_InitLock(&kdbLock, nssILockKeyDB); + if (handle->lock == NULL) { + nss_InitLock(&handle->lock, nssILockKeyDB); } return; @@ -183,9 +184,9 @@ keydb_InitLocks(NSSLOWKEYDBHandle *handle) static void keydb_DestroyLocks(NSSLOWKEYDBHandle *handle) { - if (kdbLock != NULL) { - PZ_DestroyLock(kdbLock); - kdbLock = NULL; + if (handle->lock != NULL) { + PZ_DestroyLock(handle->lock); + handle->lock = NULL; } return; @@ -348,7 +349,7 @@ get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index) int ret; /* get it from the database */ - ret = keydb_Get(handle->db, index, &entry, 0); + ret = keydb_Get(handle, index, &entry, 0); if ( ret ) { PORT_SetError(SEC_ERROR_BAD_DATABASE); return NULL; @@ -374,9 +375,9 @@ put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool u /* put it in the database */ if ( update ) { - status = keydb_Put(handle->db, index, keydata, 0); + status = keydb_Put(handle, index, keydata, 0); } else { - status = keydb_Put(handle->db, index, keydata, R_NOOVERWRITE); + status = keydb_Put(handle, index, keydata, R_NOOVERWRITE); } if ( status ) { @@ -384,7 +385,7 @@ put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool u } /* sync the database */ - status = keydb_Sync(handle->db, 0); + status = keydb_Sync(handle, 0); if ( status ) { goto loser; } @@ -414,7 +415,7 @@ nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle, return(SECFailure); } - ret = keydb_Seq(handle->db, &key, &data, R_FIRST); + ret = keydb_Seq(handle, &key, &data, R_FIRST); if ( ret ) { return(SECFailure); } @@ -441,7 +442,7 @@ nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle, return(status); } } - } while ( keydb_Seq(handle->db, &key, &data, R_NEXT) == 0 ); + } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 ); return(SECSuccess); } @@ -521,7 +522,7 @@ GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle) saltKey.data = SALT_STRING; saltKey.size = sizeof(SALT_STRING) - 1; - ret = keydb_Get(handle->db, &saltKey, &saltData, 0); + ret = keydb_Get(handle, &saltKey, &saltData, 0); if ( ret ) { return(NULL); } @@ -543,7 +544,7 @@ StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle) saltData.size = handle->global_salt->len; /* put global salt into the database now */ - status = keydb_Put(handle->db, &saltKey, &saltData, 0); + status = keydb_Put(handle, &saltKey, &saltData, 0); if ( status ) { return(SECFailure); } @@ -566,7 +567,7 @@ makeGlobalVersion(NSSLOWKEYDBHandle *handle) versionKey.size = sizeof(VERSION_STRING)-1; /* put version string into the database now */ - status = keydb_Put(handle->db, &versionKey, &versionData, 0); + status = keydb_Put(handle, &versionKey, &versionData, 0); if ( status ) { return(SECFailure); } @@ -592,7 +593,7 @@ makeGlobalSalt(NSSLOWKEYDBHandle *handle) RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf)); /* put global salt into the database now */ - status = keydb_Put(handle->db, &saltKey, &saltData, 0); + status = keydb_Put(handle, &saltKey, &saltData, 0); if ( status ) { return(SECFailure); } @@ -623,7 +624,7 @@ encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg, SECItem *encCheck); static unsigned char -nsslowkey_version(DB *db) +nsslowkey_version(NSSLOWKEYDBHandle *handle) { DBT versionKey; DBT versionData; @@ -631,8 +632,12 @@ nsslowkey_version(DB *db) versionKey.data = VERSION_STRING; versionKey.size = sizeof(VERSION_STRING)-1; + if (handle->db == NULL) { + return 255; + } + /* lookup version string in database */ - ret = keydb_Get( db, &versionKey, &versionData, 0 ); + ret = keydb_Get( handle, &versionKey, &versionData, 0 ); /* error accessing the database */ if ( ret < 0 ) { @@ -646,14 +651,14 @@ nsslowkey_version(DB *db) } static PRBool -seckey_HasAServerKey(DB *db) +seckey_HasAServerKey(NSSLOWKEYDBHandle *handle) { DBT key; DBT data; int ret; PRBool found = PR_FALSE; - ret = keydb_Seq(db, &key, &data, R_FIRST); + ret = keydb_Seq(handle, &key, &data, R_FIRST); if ( ret ) { return PR_FALSE; } @@ -690,10 +695,14 @@ seckey_HasAServerKey(DB *db) } } - } while ( keydb_Seq(db, &key, &data, R_NEXT) == 0 ); + } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 ); return found; } + +/* forward declare local create function */ +static NSSLOWKEYDBHandle * nsslowkey_NewHandle(DB *dbHandle); + /* * currently updates key database from v2 to v3 */ @@ -710,18 +719,29 @@ nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) unsigned char version; SECItem *rc4key = NULL; NSSLOWKEYDBKey *dbkey = NULL; + NSSLOWKEYDBHandle *update = NULL; SECItem *oldSalt = NULL; int ret; SECItem checkitem; if ( handle->updatedb == NULL ) { - return(SECSuccess); + return SECSuccess; + } + + /* create a full DB Handle for our update so we + * can use the correct locks for the db primatives */ + update = nsslowkey_NewHandle(handle->updatedb); + if ( update == NULL) { + return SECSuccess; } + /* update has now inherited the database handle */ + handle->updatedb = NULL; + /* * check the version record */ - version = nsslowkey_version(handle->updatedb); + version = nsslowkey_version(update); if (version != 2) { goto done; } @@ -729,7 +749,7 @@ nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) saltKey.data = SALT_STRING; saltKey.size = sizeof(SALT_STRING) - 1; - ret = keydb_Get(handle->updatedb, &saltKey, &saltData, 0); + ret = keydb_Get(update, &saltKey, &saltData, 0); if ( ret ) { /* no salt in old db, so it is corrupted */ goto done; @@ -747,8 +767,7 @@ nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) checkKey.data = KEYDB_PW_CHECK_STRING; checkKey.size = KEYDB_PW_CHECK_LEN; - ret = keydb_Get(handle->updatedb, &checkKey, - &checkData, 0 ); + ret = keydb_Get(update, &checkKey, &checkData, 0 ); if (ret) { /* * if we have a key, but no KEYDB_PW_CHECK_STRING, then this must @@ -756,7 +775,7 @@ nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) * with it. Put a fake entry in so we can identify this db when we do * get the password for it. */ - if (seckey_HasAServerKey(handle->updatedb)) { + if (seckey_HasAServerKey(update)) { DBT fcheckKey; DBT fcheckData; @@ -768,11 +787,11 @@ nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) fcheckData.data = "1"; fcheckData.size = 1; /* put global salt into the new database now */ - ret = keydb_Put( handle->db, &saltKey, &saltData, 0); + ret = keydb_Put( handle, &saltKey, &saltData, 0); if ( ret ) { goto done; } - ret = keydb_Put( handle->db, &fcheckKey, &fcheckData, 0); + ret = keydb_Put( handle, &fcheckKey, &fcheckData, 0); if ( ret ) { goto done; } @@ -781,7 +800,7 @@ nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) } } else { /* put global salt into the new database now */ - ret = keydb_Put( handle->db, &saltKey, &saltData, 0); + ret = keydb_Put( handle, &saltKey, &saltData, 0); if ( ret ) { goto done; } @@ -811,7 +830,7 @@ nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) /* now traverse the database */ - ret = keydb_Seq(handle->updatedb, &key, &data, R_FIRST); + ret = keydb_Seq(update, &key, &data, R_FIRST); if ( ret ) { goto done; } @@ -857,17 +876,15 @@ nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle) sec_destroy_dbkey(dbkey); } - } while ( keydb_Seq(handle->updatedb, &key, &data, - R_NEXT) == 0 ); + } while ( keydb_Seq(update, &key, &data, R_NEXT) == 0 ); dbkey = NULL; done: /* sync the database */ - ret = keydb_Sync(handle->db, 0); + ret = keydb_Sync(handle, 0); - keydb_Close(handle->updatedb); - handle->updatedb = NULL; + nsslowkey_CloseKeyDB(update); if ( rc4key ) { SECITEM_FreeItem(rc4key, PR_TRUE); @@ -913,7 +930,7 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, /* force a transactional read, which will verify that one and only one * process attempts the update. */ - if (nsslowkey_version(handle->db) == NSSLOWKEY_DB_FILE_VERSION) { + if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION) { /* someone else has already updated the database for us */ db_FinishTransaction(handle->db, PR_FALSE); db_InitComplete(handle->db); @@ -925,20 +942,35 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, * local database we can update from. */ if (appName) { + NSSLOWKEYDBHandle *updateHandle = nsslowkey_NewHandle(updatedb); updatedb = dbopen( dbname, NO_RDONLY, 0600, DB_HASH, 0 ); - if (updatedb) { - handle->version = nsslowkey_version(updatedb); - if (handle->version != NSSLOWKEY_DB_FILE_VERSION) { - keydb_Close(updatedb); - } else { - db_Copy(handle->db, updatedb); - keydb_Close(updatedb); - db_FinishTransaction(handle->db,PR_FALSE); - db_InitComplete(handle->db); - return SECSuccess; - } + if (!updatedb) { + goto noupdate; } + + /* nsslowkey_version needs a full handle because it calls + * the kdb_Get() function, which needs to lock. + */ + updateHandle = nsslowkey_NewHandle(updatedb); + if (!updateHandle) { + updatedb->close(updatedb); + goto noupdate; + } + + handle->version = nsslowkey_version(updateHandle); + if (handle->version != NSSLOWKEY_DB_FILE_VERSION) { + nsslowkey_CloseKeyDB(updateHandle); + goto noupdate; + } + + /* copy the new DB from the old one */ + db_Copy(handle->db, updatedb); + nsslowkey_CloseKeyDB(updateHandle); + db_FinishTransaction(handle->db,PR_FALSE); + db_InitComplete(handle->db); + return SECSuccess; } +noupdate: /* update the version number */ rv = makeGlobalVersion(handle); @@ -978,7 +1010,7 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, } /* sync the database */ - ret = keydb_Sync(handle->db, 0); + ret = keydb_Sync(handle, 0); if ( ret ) { rv = SECFailure; goto loser; @@ -994,7 +1026,7 @@ loser: static DB * openOldDB(const char *appName, const char *prefix, const char *dbname, - PRBool openflags, int *version) { + PRBool openflags) { DB *db = NULL; if (appName) { @@ -1003,54 +1035,79 @@ openOldDB(const char *appName, const char *prefix, const char *dbname, db = dbopen( dbname, openflags, 0600, DB_HASH, 0 ); } - /* check for correct version number */ - if (db != NULL) { - *version = nsslowkey_version(db); - if (*version != NSSLOWKEY_DB_FILE_VERSION ) { - /* bogus version number record, reset the database */ - keydb_Close( db ); - db = NULL; + return db; +} + +/* check for correct version number */ +static PRBool +verifyVersion(NSSLOWKEYDBHandle *handle) +{ + int version = nsslowkey_version(handle); + + handle->version = version; + if (version != NSSLOWKEY_DB_FILE_VERSION ) { + if (handle->db) { + keydb_Close(handle); + handle->db = NULL; } } - return db; + return handle->db != NULL; } -NSSLOWKEYDBHandle * -nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, - NSSLOWKEYDBNameFunc namecb, void *cbarg) +static NSSLOWKEYDBHandle * +nsslowkey_NewHandle(DB *dbHandle) { NSSLOWKEYDBHandle *handle; - SECStatus rv; - int openflags; - char *dbname = NULL; - handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc (sizeof(NSSLOWKEYDBHandle)); if (handle == NULL) { PORT_SetError (SEC_ERROR_NO_MEMORY); return NULL; } + handle->appname = NULL; + handle->dbname = NULL; + handle->global_salt = NULL; + handle->updatedb = NULL; + handle->db = dbHandle; + handle->ref = 1; + + keydb_InitLocks(handle); + return handle; +} + +NSSLOWKEYDBHandle * +nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, + NSSLOWKEYDBNameFunc namecb, void *cbarg) +{ + NSSLOWKEYDBHandle *handle = NULL; + SECStatus rv; + int openflags; + char *dbname = NULL; + + + handle = nsslowkey_NewHandle(NULL); + openflags = readOnly ? NO_RDONLY : NO_RDWR; + dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION); if ( dbname == NULL ) { goto loser; } - handle->appname = appName ? PORT_Strdup(appName) : NULL ; handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) : (prefix ? PORT_Strdup(prefix) : NULL); handle->readOnly = readOnly; - keydb_InitLocks(handle); - handle->db = openOldDB(appName, prefix, dbname, openflags, - &handle->version); - if (handle->version == 255) { - goto loser; + handle->db = openOldDB(appName, prefix, dbname, openflags); + if (handle->db) { + verifyVersion(handle); + if (handle->version == 255) { + goto loser; + } } - /* if first open fails, try to create a new DB */ if ( handle->db == NULL ) { @@ -1063,8 +1120,8 @@ nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, * The multiprocess code blocked the second one, then had it retry to * see if it can just open the database normally */ if (rv == SECWouldBlock) { - handle->db = openOldDB(appName,prefix,dbname, - openflags, &handle->version); + handle->db = openOldDB(appName,prefix,dbname, openflags); + verifyVersion(handle); if (handle->db == NULL) { goto loser; } @@ -1083,14 +1140,7 @@ loser: if ( dbname ) PORT_Free( dbname ); PORT_SetError(SEC_ERROR_BAD_DATABASE); - - if ( handle->db ) { - keydb_Close(handle->db); - } - if ( handle->updatedb ) { - keydb_Close(handle->updatedb); - } - PORT_Free(handle); + nsslowkey_CloseKeyDB(handle); return NULL; } @@ -1102,8 +1152,11 @@ nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle) { if (handle != NULL) { if (handle->db != NULL) { - keydb_Close(handle->db); + keydb_Close(handle); } + if (handle->updatedb) { + handle->updatedb->close(handle->updatedb); + } if (handle->dbname) PORT_Free(handle->dbname); if (handle->appname) PORT_Free(handle->appname); if (handle->global_salt) { @@ -1143,14 +1196,14 @@ nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, SECItem *pubkey) namekey.size = pubkey->len; /* delete it from the database */ - ret = keydb_Del(handle->db, &namekey, 0); + ret = keydb_Del(handle, &namekey, 0); if ( ret ) { PORT_SetError(SEC_ERROR_BAD_DATABASE); return(SECFailure); } /* sync the database */ - ret = keydb_Sync(handle->db, 0); + ret = keydb_Sync(handle, 0); if ( ret ) { PORT_SetError(SEC_ERROR_BAD_DATABASE); return(SECFailure); @@ -1195,7 +1248,7 @@ nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id) namekey.data = (char *)id->data; namekey.size = id->len; - status = keydb_Get(handle->db, &namekey, &dummy, 0); + status = keydb_Get(handle, &namekey, &dummy, 0); if ( status ) { return PR_FALSE; } @@ -1253,7 +1306,7 @@ nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cer namekey.size = sizeof(buf); } - status = keydb_Get(handle->db, &namekey, &dummy, 0); + status = keydb_Get(handle, &namekey, &dummy, 0); /* some databases have the key stored as a signed value */ if (status) { unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size+1); @@ -1262,7 +1315,7 @@ nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cer buf[0] = 0; namekey.data = buf; namekey.size ++; - status = keydb_Get(handle->db, &namekey, &dummy, 0); + status = keydb_Get(handle, &namekey, &dummy, 0); PORT_Free(buf); } } @@ -1290,12 +1343,12 @@ nsslowkey_HasKeyDBPassword(NSSLOWKEYDBHandle *handle) checkkey.data = KEYDB_PW_CHECK_STRING; checkkey.size = KEYDB_PW_CHECK_LEN; - ret = keydb_Get(handle->db, &checkkey, &checkdata, 0 ); + ret = keydb_Get(handle, &checkkey, &checkdata, 0 ); if ( ret ) { /* see if this was an updated DB first */ checkkey.data = KEYDB_FAKE_PW_CHECK_STRING; checkkey.size = KEYDB_FAKE_PW_CHECK_LEN; - ret = keydb_Get(handle->db, &checkkey, &checkdata, 0 ); + ret = keydb_Get(handle, &checkkey, &checkdata, 0 ); if ( ret ) { return(SECFailure); } @@ -2423,7 +2476,7 @@ nsslowkey_CheckKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem) if ( dbkey == NULL ) { checkkey.data = KEYDB_FAKE_PW_CHECK_STRING; checkkey.size = KEYDB_FAKE_PW_CHECK_LEN; - ret = keydb_Get(handle->db, &checkkey, &checkdata, 0 ); + ret = keydb_Get(handle, &checkkey, &checkdata, 0 ); if (ret) { goto loser; } @@ -2568,7 +2621,7 @@ ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, } /* delete the old record */ - ret = keydb_Del(handle->db, &node->key, 0); + ret = keydb_Del(handle, &node->key, 0); if ( ret ) { PORT_SetError(SEC_ERROR_BAD_DATABASE); rv = SECFailure; @@ -2685,7 +2738,7 @@ nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle) return SECFailure; } - keydb_Close(handle->db); + keydb_Close(handle); if (handle->appname) { handle->db= rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL); @@ -2717,17 +2770,19 @@ nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle) done: /* sync the database */ - ret = keydb_Sync(handle->db, 0); + ret = keydb_Sync(handle, 0); db_InitComplete(handle->db); return (errors == 0 ? SECSuccess : SECFailure); } static int -keydb_Get(DB *db, DBT *key, DBT *data, unsigned int flags) +keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) { PRStatus prstat; int ret; + PRLock *kdbLock = kdb->lock; + DB *db = kdb->db; PORT_Assert(kdbLock != NULL); PZ_Lock(kdbLock); @@ -2740,10 +2795,12 @@ keydb_Get(DB *db, DBT *key, DBT *data, unsigned int flags) } static int -keydb_Put(DB *db, DBT *key, DBT *data, unsigned int flags) +keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) { PRStatus prstat; int ret = 0; + PRLock *kdbLock = kdb->lock; + DB *db = kdb->db; PORT_Assert(kdbLock != NULL); PZ_Lock(kdbLock); @@ -2756,10 +2813,12 @@ keydb_Put(DB *db, DBT *key, DBT *data, unsigned int flags) } static int -keydb_Sync(DB *db, unsigned int flags) +keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags) { PRStatus prstat; int ret; + PRLock *kdbLock = kdb->lock; + DB *db = kdb->db; PORT_Assert(kdbLock != NULL); PZ_Lock(kdbLock); @@ -2772,10 +2831,12 @@ keydb_Sync(DB *db, unsigned int flags) } static int -keydb_Del(DB *db, DBT *key, unsigned int flags) +keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags) { PRStatus prstat; int ret; + PRLock *kdbLock = kdb->lock; + DB *db = kdb->db; PORT_Assert(kdbLock != NULL); PZ_Lock(kdbLock); @@ -2788,10 +2849,12 @@ keydb_Del(DB *db, DBT *key, unsigned int flags) } static int -keydb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags) +keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags) { PRStatus prstat; int ret; + PRLock *kdbLock = kdb->lock; + DB *db = kdb->db; PORT_Assert(kdbLock != NULL); PZ_Lock(kdbLock); @@ -2804,9 +2867,11 @@ keydb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags) } static void -keydb_Close(DB *db) +keydb_Close(NSSLOWKEYDBHandle *kdb) { PRStatus prstat; + PRLock *kdbLock = kdb->lock; + DB *db = kdb->db; PORT_Assert(kdbLock != NULL); PZ_Lock(kdbLock); diff --git a/security/nss/lib/softoken/keydbi.h b/security/nss/lib/softoken/keydbi.h index 1c9c2699a..f7f427266 100644 --- a/security/nss/lib/softoken/keydbi.h +++ b/security/nss/lib/softoken/keydbi.h @@ -56,6 +56,8 @@ struct NSSLOWKEYDBHandleStr { char *appname; /* multiaccess app name */ char *dbname; /* name of the openned DB */ PRBool readOnly; /* is the DB read only */ + PRLock *lock; + PRInt32 ref; /* reference count */ }; /* diff --git a/security/nss/lib/softoken/lowcert.c b/security/nss/lib/softoken/lowcert.c index 8d2ff55d0..cb048307d 100644 --- a/security/nss/lib/softoken/lowcert.c +++ b/security/nss/lib/softoken/lowcert.c @@ -449,6 +449,7 @@ nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname) cert->subjectKeyID.len = 0; cert->dbEntry = NULL; cert ->trust = NULL; + cert ->dbhandle = NULL; /* generate and save the database key for the cert */ rv = nsslowcert_KeyFromIssuerAndSNStatic(cert->certKeySpace, diff --git a/security/nss/lib/softoken/manifest.mn b/security/nss/lib/softoken/manifest.mn index cab786a97..52d1f75cd 100644 --- a/security/nss/lib/softoken/manifest.mn +++ b/security/nss/lib/softoken/manifest.mn @@ -58,6 +58,7 @@ EXPORTS = \ PRIVATE_EXPORTS = \ pk11pars.h \ + pkcs11ni.h \ $(NULL) CSRCS = \ diff --git a/security/nss/lib/softoken/pcertdb.c b/security/nss/lib/softoken/pcertdb.c index e6954f737..4a7706378 100644 --- a/security/nss/lib/softoken/pcertdb.c +++ b/security/nss/lib/softoken/pcertdb.c @@ -60,6 +60,7 @@ #include "plhash.h" #include "cdbhdl.h" +#include "pkcs11i.h" /* forward declaration */ NSSLOWCERTCertificate * @@ -3394,12 +3395,15 @@ AddCertToPermDB(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTCertificate *cert, state = 2; - cert->dbhandle = handle; + /* "Change" handles if necessary */ + if (cert->dbhandle) { + sftk_freeCertDB(cert->dbhandle); + } + cert->dbhandle = nsslowcert_reference(handle); /* add to or create new subject entry */ if ( subjectEntry ) { /* REWRITE BASED ON SUBJECT ENTRY */ - cert->dbhandle = handle; rv = AddPermSubjectNode(subjectEntry, cert, nickname); if ( rv != SECSuccess ) { goto loser; @@ -4321,7 +4325,7 @@ DecodeACert(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry) goto loser; } - cert->dbhandle = handle; + cert->dbhandle = nsslowcert_reference(handle); cert->dbEntry = entry; cert->trust = &entry->trust; @@ -4375,7 +4379,7 @@ DecodeTrustEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry, if (trust == NULL) { return trust; } - trust->dbhandle = handle; + trust->dbhandle = nsslowcert_reference(handle); trust->dbEntry = entry; trust->dbKey.data = pkcs11_copyStaticData(dbKey->data,dbKey->len, trust->dbKeySpace, sizeof(trust->dbKeySpace)); @@ -5009,6 +5013,9 @@ DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb) */ if ( lockdb && handle ) { nsslowcert_LockDB(handle); + /* keep a reference until we unlock, so handle won't disappear + * before we are through with it */ + nsslowcert_reference(handle); } nsslowcert_LockCertRefCount(cert); @@ -5042,11 +5049,15 @@ DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb) certListHead = cert; } nsslowcert_UnlockFreeList(); + if (handle) { + sftk_freeCertDB(handle); + } cert = NULL; } if ( lockdb && handle ) { nsslowcert_UnlockDB(handle); + sftk_freeCertDB(handle); } } diff --git a/security/nss/lib/softoken/pk11db.c b/security/nss/lib/softoken/pk11db.c index edf0d3103..49ae19739 100644 --- a/security/nss/lib/softoken/pk11db.c +++ b/security/nss/lib/softoken/pk11db.c @@ -120,9 +120,9 @@ secmod_parseTokens(char *tokenParams, sftk_parameters *parsed) tokenIndex += next; tokens[i].slotID = secmod_argDecodeNumber(name); - tokens[i].readOnly = PR_TRUE; - tokens[i].noCertDB = PR_TRUE; - tokens[i].noKeyDB = PR_TRUE; + tokens[i].readOnly = PR_FALSE; + tokens[i].noCertDB = PR_FALSE; + tokens[i].noKeyDB = PR_FALSE; if (!secmod_argIsBlank(*tokenIndex)) { char *args = secmod_argFetchValue(tokenIndex,&next); tokenIndex += next; diff --git a/security/nss/lib/softoken/pk11pars.h b/security/nss/lib/softoken/pk11pars.h index 6e01b7ffb..7a2b028eb 100644 --- a/security/nss/lib/softoken/pk11pars.h +++ b/security/nss/lib/softoken/pk11pars.h @@ -194,14 +194,21 @@ secmod_argFetchValue(char *string, int *pcount) char *end = secmod_argFindEnd(string); char *retString, *copyString; PRBool lastEscape = PR_FALSE; + int len; - *pcount = (end - string)+1; + len = end - string; + if (len == 0) { + *pcount = 0; + return NULL; + } - if (*pcount == 0) return NULL; + copyString = retString = (char *)PORT_Alloc(len+1); - copyString = retString = (char *)PORT_Alloc(*pcount); + if (*end) len++; + *pcount = len; if (retString == NULL) return NULL; + if (secmod_argIsQuote(*string)) string++; for (; string < end; string++) { if (secmod_argIsEscape(*string) && !lastEscape) { diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index 22adce5b6..10a7bcfb7 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.c @@ -55,6 +55,7 @@ #include "secitem.h" #include "pkcs11.h" #include "pkcs11i.h" +#include "pkcs11p.h" #include "softoken.h" #include "lowkeyi.h" #include "blapi.h" @@ -273,7 +274,7 @@ static const struct mechanismList mechanisms[] = { {CKM_RSA_PKCS_KEY_PAIR_GEN,{RSA_MIN_MODULUS_BITS,CK_MAX, CKF_GENERATE_KEY_PAIR},PR_TRUE}, {CKM_RSA_PKCS, {RSA_MIN_MODULUS_BITS,CK_MAX, - CKF_DUZ_IT_ALL}, PR_TRUE}, + CKF_DUZ_IT_ALL}, PR_TRUE}, #ifdef SFTK_RSA9796_SUPPORTED {CKM_RSA_9796, {RSA_MIN_MODULUS_BITS,CK_MAX, CKF_DUZ_IT_ALL}, PR_TRUE}, @@ -665,8 +666,10 @@ sftk_handleCertObject(SFTKSession *session,SFTKObject *object) char *email = NULL; SECStatus rv; PRBool inDB = PR_TRUE; + NSSLOWCERTCertDBHandle *certHandle = sftk_getCertDB(slot); + NSSLOWKEYDBHandle *keyHandle = NULL; - if (slot->certDB == NULL) { + if (certHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } @@ -680,25 +683,31 @@ sftk_handleCertObject(SFTKSession *session,SFTKObject *object) label = sftk_getString(object,CKA_LABEL); - cert = nsslowcert_FindCertByDERCert(slot->certDB, &derCert); - if (cert == NULL) { + cert = nsslowcert_FindCertByDERCert(certHandle, &derCert); + if (cert == NULL) { cert = nsslowcert_DecodeDERCertificate(&derCert, label); inDB = PR_FALSE; } if (cert == NULL) { if (label) PORT_Free(label); sftk_FreeAttribute(attribute); + sftk_freeCertDB(certHandle); return CKR_ATTRIBUTE_VALUE_INVALID; } - if (slot->keyDB && nsslowkey_KeyForCertExists(slot->keyDB,cert)) { - trust = &userTrust; + keyHandle = sftk_getKeyDB(slot); + if (keyHandle) { + if (nsslowkey_KeyForCertExists(keyHandle,cert)) { + trust = &userTrust; + } + sftk_freeKeyDB(keyHandle); } + if (!inDB) { if (!trust) trust = &defTrust; - rv = nsslowcert_AddPermCert(slot->certDB, cert, label, trust); + rv = nsslowcert_AddPermCert(certHandle, cert, label, trust); } else { - rv = trust ? nsslowcert_ChangeCertTrust(slot->certDB,cert,trust) : + rv = trust ? nsslowcert_ChangeCertTrust(certHandle,cert,trust) : SECSuccess; } @@ -706,6 +715,7 @@ sftk_handleCertObject(SFTKSession *session,SFTKObject *object) sftk_FreeAttribute(attribute); if (rv != SECSuccess) { + sftk_freeCertDB(certHandle); nsslowcert_DestroyCertificate(cert); return CKR_DEVICE_ERROR; } @@ -717,15 +727,16 @@ sftk_handleCertObject(SFTKSession *session,SFTKObject *object) if (email) { certDBEntrySMime *entry; - entry = nsslowcert_ReadDBSMimeEntry(slot->certDB,email); + entry = nsslowcert_ReadDBSMimeEntry(certHandle,email); if (!entry) { - nsslowcert_SaveSMimeProfile(slot->certDB, email, + nsslowcert_SaveSMimeProfile(certHandle, email, &cert->derSubject, NULL, NULL); } else { nsslowcert_DestroyDBEntry((certDBEntry *)entry); } PORT_Free(email); } + sftk_freeCertDB(certHandle); object->handle=sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_CERT); nsslowcert_DestroyCertificate(cert); } @@ -798,11 +809,12 @@ sftk_handleTrustObject(SFTKSession *session,SFTKObject *object) CK_BBOOL stepUp; NSSLOWCERTCertTrust dbTrust = { 0 }; SECStatus rv; + NSSLOWCERTCertDBHandle *certHandle = sftk_getCertDB(slot); - - if (slot->certDB == NULL) { + if (certHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } + issuer = sftk_FindAttribute(object,CKA_ISSUER); PORT_Assert(issuer); issuerSN.derIssuer.data = (unsigned char *)issuer->attrib.pValue; @@ -813,11 +825,12 @@ sftk_handleTrustObject(SFTKSession *session,SFTKObject *object) issuerSN.serialNumber.data = (unsigned char *)serial->attrib.pValue; issuerSN.serialNumber.len = serial->attrib.ulValueLen ; - cert = nsslowcert_FindCertByIssuerAndSN(slot->certDB,&issuerSN); + cert = nsslowcert_FindCertByIssuerAndSN(certHandle,&issuerSN); sftk_FreeAttribute(serial); sftk_FreeAttribute(issuer); if (cert == NULL) { + sftk_freeCertDB(certHandle); return CKR_ATTRIBUTE_VALUE_INVALID; } @@ -879,9 +892,10 @@ sftk_handleTrustObject(SFTKSession *session,SFTKObject *object) dbTrust.sslFlags |= CERTDB_GOVT_APPROVED_CA; } - rv = nsslowcert_ChangeCertTrust(slot->certDB,cert,&dbTrust); + rv = nsslowcert_ChangeCertTrust(certHandle,cert,&dbTrust); object->handle=sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_TRUST); nsslowcert_DestroyCertificate(cert); + sftk_freeCertDB(certHandle); if (rv != SECSuccess) { return CKR_DEVICE_ERROR; } @@ -918,9 +932,12 @@ sftk_handleSMimeObject(SFTKSession *session,SFTKObject *object) char *email = NULL; SFTKAttribute *subject,*profile,*time; SECStatus rv; + NSSLOWCERTCertDBHandle *certHandle; PORT_Assert(slot); - if (slot->certDB == NULL) { + certHandle = sftk_getCertDB(slot); + + if (certHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } @@ -953,9 +970,9 @@ sftk_handleSMimeObject(SFTKSession *session,SFTKObject *object) email = sftk_getString(object,CKA_NETSCAPE_EMAIL); /* Store CRL by SUBJECT */ - rv = nsslowcert_SaveSMimeProfile(slot->certDB, email, &derSubj, + rv = nsslowcert_SaveSMimeProfile(certHandle, email, &derSubj, pRawProfile,pRawTime); - + sftk_freeCertDB(certHandle); sftk_FreeAttribute(subject); if (profile) sftk_FreeAttribute(profile); if (time) sftk_FreeAttribute(time); @@ -1000,9 +1017,12 @@ sftk_handleCrlObject(SFTKSession *session,SFTKObject *object) char *url = NULL; SFTKAttribute *subject,*crl; SECStatus rv; + NSSLOWCERTCertDBHandle *certHandle; PORT_Assert(slot); - if (slot->certDB == NULL) { + certHandle = sftk_getCertDB(slot); + + if (certHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } @@ -1023,7 +1043,8 @@ sftk_handleCrlObject(SFTKSession *session,SFTKObject *object) isKRL = sftk_isTrue(object,CKA_NETSCAPE_KRL); /* Store CRL by SUBJECT */ - rv = nsslowcert_AddCrl(slot->certDB, &derCrl, &derSubj, url, isKRL); + rv = nsslowcert_AddCrl(certHandle, &derCrl, &derSubj, url, isKRL); + sftk_freeCertDB(certHandle); if (url) { PORT_Free(url); @@ -1162,16 +1183,18 @@ sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object, SFTKSlot *slot = session->slot; NSSLOWKEYPrivateKey *priv; SECItem pubKey; + NSSLOWKEYDBHandle *keyHandle = NULL; crv = sftk_Attribute2SSecItem(NULL,&pubKey,object,pubKeyAttr); if (crv != CKR_OK) return crv; PORT_Assert(pubKey.data); - if (slot->keyDB == NULL) { + keyHandle = sftk_getKeyDB(slot); + if (keyHandle == NULL) { PORT_Free(pubKey.data); return CKR_TOKEN_WRITE_PROTECTED; } - if (slot->keyDB->version != 3) { + if (keyHandle->version != 3) { unsigned char buf[SHA1_LENGTH]; SHA1_HashBuf(buf,pubKey.data,pubKey.len); PORT_Memcpy(pubKey.data,buf,sizeof(buf)); @@ -1179,11 +1202,11 @@ sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object, } /* make sure the associated private key already exists */ /* only works if we are logged in */ - priv = nsslowkey_FindKeyByPublicKey(slot->keyDB, &pubKey, - slot->password); + priv = nsslowkey_FindKeyByPublicKey(keyHandle, &pubKey, slot->password); + sftk_freeKeyDB(keyHandle); if (priv == NULL) { PORT_Free(pubKey.data); - return CKR_ATTRIBUTE_VALUE_INVALID; + return crv; } nsslowkey_DestroyPrivateKey(priv); @@ -1321,9 +1344,11 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE NSSLOWKEYPrivateKey *privKey; char *label; SECStatus rv = SECSuccess; + CK_RV crv = CKR_DEVICE_ERROR; SECItem pubKey; + NSSLOWKEYDBHandle *keyHandle = sftk_getKeyDB(slot); - if (slot->keyDB == NULL) { + if (keyHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } @@ -1333,11 +1358,11 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE crv = sftk_Attribute2SSecItem(NULL,&pubKey,object,CKA_NETSCAPE_DB); if (crv != CKR_OK) { - if (label) PORT_Free(label); - nsslowkey_DestroyPrivateKey(privKey); - return CKR_TEMPLATE_INCOMPLETE; + crv = CKR_TEMPLATE_INCOMPLETE; + rv = SECFailure; + goto fail; } - if (slot->keyDB->version != 3) { + if (keyHandle->version != 3) { unsigned char buf[SHA1_LENGTH]; SHA1_HashBuf(buf,pubKey.data,pubKey.len); PORT_Memcpy(pubKey.data,buf,sizeof(buf)); @@ -1350,15 +1375,16 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE goto fail; } } - rv = nsslowkey_StoreKeyByPublicKey(object->slot->keyDB, - privKey, &pubKey, label, object->slot->password); + rv = nsslowkey_StoreKeyByPublicKey(keyHandle, privKey, &pubKey, + label, slot->password); fail: + sftk_freeKeyDB(keyHandle); if (label) PORT_Free(label); object->handle = sftk_mkHandle(slot,&pubKey,SFTK_TOKEN_TYPE_PRIV); if (pubKey.data) PORT_Free(pubKey.data); nsslowkey_DestroyPrivateKey(privKey); - if (rv != SECSuccess) return CKR_DEVICE_ERROR; + if (rv != SECSuccess) return crv; } else { object->objectInfo = sftk_mkPrivKey(object,key_type,&crv); if (object->objectInfo == NULL) return crv; @@ -1522,7 +1548,8 @@ sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object, CK_KEY_TYPE key_type, PRBool isFIPS) { CK_RV crv; - NSSLOWKEYPrivateKey *privKey = NULL; + NSSLOWKEYPrivateKey *privKey = NULL; + NSSLOWKEYDBHandle *keyHandle = NULL; SECItem pubKey; char *label = NULL; @@ -1536,8 +1563,9 @@ sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object, if (sftk_isTrue(object,CKA_TOKEN)) { SFTKSlot *slot = session->slot; SECStatus rv = SECSuccess; + keyHandle = sftk_getKeyDB(slot); - if (slot->keyDB == NULL) { + if (keyHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } @@ -1553,21 +1581,20 @@ sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object, PORT_Free(pubKey.data); pubKey.data = NULL; } - crv = sftk_GenerateSecretCKA_ID(slot->keyDB, &pubKey, label); + crv = sftk_GenerateSecretCKA_ID(keyHandle, &pubKey, label); if (crv != CKR_OK) goto loser; crv = sftk_forceAttribute(object, CKA_ID, pubKey.data, pubKey.len); if (crv != CKR_OK) goto loser; } - privKey=sftk_mkSecretKeyRep(object); + privKey = sftk_mkSecretKeyRep(object); if (privKey == NULL) { crv = CKR_HOST_MEMORY; goto loser; } - PORT_Assert(slot->keyDB); - rv = nsslowkey_StoreKeyByPublicKey(slot->keyDB, + rv = nsslowkey_StoreKeyByPublicKey(keyHandle, privKey, &pubKey, label, slot->password); if (rv != SECSuccess) { crv = CKR_DEVICE_ERROR; @@ -1578,6 +1605,7 @@ sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object, } loser: + if (keyHandle) sftk_freeKeyDB(keyHandle); if (label) PORT_Free(label); if (privKey) nsslowkey_DestroyPrivateKey(privKey); if (pubKey.data) PORT_Free(pubKey.data); @@ -2095,10 +2123,8 @@ sftk_GetPrivKey(SFTKObject *object,CK_KEY_TYPE key_type, CK_RV *crvp) SFTKTokenObject *to = sftk_narrowToTokenObject(object); PORT_Assert(to); - PORT_Assert(object->slot->keyDB); - priv = nsslowkey_FindKeyByPublicKey(object->slot->keyDB, &to->dbKey, - object->slot->password); - *crvp = priv ? CKR_OK : CKR_DEVICE_ERROR; + priv = sftk_FindKeyByPublicKey(object->slot, &to->dbKey); + *crvp = (priv == NULL) ? CKR_DEVICE_ERROR : CKR_OK; } else { priv = sftk_mkPrivKey(object, key_type, crvp); } @@ -2347,7 +2373,7 @@ static PLHashTable *nscSlotHashTable[2] = {NULL, NULL}; static int sftk_GetModuleIndex(CK_SLOT_ID slotID) { - if ((slotID == FIPS_SLOT_ID) || (slotID > 100)) { + if ((slotID == FIPS_SLOT_ID) || (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID)) { return NSC_FIPS_MODULE; } return NSC_NON_FIPS_MODULE; @@ -2355,12 +2381,18 @@ sftk_GetModuleIndex(CK_SLOT_ID slotID) /* look up a slot structure from the ID (used to be a macro when we only * had two slots) */ +/* if all is true, return the slot even if it has been 'unloaded' */ +/* if all is false, only return the slots which are present */ SFTKSlot * -sftk_SlotFromID(CK_SLOT_ID slotID) +sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all) { + SFTKSlot *slot; int index = sftk_GetModuleIndex(slotID); - return (SFTKSlot *)PL_HashTableLookupConst(nscSlotHashTable[index], + slot = (SFTKSlot *)PL_HashTableLookupConst(nscSlotHashTable[index], (void *)slotID); + /* cleared slots shouldn't 'show up' */ + if (slot && !all && !slot->present) slot = NULL; + return slot; } SFTKSlot * @@ -2373,7 +2405,7 @@ sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle) return NULL; } - return sftk_SlotFromID(nscSlotList[moduleIndex][slotIDIndex]); + return sftk_SlotFromID(nscSlotList[moduleIndex][slotIDIndex], PR_FALSE); } static CK_RV @@ -2428,13 +2460,19 @@ sftk_RegisterSlot(SFTKSlot *slot, int moduleIndex) return CKR_OK; } +typedef struct sftk_DBsStr { + NSSLOWCERTCertDBHandle *certHandle; + NSSLOWKEYDBHandle *keyHandle; +} sftkDBs; + static SECStatus sftk_set_user(NSSLOWCERTCertificate *cert, SECItem *dummy, void *arg) { - SFTKSlot *slot = (SFTKSlot *)arg; + sftkDBs *param = (sftkDBs *)arg; NSSLOWCERTCertTrust trust = *cert->trust; - if (nsslowkey_KeyForCertExists(slot->keyDB,cert)) { + if (param->keyHandle && + nsslowkey_KeyForCertExists(param->keyHandle,cert)) { trust.sslFlags |= CERTDB_USER; trust.emailFlags |= CERTDB_USER; trust.objectSigningFlags |= CERTDB_USER; @@ -2445,26 +2483,120 @@ sftk_set_user(NSSLOWCERTCertificate *cert, SECItem *dummy, void *arg) } if (PORT_Memcmp(&trust,cert->trust, sizeof (trust)) != 0) { - nsslowcert_ChangeCertTrust(slot->certDB,cert, &trust); + nsslowcert_ChangeCertTrust(param->certHandle, cert, &trust); } /* should check for email address and make sure we have an s/mime profile */ return SECSuccess; } +/* + * this function fixes up old databases that may not have the CERTDB_USER + * flags set correctly. it expects the owner already has references to + * the cert and key handles. + */ static void -sftk_DBVerify(SFTKSlot *slot) +sftk_DBVerify(NSSLOWCERTCertDBHandle *certHandle, NSSLOWKEYDBHandle *keyHandle) { /* walk through all the certs and check to see if there are any * user certs, and make sure there are s/mime profiles for all certs with * email addresses */ - nsslowcert_TraversePermCerts(slot->certDB,sftk_set_user,slot); + sftkDBs param; + param.certHandle = certHandle; + param.keyHandle = keyHandle; + + nsslowcert_TraversePermCerts(certHandle, sftk_set_user, ¶m); return; } -/* forward static declaration. */ -static CK_RV sftk_DestroySlotData(SFTKSlot *slot); + +/* + * ths function has all the common initialization that happens whenever we + * create a new slot or repurpose an old slot (only valid for slotID's 4 + * and greater). + * + * things that are not reinitialized are: + * slotID (can't change) + * slotDescription (can't change once defined) + * the locks and hash tables (difficult to change in running code, and + * unnecessary. hash tables and list are cleared on shutdown, but they + * are cleared in a 'friendly' way). + * session and object ID counters -- so any old sessions and objects in the + * application will get properly notified that the world has changed. + * + * things that are reinitialized: + * database (otherwise what would the point be;). + * state variables related to databases. + * session count stat info. + * tokenDescription. + * + * NOTE: slotID's 4 and greater show up as removable devices. + * + */ +CK_RV +SFTK_SlotReInit(SFTKSlot *slot, + char *configdir,sftk_token_parameters *params, int moduleIndex) +{ + PRBool needLogin = !params->noKeyDB; + CK_RV crv; + + slot->hasTokens = PR_FALSE; + slot->sessionIDConflict = 0; + slot->sessionCount = 0; + slot->rwSessionCount = 0; + slot->needLogin = PR_FALSE; + slot->isLoggedIn = PR_FALSE; + slot->ssoLoggedIn = PR_FALSE; + slot->DB_loaded = PR_FALSE; + slot->certDB = NULL; + slot->keyDB = NULL; + slot->minimumPinLen = 0; + slot->readOnly = params->readOnly; + sftk_setStringName(params->tokdes ? params->tokdes : + sftk_getDefTokName(slot->slotID), slot->tokDescription, + sizeof(slot->tokDescription)); + + if ((!params->noCertDB) || (!params->noKeyDB)) { + NSSLOWCERTCertDBHandle * certHandle = NULL; + NSSLOWKEYDBHandle *keyHandle = NULL; + crv = sftk_DBInit(params->configdir ? params->configdir : configdir, + params->certPrefix, params->keyPrefix, params->readOnly, + params->noCertDB, params->noKeyDB, params->forceOpen, + &certHandle, &keyHandle); + if (crv != CKR_OK) { + goto loser; + } + + if (nsslowcert_needDBVerify(certHandle)) { + sftk_DBVerify(certHandle, keyHandle); + } + slot->certDB = certHandle; + slot->keyDB = keyHandle; + } + if (needLogin) { + /* if the data base is initialized with a null password,remember that */ + slot->needLogin = + (PRBool)!sftk_hasNullPassword(slot->keyDB,&slot->password); + if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) { + slot->minimumPinLen = params->minPW; + } + if ((slot->minimumPinLen == 0) && (params->pwRequired)) { + slot->minimumPinLen = 1; + } + if ((moduleIndex == NSC_FIPS_MODULE) && + (slot->minimumPinLen < FIPS_MIN_PIN)) { + slot->minimumPinLen = FIPS_MIN_PIN; + } + } + + slot->present = PR_TRUE; + return CKR_OK; + +loser: + SFTK_ShutdownSlot(slot); + return crv; +} /* * initialize one of the slot structures. figure out which by the ID @@ -2474,9 +2606,15 @@ SFTK_SlotInit(char *configdir,sftk_token_parameters *params, int moduleIndex) { unsigned int i; CK_SLOT_ID slotID = params->slotID; - SFTKSlot *slot = PORT_ZNew(SFTKSlot); - PRBool needLogin = !params->noKeyDB; - CK_RV crv; + SFTKSlot *slot; + CK_RV crv = CKR_HOST_MEMORY; + + /* + * first we initialize everything that is 'permanent' with this slot. + * that is everything we aren't going to shutdown if we close this slot + * and open it up again with different databases */ + + slot = PORT_ZNew(SFTKSlot); if (slot == NULL) { return CKR_HOST_MEMORY; @@ -2522,56 +2660,18 @@ SFTK_SlotInit(char *configdir,sftk_token_parameters *params, int moduleIndex) if (slot->tokenHashTable == NULL) goto mem_loser; - slot->password = NULL; - slot->hasTokens = PR_FALSE; slot->sessionIDCount = 0; - slot->sessionIDConflict = 0; - slot->sessionCount = 0; - slot->rwSessionCount = 0; slot->tokenIDCount = 1; - slot->needLogin = PR_FALSE; - slot->isLoggedIn = PR_FALSE; - slot->ssoLoggedIn = PR_FALSE; - slot->DB_loaded = PR_FALSE; slot->slotID = slotID; - slot->certDB = NULL; - slot->keyDB = NULL; - slot->minimumPinLen = 0; - slot->readOnly = params->readOnly; - sftk_setStringName(params->tokdes ? params->tokdes : - sftk_getDefTokName(slotID), slot->tokDescription, - sizeof(slot->tokDescription)); sftk_setStringName(params->slotdes ? params->slotdes : - sftk_getDefSlotName(slotID), slot->slotDescription, + sftk_getDefSlotName(slotID), slot->slotDescription, sizeof(slot->slotDescription)); - if ((!params->noCertDB) || (!params->noKeyDB)) { - crv = sftk_DBInit(params->configdir ? params->configdir : configdir, - params->certPrefix, params->keyPrefix, params->readOnly, - params->noCertDB, params->noKeyDB, params->forceOpen, - &slot->certDB, &slot->keyDB); - if (crv != CKR_OK) { - goto loser; - } - - if (nsslowcert_needDBVerify(slot->certDB)) { - sftk_DBVerify(slot); - } - } - if (needLogin) { - /* if the data base is initialized with a null password,remember that */ - slot->needLogin = - (PRBool)!sftk_hasNullPassword(slot->keyDB,&slot->password); - if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) { - slot->minimumPinLen = params->minPW; - } - if ((slot->minimumPinLen == 0) && (params->pwRequired)) { - slot->minimumPinLen = 1; - } - if ((moduleIndex == NSC_FIPS_MODULE) && - (slot->minimumPinLen < FIPS_MIN_PIN)) { - slot->minimumPinLen = FIPS_MIN_PIN; - } + /* call the reinit code to set everything that changes between token + * init calls */ + crv = SFTK_SlotReInit(slot, configdir, params, moduleIndex); + if (crv != CKR_OK) { + goto loser; } crv = sftk_RegisterSlot(slot, moduleIndex); if (crv != CKR_OK) { @@ -2582,27 +2682,145 @@ SFTK_SlotInit(char *configdir,sftk_token_parameters *params, int moduleIndex) mem_loser: crv = CKR_HOST_MEMORY; loser: - sftk_DestroySlotData(slot); + SFTK_DestroySlotData(slot); return crv; } -static PRIntn -sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg) + +static CK_RV sft_CloseAllSession(SFTKSlot *slot) { - SECItem *item = (SECItem *)entry->value; + SECItem *pw = NULL; + SFTKSession *session; + unsigned int i; + /* first log out the card */ + PZ_Lock(slot->slotLock); + pw = slot->password; + slot->isLoggedIn = PR_FALSE; + slot->password = NULL; + PZ_Unlock(slot->slotLock); + if (pw) SECITEM_ZfreeItem(pw, PR_TRUE); - SECITEM_FreeItem(item, PR_TRUE); - return HT_ENUMERATE_NEXT; + /* now close all the current sessions */ + /* NOTE: If you try to open new sessions before NSC_CloseAllSessions + * completes, some of those new sessions may or may not be closed by + * NSC_CloseAllSessions... but any session running when this code starts + * will guarrenteed be close, and no session will be partially closed */ + for (i=0; i < slot->sessHashSize; i++) { + PZLock *lock = SFTK_SESSION_LOCK(slot,i); + do { + PZ_Lock(lock); + session = slot->head[i]; + /* hand deque */ + /* this duplicates function of NSC_close session functions, but + * because we know that we are freeing all the sessions, we can + * do more efficient processing */ + if (session) { + slot->head[i] = session->next; + if (session->next) session->next->prev = NULL; + session->next = session->prev = NULL; + PZ_Unlock(lock); + PZ_Lock(slot->slotLock); + --slot->sessionCount; + PZ_Unlock(slot->slotLock); + if (session->info.flags & CKF_RW_SESSION) { + PR_AtomicDecrement(&slot->rwSessionCount); + } + } else { + PZ_Unlock(lock); + } + if (session) sftk_FreeSession(session); + } while (session != NULL); + } + return CKR_OK; +} + +/* + * shut down the databases. + * we get the slot lock (which also protects slot->certDB and slot->keyDB) + * and clear the values so the new users will not find the databases. + * once things are clear, we can release our references to the databases. + * The databases will close when the last reference is released. + * + * We use reference counts so that we don't crash if someone shuts down + * a token that another thread is actively using. + */ +static void +sftk_DBShutdown(SFTKSlot *slot) +{ + NSSLOWCERTCertDBHandle *certHandle; + NSSLOWKEYDBHandle *keyHandle; + PZ_Lock(slot->slotLock); + certHandle = slot->certDB; + slot->certDB = NULL; + keyHandle = slot->keyDB; + slot->keyDB = NULL; + PZ_Unlock(slot->slotLock); + if (certHandle) { + sftk_freeCertDB(certHandle); + } + if (keyHandle) { + sftk_freeKeyDB(keyHandle); + } +} + +CK_RV +SFTK_ShutdownSlot(SFTKSlot *slot) +{ + /* make sure no new PK11 calls work except C_GetSlotInfo */ + slot->present = PR_FALSE; + + /* close all outstanding sessions + * the sessHashSize variable guarentees we have all the session + * mechanism set up */ + if (slot->head) { + sft_CloseAllSession(slot); + } + + /* clear all objects.. session objects are cleared as a result of + * closing all the sessions. We just need to clear the token object + * cache. slot->tokenHashTable guarentees we have the token + * infrastructure set up. */ + if (slot->tokenHashTable) { + SFTK_ClearTokenKeyHashTable(slot); + } + + /* clear the slot description for the next guy */ + PORT_Memset(slot->tokDescription, 0, sizeof(slot->tokDescription)); + + /* now shut down the databases. */ + sftk_DBShutdown(slot); + return CKR_OK; } /* * initialize one of the slot structures. figure out which by the ID */ -static CK_RV -sftk_DestroySlotData(SFTKSlot *slot) +CK_RV +SFTK_DestroySlotData(SFTKSlot *slot) { unsigned int i; + SFTK_ShutdownSlot(slot); + + if (slot->tokenHashTable) { + PL_HashTableDestroy(slot->tokenHashTable); + slot->tokenHashTable = NULL; + } + + if (slot->tokObjects) { + PORT_Free(slot->tokObjects); + slot->tokObjects = NULL; + } + slot->tokObjHashSize = 0; + + if (slot->head) { + PORT_Free(slot->head); + slot->head = NULL; + } + slot->sessHashSize = 0; + + /* OK everything has been disassembled, now we can finally get rid + * of the locks */ if (slot->slotLock) { PZ_DestroyLock(slot->slotLock); slot->slotLock = NULL; @@ -2625,36 +2843,6 @@ sftk_DestroySlotData(SFTKSlot *slot) PR_DestroyLock(slot->pwCheckLock); slot->pwCheckLock = NULL; } - - if (slot->tokenHashTable) { - PL_HashTableEnumerateEntries(slot->tokenHashTable, - sftk_freeHashItem,NULL); - PL_HashTableDestroy(slot->tokenHashTable); - slot->tokenHashTable = NULL; - } - - if (slot->tokObjects) { - for(i=0; i < slot->tokObjHashSize; i++) { - SFTKObject *object = slot->tokObjects[i]; - slot->tokObjects[i] = NULL; - if (object) sftk_FreeObject(object); - } - PORT_Free(slot->tokObjects); - slot->tokObjects = NULL; - } - slot->tokObjHashSize = 0; - if (slot->head) { - for(i=0; i < slot->sessHashSize; i++) { - SFTKSession *session = slot->head[i]; - slot->head[i] = NULL; - if (session) sftk_FreeSession(session); - } - PORT_Free(slot->head); - slot->head = NULL; - } - slot->sessHashSize = 0; - sftk_DBShutdown(slot->certDB,slot->keyDB); - PORT_Free(slot); return CKR_OK; } @@ -2727,7 +2915,7 @@ static void nscFreeAllSlots(int moduleIndex) PL_HashTableLookup(tmpSlotHashTable, (void *)slotID); PORT_Assert(slot); if (!slot) continue; - sftk_DestroySlotData(slot); + SFTK_DestroySlotData(slot); PL_HashTableRemove(tmpSlotHashTable, (void *)slotID); } PORT_Free(tmpSlotList); @@ -2747,9 +2935,7 @@ sftk_closePeer(PRBool isFIPS) if (slot == NULL) { return; } - sftk_DBShutdown(slot->certDB,slot->keyDB); - slot->certDB = NULL; - slot->keyDB = NULL; + sftk_DBShutdown(slot); return; } @@ -2839,8 +3025,8 @@ CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS) } for (i=0; i < paramStrings.token_count; i++) { - crv = - SFTK_SlotInit(paramStrings.configdir, ¶mStrings.tokens[i], + crv = SFTK_SlotInit(paramStrings.configdir, + ¶mStrings.tokens[i], moduleIndex); if (crv != CKR_OK) { nscFreeAllSlots(moduleIndex); @@ -2972,7 +3158,7 @@ CK_RV NSC_GetSlotList(CK_BBOOL tokenPresent, /* NSC_GetSlotInfo obtains information about a particular slot in the system. */ CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { - SFTKSlot *slot = sftk_SlotFromID(slotID); + SFTKSlot *slot = sftk_SlotFromID(slotID, PR_TRUE); if (slot == NULL) return CKR_SLOT_ID_INVALID; pInfo->firmwareVersion.major = 0; @@ -2980,7 +3166,11 @@ CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) PORT_Memcpy(pInfo->manufacturerID,manufacturerID,32); PORT_Memcpy(pInfo->slotDescription,slot->slotDescription,64); - pInfo->flags = CKF_TOKEN_PRESENT; + pInfo->flags = (slot->present) ? CKF_TOKEN_PRESENT : 0; + /* all user defined slots are defined as removable */ + if (slotID >= SFTK_MIN_USER_SLOT_ID) { + pInfo->flags |= CKF_REMOVABLE_DEVICE; + } /* ok we really should read it out of the keydb file. */ /* pInfo->hardwareVersion.major = NSSLOWKEY_DB_FILE_VERSION; */ pInfo->hardwareVersion.major = NSS_VMAJOR; @@ -2994,11 +3184,12 @@ CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) * been changed underneath us. */ static PRBool -sftk_checkNeedLogin(SFTKSlot *slot) +sftk_checkNeedLogin(SFTKSlot *slot, NSSLOWKEYDBHandle *keyHandle) { if (slot->password) { - if (nsslowkey_CheckKeyDBPassword(slot->keyDB,slot->password) - == SECSuccess) { + SECStatus rv; + rv = nsslowkey_CheckKeyDBPassword(keyHandle,slot->password); + if ( rv == SECSuccess) { return slot->needLogin; } else { SECITEM_FreeItem(slot->password, PR_TRUE); @@ -3007,7 +3198,7 @@ sftk_checkNeedLogin(SFTKSlot *slot) } } slot->needLogin = - (PRBool)!sftk_hasNullPassword(slot->keyDB,&slot->password); + (PRBool)!sftk_hasNullPassword(keyHandle,&slot->password); return (slot->needLogin); } @@ -3015,7 +3206,7 @@ sftk_checkNeedLogin(SFTKSlot *slot) * the system. */ CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo) { - SFTKSlot *slot = sftk_SlotFromID(slotID); + SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE); NSSLOWKEYDBHandle *handle; if (slot == NULL) return CKR_SLOT_ID_INVALID; @@ -3030,7 +3221,7 @@ CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo) pInfo->firmwareVersion.major = 0; pInfo->firmwareVersion.minor = 0; PORT_Memcpy(pInfo->label,slot->tokDescription,32); - handle = slot->keyDB; + handle = sftk_getKeyDB(slot); if (handle == NULL) { pInfo->flags= CKF_RNG | CKF_WRITE_PROTECTED | CKF_THREAD_SAFE; pInfo->ulMaxPinLen = 0; @@ -3053,7 +3244,7 @@ CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo) */ if (nsslowkey_HasKeyDBPassword(handle) == SECFailure) { pInfo->flags = CKF_THREAD_SAFE | CKF_LOGIN_REQUIRED; - } else if (!sftk_checkNeedLogin(slot)) { + } else if (!sftk_checkNeedLogin(slot,handle)) { pInfo->flags = CKF_THREAD_SAFE | CKF_USER_PIN_INITIALIZED; } else { pInfo->flags = CKF_THREAD_SAFE | @@ -3067,6 +3258,7 @@ CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo) pInfo->ulFreePrivateMemory = 1; pInfo->hardwareVersion.major = CERT_DB_FILE_VERSION; pInfo->hardwareVersion.minor = handle->version; + sftk_freeKeyDB(handle); } return CKR_OK; } @@ -3181,7 +3373,7 @@ sftk_TurnOffUser(NSSLOWCERTCertificate *cert, SECItem *k, void *arg) /* NSC_InitToken initializes a token. */ CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin, CK_ULONG ulPinLen,CK_CHAR_PTR pLabel) { - SFTKSlot *slot = sftk_SlotFromID(slotID); + SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE); NSSLOWKEYDBHandle *handle; NSSLOWCERTCertDBHandle *certHandle; SECStatus rv; @@ -3220,19 +3412,23 @@ CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin, PZ_Unlock(slot->objectLock); /* then clear out the key database */ - handle = slot->keyDB; + handle = sftk_getKeyDB(slot); if (handle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } - /* what to do on an error here? */ rv = nsslowkey_ResetKeyDB(handle); + sftk_freeKeyDB(handle); + if (rv != SECSuccess) { + return CKR_DEVICE_ERROR; + } /* finally mark all the user certs as non-user certs */ - certHandle = slot->certDB; + certHandle = sftk_getCertDB(slot); if (certHandle == NULL) return CKR_OK; nsslowcert_TraversePermCerts(certHandle,sftk_TurnOffUser, NULL); + sftk_freeCertDB(certHandle); return CKR_OK; /*is this the right function for not implemented*/ } @@ -3242,49 +3438,53 @@ CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin, CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) { - SFTKSession *sp; + SFTKSession *sp = NULL; SFTKSlot *slot; - NSSLOWKEYDBHandle *handle; + NSSLOWKEYDBHandle *handle = NULL; SECItem *newPin; char newPinStr[SFTK_MAX_PIN+1]; SECStatus rv; + CK_RV crv = CKR_SESSION_HANDLE_INVALID; sp = sftk_SessionFromHandle(hSession); if (sp == NULL) { - return CKR_SESSION_HANDLE_INVALID; + goto loser; } slot = sftk_SlotFromSession(sp); if (slot == NULL) { - sftk_FreeSession(sp); - return CKR_SESSION_HANDLE_INVALID;; + goto loser; } - handle = slot->keyDB; + handle = sftk_getKeyDB(slot); if (handle == NULL) { - sftk_FreeSession(sp); - return CKR_PIN_LEN_RANGE; + crv = CKR_PIN_LEN_RANGE; + goto loser; } if (sp->info.state != CKS_RW_SO_FUNCTIONS) { - sftk_FreeSession(sp); - return CKR_USER_NOT_LOGGED_IN; + crv = CKR_USER_NOT_LOGGED_IN; + goto loser; } sftk_FreeSession(sp); + sp = NULL; /* make sure the pins aren't too long */ if (ulPinLen > SFTK_MAX_PIN) { - return CKR_PIN_LEN_RANGE; + crv = CKR_PIN_LEN_RANGE; + goto loser; } if (ulPinLen < (CK_ULONG)slot->minimumPinLen) { - return CKR_PIN_LEN_RANGE; + crv = CKR_PIN_LEN_RANGE; + goto loser; } if (nsslowkey_HasKeyDBPassword(handle) != SECFailure) { - return CKR_DEVICE_ERROR; + crv = CKR_DEVICE_ERROR; + goto loser; } /* convert to null terminated string */ @@ -3297,6 +3497,8 @@ CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession, /* change the data base */ rv = nsslowkey_SetKeyDBPassword(handle,newPin); + sftk_freeKeyDB(handle); + handle = NULL; /* Now update our local copy of the pin */ if (rv == SECSuccess) { @@ -3308,7 +3510,16 @@ CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession, return CKR_OK; } SECITEM_ZfreeItem(newPin, PR_TRUE); - return CKR_PIN_INCORRECT; + crv = CKR_PIN_INCORRECT; + +loser: + if (sp) { + sftk_FreeSession(sp); + } + if (handle) { + sftk_freeKeyDB(handle); + } + return crv; } @@ -3317,45 +3528,48 @@ CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession, CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen) { - SFTKSession *sp; + SFTKSession *sp = NULL; SFTKSlot *slot; - NSSLOWKEYDBHandle *handle; + NSSLOWKEYDBHandle *handle = NULL; SECItem *newPin; SECItem *oldPin; char newPinStr[SFTK_MAX_PIN+1],oldPinStr[SFTK_MAX_PIN+1]; SECStatus rv; + CK_RV crv = CKR_SESSION_HANDLE_INVALID; sp = sftk_SessionFromHandle(hSession); if (sp == NULL) { - return CKR_SESSION_HANDLE_INVALID; + goto loser; } slot = sftk_SlotFromSession(sp); if (!slot) { - sftk_FreeSession(sp); - return CKR_SESSION_HANDLE_INVALID;; + goto loser; } - handle = slot->keyDB; + handle = sftk_getKeyDB(slot); if (handle == NULL) { sftk_FreeSession(sp); return CKR_PIN_LEN_RANGE; } if (slot->needLogin && sp->info.state != CKS_RW_USER_FUNCTIONS) { - sftk_FreeSession(sp); - return CKR_USER_NOT_LOGGED_IN; + crv = CKR_USER_NOT_LOGGED_IN; + goto loser; } sftk_FreeSession(sp); + sp = NULL; /* make sure the pins aren't too long */ if ((ulNewLen > SFTK_MAX_PIN) || (ulOldLen > SFTK_MAX_PIN)) { - return CKR_PIN_LEN_RANGE; + crv = CKR_PIN_LEN_RANGE; + goto loser; } if (ulNewLen < (CK_ULONG)slot->minimumPinLen) { - return CKR_PIN_LEN_RANGE; + crv = CKR_PIN_LEN_RANGE; + goto loser; } @@ -3374,6 +3588,8 @@ CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, /* change the data base password */ PR_Lock(slot->pwCheckLock); rv = nsslowkey_ChangeKeyDBPassword(handle,oldPin,newPin); + sftk_freeKeyDB(handle); + handle = NULL; if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) { PR_Sleep(loginWaitTime); } @@ -3390,7 +3606,15 @@ CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, return CKR_OK; } SECITEM_ZfreeItem(newPin, PR_TRUE); - return CKR_PIN_INCORRECT; + crv = CKR_PIN_INCORRECT; +loser: + if (sp) { + sftk_FreeSession(sp); + } + if (handle) { + sftk_freeKeyDB(handle); + } + return crv; } /* NSC_OpenSession opens a session between an application and a token. */ @@ -3402,7 +3626,7 @@ CK_RV NSC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, SFTKSession *session; SFTKSession *sameID; - slot = sftk_SlotFromID(slotID); + slot = sftk_SlotFromID(slotID, PR_FALSE); if (slot == NULL) return CKR_SLOT_ID_INVALID; /* new session (we only have serial sessions) */ @@ -3493,56 +3717,15 @@ CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession) CK_RV NSC_CloseAllSessions (CK_SLOT_ID slotID) { SFTKSlot *slot; - SECItem *pw = NULL; - SFTKSession *session; - unsigned int i; - slot = sftk_SlotFromID(slotID); + slot = sftk_SlotFromID(slotID, PR_FALSE); if (slot == NULL) return CKR_SLOT_ID_INVALID; - /* first log out the card */ - PZ_Lock(slot->slotLock); - pw = slot->password; - slot->isLoggedIn = PR_FALSE; - slot->password = NULL; - PZ_Unlock(slot->slotLock); - if (pw) SECITEM_ZfreeItem(pw, PR_TRUE); - - /* now close all the current sessions */ - /* NOTE: If you try to open new sessions before NSC_CloseAllSessions - * completes, some of those new sessions may or may not be closed by - * NSC_CloseAllSessions... but any session running when this code starts - * will guarrenteed be close, and no session will be partially closed */ - for (i=0; i < slot->sessHashSize; i++) { - PZLock *lock = SFTK_SESSION_LOCK(slot,i); - do { - PZ_Lock(lock); - session = slot->head[i]; - /* hand deque */ - /* this duplicates function of NSC_close session functions, but - * because we know that we are freeing all the sessions, we can - * do more efficient processing */ - if (session) { - slot->head[i] = session->next; - if (session->next) session->next->prev = NULL; - session->next = session->prev = NULL; - PZ_Unlock(lock); - PZ_Lock(slot->slotLock); - --slot->sessionCount; - PZ_Unlock(slot->slotLock); - if (session->info.flags & CKF_RW_SESSION) { - PR_AtomicDecrement(&slot->rwSessionCount); - } - } else { - PZ_Unlock(lock); - } - if (session) sftk_FreeSession(session); - } while (session != NULL); - } - return CKR_OK; + return sft_CloseAllSession(slot); } + /* NSC_GetSessionInfo obtains information about the session. */ CK_RV NSC_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) @@ -3565,9 +3748,10 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, SFTKSession *session; NSSLOWKEYDBHandle *handle; CK_FLAGS sessionFlags; + SECStatus rv; + CK_RV crv; SECItem *pin; char pinStr[SFTK_MAX_PIN+1]; - SECStatus rv; /* get the slot */ @@ -3575,14 +3759,17 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, /* make sure the session is valid */ session = sftk_SessionFromHandle(hSession); - if (session == NULL) return CKR_SESSION_HANDLE_INVALID; + if (session == NULL) { + return CKR_SESSION_HANDLE_INVALID; + } sessionFlags = session->info.flags; sftk_FreeSession(session); session = NULL; /* can't log into the Netscape Slot */ - if (slot->slotID == NETSCAPE_SLOT_ID) + if (slot->slotID == NETSCAPE_SLOT_ID) { return CKR_USER_TYPE_INVALID; + } if (slot->isLoggedIn) return CKR_USER_ALREADY_LOGGED_IN; slot->ssoLoggedIn = PR_FALSE; @@ -3593,7 +3780,7 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, PORT_Memcpy(pinStr,pPin,ulPinLen); pinStr[ulPinLen] = 0; - handle = slot->keyDB; + handle = sftk_getKeyDB(slot); if (handle == NULL) { return CKR_USER_TYPE_INVALID; } @@ -3603,7 +3790,8 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, * password if and only if we haven't initialized the KEY DB yet. * We only allow this on a RW session. */ - if (nsslowkey_HasKeyDBPassword(handle) == SECFailure) { + rv = nsslowkey_HasKeyDBPassword(handle); + if (rv == SECFailure) { /* allow SSO's to log in only if there is not password on the * key database */ if (((userType == CKU_SO) && (sessionFlags & CKF_RW_SESSION)) @@ -3620,23 +3808,34 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, PZ_Unlock(slot->slotLock); sftk_update_all_states(slot); SECITEM_ZfreeItem(pw,PR_TRUE); - return CKR_OK; + crv = CKR_OK; + goto done; } - return CKR_PIN_INCORRECT; + crv = CKR_PIN_INCORRECT; + goto done; } - return CKR_USER_TYPE_INVALID; + crv = CKR_USER_TYPE_INVALID; + goto done; } /* don't allow the SSO to log in if the user is already initialized */ - if (userType != CKU_USER) { return CKR_USER_TYPE_INVALID; } + if (userType != CKU_USER) { + crv = CKR_USER_TYPE_INVALID; + goto done; + } /* build the hashed pins which we pass around */ pin = nsslowkey_HashPassword(pinStr,handle->global_salt); - if (pin == NULL) return CKR_HOST_MEMORY; + if (pin == NULL) { + crv = CKR_HOST_MEMORY; + goto done; + } PR_Lock(slot->pwCheckLock); rv = nsslowkey_CheckKeyDBPassword(handle,pin); + sftk_freeKeyDB(handle); + handle = NULL; if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) { PR_Sleep(loginWaitTime); } @@ -3656,7 +3855,12 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, } SECITEM_ZfreeItem(pin, PR_TRUE); - return CKR_PIN_INCORRECT; + crv = CKR_PIN_INCORRECT; +done: + if (handle) { + sftk_freeKeyDB(handle); + } + return crv; } /* NSC_Logout logs a user out from a token. */ @@ -3685,6 +3889,98 @@ CK_RV NSC_Logout(CK_SESSION_HANDLE hSession) return CKR_OK; } +/* + * Create a new slot on the fly. The slot that is passed in is the + * slot the request came from. Only the crypto or FIPS slots can + * be used. The resulting slot will live in the same module as + * the slot the request was passed to. object is the creation object + * that specifies the module spec for the new slot. + */ +static CK_RV sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class, + SFTKObject *object) +{ + CK_SLOT_ID idMin, idMax; + PRBool isFIPS = PR_FALSE; + unsigned long moduleIndex; + SFTKAttribute *attribute; + sftk_parameters paramStrings; + char *paramString; + CK_SLOT_ID slotID = 0; + SFTKSlot *newSlot = NULL; + CK_RV crv = CKR_OK; + + /* only the crypto or FIPS slots can create new slot objects */ + if (slot->slotID == NETSCAPE_SLOT_ID) { + idMin = SFTK_MIN_USER_SLOT_ID; + idMax = SFTK_MAX_USER_SLOT_ID; + moduleIndex = NSC_NON_FIPS_MODULE; + isFIPS = PR_FALSE; + } else if (slot->slotID == FIPS_SLOT_ID) { + idMin = SFTK_MIN_FIPS_USER_SLOT_ID; + idMax = SFTK_MAX_FIPS_USER_SLOT_ID; + moduleIndex = NSC_FIPS_MODULE; + isFIPS = PR_TRUE; + } else { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + attribute = sftk_FindAttribute(object,CKA_NETSCAPE_MODULE_SPEC); + if (attribute == NULL) { + return CKR_TEMPLATE_INCOMPLETE; + } + paramString = (unsigned char *)attribute->attrib.pValue; + crv = secmod_parseParameters(paramString, ¶mStrings, isFIPS); + if (crv != CKR_OK) { + goto loser; + } + + /* enforce only one at a time */ + if (paramStrings.token_count != 1) { + crv = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + + slotID = paramStrings.tokens[0].slotID; + + /* stay within the valid ID space */ + if ((slotID < idMin) || (slotID > idMax)) { + crv = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + + /* unload any existing slot at this id */ + newSlot = sftk_SlotFromID(slotID, PR_TRUE); + if (newSlot && newSlot->present) { + crv = SFTK_ShutdownSlot(newSlot); + if (crv != CKR_OK) { + goto loser; + } + } + + /* if we were just planning on deleting the slot, then do so now */ + if (class == CKO_NETSCAPE_DELSLOT) { + /* sort of a unconventional use of this error code, be we are + * overusing CKR_ATTRIBUTE_VALUE_INVALID, and it does apply */ + crv = newSlot ? CKR_OK : CKR_SLOT_ID_INVALID; + goto loser; /* really exit */ + } + + if (newSlot) { + crv = SFTK_SlotReInit(newSlot, paramStrings.configdir, + ¶mStrings.tokens[0], moduleIndex); + } else { + crv = SFTK_SlotInit(paramStrings.configdir, + ¶mStrings.tokens[0], moduleIndex); + } + if (crv != CKR_OK) { + goto loser; + } +loser: + secmod_freeParams(¶mStrings); + sftk_FreeAttribute(attribute); + + return crv; +} + /* NSC_CreateObject creates a new object. */ CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession, @@ -3694,9 +3990,11 @@ CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession, SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); SFTKSession *session; SFTKObject *object; + CK_OBJECT_CLASS class; CK_RV crv; int i; + *phObject = CK_INVALID_HANDLE; /* * now lets create an object to hang the attributes off of @@ -3715,6 +4013,9 @@ CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession, sftk_FreeObject(object); return crv; } + if ((pTemplate[i].type == CKA_CLASS) && pTemplate[i].pValue) { + class = *(CK_OBJECT_CLASS *)pTemplate[i].pValue; + } } /* get the session */ @@ -3724,11 +4025,20 @@ CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession, return CKR_SESSION_HANDLE_INVALID; } + /* + * handle pseudo objects (CKO_NEWSLOT) + */ + if ((class == CKO_NETSCAPE_NEWSLOT) || (class == CKO_NETSCAPE_DELSLOT)) { + crv = sftk_CreateNewSlot(slot, class, object); + goto done; + } + /* * handle the base object stuff */ crv = sftk_handleObject(object,session); *phObject = object->handle; +done: sftk_FreeSession(session); sftk_FreeObject(object); @@ -3736,6 +4046,7 @@ CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession, } + /* NSC_CopyObject copies an object, creating a new object for the copy. */ CK_RV NSC_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, @@ -4021,7 +4332,7 @@ sftk_searchCrls(SFTKSlot *slot, SECItem *derSubject, PRBool isKrl, { NSSLOWCERTCertDBHandle *certHandle = NULL; - certHandle = slot->certDB; + certHandle = sftk_getCertDB(slot); if (certHandle == NULL) { return; } @@ -4047,6 +4358,7 @@ sftk_searchCrls(SFTKSlot *slot, SECItem *derSubject, PRBool isKrl, nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeKeyRevocation, sftk_crl_collect, (void *)&crlData); } + sftk_freeCertDB(certHandle); } /* @@ -4054,6 +4366,7 @@ sftk_searchCrls(SFTKSlot *slot, SECItem *derSubject, PRBool isKrl, */ typedef struct sftkKeyDataStr { SFTKSlot *slot; + NSSLOWKEYDBHandle *keyHandle; SFTKSearchResults *searchHandles; SECItem *id; CK_ATTRIBUTE *template; @@ -4079,7 +4392,7 @@ sftk_key_collect(DBT *key, DBT *data, void *arg) tmpDBKey.len = key->size; tmpDBKey.type = siBuffer; - PORT_Assert(slot->keyDB); + PORT_Assert(keyData->keyHandle); if (!keyData->strict && keyData->id) { SECItem result; PRBool haveMatch= PR_FALSE; @@ -4089,7 +4402,7 @@ sftk_key_collect(DBT *key, DBT *data, void *arg) if (keyData->id->len == 0) { /* Make sure this isn't a NSC_KEY */ - privKey = nsslowkey_FindKeyByPublicKey(keyData->slot->keyDB, + privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, keyData->slot->password); if (privKey) { haveMatch = isSecretKey(privKey) ? @@ -4132,7 +4445,7 @@ sftk_key_collect(DBT *key, DBT *data, void *arg) return SECSuccess; } - privKey = nsslowkey_FindKeyByPublicKey(keyData->slot->keyDB, &tmpDBKey, + privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, keyData->slot->password); if ( privKey == NULL ) { goto loser; @@ -4177,7 +4490,7 @@ sftk_searchKeys(SFTKSlot *slot, SECItem *key_id, PRBool isLoggedIn, sftkKeyData keyData; PRBool found = PR_FALSE; - keyHandle = slot->keyDB; + keyHandle = sftk_getKeyDB(slot); if (keyHandle == NULL) { return; } @@ -4204,19 +4517,20 @@ sftk_searchKeys(SFTKSlot *slot, SECItem *key_id, PRBool isLoggedIn, } /* don't do the traversal if we have an up to date db */ if (keyHandle->version != 3) { - return; + goto loser; } /* don't do the traversal if it can't possibly be the correct id */ /* all soft token id's are SHA1_HASH_LEN's */ if (key_id->len != SHA1_LENGTH) { - return; + goto loser; } if (found) { /* if we already found some keys, don't do the traversal */ - return; + goto loser; } } keyData.slot = slot; + keyData.keyHandle = keyHandle; keyData.searchHandles = search; keyData.id = key_id; keyData.template = pTemplate; @@ -4226,6 +4540,9 @@ sftk_searchKeys(SFTKSlot *slot, SECItem *key_id, PRBool isLoggedIn, keyData.strict = mustStrict ? mustStrict : NSC_STRICT; nsslowkey_TraverseKeys(keyHandle, sftk_key_collect, &keyData); +loser: + sftk_freeKeyDB(keyHandle); + } /* @@ -4339,7 +4656,7 @@ sftk_searchCertsAndTrust(SFTKSlot *slot, SECItem *derCert, SECItem *name, sftkCertData certData; int i; - certHandle = slot->certDB; + certHandle = sftk_getCertDB(slot); if (certHandle == NULL) return; certData.slot = slot; @@ -4425,10 +4742,11 @@ sftk_searchCertsAndTrust(SFTKSlot *slot, SECItem *derCert, SECItem *name, } else { /* we aren't filtering the certs, we are working on all, so turn * on the strict filters. */ - certData.strict = PR_TRUE; + certData.strict = PR_TRUE; sftk_CertSetupData(&certData,NSC_CERT_BLOCK_SIZE); nsslowcert_TraversePermCerts(certHandle, sftk_cert_collect2, &certData); } + sftk_freeCertDB(certHandle); /* * build the handles @@ -4459,13 +4777,14 @@ sftk_searchSMime(SFTKSlot *slot, SECItem *email, SFTKSearchResults *handles, NSSLOWCERTCertDBHandle *certHandle = NULL; certDBEntrySMime *entry; - certHandle = slot->certDB; + certHandle = sftk_getCertDB(slot); if (certHandle == NULL) return; if (email->data != NULL) { char *tmp_name = (char*)PORT_Alloc(email->len+1); if (tmp_name == NULL) { + sftk_freeCertDB(certHandle); return; } PORT_Memcpy(tmp_name,email->data,email->len); @@ -4484,6 +4803,7 @@ sftk_searchSMime(SFTKSlot *slot, SECItem *email, SFTKSearchResults *handles, } PORT_Free(tmp_name); } + sftk_freeCertDB(certHandle); return; } diff --git a/security/nss/lib/softoken/pkcs11i.h b/security/nss/lib/softoken/pkcs11i.h index 3374d66e8..0eaf5bf37 100644 --- a/security/nss/lib/softoken/pkcs11i.h +++ b/security/nss/lib/softoken/pkcs11i.h @@ -325,39 +325,56 @@ struct SFTKSessionStr { * password, isLoggedIn, ssoLoggedIn, and sessionCount, * and pwCheckLock serializes the key database password checks in * NSC_SetPIN and NSC_Login. + * + * Each of the fields below has the following lifetime as commented + * next to the fields: + * invariant - This value is set when the slot is first created and + * never changed until it is destroyed. + * per load - This value is set when the slot is first created, or + * when the slot is used to open another directory. Between open and close + * this field does not change. + * variable - This value changes through the normal process of slot operation. + * - reset. The value of this variable is cleared during an open/close + * cycles. + * - preserved. The value of this variable is preserved over open/close + * cycles. */ struct SFTKSlotStr { - CK_SLOT_ID slotID; - PZLock *slotLock; - PZLock **sessionLock; - unsigned int numSessionLocks; - unsigned long sessionLockMask; - PZLock *objectLock; - PRLock *pwCheckLock; - SECItem *password; - PRBool hasTokens; - PRBool isLoggedIn; - PRBool ssoLoggedIn; - PRBool needLogin; - PRBool DB_loaded; - PRBool readOnly; - PRBool optimizeSpace; - NSSLOWCERTCertDBHandle *certDB; - NSSLOWKEYDBHandle *keyDB; - int minimumPinLen; - PRInt32 sessionIDCount; /* atomically incremented */ - int sessionIDConflict; /* not protected by a lock */ - int sessionCount; - PRInt32 rwSessionCount; /* set by atomic operations */ - int tokenIDCount; - int index; - PLHashTable *tokenHashTable; - SFTKObject **tokObjects; - unsigned int tokObjHashSize; - SFTKSession **head; - unsigned int sessHashSize; - char tokDescription[33]; - char slotDescription[64]; + CK_SLOT_ID slotID; /* invariant */ + PZLock *slotLock; /* invariant */ + PZLock **sessionLock; /* invariant */ + unsigned int numSessionLocks; /* invariant */ + unsigned long sessionLockMask; /* invariant */ + PZLock *objectLock; /* invariant */ + PRLock *pwCheckLock; /* invariant */ + SECItem *password; /* variable - reset */ + PRBool present; /* variable -set */ + PRBool hasTokens; /* per load */ + PRBool isLoggedIn; /* variable - reset */ + PRBool ssoLoggedIn; /* variable - reset */ + PRBool needLogin; /* per load */ + PRBool DB_loaded; /* per load */ + PRBool readOnly; /* per load */ + PRBool optimizeSpace; /* invariant */ + NSSLOWCERTCertDBHandle *certDB; /* per load */ + NSSLOWKEYDBHandle *keyDB; /* per load */ + int minimumPinLen; /* per load */ + PRInt32 sessionIDCount; /* atomically incremented */ + /* (preserved) */ + int sessionIDConflict; /* not protected by a lock */ + /* (preserved) */ + int sessionCount; /* variable - reset */ + PRInt32 rwSessionCount; /* set by atomic operations */ + /* (reset) */ + int tokenIDCount; /* variable - perserved */ + int index; /* invariant */ + PLHashTable *tokenHashTable; /* invariant */ + SFTKObject **tokObjects; /* variable - reset */ + unsigned int tokObjHashSize; /* invariant */ + SFTKSession **head; /* variable -reset */ + unsigned int sessHashSize; /* invariant */ + char tokDescription[33]; /* per load */ + char slotDescription[64]; /* invariant */ }; /* @@ -538,14 +555,21 @@ typedef struct sftk_parametersStr { SEC_BEGIN_PROTOS +/* shared functions between PKCS11.c and SFTKFIPS.c */ extern int nsf_init; extern CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS); extern CK_RV nsc_CommonFinalize(CK_VOID_PTR pReserved, PRBool isFIPS); extern CK_RV nsc_CommonGetSlotList(CK_BBOOL tokPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount, int moduleIndex); -/* shared functions between PKCS11.c and SFTKFIPS.c */ -extern CK_RV SFTK_SlotInit(char *configdir,sftk_token_parameters *params, - int moduleIndex); + +/* slot initialization, reinit, shutdown and destruction */ +extern CK_RV SFTK_SlotInit(char *configdir, + sftk_token_parameters *params, int moduleIndex); +extern CK_RV SFTK_SlotReInit(SFTKSlot *slot, char *configdir, + sftk_token_parameters *params, int moduleIndex); +extern CK_RV SFTK_DestroySlotData(SFTKSlot *slot); +extern CK_RV SFTK_ShutdownSlot(SFTKSlot *slot); + /* internal utility functions used by pkcs11.c */ extern SFTKAttribute *sftk_FindAttribute(SFTKObject *object, @@ -591,6 +615,9 @@ extern SFTKObject *sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session); extern void sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object); extern void sftk_AddObject(SFTKSession *session, SFTKObject *object); +/* clear out all the existing object ID to database key mappings. + * used to reinit a token */ +extern CK_RV SFTK_ClearTokenKeyHashTable(SFTKSlot *slot); extern CK_RV sftk_searchObjectList(SFTKSearchResults *search, SFTKObject **head, unsigned int size, @@ -602,7 +629,7 @@ extern void sftk_FreeObjectList(SFTKObjectListElement *objectList); extern void sftk_FreeSearch(SFTKSearchResults *search); extern CK_RV sftk_handleObject(SFTKObject *object, SFTKSession *session); -extern SFTKSlot *sftk_SlotFromID(CK_SLOT_ID slotID); +extern SFTKSlot *sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all); extern SFTKSlot *sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle); extern SFTKSession *sftk_SessionFromHandle(CK_SESSION_HANDLE handle); extern void sftk_FreeSession(SFTKSession *session); @@ -658,9 +685,14 @@ CK_RV sftk_DBInit(const char *configdir, const char *certPrefix, const char *keyPrefix, PRBool readOnly, PRBool noCertDB, PRBool noKeyDB, PRBool forceOpen, NSSLOWCERTCertDBHandle **certDB, NSSLOWKEYDBHandle **keyDB); - -void sftk_DBShutdown(NSSLOWCERTCertDBHandle *certHandle, - NSSLOWKEYDBHandle *keyHandle); +NSSLOWCERTCertDBHandle *sftk_getCertDB(SFTKSlot *slot); +NSSLOWKEYDBHandle *sftk_getKeyDB(SFTKSlot *slot); +void sftk_freeCertDB(NSSLOWCERTCertDBHandle *certHandle); +void sftk_freeKeyDB(NSSLOWKEYDBHandle *keyHandle); + +/* helper function which calls nsslowkey_FindKeyByPublicKey after safely + * acquiring a reference to the keydb from the slot */ +NSSLOWKEYPrivateKey *sftk_FindKeyByPublicKey(SFTKSlot *slot, SECItem *dbKey); const char *sftk_EvaluateConfigDir(const char *configdir, char **domain); diff --git a/security/nss/lib/softoken/pkcs11n.h b/security/nss/lib/softoken/pkcs11n.h index 31137c4d2..b1dce6c12 100644 --- a/security/nss/lib/softoken/pkcs11n.h +++ b/security/nss/lib/softoken/pkcs11n.h @@ -73,6 +73,8 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; #define CKO_NETSCAPE_SMIME (CKO_NETSCAPE + 2) #define CKO_NETSCAPE_TRUST (CKO_NETSCAPE + 3) #define CKO_NETSCAPE_BUILTIN_ROOT_LIST (CKO_NETSCAPE + 4) +#define CKO_NETSCAPE_NEWSLOT (CKO_NETSCAPE + 5) +#define CKO_NETSCAPE_DELSLOT (CKO_NETSCAPE + 6) /* * Netscape-defined key types @@ -106,6 +108,7 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; #define CKA_NETSCAPE_PQG_SEED (CKA_NETSCAPE + 21) #define CKA_NETSCAPE_PQG_H (CKA_NETSCAPE + 22) #define CKA_NETSCAPE_PQG_SEED_BITS (CKA_NETSCAPE + 23) +#define CKA_NETSCAPE_MODULE_SPEC (CKA_NETSCAPE + 24) /* * Trust attributes: @@ -233,4 +236,11 @@ typedef CK_ULONG CK_TRUST; typedef char ** (PR_CALLBACK *SECMODModuleDBFunc)(unsigned long function, char *parameters, void *moduleSpec); +/* softoken slot ID's */ +#define SFTK_MIN_USER_SLOT_ID 4 +#define SFTK_MAX_USER_SLOT_ID 100 +#define SFTK_MIN_FIPS_USER_SLOT_ID 101 +#define SFTK_MAX_FIPS_USER_SLOT_ID 127 + + #endif /* _PKCS11N_H_ */ diff --git a/security/nss/lib/softoken/pkcs11u.c b/security/nss/lib/softoken/pkcs11u.c index eb8f5b3e8..8e68587ce 100644 --- a/security/nss/lib/softoken/pkcs11u.c +++ b/security/nss/lib/softoken/pkcs11u.c @@ -240,10 +240,51 @@ static const SFTKAttribute sftk_StaticMustVerifyAttr = SFTK_DEF_ATTRIBUTE(&sftk_staticMustVerifyValue, sizeof(sftk_staticMustVerifyValue)); +/* + * helper functions which get the database and call the underlying + * low level database function. + */ +static char * +sftk_FindKeyNicknameByPublicKey(SFTKSlot *slot, SECItem *dbKey) +{ + NSSLOWKEYDBHandle *keyHandle; + char * label; + + keyHandle = sftk_getKeyDB(slot); + if (!keyHandle) { + return NULL; + } + + label = nsslowkey_FindKeyNicknameByPublicKey(keyHandle, dbKey, + slot->password); + sftk_freeKeyDB(keyHandle); + return label; +} + + +NSSLOWKEYPrivateKey * +sftk_FindKeyByPublicKey(SFTKSlot *slot, SECItem *dbKey) +{ + NSSLOWKEYPrivateKey *privKey; + NSSLOWKEYDBHandle *keyHandle; + + keyHandle = sftk_getKeyDB(slot); + if (keyHandle == NULL) { + return NULL; + } + privKey = nsslowkey_FindKeyByPublicKey(keyHandle, dbKey, slot->password); + sftk_freeKeyDB(keyHandle); + if (privKey == NULL) { + return NULL; + } + return privKey; +} + static certDBEntrySMime * sftk_getSMime(SFTKTokenObject *object) { certDBEntrySMime *entry; + NSSLOWCERTCertDBHandle *certHandle; if (object->obj.objclass != CKO_NETSCAPE_SMIME) { return NULL; @@ -252,10 +293,14 @@ sftk_getSMime(SFTKTokenObject *object) return (certDBEntrySMime *)object->obj.objectInfo; } - entry = nsslowcert_ReadDBSMimeEntry(object->obj.slot->certDB, - (char *)object->dbKey.data); + certHandle = sftk_getCertDB(object->obj.slot); + if (!certHandle) { + return NULL; + } + entry = nsslowcert_ReadDBSMimeEntry(certHandle, (char *)object->dbKey.data); object->obj.objectInfo = (void *)entry; object->obj.infoFree = (SFTKFree) nsslowcert_DestroyDBEntry; + sftk_freeCertDB(certHandle); return entry; } @@ -264,6 +309,7 @@ sftk_getCrl(SFTKTokenObject *object) { certDBEntryRevocation *crl; PRBool isKrl; + NSSLOWCERTCertDBHandle *certHandle; if (object->obj.objclass != CKO_NETSCAPE_CRL) { return NULL; @@ -273,15 +319,20 @@ sftk_getCrl(SFTKTokenObject *object) } isKrl = (PRBool) (object->obj.handle == SFTK_TOKEN_KRL_HANDLE); - crl = nsslowcert_FindCrlByKey(object->obj.slot->certDB, - &object->dbKey, isKrl); + certHandle = sftk_getCertDB(object->obj.slot); + if (!certHandle) { + return NULL; + } + + crl = nsslowcert_FindCrlByKey(certHandle, &object->dbKey, isKrl); object->obj.objectInfo = (void *)crl; object->obj.infoFree = (SFTKFree) nsslowcert_DestroyDBEntry; + sftk_freeCertDB(certHandle); return crl; } static NSSLOWCERTCertificate * -sftk_getCert(SFTKTokenObject *object) +sftk_getCert(SFTKTokenObject *object, NSSLOWCERTCertDBHandle *certHandle) { NSSLOWCERTCertificate *cert; CK_OBJECT_CLASS objClass = object->obj.objclass; @@ -292,7 +343,7 @@ sftk_getCert(SFTKTokenObject *object) if (objClass == CKO_CERTIFICATE && object->obj.objectInfo) { return (NSSLOWCERTCertificate *)object->obj.objectInfo; } - cert = nsslowcert_FindCertByKey(object->obj.slot->certDB,&object->dbKey); + cert = nsslowcert_FindCertByKey(certHandle, &object->dbKey); if (objClass == CKO_CERTIFICATE) { object->obj.objectInfo = (void *)cert; object->obj.infoFree = (SFTKFree) nsslowcert_DestroyCertificate ; @@ -304,6 +355,7 @@ static NSSLOWCERTTrust * sftk_getTrust(SFTKTokenObject *object) { NSSLOWCERTTrust *trust; + NSSLOWCERTCertDBHandle *certHandle; if (object->obj.objclass != CKO_NETSCAPE_TRUST) { return NULL; @@ -311,9 +363,14 @@ sftk_getTrust(SFTKTokenObject *object) if (object->obj.objectInfo) { return (NSSLOWCERTTrust *)object->obj.objectInfo; } - trust = nsslowcert_FindTrustByKey(object->obj.slot->certDB,&object->dbKey); + certHandle = sftk_getCertDB(object->obj.slot); + if (!certHandle) { + return NULL; + } + trust = nsslowcert_FindTrustByKey(certHandle, &object->dbKey); object->obj.objectInfo = (void *)trust; object->obj.infoFree = (SFTKFree) nsslowcert_DestroyTrust ; + sftk_freeCertDB(certHandle); return trust; } @@ -329,8 +386,7 @@ sftk_GetPublicKey(SFTKTokenObject *object) if (object->obj.objectInfo) { return (NSSLOWKEYPublicKey *)object->obj.objectInfo; } - privKey = nsslowkey_FindKeyByPublicKey(object->obj.slot->keyDB, - &object->dbKey, object->obj.slot->password); + privKey = sftk_FindKeyByPublicKey(object->obj.slot, &object->dbKey); if (privKey == NULL) { return NULL; } @@ -341,8 +397,16 @@ sftk_GetPublicKey(SFTKTokenObject *object) return pubKey; } +/* + * we need two versions of sftk_GetPrivateKey. One version that takes the + * DB handle so we can pass the handle we have already acquired in, + * rather than going through the 'getKeyDB' code again, + * which may fail the second time and another which just aquires + * the key handle from the slot (where we don't already have a key handle. + * This version does the former. + */ static NSSLOWKEYPrivateKey * -sftk_GetPrivateKey(SFTKTokenObject *object) +sftk_GetPrivateKeyWithDB(SFTKTokenObject *object, NSSLOWKEYDBHandle *keyHandle) { NSSLOWKEYPrivateKey *privKey; @@ -353,8 +417,8 @@ sftk_GetPrivateKey(SFTKTokenObject *object) if (object->obj.objectInfo) { return (NSSLOWKEYPrivateKey *)object->obj.objectInfo; } - privKey = nsslowkey_FindKeyByPublicKey(object->obj.slot->keyDB, - &object->dbKey, object->obj.slot->password); + privKey = nsslowkey_FindKeyByPublicKey(keyHandle, &object->dbKey, + object->obj.slot->password); if (privKey == NULL) { return NULL; } @@ -363,6 +427,22 @@ sftk_GetPrivateKey(SFTKTokenObject *object) return privKey; } +/* this version does the latter */ +static NSSLOWKEYPrivateKey * +sftk_GetPrivateKey(SFTKTokenObject *object) +{ + NSSLOWKEYDBHandle *keyHandle; + NSSLOWKEYPrivateKey *privKey; + + keyHandle = sftk_getKeyDB(object->obj.slot); + if (!keyHandle) { + return NULL; + } + privKey = sftk_GetPrivateKeyWithDB(object, keyHandle); + sftk_freeKeyDB(keyHandle); + return privKey; +} + /* sftk_GetPubItem returns data associated with the public key. * one only needs to free the public key. This comment is here * because this sematic would be non-obvious otherwise. All callers @@ -540,10 +620,11 @@ sftk_FindECPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type) } #endif /* NSS_ENABLE_ECC */ + static SFTKAttribute * sftk_FindPublicKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) { - NSSLOWKEYPublicKey *key; + NSSLOWKEYPublicKey *key; SFTKAttribute *att = NULL; char *label; @@ -557,8 +638,8 @@ sftk_FindPublicKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) case CKA_EXTRACTABLE: return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); case CKA_LABEL: - label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB, - &object->dbKey, object->obj.slot->password); + label = sftk_FindKeyNicknameByPublicKey(object->obj.slot, + &object->dbKey); if (label == NULL) { return SFTK_CLONE_ATTR(type,sftk_StaticOneAttr); } @@ -595,7 +676,7 @@ sftk_FindPublicKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) static SFTKAttribute * sftk_FindSecretKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) { - NSSLOWKEYPrivateKey *key; + NSSLOWKEYPrivateKey *key; char *label; unsigned char *keyString; SFTKAttribute *att; @@ -621,8 +702,8 @@ sftk_FindSecretKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) case CKA_NEVER_EXTRACTABLE: return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); case CKA_LABEL: - label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB, - &object->dbKey, object->obj.slot->password); + label = sftk_FindKeyNicknameByPublicKey(object->obj.slot, + &object->dbKey); if (label == NULL) { return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); } @@ -889,7 +970,7 @@ sftk_FindECPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type) static SFTKAttribute * sftk_FindPrivateKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) { - NSSLOWKEYPrivateKey *key; + NSSLOWKEYPrivateKey *key; char *label; SFTKAttribute *att; @@ -905,8 +986,8 @@ sftk_FindPrivateKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) case CKA_SUBJECT: return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); case CKA_LABEL: - label = nsslowkey_FindKeyNicknameByPublicKey(object->obj.slot->keyDB, - &object->dbKey, object->obj.slot->password); + label = sftk_FindKeyNicknameByPublicKey(object->obj.slot, + &object->dbKey); if (label == NULL) { return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); } @@ -1122,8 +1203,9 @@ sftk_FindCrlAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) static SFTKAttribute * sftk_FindCertAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) { - NSSLOWCERTCertificate *cert; - NSSLOWKEYPublicKey *pubKey; + NSSLOWCERTCertificate *cert; + NSSLOWCERTCertDBHandle *certHandle; + NSSLOWKEYPublicKey *pubKey; unsigned char hash[SHA1_LENGTH]; SECItem *item; @@ -1146,7 +1228,14 @@ sftk_FindCertAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) default: return NULL; } - cert = sftk_getCert(object); + + certHandle = sftk_getCertDB(object->obj.slot); + if (certHandle == NULL) { + return NULL; + } + + cert = sftk_getCert(object, certHandle); + sftk_freeCertDB(certHandle); if (cert == NULL) { return NULL; } @@ -1269,6 +1358,7 @@ sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen) { unsigned int size = bufLen * 8; unsigned int i; + /* Get the real length in bytes */ for (i=0; i < bufLen; i++) { unsigned char c = *buf++; @@ -1300,7 +1390,7 @@ sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, int minLength, int maxLength, int minMultiple) { SFTKAttribute *attribute; - unsigned int size; + int size; unsigned char *ptr; attribute = sftk_FindAttribute(object, type); @@ -1462,9 +1552,11 @@ static CK_RV sftk_SetCertAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, void *value, unsigned int len) { - NSSLOWCERTCertificate *cert; + NSSLOWCERTCertificate *cert; + NSSLOWCERTCertDBHandle *certHandle; char *nickname = NULL; SECStatus rv; + CK_RV crv; /* we can't change the EMAIL values, but let the * upper layers feel better about the fact we tried to set these */ @@ -1472,17 +1564,21 @@ sftk_SetCertAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, return CKR_OK; } - if (to->obj.slot->certDB == NULL) { - return CKR_TOKEN_WRITE_PROTECTED; + certHandle = sftk_getCertDB(to->obj.slot); + if (certHandle == NULL) { + crv = CKR_TOKEN_WRITE_PROTECTED; + goto done; } if ((type != CKA_LABEL) && (type != CKA_ID)) { - return CKR_ATTRIBUTE_READ_ONLY; + crv = CKR_ATTRIBUTE_READ_ONLY; + goto done; } - cert = sftk_getCert(to); + cert = sftk_getCert(to, certHandle); if (cert == NULL) { - return CKR_OBJECT_HANDLE_INVALID; + crv = CKR_OBJECT_HANDLE_INVALID; + goto done; } /* if the app is trying to set CKA_ID, it's probably because it just @@ -1493,33 +1589,45 @@ sftk_SetCertAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, ((cert->trust->emailFlags & CERTDB_USER) == 0) && ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) { SFTKSlot *slot = to->obj.slot; - - if (slot->keyDB && nsslowkey_KeyForCertExists(slot->keyDB,cert)) { - NSSLOWCERTCertTrust trust = *cert->trust; - trust.sslFlags |= CERTDB_USER; - trust.emailFlags |= CERTDB_USER; - trust.objectSigningFlags |= CERTDB_USER; - nsslowcert_ChangeCertTrust(slot->certDB,cert,&trust); + NSSLOWKEYDBHandle *keyHandle; + + keyHandle = sftk_getKeyDB(slot); + if (keyHandle) { + if (nsslowkey_KeyForCertExists(keyHandle, cert)) { + NSSLOWCERTCertTrust trust = *cert->trust; + trust.sslFlags |= CERTDB_USER; + trust.emailFlags |= CERTDB_USER; + trust.objectSigningFlags |= CERTDB_USER; + nsslowcert_ChangeCertTrust(certHandle,cert,&trust); + } + sftk_freeKeyDB(keyHandle); } } - return CKR_OK; + crv = CKR_OK; + goto done; } /* must be CKA_LABEL */ if (value != NULL) { nickname = PORT_ZAlloc(len+1); if (nickname == NULL) { - return CKR_HOST_MEMORY; + crv = CKR_HOST_MEMORY; + goto done; } PORT_Memcpy(nickname,value,len); nickname[len] = 0; } - rv = nsslowcert_AddPermNickname(to->obj.slot->certDB, cert, nickname); - if (nickname) PORT_Free(nickname); - if (rv != SECSuccess) { - return CKR_DEVICE_ERROR; + rv = nsslowcert_AddPermNickname(certHandle, cert, nickname); + crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; + +done: + if (nickname) { + PORT_Free(nickname); } - return CKR_OK; + if (certHandle) { + sftk_freeCertDB(certHandle); + } + return crv; } static CK_RV @@ -1527,8 +1635,10 @@ sftk_SetPrivateKeyAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, void *value, unsigned int len) { NSSLOWKEYPrivateKey *privKey; + NSSLOWKEYDBHandle *keyHandle; char *nickname = NULL; SECStatus rv; + CK_RV crv; /* we can't change the ID and we don't store the subject, but let the * upper layers feel better about the fact we tried to set these */ @@ -1536,32 +1646,41 @@ sftk_SetPrivateKeyAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, return CKR_OK; } - if (to->obj.slot->keyDB == NULL) { - return CKR_TOKEN_WRITE_PROTECTED; + keyHandle = sftk_getKeyDB(to->obj.slot); + if (keyHandle == NULL) { + crv = CKR_TOKEN_WRITE_PROTECTED; + goto done; } if (type != CKA_LABEL) { - return CKR_ATTRIBUTE_READ_ONLY; + crv = CKR_ATTRIBUTE_READ_ONLY; + goto done; } - privKey = sftk_GetPrivateKey(to); + privKey = sftk_GetPrivateKeyWithDB(to, keyHandle); if (privKey == NULL) { - return CKR_OBJECT_HANDLE_INVALID; + crv = CKR_OBJECT_HANDLE_INVALID; + goto done; } if (value != NULL) { nickname = PORT_ZAlloc(len+1); if (nickname == NULL) { - return CKR_HOST_MEMORY; + crv = CKR_HOST_MEMORY; + goto done; } PORT_Memcpy(nickname,value,len); nickname[len] = 0; } - rv = nsslowkey_UpdateNickname(to->obj.slot->keyDB, privKey, &to->dbKey, + rv = nsslowkey_UpdateNickname(keyHandle, privKey, &to->dbKey, nickname, to->obj.slot->password); - if (nickname) PORT_Free(nickname); - if (rv != SECSuccess) { - return CKR_DEVICE_ERROR; + crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; +done: + if (nickname) { + PORT_Free(nickname); } - return CKR_OK; + if (keyHandle) { + sftk_freeKeyDB(keyHandle); + } + return crv; } static CK_RV @@ -1570,22 +1689,29 @@ sftk_SetTrustAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, { unsigned int flags; CK_TRUST trust; - NSSLOWCERTCertificate *cert; - NSSLOWCERTCertTrust dbTrust; + NSSLOWCERTCertificate *cert; + NSSLOWCERTCertDBHandle *certHandle; + NSSLOWCERTCertTrust dbTrust; SECStatus rv; + CK_RV crv; - if (to->obj.slot->certDB == NULL) { - return CKR_TOKEN_WRITE_PROTECTED; - } if (len != sizeof (CK_TRUST)) { return CKR_ATTRIBUTE_VALUE_INVALID; } trust = *(CK_TRUST *)value; flags = sftk_MapTrust(trust, (PRBool) (type == CKA_TRUST_SERVER_AUTH)); - cert = sftk_getCert(to); + certHandle = sftk_getCertDB(to->obj.slot); + + if (certHandle == NULL) { + crv = CKR_TOKEN_WRITE_PROTECTED; + goto done; + } + + cert = sftk_getCert(to, certHandle); if (cert == NULL) { - return CKR_OBJECT_HANDLE_INVALID; + crv = CKR_OBJECT_HANDLE_INVALID; + goto done; } dbTrust = *cert->trust; @@ -1607,14 +1733,17 @@ sftk_SetTrustAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CLIENT_CA)); break; default: - return CKR_ATTRIBUTE_READ_ONLY; + crv = CKR_ATTRIBUTE_READ_ONLY; + goto done; } - rv = nsslowcert_ChangeCertTrust(to->obj.slot->certDB,cert,&dbTrust); - if (rv != SECSuccess) { - return CKR_DEVICE_ERROR; + rv = nsslowcert_ChangeCertTrust(certHandle, cert, &dbTrust); + crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; +done: + if (certHandle) { + sftk_freeCertDB(certHandle); } - return CKR_OK; + return crv; } static CK_RV @@ -1957,12 +2086,18 @@ sftk_deleteTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle) return rem ? SECSuccess : SECFailure; } +/* must be called holding sftk_tokenKeyLock(slot) */ static SECStatus sftk_addTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle, SECItem *key) { PLHashEntry *entry; SECItem *item; + /* don't add a new handle in the middle of closing down a slot */ + if (!slot->present) { + return SECFailure; + } + item = SECITEM_DupItem(key); if (item == NULL) { return SECFailure; @@ -1975,6 +2110,7 @@ sftk_addTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle, SECItem *key) return SECSuccess; } +/* must be called holding sftk_tokenKeyLock(slot) */ static SECItem * sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle) { @@ -1996,6 +2132,25 @@ sftk_tokenKeyUnlock(SFTKSlot *slot) { PZ_Unlock(slot->objectLock); } +static PRIntn +sftk_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg) +{ + SECItem *item = (SECItem *)entry->value; + + SECITEM_FreeItem(item, PR_TRUE); + return HT_ENUMERATE_NEXT; +} + +CK_RV +SFTK_ClearTokenKeyHashTable(SFTKSlot *slot) +{ + sftk_tokenKeyLock(slot); + PORT_Assert(!slot->present); + PL_HashTableEnumerateEntries(slot->tokenHashTable, sftk_freeHashItem, NULL); + sftk_tokenKeyUnlock(slot); + return CKR_OK; +} + /* allocation hooks that allow us to recycle old object structures */ static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 }; @@ -2349,6 +2504,9 @@ sftk_DeleteObject(SFTKSession *session, SFTKObject *object) sftkqueue_clear_deleted_element(object); sftk_FreeObject(object); /* reduce it's reference count */ } else { + NSSLOWKEYDBHandle *keyHandle; + NSSLOWCERTCertDBHandle *certHandle; + PORT_Assert(to); /* remove the objects from the real data base */ switch (object->handle & SFTK_TOKEN_TYPE_MASK) { @@ -2356,30 +2514,57 @@ sftk_DeleteObject(SFTKSession *session, SFTKObject *object) case SFTK_TOKEN_TYPE_KEY: /* KEYID is the public KEY for DSA and DH, and the MODULUS for * RSA */ - PORT_Assert(slot->keyDB); - rv = nsslowkey_DeleteKey(slot->keyDB, &to->dbKey); - if (rv != SECSuccess) crv= CKR_DEVICE_ERROR; + keyHandle = sftk_getKeyDB(slot); + if (!keyHandle) { + crv = CKR_TOKEN_WRITE_PROTECTED; + break; + } + rv = nsslowkey_DeleteKey(keyHandle, &to->dbKey); + sftk_freeKeyDB(keyHandle); + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + } break; case SFTK_TOKEN_TYPE_PUB: break; /* public keys only exist at the behest of the priv key */ case SFTK_TOKEN_TYPE_CERT: - cert = nsslowcert_FindCertByKey(slot->certDB,&to->dbKey); + certHandle = sftk_getCertDB(slot); + if (!certHandle) { + crv = CKR_TOKEN_WRITE_PROTECTED; + break; + } + cert = nsslowcert_FindCertByKey(certHandle,&to->dbKey); + sftk_freeCertDB(certHandle); if (cert == NULL) { crv = CKR_DEVICE_ERROR; break; } rv = nsslowcert_DeletePermCertificate(cert); - if (rv != SECSuccess) crv = CKR_DEVICE_ERROR; + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + } nsslowcert_DestroyCertificate(cert); break; case SFTK_TOKEN_TYPE_CRL: + certHandle = sftk_getCertDB(slot); + if (!certHandle) { + crv = CKR_TOKEN_WRITE_PROTECTED; + break; + } isKrl = (PRBool) (object->handle == SFTK_TOKEN_KRL_HANDLE); - rv = nsslowcert_DeletePermCRL(slot->certDB,&to->dbKey,isKrl); + rv = nsslowcert_DeletePermCRL(certHandle, &to->dbKey, isKrl); + sftk_freeCertDB(certHandle); if (rv == SECFailure) crv = CKR_DEVICE_ERROR; break; case SFTK_TOKEN_TYPE_TRUST: - cert = nsslowcert_FindCertByKey(slot->certDB,&to->dbKey); + certHandle = sftk_getCertDB(slot); + if (!certHandle) { + crv = CKR_TOKEN_WRITE_PROTECTED; + break; + } + cert = nsslowcert_FindCertByKey(certHandle, &to->dbKey); if (cert == NULL) { + sftk_freeCertDB(certHandle); crv = CKR_DEVICE_ERROR; break; } @@ -2390,7 +2575,8 @@ sftk_DeleteObject(SFTKSession *session, SFTKObject *object) tmptrust.sslFlags |= CERTDB_TRUSTED_UNKNOWN; tmptrust.emailFlags |= CERTDB_TRUSTED_UNKNOWN; tmptrust.objectSigningFlags |= CERTDB_TRUSTED_UNKNOWN; - rv = nsslowcert_ChangeCertTrust(slot->certDB,cert,&tmptrust); + rv = nsslowcert_ChangeCertTrust(certHandle, cert, &tmptrust); + sftk_freeCertDB(certHandle); if (rv != SECSuccess) crv = CKR_DEVICE_ERROR; nsslowcert_DestroyCertificate(cert); break; @@ -2960,7 +3146,7 @@ sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags) { SFTKSession *session; - SFTKSlot *slot = sftk_SlotFromID(slotID); + SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE); if (slot == NULL) return NULL; @@ -3034,7 +3220,10 @@ sftk_SessionFromHandle(CK_SESSION_HANDLE handle) { SFTKSlot *slot = sftk_SlotFromSessionHandle(handle); SFTKSession *session; - PZLock *lock = SFTK_SESSION_LOCK(slot,handle); + PZLock *lock; + + if (!slot) return NULL; + lock = SFTK_SESSION_LOCK(slot,handle); PZ_Lock(lock); sftkqueue_find(session,handle,slot->head,slot->sessHashSize); -- cgit v1.2.1