diff options
author | rrelyea%redhat.com <devnull@localhost> | 2007-06-13 00:24:57 +0000 |
---|---|---|
committer | rrelyea%redhat.com <devnull@localhost> | 2007-06-13 00:24:57 +0000 |
commit | bc02abfdccbf6e07ce9036c85c3371c4bac5a5bc (patch) | |
tree | 58cb311a457ccceb1b291ada3cd9983b608c6e76 /security/nss | |
parent | 892018c57ede2a3b4d8d00a41fc583316a71d4e6 (diff) | |
download | nss-hg-bc02abfdccbf6e07ce9036c85c3371c4bac5a5bc.tar.gz |
Bug 217538 Add shared database to nss.
core Checking.
Diffstat (limited to 'security/nss')
46 files changed, 12670 insertions, 5037 deletions
diff --git a/security/nss/lib/softoken/config.mk b/security/nss/lib/softoken/config.mk index bc48130aa..905ad5284 100644 --- a/security/nss/lib/softoken/config.mk +++ b/security/nss/lib/softoken/config.mk @@ -46,7 +46,7 @@ endif EXTRA_LIBS += \ $(CRYPTOLIB) \ $(DIST)/lib/$(LIB_PREFIX)secutil.$(LIB_SUFFIX) \ - $(DIST)/lib/$(LIB_PREFIX)dbm.$(LIB_SUFFIX) \ + -lsqlite3 \ $(NULL) # can't do this in manifest.mn because OS_TARGET isn't defined there. diff --git a/security/nss/lib/softoken/fipstest.c b/security/nss/lib/softoken/fipstest.c index 942bd4034..a3e6938f8 100644 --- a/security/nss/lib/softoken/fipstest.c +++ b/security/nss/lib/softoken/fipstest.c @@ -49,11 +49,6 @@ #ifdef NSS_ENABLE_ECC #include "secdert.h" /* Required for ECDSA */ #include "ec.h" /* Required for ECDSA */ -extern SECStatus -EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams); -extern SECStatus -EC_CopyParams(PRArenaPool *arena, ECParams *dstParams, - const ECParams *srcParams); #endif diff --git a/security/nss/lib/softoken/fipstokn.c b/security/nss/lib/softoken/fipstokn.c index 6cfcfcb05..3dd386b03 100644 --- a/security/nss/lib/softoken/fipstokn.c +++ b/security/nss/lib/softoken/fipstokn.c @@ -52,7 +52,6 @@ #include "seccomon.h" #include "softoken.h" #include "lowkeyi.h" -#include "pcert.h" #include "pkcs11.h" #include "pkcs11i.h" #include "prenv.h" diff --git a/security/nss/lib/softoken/legacydb/Makefile b/security/nss/lib/softoken/legacydb/Makefile new file mode 100644 index 000000000..a41aa72c6 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/Makefile @@ -0,0 +1,80 @@ +#! gmake +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1994-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include config.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +export:: private_export + diff --git a/security/nss/lib/softoken/cdbhdl.h b/security/nss/lib/softoken/legacydb/cdbhdl.h index 238a48669..aec617b73 100644 --- a/security/nss/lib/softoken/cdbhdl.h +++ b/security/nss/lib/softoken/legacydb/cdbhdl.h @@ -57,8 +57,6 @@ struct NSSLOWCERTCertDBHandleStr { 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 @@ -82,8 +80,6 @@ DB * rdbopen(const char *appName, const char *prefix, DB *dbsopen (const char *dbname , int flags, int mode, DBTYPE type, const void * appData); SECStatus db_Copy(DB *dest,DB *src); -int db_BeginTransaction(DB *db); -int db_FinishTransaction(DB *db, PRBool abort); int db_InitComplete(DB *db); #endif diff --git a/security/nss/lib/softoken/legacydb/config.mk b/security/nss/lib/softoken/legacydb/config.mk new file mode 100644 index 000000000..815f25785 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/config.mk @@ -0,0 +1,102 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1994-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) +CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)freebl.$(LIB_SUFFIX) +CRYPTODIR=../freebl +ifdef MOZILLA_SECURITY_BUILD + CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)crypto.$(LIB_SUFFIX) + CRYPTODIR=../crypto +endif + +EXTRA_LIBS += \ + $(CRYPTOLIB) \ + $(DIST)/lib/$(LIB_PREFIX)secutil.$(LIB_SUFFIX) + $(DIST)/lib/$(LIB_PREFIX)dbm.$(LIB_SUFFIX) \ + $(NULL) + +# can't do this in manifest.mn because OS_TARGET isn't defined there. +ifeq (,$(filter-out WIN%,$(OS_TARGET))) + +# don't want the 32 in the shared library name +SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX) +IMPORT_LIBRARY = $(OBJDIR)/$(IMPORT_LIB_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION)$(IMPORT_LIB_SUFFIX) + +RES = $(OBJDIR)/$(LIBRARY_NAME).res +RESNAME = $(LIBRARY_NAME).rc + +ifdef NS_USE_GCC +EXTRA_SHARED_LIBS += \ + -L$(NSPR_LIB_DIR) \ + -lplc4 \ + -lplds4 \ + -lnspr4 \ + $(NULL) +else # ! NS_USE_GCC + +EXTRA_SHARED_LIBS += \ + $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \ + $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \ + $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \ + $(NULL) +endif # NS_USE_GCC + +else + +# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS) +# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX. +EXTRA_SHARED_LIBS += \ + -L$(NSPR_LIB_DIR) \ + -lplc4 \ + -lplds4 \ + -lnspr4 \ + $(NULL) +endif + +ifeq ($(OS_TARGET),SunOS) +# The -R '$ORIGIN' linker option instructs this library to search for its +# dependencies in the same directory where it resides. +MKSHLIB += -R '$$ORIGIN' +OS_LIBS += -lbsm +endif + +ifeq ($(OS_TARGET),WINCE) +DEFINES += -DDBM_USING_NSPR +endif + +# indicates dependency on freebl static lib +$(SHARED_LIBRARY): $(CRYPTOLIB) diff --git a/security/nss/lib/softoken/dbmshim.c b/security/nss/lib/softoken/legacydb/dbmshim.c index d429dae7c..9d512ac41 100644 --- a/security/nss/lib/softoken/dbmshim.c +++ b/security/nss/lib/softoken/legacydb/dbmshim.c @@ -41,20 +41,11 @@ */ #include "mcom_db.h" #include "secitem.h" -#include "secder.h" -#include "prprf.h" -#include "cdbhdl.h" - -/* Call to SFTK_FreeSlot below */ - -#include "pcertt.h" -#include "secasn1.h" -#include "secerr.h" #include "nssb64.h" #include "blapi.h" -#include "sechash.h" +#include "secerr.h" -#include "pkcs11i.h" +#include "lgdb.h" /* * Blob block: diff --git a/security/nss/lib/softoken/keydb.c b/security/nss/lib/softoken/legacydb/keydb.c index bfa99c256..a57c59fb9 100644 --- a/security/nss/lib/softoken/keydb.c +++ b/security/nss/lib/softoken/legacydb/keydb.c @@ -37,23 +37,18 @@ /* $Id$ */ #include "lowkeyi.h" -#include "seccomon.h" -#include "sechash.h" -#include "secder.h" #include "secasn1.h" +#include "secder.h" #include "secoid.h" #include "blapi.h" #include "secitem.h" #include "pcert.h" #include "mcom_db.h" -#include "lowpbe.h" #include "secerr.h" -#include "cdbhdl.h" #include "nsslocks.h" #include "keydbi.h" -#include "softoken.h" - +#include "lgdb.h" /* * Record keys for keydb @@ -68,39 +63,6 @@ /* Size of the global salt for key database */ #define SALT_LENGTH 16 -const SEC_ASN1Template nsslowkey_AttributeTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(NSSLOWKEYAttribute) }, - { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, - { SEC_ASN1_SET_OF, offsetof(NSSLOWKEYAttribute, attrValue), - SEC_AnyTemplate }, - { 0 } -}; - -const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = { - { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate }, -}; -/* ASN1 Templates for new decoder/encoder */ -const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, - { SEC_ASN1_INTEGER, - offsetof(NSSLOWKEYPrivateKeyInfo,version) }, - { SEC_ASN1_INLINE, - offsetof(NSSLOWKEYPrivateKeyInfo,algorithm), - SECOID_AlgorithmIDTemplate }, - { SEC_ASN1_OCTET_STRING, - offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) }, - { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, - offsetof(NSSLOWKEYPrivateKeyInfo, attributes), - nsslowkey_SetOfAttributeTemplate }, - { 0 } -}; - -const SEC_ASN1Template nsslowkey_PointerToPrivateKeyInfoTemplate[] = { - { SEC_ASN1_POINTER, 0, nsslowkey_PrivateKeyInfoTemplate } -}; - const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) }, @@ -118,26 +80,6 @@ const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = { /* ====== Default key databse encryption algorithm ====== */ - -static SECOidTag defaultKeyDBAlg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC; - -/* - * Default algorithm for encrypting data in the key database - */ -SECOidTag -nsslowkey_GetDefaultKeyDBAlg(void) -{ - return(defaultKeyDBAlg); -} - -void -nsslowkey_SetDefaultKeyDBAlg(SECOidTag alg) -{ - defaultKeyDBAlg = alg; - - return; -} - static void sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey) { @@ -443,6 +385,7 @@ nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle, return(SECSuccess); } +#ifdef notdef typedef struct keyNode { struct keyNode *next; DBT key; @@ -485,6 +428,7 @@ sec_add_key_to_list(DBT *key, DBT *data, void *arg) return(SECSuccess); } +#endif static SECItem * decodeKeyDBGlobalSalt(DBT *saltData) @@ -527,7 +471,7 @@ GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle) } static SECStatus -StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle) +StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle, SECItem *salt) { DBT saltKey; DBT saltData; @@ -536,8 +480,8 @@ StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle) saltKey.data = SALT_STRING; saltKey.size = sizeof(SALT_STRING) - 1; - saltData.data = (void *)handle->global_salt->data; - saltData.size = handle->global_salt->len; + saltData.data = (void *)salt->data; + saltData.size = salt->len; /* put global salt into the database now */ status = keydb_Put(handle, &saltKey, &saltData, 0); @@ -580,18 +524,13 @@ makeGlobalSalt(NSSLOWKEYDBHandle *handle) DBT saltData; unsigned char saltbuf[16]; int status; - SECStatus rv; saltKey.data = SALT_STRING; saltKey.size = sizeof(SALT_STRING) - 1; saltData.data = (void *)saltbuf; saltData.size = sizeof(saltbuf); - rv = RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf)); - if ( rv != SECSuccess ) { - sftk_fatalError = PR_TRUE; - return(rv); - } + RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf)); /* put global salt into the database now */ status = keydb_Put(handle, &saltKey, &saltData, 0); @@ -603,24 +542,6 @@ makeGlobalSalt(NSSLOWKEYDBHandle *handle) } static SECStatus -ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, - SECItem *oldpwitem, SECItem *newpwitem, - SECOidTag new_algorithm); -/* - * Second pass of updating the key db. This time we have a password. - */ -static SECStatus -nsslowkey_UpdateKeyDBPass2(NSSLOWKEYDBHandle *handle, SECItem *pwitem) -{ - SECStatus rv; - - rv = ChangeKeyDBPasswordAlg(handle, pwitem, pwitem, - nsslowkey_GetDefaultKeyDBAlg()); - - return(rv); -} - -static SECStatus encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg, SECItem *encCheck); @@ -918,17 +839,10 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, return (status == RDB_RETRY) ? SECWouldBlock: SECFailure; } - rv = db_BeginTransaction(handle->db); - if (rv != SECSuccess) { - db_InitComplete(handle->db); - return rv; - } - /* force a transactional read, which will verify that one and only one * process attempts the update. */ 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); return SECSuccess; } @@ -962,7 +876,6 @@ openNewDB(const char *appName, const char *prefix, const char *dbname, /* 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; } @@ -1014,7 +927,6 @@ noupdate: rv = SECSuccess; loser: - db_FinishTransaction(handle->db, rv != SECSuccess); db_InitComplete(handle->db); return rv; } @@ -1082,10 +994,6 @@ nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix, handle = nsslowkey_NewHandle(NULL); - if (!handle) { - /* error code is set */ - return NULL; - } openflags = readOnly ? NO_RDONLY : NO_RDWR; @@ -1181,7 +1089,7 @@ nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle) * Delete a private key that was stored in the database */ SECStatus -nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, SECItem *pubkey) +nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, const SECItem *pubkey) { DBT namekey; int ret; @@ -1220,10 +1128,10 @@ nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle, NSSLOWKEYPrivateKey *privkey, SECItem *pubKeyData, char *nickname, - SECItem *arg) + SDB *sdb) { return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, - nickname, arg, nsslowkey_GetDefaultKeyDBAlg(),PR_FALSE); + nickname, sdb, PR_FALSE); } SECStatus @@ -1231,10 +1139,10 @@ nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle, NSSLOWKEYPrivateKey *privkey, SECItem *pubKeyData, char *nickname, - SECItem *arg) + SDB *sdb) { return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, - nickname, arg, nsslowkey_GetDefaultKeyDBAlg(),PR_TRUE); + nickname, sdb, PR_TRUE); } /* see if the symetric CKA_ID already Exists. @@ -1327,218 +1235,272 @@ nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cer return PR_TRUE; } -/* - * check to see if the user has a password - */ -SECStatus -nsslowkey_HasKeyDBPassword(NSSLOWKEYDBHandle *handle) +typedef struct NSSLowPasswordDataParamStr { + SECItem salt; + SECItem iter; +} NSSLowPasswordDataParam; + +static const SEC_ASN1Template NSSLOWPasswordParamTemplate[] = { - DBT checkkey, checkdata; - int ret; + {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLowPasswordDataParam) }, + {SEC_ASN1_OCTET_STRING, offsetof(NSSLowPasswordDataParam, salt) }, + {SEC_ASN1_INTEGER, offsetof(NSSLowPasswordDataParam, iter) }, + {0} +}; +struct LGEncryptedDataInfoStr { + SECAlgorithmID algorithm; + SECItem encryptedData; +}; +typedef struct LGEncryptedDataInfoStr LGEncryptedDataInfo; - if (handle == NULL) { - return(SECFailure); - } +const SEC_ASN1Template lg_EncryptedDataInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(LGEncryptedDataInfo) }, + { SEC_ASN1_INLINE, + offsetof(LGEncryptedDataInfo,algorithm), + SECOID_AlgorithmIDTemplate }, + { SEC_ASN1_OCTET_STRING, + offsetof(LGEncryptedDataInfo,encryptedData) }, + { 0 } +}; +static const unsigned char def_iter_data[] = { SEC_ASN1_INTEGER, 0x01, 0x01 }; +static const SECItem def_iter = { siBuffer , + (unsigned char *)def_iter_data, + sizeof(def_iter_data) }; - checkkey.data = KEYDB_PW_CHECK_STRING; - checkkey.size = KEYDB_PW_CHECK_LEN; - - 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, &checkkey, &checkdata, 0 ); - if ( ret ) { - return(SECFailure); - } - } +static SECItem * +nsslowkey_EncodePW(SECOidTag alg, const SECItem *salt, SECItem *data) +{ + NSSLowPasswordDataParam param; + LGEncryptedDataInfo edi; + PLArenaPool *arena; + unsigned char one = 1; + SECItem *epw = NULL; + SECItem *encParam; + SECStatus rv; - return(SECSuccess); -} + param.salt = *salt; + param.iter.data = &one; + param.iter.len = 1; + edi.encryptedData = *data; -/* - * Set up the password checker in the key database. - * This is done by encrypting a known plaintext with the user's key. - */ -SECStatus -nsslowkey_SetKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem) -{ - return nsslowkey_SetKeyDBPasswordAlg(handle, pwitem, - nsslowkey_GetDefaultKeyDBAlg()); -} + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + return NULL; + } -static SECStatus -HashPassword(unsigned char *hashresult, char *pw, SECItem *salt) -{ - SHA1Context *cx; - unsigned int outlen; - cx = SHA1_NewContext(); - if ( cx == NULL ) { - return(SECFailure); + encParam = SEC_ASN1EncodeItem(arena, NULL, ¶m, + NSSLOWPasswordParamTemplate); + if (encParam == NULL) { + goto loser; } - - SHA1_Begin(cx); - if ( ( salt != NULL ) && ( salt->data != NULL ) ) { - SHA1_Update(cx, salt->data, salt->len); + rv = SECOID_SetAlgorithmID(arena, &edi.algorithm, alg, encParam); + if (rv != SECSuccess) { + goto loser; } - - SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw)); - SHA1_End(cx, hashresult, &outlen, SHA1_LENGTH); - - SHA1_DestroyContext(cx, PR_TRUE); - - return(SECSuccess); + epw = SEC_ASN1EncodeItem(NULL, NULL, &edi, lg_EncryptedDataInfoTemplate); + +loser: + PORT_FreeArena(arena, PR_FALSE); + return epw; } -SECItem * -nsslowkey_HashPassword(char *pw, SECItem *salt) +static SECItem * +nsslowkey_DecodePW(const SECItem *derData, SECOidTag *alg, SECItem *salt) { - SECItem *pwitem; + NSSLowPasswordDataParam param; + LGEncryptedDataInfo edi; + PLArenaPool *arena; + SECItem *pwe = NULL; SECStatus rv; - - pwitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); - if ( pwitem == NULL ) { - return(NULL); + + salt->data = NULL; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + return NULL; } - pwitem->len = SHA1_LENGTH; - pwitem->data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH); - if ( pwitem->data == NULL ) { - PORT_Free(pwitem); - return(NULL); + + rv = SEC_QuickDERDecodeItem(arena, &edi, lg_EncryptedDataInfoTemplate, + derData); + if (rv != SECSuccess) { + goto loser; } - if ( pw ) { - rv = HashPassword(pwitem->data, pw, salt); - if ( rv != SECSuccess ) { - SECITEM_ZfreeItem(pwitem, PR_TRUE); - return(NULL); - } + *alg = SECOID_GetAlgorithmTag(&edi.algorithm); + rv = SEC_QuickDERDecodeItem(arena, ¶m, NSSLOWPasswordParamTemplate, + &edi.algorithm.parameters); + if (rv != SECSuccess) { + goto loser; } - - return(pwitem); -} - -/* Derive the actual password value for the database from a pw string */ -SECItem * -nsslowkey_DeriveKeyDBPassword(NSSLOWKEYDBHandle *keydb, char *pw) -{ - PORT_Assert(keydb != NULL); - PORT_Assert(pw != NULL); - if (keydb == NULL || pw == NULL) return(NULL); + if (SECITEM_ItemsAreEqual(¶m.iter, &def_iter) ) { + goto loser; + } + rv = SECITEM_CopyItem(NULL, salt, ¶m.salt); + if (rv != SECSuccess) { + goto loser; + } + pwe = SECITEM_DupItem(&edi.encryptedData); - return nsslowkey_HashPassword(pw, keydb->global_salt); +loser: + if (!pwe && salt->data) { + PORT_Free(salt->data); + salt->data = NULL; + } + PORT_FreeArena(arena, PR_FALSE); + return pwe; } + /* - * Derive an RC4 key from a password key and a salt. This - * was the method to used to encrypt keys in the version 2? - * database + * check to see if the user has a password */ -SECItem * -seckey_create_rc4_key(SECItem *pwitem, SECItem *salt) +static SECStatus +nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle,SDBPasswordEntry *entry) { - MD5Context *md5 = NULL; - unsigned int part; + DBT checkkey; /*, checkdata; */ + NSSLOWKEYDBKey *dbkey = NULL; + SECItem *global_salt = NULL; + SECItem *item = NULL; + SECItem entryData, oid; SECStatus rv = SECFailure; - SECItem *key = NULL; + SECOidTag algorithm; - key = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); - if(key != NULL) - { - key->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) * - MD5_LENGTH); - key->len = MD5_LENGTH; - if(key->data != NULL) - { - md5 = MD5_NewContext(); - if ( md5 != NULL ) - { - MD5_Begin(md5); - MD5_Update(md5, salt->data, salt->len); - MD5_Update(md5, pwitem->data, pwitem->len); - MD5_End(md5, key->data, &part, MD5_LENGTH); - MD5_DestroyContext(md5, PR_TRUE); - rv = SECSuccess; - } - } + if (handle == NULL) { + /* PORT_SetError */ + return(SECFailure); + } + + global_salt = GetKeyDBGlobalSalt(handle); + if (!global_salt) { + return SECFailure; + } + if (global_salt->len > sizeof(entry->data)) { + /* PORT_SetError */ + goto loser; + } - if(rv != SECSuccess) - { - SECITEM_FreeItem(key, PR_TRUE); - key = NULL; - } + PORT_Memcpy(entry->data, global_salt->data, global_salt->len); + entry->salt.data = entry->data; + entry->salt.len = global_salt->len; + entry->value.data = &entry->data[entry->salt.len]; + + checkkey.data = KEYDB_PW_CHECK_STRING; + checkkey.size = KEYDB_PW_CHECK_LEN; + dbkey = get_dbkey(handle, &checkkey); + if (dbkey == NULL) { + /* handle 'FAKE' check here */ + goto loser; } - return key; + oid.len = dbkey->derPK.data[0]; + oid.data = &dbkey->derPK.data[1]; + + if (dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 +oid.len)) { + goto loser; + } + algorithm = SECOID_FindOIDTag(&oid); + entryData.len = dbkey->derPK.len - (oid.len+1); + entryData.data = &dbkey->derPK.data[oid.len+1]; + + item = nsslowkey_EncodePW(algorithm, &dbkey->salt, &entryData); + if (!item || (item->len + entry->salt.len) > sizeof(entry->data)) { + goto loser; + } + PORT_Memcpy(entry->value.data, item->data, item->len); + entry->value.len = item->len; + rv = SECSuccess; + +loser: + if (item) { + SECITEM_FreeItem(item, PR_TRUE); + } + if (dbkey) { + sec_destroy_dbkey(dbkey); + } + if (global_salt) { + SECITEM_FreeItem(global_salt,PR_TRUE); + } + return rv; } -SECItem * -seckey_create_rc4_salt(void) +/* + * check to see if the user has a password + */ +static SECStatus +nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle,SDBPasswordEntry *entry) { - SECItem *salt = NULL; + DBT checkkey; + NSSLOWKEYDBKey *dbkey = NULL; + SECItem *item = NULL; + SECItem salt; + SECOidTag algid; SECStatus rv = SECFailure; + PLArenaPool *arena; - salt = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); - if(salt == NULL) - return NULL; + if (handle == NULL) { + /* PORT_SetError */ + return(SECFailure); + } - salt->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) * - SALT_LENGTH); - if(salt->data != NULL) - { - salt->len = SALT_LENGTH; - rv = RNG_GenerateGlobalRandomBytes(salt->data, salt->len); - if(rv != SECSuccess) - sftk_fatalError = PR_TRUE; + checkkey.data = KEYDB_PW_CHECK_STRING; + checkkey.size = KEYDB_PW_CHECK_LEN; + + salt.data = NULL; + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + return SECFailure; } - - if(rv != SECSuccess) - { - SECITEM_FreeItem(salt, PR_TRUE); - salt = NULL; + + item = nsslowkey_DecodePW(&entry->value, &algid, &salt); + if (item == NULL) { + goto loser; } - return salt; -} + dbkey = PORT_ArenaZNew(arena, NSSLOWKEYDBKey); + if (dbkey == NULL) { + goto loser; + } -SECItem * -seckey_rc4_decode(SECItem *key, SECItem *src) -{ - SECItem *dest = NULL; - RC4Context *ctxt = NULL; - SECStatus rv = SECFailure; + dbkey->arena = arena; - if((key == NULL) || (src == NULL)) - return NULL; + rv = SECITEM_CopyItem(arena, &dbkey->salt, &salt); + if (rv != SECSuccess) { + goto loser; + } - dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); - if(dest == NULL) - return NULL; + rv = encodePWCheckEntry(arena, &dbkey->derPK, algid, item); + if (rv != SECSuccess) { + goto loser; + } - dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) * - (src->len + 64)); /* TNH - padding? */ - if(dest->data != NULL) - { - ctxt = RC4_CreateContext(key->data, key->len); - if(ctxt != NULL) - { - rv = RC4_Decrypt(ctxt, dest->data, &dest->len, - src->len + 64, src->data, src->len); - RC4_DestroyContext(ctxt, PR_TRUE); - } + rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE); + if (rv != SECSuccess) { + goto loser; } - if(rv == SECFailure) - if(dest != NULL) - { - SECITEM_FreeItem(dest, PR_TRUE); - dest = NULL; - } + if (handle->global_salt) { + SECITEM_FreeItem(handle->global_salt, PR_TRUE); + handle->global_salt = NULL; + } + rv = StoreKeyDBGlobalSalt(handle, &entry->salt); + if (rv != SECSuccess) { + goto loser; + } + handle->global_salt = GetKeyDBGlobalSalt(handle); - return dest; +loser: + if (item) { + SECITEM_FreeItem(item, PR_TRUE); + } + if (arena) { + PORT_FreeArena(arena, PR_TRUE); + } + if (salt.data) { + PORT_Free(salt.data); + } + return rv; } - #ifdef EC_DEBUG #define SEC_PRINT(str1, str2, num, sitem) \ printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \ @@ -1551,46 +1513,33 @@ seckey_rc4_decode(SECItem *key, SECItem *src) #define SEC_PRINT(a, b, c, d) #endif /* EC_DEBUG */ -/* TNH - keydb is unused */ -/* TNH - the pwitem should be the derived key for RC4 */ -NSSLOWKEYEncryptedPrivateKeyInfo * -seckey_encrypt_private_key( - NSSLOWKEYPrivateKey *pk, SECItem *pwitem, NSSLOWKEYDBHandle *keydb, - SECOidTag algorithm, SECItem **salt) + +SECStatus +seckey_encrypt_private_key( PLArenaPool *permarena, NSSLOWKEYPrivateKey *pk, + SDB *sdbpw, SECItem *result) { - NSSLOWKEYEncryptedPrivateKeyInfo *epki = NULL; NSSLOWKEYPrivateKeyInfo *pki = NULL; SECStatus rv = SECFailure; - PLArenaPool *temparena = NULL, *permarena = NULL; + PLArenaPool *temparena = NULL; SECItem *der_item = NULL; - NSSPKCS5PBEParameter *param = NULL; - SECItem *dummy = NULL, *dest = NULL; - SECAlgorithmID *algid; + SECItem *cipherText = NULL; + SECItem *dummy = NULL; #ifdef NSS_ENABLE_ECC SECItem *fordebug = NULL; int savelen; - int i; #endif - *salt = NULL; - permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); - if(permarena == NULL) - return NULL; - temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); if(temparena == NULL) goto loser; /* allocate structures */ - epki = (NSSLOWKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(permarena, - sizeof(NSSLOWKEYEncryptedPrivateKeyInfo)); pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, sizeof(NSSLOWKEYPrivateKeyInfo)); der_item = (SECItem *)PORT_ArenaZAlloc(temparena, sizeof(SECItem)); - if((epki == NULL) || (pki == NULL) || (der_item == NULL)) + if((pki == NULL) || (der_item == NULL)) goto loser; - epki->arena = permarena; /* setup private key info */ dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version), @@ -1713,72 +1662,30 @@ seckey_encrypt_private_key( goto loser; } - rv = SECFailure; /* assume failure */ - *salt = seckey_create_rc4_salt(); - if (*salt == NULL) { - goto loser; - } - - param = nsspkcs5_NewParam(algorithm,*salt,1); - if (param == NULL) { - goto loser; - } - - dest = nsspkcs5_CipherData(param, pwitem, der_item, PR_TRUE, NULL); - if (dest == NULL) { - goto loser; - } - - rv = SECITEM_CopyItem(permarena, &epki->encryptedData, dest); + rv = lg_util_encrypt(temparena, sdbpw, dummy, &cipherText); if (rv != SECSuccess) { goto loser; } - algid = nsspkcs5_CreateAlgorithmID(permarena, algorithm, param); - if (algid == NULL) { - rv = SECFailure; - goto loser; - } - - rv = SECOID_CopyAlgorithmID(permarena, &epki->algorithm, algid); - SECOID_DestroyAlgorithmID(algid, PR_TRUE); + rv = SECITEM_CopyItem ( permarena, result, cipherText); loser: - if(dest != NULL) - SECITEM_FreeItem(dest, PR_TRUE); - - if(param != NULL) - nsspkcs5_DestroyPBEParameter(param); - - /* let success fall through */ - - if(rv == SECFailure) - { - PORT_FreeArena(permarena, PR_TRUE); - epki = NULL; - if(*salt != NULL) - SECITEM_FreeItem(*salt, PR_TRUE); - } if(temparena != NULL) PORT_FreeArena(temparena, PR_TRUE); - return epki; + return rv; } static SECStatus -seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SECItem *pwitem, - NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update, - SECOidTag algorithm) +seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SDB *sdbpw, + NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update) { NSSLOWKEYDBKey *dbkey = NULL; - NSSLOWKEYEncryptedPrivateKeyInfo *epki = NULL; - PLArenaPool *arena = NULL; - SECItem *dummy = NULL; - SECItem *salt = NULL; + PLArenaPool *arena = NULL; SECStatus rv = SECFailure; - if((keydb == NULL) || (index == NULL) || (pwitem == NULL) || + if((keydb == NULL) || (index == NULL) || (sdbpw == NULL) || (pk == NULL)) return SECFailure; @@ -1792,31 +1699,16 @@ seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SECItem *pwitem, dbkey->arena = arena; dbkey->nickname = nickname; - /* TNH - for RC4, the salt should be created here */ - - epki = seckey_encrypt_private_key(pk, pwitem, keydb, algorithm, &salt); - if(epki == NULL) + rv = seckey_encrypt_private_key(arena, pk, sdbpw, &dbkey->derPK); + if(rv != SECSuccess) goto loser; - if(salt != NULL) - { - rv = SECITEM_CopyItem(arena, &(dbkey->salt), salt); - SECITEM_ZfreeItem(salt, PR_TRUE); - } - - dummy = SEC_ASN1EncodeItem(arena, &(dbkey->derPK), epki, - nsslowkey_EncryptedPrivateKeyInfoTemplate); - if(dummy == NULL) - rv = SECFailure; - else - rv = put_dbkey(keydb, index, dbkey, update); + rv = put_dbkey(keydb, index, dbkey, update); /* let success fall through */ loser: if(arena != NULL) - PORT_FreeArena(arena, PR_TRUE); - if(epki != NULL) - PORT_FreeArena(epki->arena, PR_TRUE); + PORT_FreeArena(arena, PR_TRUE); return rv; } @@ -1830,8 +1722,7 @@ nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, NSSLOWKEYPrivateKey *privkey, SECItem *pubKeyData, char *nickname, - SECItem *pwitem, - SECOidTag algorithm, + SDB *sdbpw, PRBool update) { DBT namekey; @@ -1847,30 +1738,26 @@ nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, namekey.size = pubKeyData->len; /* encrypt the private key */ - rv = seckey_put_private_key(handle, &namekey, pwitem, privkey, nickname, - update, algorithm); + rv = seckey_put_private_key(handle, &namekey, sdbpw, privkey, nickname, + update); return(rv); } -NSSLOWKEYPrivateKey * -seckey_decrypt_private_key(NSSLOWKEYEncryptedPrivateKeyInfo *epki, - SECItem *pwitem) +static NSSLOWKEYPrivateKey * +seckey_decrypt_private_key(SECItem*epki, + SDB *sdbpw) { NSSLOWKEYPrivateKey *pk = NULL; NSSLOWKEYPrivateKeyInfo *pki = NULL; SECStatus rv = SECFailure; - SECOidTag algorithm; PLArenaPool *temparena = NULL, *permarena = NULL; - SECItem *salt = NULL, *dest = NULL, *key = NULL; - NSSPKCS5PBEParameter *param; + SECItem *dest = NULL; #ifdef NSS_ENABLE_ECC - ECPrivateKey *ecpriv; SECItem *fordebug = NULL; - int i; #endif - if((epki == NULL) || (pwitem == NULL)) + if((epki == NULL) || (sdbpw == NULL)) goto loser; temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); @@ -1890,39 +1777,12 @@ seckey_decrypt_private_key(NSSLOWKEYEncryptedPrivateKeyInfo *epki, goto loser; pk->arena = permarena; - - algorithm = SECOID_GetAlgorithmTag(&(epki->algorithm)); - switch(algorithm) - { - case SEC_OID_RC4: - salt = SECITEM_DupItem(&epki->algorithm.parameters); - if(salt != NULL) - { - key = seckey_create_rc4_key(pwitem, salt); - if(key != NULL) - { - dest = seckey_rc4_decode(key, &epki->encryptedData); - } - } - if(salt != NULL) - SECITEM_ZfreeItem(salt, PR_TRUE); - if(key != NULL) - SECITEM_ZfreeItem(key, PR_TRUE); - break; - default: - /* we depend on the fact that if this key was encoded with - * DES, that the pw was also encoded with DES, so we don't have - * to do the update here, the password code will handle it. */ - param = nsspkcs5_AlgidToParam(&epki->algorithm); - if (param == NULL) { - break; - } - dest = nsspkcs5_CipherData(param, pwitem, &epki->encryptedData, - PR_FALSE, NULL); - nsspkcs5_DestroyPBEParameter(param); - break; - } + rv = lg_util_decrypt(sdbpw, epki, &dest); + if (rv != SECSuccess) { + goto loser; + } + if(dest != NULL) { SECItem newPrivateKey; @@ -1998,32 +1858,13 @@ seckey_decrypt_private_key(NSSLOWKEYEncryptedPrivateKeyInfo *epki, goto loser; /* Fill out the rest of EC params */ - rv = EC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding, + rv = LGEC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding, &pk->u.ec.ecParams); if (rv != SECSuccess) goto loser; - /* - * NOTE: Encoding of the publicValue is optional - * so we need to be able to regenerate the publicValue - * from the base point and the private key. - * - * XXX This part of the code needs more testing. - */ - if (pk->u.ec.publicValue.len == 0) { - rv = EC_NewKeyFromSeed(&pk->u.ec.ecParams, - &ecpriv, pk->u.ec.privateValue.data, - pk->u.ec.privateValue.len); - if (rv == SECSuccess) { - SECITEM_CopyItem(permarena, &pk->u.ec.publicValue, - &(ecpriv->publicValue)); - PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE); - } - } else { - /* If publicValue was filled as part of DER decoding, - * change length in bits to length in bytes. - */ + if (pk->u.ec.publicValue.len != 0) { pk->u.ec.publicValue.len >>= 3; } @@ -2059,67 +1900,23 @@ loser: } static NSSLOWKEYPrivateKey * -seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SECItem *pwitem) +seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SDB *sdbpw) { - NSSLOWKEYPrivateKey *pk = NULL; - NSSLOWKEYEncryptedPrivateKeyInfo *epki; - PLArenaPool *temparena = NULL; - SECStatus rv; - SECOidTag algorithm; - - if( ( dbkey == NULL ) || ( pwitem == NULL ) ) { + if( ( dbkey == NULL ) || ( sdbpw == NULL ) ) { return NULL; } - temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if(temparena == NULL) { - return NULL; - } - - epki = (NSSLOWKEYEncryptedPrivateKeyInfo *) - PORT_ArenaZAlloc(temparena, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo)); - - if(epki == NULL) { - goto loser; - } - - rv = SEC_QuickDERDecodeItem(temparena, epki, - nsslowkey_EncryptedPrivateKeyInfoTemplate, - &(dbkey->derPK)); - if(rv != SECSuccess) { - goto loser; - } - - algorithm = SECOID_GetAlgorithmTag(&(epki->algorithm)); - switch(algorithm) - { - case SEC_OID_RC4: - /* TNH - this code should derive the actual RC4 key from salt and - pwitem */ - rv = SECITEM_CopyItem(temparena, &(epki->algorithm.parameters), - &(dbkey->salt)); - break; - default: - break; - } - - pk = seckey_decrypt_private_key(epki, pwitem); - - /* let success fall through */ -loser: - - PORT_FreeArena(temparena, PR_TRUE); - return pk; + return seckey_decrypt_private_key(&(dbkey->derPK), sdbpw); } -NSSLOWKEYPrivateKey * +static NSSLOWKEYPrivateKey * seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname, - SECItem *pwitem) + SDB *sdbpw) { NSSLOWKEYDBKey *dbkey = NULL; NSSLOWKEYPrivateKey *pk = NULL; - if( ( keydb == NULL ) || ( index == NULL ) || ( pwitem == NULL ) ) { + if( ( keydb == NULL ) || ( index == NULL ) || ( sdbpw == NULL ) ) { return NULL; } @@ -2136,7 +1933,7 @@ seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname, } } - pk = seckey_decode_encrypted_private_key(dbkey, pwitem); + pk = seckey_decode_encrypted_private_key(dbkey, sdbpw); /* let success fall through */ loser: @@ -2149,16 +1946,6 @@ loser: } /* - * used by pkcs11 to import keys into it's object format... In the future - * we really need a better way to tie in... - */ -NSSLOWKEYPrivateKey * -nsslowkey_DecryptKey(DBT *key, SECItem *pwitem, - NSSLOWKEYDBHandle *handle) { - return seckey_get_private_key(handle,key,NULL,pwitem); -} - -/* * Find a key in the database, indexed by its public key modulus * This is used to find keys that have been stored before their * certificate arrives. Once the certificate arrives the key @@ -2167,7 +1954,7 @@ nsslowkey_DecryptKey(DBT *key, SECItem *pwitem, */ NSSLOWKEYPrivateKey * nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus, - SECItem *pwitem) + SDB *sdbpw) { DBT namekey; NSSLOWKEYPrivateKey *pk = NULL; @@ -2181,7 +1968,7 @@ nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus, namekey.data = modulus->data; namekey.size = modulus->len; - pk = seckey_get_private_key(handle, &namekey, NULL, pwitem); + pk = seckey_get_private_key(handle, &namekey, NULL, sdbpw); /* no need to free dbkey, since its on the stack, and the data it * points to is owned by the database @@ -2191,7 +1978,7 @@ nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus, char * nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, - SECItem *modulus, SECItem *pwitem) + SECItem *modulus, SDB *sdbpw) { DBT namekey; NSSLOWKEYPrivateKey *pk = NULL; @@ -2206,7 +1993,7 @@ nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, namekey.data = modulus->data; namekey.size = modulus->len; - pk = seckey_get_private_key(handle, &namekey, &nickname, pwitem); + pk = seckey_get_private_key(handle, &namekey, &nickname, sdbpw); if (pk) { nsslowkey_DestroyPrivateKey(pk); } @@ -2255,428 +2042,13 @@ encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg, loser: return(SECFailure); } - -/* - * Set up the password checker in the key database. - * This is done by encrypting a known plaintext with the user's key. - */ -SECStatus -nsslowkey_SetKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, - SECItem *pwitem, SECOidTag algorithm) -{ - DBT checkkey; - NSSPKCS5PBEParameter *param = NULL; - SECStatus rv = SECFailure; - NSSLOWKEYDBKey *dbkey = NULL; - PLArenaPool *arena; - SECItem *salt = NULL; - SECItem *dest = NULL, test_key; - - if (handle == NULL) { - return(SECFailure); - } - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if ( arena == NULL ) { - rv = SECFailure; - goto loser; - } - - dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey)); - if ( dbkey == NULL ) { - rv = SECFailure; - goto loser; - } - - dbkey->arena = arena; - - /* encrypt key */ - checkkey.data = test_key.data = (unsigned char *)KEYDB_PW_CHECK_STRING; - checkkey.size = test_key.len = KEYDB_PW_CHECK_LEN; - - salt = seckey_create_rc4_salt(); - if(salt == NULL) { - rv = SECFailure; - goto loser; - } - - param = nsspkcs5_NewParam(algorithm, salt, 1); - if (param == NULL) { - rv = SECFailure; - goto loser; - } - - dest = nsspkcs5_CipherData(param, pwitem, &test_key, PR_TRUE, NULL); - if (dest == NULL) - { - rv = SECFailure; - goto loser; - } - - rv = SECITEM_CopyItem(arena, &dbkey->salt, salt); - if (rv == SECFailure) { - goto loser; - } - - rv = encodePWCheckEntry(arena, &dbkey->derPK, algorithm, dest); - - if ( rv != SECSuccess ) { - goto loser; - } - - rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE); - - /* let success fall through */ -loser: - if ( arena != NULL ) { - PORT_FreeArena(arena, PR_TRUE); - } - - if ( dest != NULL ) { - SECITEM_ZfreeItem(dest, PR_TRUE); - } - - if ( salt != NULL ) { - SECITEM_ZfreeItem(salt, PR_TRUE); - } - - if (param != NULL) { - nsspkcs5_DestroyPBEParameter(param); - } - - return(rv); -} - -static SECStatus -seckey_CheckKeyDB1Password(NSSLOWKEYDBHandle *handle, SECItem *pwitem) -{ - SECStatus rv = SECFailure; - keyList keylist; - keyNode *node = NULL; - NSSLOWKEYPrivateKey *privkey = NULL; - - - /* - * first find a key - */ - - /* traverse the database, collecting the keys of all records */ - keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if ( keylist.arena == NULL ) - { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return(SECFailure); - } - keylist.head = NULL; - - /* TNH - TraverseKeys should not be public, since it exposes - the underlying DBT data type. */ - rv = nsslowkey_TraverseKeys(handle, sec_add_key_to_list, (void *)&keylist); - if ( rv != SECSuccess ) - goto done; - - /* just get the first key from the list */ - node = keylist.head; - - /* no private keys, accept any password */ - if (node == NULL) { - rv = SECSuccess; - goto done; - } - privkey = seckey_get_private_key(handle, &node->key, NULL, pwitem); - if (privkey == NULL) { - rv = SECFailure; - goto done; - } - - /* if we can decrypt the private key, then we had the correct password */ - rv = SECSuccess; - nsslowkey_DestroyPrivateKey(privkey); - -done: - - /* free the arena */ - if ( keylist.arena ) { - PORT_FreeArena(keylist.arena, PR_FALSE); - } - - return(rv); -} - -/* - * check to see if the user has typed the right password - */ -SECStatus -nsslowkey_CheckKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem) -{ - DBT checkkey; - DBT checkdata; - NSSPKCS5PBEParameter *param = NULL; - SECStatus rv = SECFailure; - NSSLOWKEYDBKey *dbkey = NULL; - SECItem *key = NULL; - SECItem *dest = NULL; - SECOidTag algorithm; - SECItem oid; - SECItem encstring; - PRBool update = PR_FALSE; - int ret; - - if (handle == NULL) { - goto loser; - } - - checkkey.data = KEYDB_PW_CHECK_STRING; - checkkey.size = KEYDB_PW_CHECK_LEN; - - dbkey = get_dbkey(handle, &checkkey); - - if ( dbkey == NULL ) { - checkkey.data = KEYDB_FAKE_PW_CHECK_STRING; - checkkey.size = KEYDB_FAKE_PW_CHECK_LEN; - ret = keydb_Get(handle, &checkkey, &checkdata, 0 ); - if (ret) { - goto loser; - } - /* if we have the fake PW_CHECK, then try to decode the key - * rather than the pwcheck item. - */ - rv = seckey_CheckKeyDB1Password(handle,pwitem); - if (rv == SECSuccess) { - /* OK we have enough to complete our conversion */ - nsslowkey_UpdateKeyDBPass2(handle,pwitem); - } - return rv; - } - - /* build the oid item */ - oid.len = dbkey->derPK.data[0]; - oid.data = &dbkey->derPK.data[1]; - - /* make sure entry is the correct length - * since we are probably using a block cipher, the block will be - * padded, so we may get a bit more than the exact size we need. - */ - if ( dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 + oid.len ) ) { - goto loser; - } - - /* find the algorithm tag */ - algorithm = SECOID_FindOIDTag(&oid); - - /* make a secitem of the encrypted check string */ - encstring.len = dbkey->derPK.len - ( oid.len + 1 ); - encstring.data = &dbkey->derPK.data[oid.len+1]; - encstring.type = 0; - - switch(algorithm) - { - case SEC_OID_RC4: - key = seckey_create_rc4_key(pwitem, &dbkey->salt); - if(key != NULL) { - dest = seckey_rc4_decode(key, &encstring); - SECITEM_FreeItem(key, PR_TRUE); - } - break; - default: - param = nsspkcs5_NewParam(algorithm, &dbkey->salt, 1); - if (param != NULL) { - /* Decrypt - this function implements a workaround for - * a previous coding error. It will decrypt values using - * DES rather than 3DES, if the initial try at 3DES - * decryption fails. In this case, the update flag is - * set to TRUE. This indication is used later to force - * an update of the database to "real" 3DES encryption. - */ - dest = nsspkcs5_CipherData(param, pwitem, - &encstring, PR_FALSE, &update); - nsspkcs5_DestroyPBEParameter(param); - } - break; - } - - if(dest == NULL) { - goto loser; - } - - if ((dest->len == KEYDB_PW_CHECK_LEN) && - (PORT_Memcmp(dest->data, - KEYDB_PW_CHECK_STRING, KEYDB_PW_CHECK_LEN) == 0)) { - rv = SECSuccess; - /* we succeeded */ - if ( algorithm == SEC_OID_RC4 ) { - /* partially updated database */ - nsslowkey_UpdateKeyDBPass2(handle, pwitem); - } - /* Force an update of the password to remove the incorrect DES - * encryption (see the note above) - */ - if (update && - (algorithm == SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC)) { - /* data base was encoded with DES not triple des, fix it */ - nsslowkey_UpdateKeyDBPass2(handle,pwitem); - } - } - -loser: - sec_destroy_dbkey(dbkey); - if(dest != NULL) { - SECITEM_ZfreeItem(dest, PR_TRUE); - } - - return(rv); -} - -/* - * Change the database password and/or algorithm. This internal - * routine does not check the old password. That must be done by - * the caller. - */ -static SECStatus -ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, - SECItem *oldpwitem, SECItem *newpwitem, - SECOidTag new_algorithm) -{ - SECStatus rv; - keyList keylist; - keyNode *node = NULL; - NSSLOWKEYPrivateKey *privkey = NULL; - char *nickname; - DBT newkey; - int ret; - - /* traverse the database, collecting the keys of all records */ - keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if ( keylist.arena == NULL ) - { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return(SECFailure); - } - keylist.head = NULL; - - rv = db_BeginTransaction(handle->db); - if (rv != SECSuccess) { - goto loser; - } - - /* TNH - TraverseKeys should not be public, since it exposes - the underlying DBT data type. */ - rv = nsslowkey_TraverseKeys(handle, sec_add_key_to_list, (void *)&keylist); - if ( rv != SECSuccess ) - goto loser; - - /* walk the list, re-encrypting each entry */ - node = keylist.head; - while ( node != NULL ) - { - privkey = seckey_get_private_key(handle, &node->key, &nickname, - oldpwitem); - - if (privkey == NULL) { - PORT_SetError(SEC_ERROR_BAD_DATABASE); - rv = SECFailure; - goto loser; - } - - /* delete the old record */ - ret = keydb_Del(handle, &node->key, 0); - if ( ret ) { - PORT_SetError(SEC_ERROR_BAD_DATABASE); - rv = SECFailure; - goto loser; - } - - /* get the public key, which we use as the database index */ - - switch (privkey->keyType) { - case NSSLOWKEYRSAKey: - newkey.data = privkey->u.rsa.modulus.data; - newkey.size = privkey->u.rsa.modulus.len; - break; - case NSSLOWKEYDSAKey: - newkey.data = privkey->u.dsa.publicValue.data; - newkey.size = privkey->u.dsa.publicValue.len; - break; - case NSSLOWKEYDHKey: - newkey.data = privkey->u.dh.publicValue.data; - newkey.size = privkey->u.dh.publicValue.len; - break; -#ifdef NSS_ENABLE_ECC - case NSSLOWKEYECKey: - newkey.data = privkey->u.ec.publicValue.data; - newkey.size = privkey->u.ec.publicValue.len; - break; -#endif /* NSS_ENABLE_ECC */ - default: - /* should we continue here and loose the key? */ - PORT_SetError(SEC_ERROR_BAD_DATABASE); - rv = SECFailure; - goto loser; - } - - rv = seckey_put_private_key(handle, &newkey, newpwitem, privkey, - nickname, PR_TRUE, new_algorithm); - - if ( rv != SECSuccess ) - { - PORT_SetError(SEC_ERROR_BAD_DATABASE); - rv = SECFailure; - goto loser; - } - - /* next node */ - node = node->next; - } - - rv = nsslowkey_SetKeyDBPasswordAlg(handle, newpwitem, new_algorithm); - -loser: - - db_FinishTransaction(handle->db,rv != SECSuccess); - - /* free the arena */ - if ( keylist.arena ) { - PORT_FreeArena(keylist.arena, PR_FALSE); - } - - return(rv); -} - -/* - * Re-encrypt the entire key database with a new password. - * NOTE: The really should create a new database rather than doing it - * in place in the original - */ -SECStatus -nsslowkey_ChangeKeyDBPassword(NSSLOWKEYDBHandle *handle, - SECItem *oldpwitem, SECItem *newpwitem) -{ - SECStatus rv; - - if (handle == NULL) { - PORT_SetError(SEC_ERROR_BAD_DATABASE); - rv = SECFailure; - goto loser; - } - - rv = nsslowkey_CheckKeyDBPassword(handle, oldpwitem); - if ( rv != SECSuccess ) { - return(SECFailure); /* return rv? */ - } - - rv = ChangeKeyDBPasswordAlg(handle, oldpwitem, newpwitem, - nsslowkey_GetDefaultKeyDBAlg()); - -loser: - return(rv); -} #define MAX_DB_SIZE 0xffff /* * Clear out all the keys in the existing database */ -SECStatus +static SECStatus nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle) { SECStatus rv; @@ -2715,7 +2087,7 @@ nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle) } if (handle->global_salt) { - rv = StoreKeyDBGlobalSalt(handle); + rv = StoreKeyDBGlobalSalt(handle, handle->global_salt); } else { rv = makeGlobalSalt(handle); if ( rv == SECSuccess ) { @@ -2841,3 +2213,58 @@ keydb_Close(NSSLOWKEYDBHandle *kdb) return; } +/* + * SDB Entry Points for the Key DB + */ + +CK_RV +lg_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry) +{ + NSSLOWKEYDBHandle *keydb; + SECStatus rv; + + keydb = lg_getKeyDB(sdb); + if (keydb == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + rv = nsslowkey_GetPWCheckEntry(keydb, entry); + if (rv != SECSuccess) { + return CKR_GENERAL_ERROR; + } + return CKR_OK; +} + +CK_RV +lg_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry) +{ + NSSLOWKEYDBHandle *keydb; + SECStatus rv; + + keydb = lg_getKeyDB(sdb); + if (keydb == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + rv = nsslowkey_PutPWCheckEntry(keydb, entry); + if (rv != SECSuccess) { + return CKR_GENERAL_ERROR; + } + return CKR_OK; +} + +CK_RV +lg_Reset(SDB *sdb) +{ + NSSLOWKEYDBHandle *keydb; + SECStatus rv; + + keydb = lg_getKeyDB(sdb); + if (keydb == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + rv = nsslowkey_ResetKeyDB(keydb); + if (rv != SECSuccess) { + return CKR_GENERAL_ERROR; + } + return CKR_OK; +} + diff --git a/security/nss/lib/softoken/keydbi.h b/security/nss/lib/softoken/legacydb/keydbi.h index f7f427266..f7f427266 100644 --- a/security/nss/lib/softoken/keydbi.h +++ b/security/nss/lib/softoken/legacydb/keydbi.h diff --git a/security/nss/lib/softoken/legacydb/legacydb.def b/security/nss/lib/softoken/legacydb/legacydb.def new file mode 100644 index 000000000..3e3247099 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/legacydb.def @@ -0,0 +1,64 @@ +;+# +;+# ***** BEGIN LICENSE BLOCK ***** +;+# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +;+# +;+# The contents of this file are subject to the Mozilla Public License Version +;+# 1.1 (the "License"); you may not use this file except in compliance with +;+# the License. You may obtain a copy of the License at +;+# http://www.mozilla.org/MPL/ +;+# +;+# Software distributed under the License is distributed on an "AS IS" basis, +;+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +;+# for the specific language governing rights and limitations under the +;+# License. +;+# +;+# The Original Code is the Netscape security libraries. +;+# +;+# The Initial Developer of the Original Code is +;+# Netscape Communications Corporation. +;+# Portions created by the Initial Developer are Copyright (C) 2000 +;+# the Initial Developer. All Rights Reserved. +;+# +;+# Contributor(s): +;+# Dr Stephen Henson <stephen.henson@gemplus.com> +;+# +;+# Alternatively, the contents of this file may be used under the terms of +;+# either the GNU General Public License Version 2 or later (the "GPL"), or +;+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +;+# in which case the provisions of the GPL or the LGPL are applicable instead +;+# of those above. If you wish to allow use of your version of this file only +;+# under the terms of either the GPL or the LGPL, and not to allow others to +;+# use your version of this file under the terms of the MPL, indicate your +;+# decision by deleting the provisions above and replace them with the notice +;+# and other provisions required by the GPL or the LGPL. If you do not delete +;+# the provisions above, a recipient may use your version of this file under +;+# the terms of any one of the MPL, the GPL or the LGPL. +;+# +;+# ***** END LICENSE BLOCK ***** +;+# +;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS +;+# 1. For all unix platforms, the string ";-" means "remove this line" +;+# 2. For all unix platforms, the string " DATA " will be removed from any +;+# line on which it occurs. +;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX. +;+# On AIX, lines containing ";+" will be removed. +;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed. +;+# 5. For all unix platforms, after the above processing has taken place, +;+# all characters after the first ";" on the line will be removed. +;+# And for AIX, the first ";" will also be removed. +;+# This file is passed directly to windows. Since ';' is a comment, all UNIX +;+# directives are hidden behind ";", ";+", and ";-" +;+LGDBM_3.12 { # NSS 3.12 release +;+ global: +LIBRARY lgdbm3 ;- +EXPORTS ;- +legacy_Open; +legacy_Shutdown; +legacy_ReadSecmodDB; +legacy_ReleaseSecmodDBData; +legacy_AddSecmodDB; +legacy_DeleteSecmodDB; +legacy_SetCryptFunctions; +;+ local: +;+ *; +;+}; diff --git a/security/nss/lib/softoken/legacydb/lgattr.c b/security/nss/lib/softoken/legacydb/lgattr.c new file mode 100644 index 000000000..428d2ae66 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lgattr.c @@ -0,0 +1,1748 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Internal PKCS #11 functions. Should only be called by pkcs11.c + */ +#include "pkcs11.h" +#include "lgdb.h" + +#include "pcertt.h" +#include "lowkeyi.h" +#include "pcert.h" +#include "blapi.h" +#include "secerr.h" + +/* + * Cache the object we are working on during Set's and Get's + */ +typedef struct LGObjectCacheStr { + CK_OBJECT_CLASS objclass; + CK_OBJECT_HANDLE handle; + SDB *sdb; + void *objectInfo; + LGFreeFunc infoFree; + SECItem dbKey; +} LGObjectCache; + +static const CK_OBJECT_HANDLE lg_classArray[] = { + 0, CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, CKO_SECRET_KEY, + CKO_NETSCAPE_TRUST, CKO_NETSCAPE_CRL, CKO_NETSCAPE_SMIME, + CKO_CERTIFICATE }; + +#define handleToClass(handle) \ + lg_classArray[((handle & LG_TOKEN_TYPE_MASK))>>LG_TOKEN_TYPE_SHIFT] + + +static void lg_DestroyObjectCache(LGObjectCache *obj); + +static LGObjectCache * +lg_NewObjectCache(SDB *sdb, const SECItem *dbKey, CK_OBJECT_HANDLE handle) +{ + LGObjectCache *obj = NULL; + SECStatus rv; + + obj = PORT_New(LGObjectCache); + if (obj == NULL) { + return NULL; + } + + obj->objclass = handleToClass(handle); + obj->handle = handle; + obj->sdb = sdb; + obj->objectInfo = NULL; + obj->infoFree = NULL; + lg_DBLock(sdb); + if (dbKey == NULL) { + dbKey = lg_lookupTokenKeyByHandle(sdb,handle); + } + if (dbKey == NULL) { + lg_DBUnlock(sdb); + goto loser; + } + rv = SECITEM_CopyItem(NULL,&obj->dbKey,dbKey); + lg_DBUnlock(sdb); + if (rv != SECSuccess) { + goto loser; + } + + return obj; +loser: + if (obj) { + (void) lg_DestroyObjectCache(obj); + } + return NULL; + +} + +/* + * free all the data associated with an object. Object reference count must + * be 'zero'. + */ +static void +lg_DestroyObjectCache(LGObjectCache *obj) +{ + if (obj->dbKey.data) { + PORT_Free(obj->dbKey.data); + obj->dbKey.data = NULL; + } + if (obj->objectInfo) { + (*obj->infoFree)(obj->objectInfo); + obj->objectInfo = NULL; + obj->infoFree = NULL; + } + PORT_Free(obj); +} +/* + * ******************** Attribute Utilities ******************************* + */ + +static CK_RV +lg_ULongAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE_TYPE type, CK_ULONG value) +{ + unsigned char *data; + int i; + + if (attr->pValue == NULL) { + attr->ulValueLen = 4; + return CKR_OK; + } + if (attr->ulValueLen < 4) { + attr->ulValueLen = (CK_ULONG) -1; + return CKR_BUFFER_TOO_SMALL; + } + + data = (unsigned char *)attr->pValue; + for (i=0; i < 4; i++) { + data[i] = (value >> ((3-i)*8)) & 0xff; + } + attr->ulValueLen = 4; + return CKR_OK; +} + +static CK_RV +lg_CopyAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE_TYPE type, + CK_VOID_PTR value, CK_ULONG len) +{ + + if (attr->pValue == NULL) { + attr->ulValueLen = len; + return CKR_OK; + } + if (attr->ulValueLen < len) { + attr->ulValueLen = (CK_ULONG) -1; + return CKR_BUFFER_TOO_SMALL; + } + PORT_Memcpy(attr->pValue,value,len); + attr->ulValueLen = len; + return CKR_OK; +} + +static CK_RV +lg_CopyAttributeSigned(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type, + void *value, CK_ULONG len) +{ + unsigned char * dval = (unsigned char *)value; + if (*dval == 0) { + dval++; + len--; + } + return lg_CopyAttribute(attribute,type,dval,len); +} + +static CK_RV +lg_CopyPrivAttribute(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type, + void *value, CK_ULONG len, SDB *sdbpw) +{ + SECItem plainText, *cipherText = NULL; + CK_RV crv = CKR_USER_NOT_LOGGED_IN; + SECStatus rv; + + plainText.data = value; + plainText.len = len; + rv = lg_util_encrypt(NULL, sdbpw, &plainText, &cipherText); + if (rv != SECSuccess) { + goto loser; + } + crv = lg_CopyAttribute(attribute,type,cipherText->data,cipherText->len); +loser: + if (cipherText) { + SECITEM_FreeItem(cipherText,PR_TRUE); + } + return crv; +} + +static CK_RV +lg_CopyPrivAttrSigned(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type, + void *value, CK_ULONG len, SDB *sdbpw) +{ + unsigned char * dval = (unsigned char *)value; + + if (*dval == 0) { + dval++; + len--; + } + return lg_CopyPrivAttribute(attribute,type,dval,len,sdbpw); +} + +static CK_RV +lg_invalidAttribute(CK_ATTRIBUTE *attr) +{ + attr->ulValueLen = (CK_ULONG) -1; + return CKR_ATTRIBUTE_TYPE_INVALID; +} + + +#define LG_DEF_ATTRIBUTE(value,len) \ + { 0, value, len } + +#define LG_CLONE_ATTR(attribute, type, staticAttr) \ + lg_CopyAttribute(attribute, type, staticAttr.pValue, staticAttr.ulValueLen) + +CK_BBOOL lg_staticTrueValue = CK_TRUE; +CK_BBOOL lg_staticFalseValue = CK_FALSE; +static const CK_ATTRIBUTE lg_StaticTrueAttr = + LG_DEF_ATTRIBUTE(&lg_staticTrueValue,sizeof(lg_staticTrueValue)); +static const CK_ATTRIBUTE lg_StaticFalseAttr = + LG_DEF_ATTRIBUTE(&lg_staticFalseValue,sizeof(lg_staticFalseValue)); +static const CK_ATTRIBUTE lg_StaticNullAttr = LG_DEF_ATTRIBUTE(NULL,0); +char lg_StaticOneValue = 1; +static const CK_ATTRIBUTE lg_StaticOneAttr = + LG_DEF_ATTRIBUTE(&lg_StaticOneValue,sizeof(lg_StaticOneValue)); + +/* + * helper functions which get the database and call the underlying + * low level database function. + */ +static char * +lg_FindKeyNicknameByPublicKey(SDB *sdb, SECItem *dbKey) +{ + NSSLOWKEYDBHandle *keyHandle; + char * label; + + keyHandle = lg_getKeyDB(sdb); + if (!keyHandle) { + return NULL; + } + + label = nsslowkey_FindKeyNicknameByPublicKey(keyHandle, dbKey, + sdb); + return label; +} + + +NSSLOWKEYPrivateKey * +lg_FindKeyByPublicKey(SDB *sdb, SECItem *dbKey) +{ + NSSLOWKEYPrivateKey *privKey; + NSSLOWKEYDBHandle *keyHandle; + + keyHandle = lg_getKeyDB(sdb); + if (keyHandle == NULL) { + return NULL; + } + privKey = nsslowkey_FindKeyByPublicKey(keyHandle, dbKey, sdb); + if (privKey == NULL) { + return NULL; + } + return privKey; +} + +static certDBEntrySMime * +lg_getSMime(LGObjectCache *obj) +{ + certDBEntrySMime *entry; + NSSLOWCERTCertDBHandle *certHandle; + + if (obj->objclass != CKO_NETSCAPE_SMIME) { + return NULL; + } + if (obj->objectInfo) { + return (certDBEntrySMime *)obj->objectInfo; + } + + certHandle = lg_getCertDB(obj->sdb); + if (!certHandle) { + return NULL; + } + entry = nsslowcert_ReadDBSMimeEntry(certHandle, (char *)obj->dbKey.data); + obj->objectInfo = (void *)entry; + obj->infoFree = (LGFreeFunc) nsslowcert_DestroyDBEntry; + return entry; +} + +static certDBEntryRevocation * +lg_getCrl(LGObjectCache *obj) +{ + certDBEntryRevocation *crl; + PRBool isKrl; + NSSLOWCERTCertDBHandle *certHandle; + + if (obj->objclass != CKO_NETSCAPE_CRL) { + return NULL; + } + if (obj->objectInfo) { + return (certDBEntryRevocation *)obj->objectInfo; + } + + isKrl = (PRBool) (obj->handle == LG_TOKEN_KRL_HANDLE); + certHandle = lg_getCertDB(obj->sdb); + if (!certHandle) { + return NULL; + } + + crl = nsslowcert_FindCrlByKey(certHandle, &obj->dbKey, isKrl); + obj->objectInfo = (void *)crl; + obj->infoFree = (LGFreeFunc) nsslowcert_DestroyDBEntry; + return crl; +} + +static NSSLOWCERTCertificate * +lg_getCert(LGObjectCache *obj, NSSLOWCERTCertDBHandle *certHandle) +{ + NSSLOWCERTCertificate *cert; + CK_OBJECT_CLASS objClass = obj->objclass; + + if ((objClass != CKO_CERTIFICATE) && (objClass != CKO_NETSCAPE_TRUST)) { + return NULL; + } + if (objClass == CKO_CERTIFICATE && obj->objectInfo) { + return (NSSLOWCERTCertificate *)obj->objectInfo; + } + cert = nsslowcert_FindCertByKey(certHandle, &obj->dbKey); + if (objClass == CKO_CERTIFICATE) { + obj->objectInfo = (void *)cert; + obj->infoFree = (LGFreeFunc) nsslowcert_DestroyCertificate ; + } + return cert; +} + +static NSSLOWCERTTrust * +lg_getTrust(LGObjectCache *obj, NSSLOWCERTCertDBHandle *certHandle) +{ + NSSLOWCERTTrust *trust; + + if (obj->objclass != CKO_NETSCAPE_TRUST) { + return NULL; + } + if (obj->objectInfo) { + return (NSSLOWCERTTrust *)obj->objectInfo; + } + trust = nsslowcert_FindTrustByKey(certHandle, &obj->dbKey); + obj->objectInfo = (void *)trust; + obj->infoFree = (LGFreeFunc) nsslowcert_DestroyTrust ; + return trust; +} + +static NSSLOWKEYPublicKey * +lg_GetPublicKey(LGObjectCache *obj) +{ + NSSLOWKEYPublicKey *pubKey; + NSSLOWKEYPrivateKey *privKey; + + if (obj->objclass != CKO_PUBLIC_KEY) { + return NULL; + } + if (obj->objectInfo) { + return (NSSLOWKEYPublicKey *)obj->objectInfo; + } + privKey = lg_FindKeyByPublicKey(obj->sdb, &obj->dbKey); + if (privKey == NULL) { + return NULL; + } + pubKey = nsslowkey_ConvertToPublicKey(privKey); + nsslowkey_DestroyPrivateKey(privKey); + obj->objectInfo = (void *) pubKey; + obj->infoFree = (LGFreeFunc) nsslowkey_DestroyPublicKey ; + return pubKey; +} + +/* + * we need two versions of lg_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 sdb (where we don't already have a key handle. + * This version does the former. + */ +static NSSLOWKEYPrivateKey * +lg_GetPrivateKeyWithDB(LGObjectCache *obj, NSSLOWKEYDBHandle *keyHandle) +{ + NSSLOWKEYPrivateKey *privKey; + + if ((obj->objclass != CKO_PRIVATE_KEY) && + (obj->objclass != CKO_SECRET_KEY)) { + return NULL; + } + if (obj->objectInfo) { + return (NSSLOWKEYPrivateKey *)obj->objectInfo; + } + privKey = nsslowkey_FindKeyByPublicKey(keyHandle, &obj->dbKey, obj->sdb); + if (privKey == NULL) { + return NULL; + } + obj->objectInfo = (void *) privKey; + obj->infoFree = (LGFreeFunc) nsslowkey_DestroyPrivateKey ; + return privKey; +} + +/* this version does the latter */ +static NSSLOWKEYPrivateKey * +lg_GetPrivateKey(LGObjectCache *obj) +{ + NSSLOWKEYDBHandle *keyHandle; + NSSLOWKEYPrivateKey *privKey; + + keyHandle = lg_getKeyDB(obj->sdb); + if (!keyHandle) { + return NULL; + } + privKey = lg_GetPrivateKeyWithDB(obj, keyHandle); + return privKey; +} + +/* lg_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 + * should include this comment. + */ +static SECItem * +lg_GetPubItem(NSSLOWKEYPublicKey *pubKey) { + SECItem *pubItem = NULL; + /* get value to compare from the cert's public key */ + switch ( pubKey->keyType ) { + case NSSLOWKEYRSAKey: + pubItem = &pubKey->u.rsa.modulus; + break; + case NSSLOWKEYDSAKey: + pubItem = &pubKey->u.dsa.publicValue; + break; + case NSSLOWKEYDHKey: + pubItem = &pubKey->u.dh.publicValue; + break; +#ifdef NSS_ENABLE_ECC + case NSSLOWKEYECKey: + pubItem = &pubKey->u.ec.publicValue; + break; +#endif /* NSS_ENABLE_ECC */ + default: + break; + } + return pubItem; +} + +static const SEC_ASN1Template lg_SerialTemplate[] = { + { SEC_ASN1_INTEGER, offsetof(NSSLOWCERTCertificate,serialNumber) }, + { 0 } +}; + +static CK_RV +lg_FindRSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + unsigned char hash[SHA1_LENGTH]; + CK_KEY_TYPE keyType = CKK_RSA; + + switch (type) { + case CKA_KEY_TYPE: + return lg_ULongAttribute(attribute, type, keyType); + case CKA_ID: + SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len); + return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); + case CKA_DERIVE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_ENCRYPT: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + case CKA_WRAP: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_MODULUS: + return lg_CopyAttributeSigned(attribute,type,key->u.rsa.modulus.data, + key->u.rsa.modulus.len); + case CKA_PUBLIC_EXPONENT: + return lg_CopyAttributeSigned(attribute, type, + key->u.rsa.publicExponent.data, + key->u.rsa.publicExponent.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindDSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + unsigned char hash[SHA1_LENGTH]; + CK_KEY_TYPE keyType = CKK_DSA; + + switch (type) { + case CKA_KEY_TYPE: + return lg_ULongAttribute(attribute, type, keyType); + case CKA_ID: + SHA1_HashBuf(hash,key->u.dsa.publicValue.data, + key->u.dsa.publicValue.len); + return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); + case CKA_DERIVE: + case CKA_ENCRYPT: + case CKA_VERIFY_RECOVER: + case CKA_WRAP: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_VERIFY: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_VALUE: + return lg_CopyAttributeSigned(attribute,type, + key->u.dsa.publicValue.data, + key->u.dsa.publicValue.len); + case CKA_PRIME: + return lg_CopyAttributeSigned(attribute,type, + key->u.dsa.params.prime.data, + key->u.dsa.params.prime.len); + case CKA_SUBPRIME: + return lg_CopyAttributeSigned(attribute,type, + key->u.dsa.params.subPrime.data, + key->u.dsa.params.subPrime.len); + case CKA_BASE: + return lg_CopyAttributeSigned(attribute,type, + key->u.dsa.params.base.data, + key->u.dsa.params.base.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindDHPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + unsigned char hash[SHA1_LENGTH]; + CK_KEY_TYPE keyType = CKK_DH; + + switch (type) { + case CKA_KEY_TYPE: + return lg_ULongAttribute(attribute, type, keyType); + case CKA_ID: + SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len); + return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); + case CKA_DERIVE: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_ENCRYPT: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + case CKA_WRAP: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_VALUE: + return lg_CopyAttributeSigned(attribute,type, + key->u.dh.publicValue.data, + key->u.dh.publicValue.len); + case CKA_PRIME: + return lg_CopyAttributeSigned(attribute,type,key->u.dh.prime.data, + key->u.dh.prime.len); + case CKA_BASE: + return lg_CopyAttributeSigned(attribute,type,key->u.dh.base.data, + key->u.dh.base.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +#ifdef NSS_ENABLE_ECC +static CK_RV +lg_FindECPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + unsigned char hash[SHA1_LENGTH]; + CK_KEY_TYPE keyType = CKK_EC; + + switch (type) { + case CKA_KEY_TYPE: + return lg_ULongAttribute(attribute, type, keyType); + case CKA_ID: + SHA1_HashBuf(hash, key->u.ec.publicValue.data, + key->u.ec.publicValue.len); + return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); + case CKA_DERIVE: + case CKA_VERIFY: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_ENCRYPT: + case CKA_VERIFY_RECOVER: + case CKA_WRAP: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_EC_PARAMS: + return lg_CopyAttributeSigned(attribute,type, + key->u.ec.ecParams.DEREncoding.data, + key->u.ec.ecParams.DEREncoding.len); + case CKA_EC_POINT: + return lg_CopyAttributeSigned(attribute, type, + key->u.ec.publicValue.data, + key->u.ec.publicValue.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} +#endif /* NSS_ENABLE_ECC */ + + +static CK_RV +lg_FindPublicKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + NSSLOWKEYPublicKey *key; + CK_RV crv; + char *label; + + switch (type) { + case CKA_PRIVATE: + case CKA_SENSITIVE: + case CKA_ALWAYS_SENSITIVE: + case CKA_NEVER_EXTRACTABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_MODIFIABLE: + case CKA_EXTRACTABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_LABEL: + label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey); + if (label == NULL) { + return LG_CLONE_ATTR(attribute,type,lg_StaticOneAttr); + } + crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label)); + PORT_Free(label); + return crv; + default: + break; + } + + key = lg_GetPublicKey(obj); + if (key == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + + switch (key->keyType) { + case NSSLOWKEYRSAKey: + return lg_FindRSAPublicKeyAttribute(key,type,attribute); + case NSSLOWKEYDSAKey: + return lg_FindDSAPublicKeyAttribute(key,type,attribute); + case NSSLOWKEYDHKey: + return lg_FindDHPublicKeyAttribute(key,type,attribute); +#ifdef NSS_ENABLE_ECC + case NSSLOWKEYECKey: + return lg_FindECPublicKeyAttribute(key,type,attribute); +#endif /* NSS_ENABLE_ECC */ + default: + break; + } + + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindSecretKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + NSSLOWKEYPrivateKey *key; + char *label; + unsigned char *keyString; + CK_RV crv; + int keyTypeLen; + CK_ULONG keyLen; + CK_KEY_TYPE keyType; + PRUint32 keyTypeStorage; + + switch (type) { + case CKA_PRIVATE: + case CKA_SENSITIVE: + case CKA_ALWAYS_SENSITIVE: + case CKA_EXTRACTABLE: + case CKA_DERIVE: + case CKA_ENCRYPT: + case CKA_DECRYPT: + case CKA_SIGN: + case CKA_VERIFY: + case CKA_WRAP: + case CKA_UNWRAP: + case CKA_MODIFIABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_NEVER_EXTRACTABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_LABEL: + label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey); + if (label == NULL) { + return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); + } + crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label)); + PORT_Free(label); + return crv; + case CKA_ID: + return lg_CopyAttribute(attribute,type,obj->dbKey.data, + obj->dbKey.len); + case CKA_KEY_TYPE: + case CKA_VALUE_LEN: + case CKA_VALUE: + break; + default: + return lg_invalidAttribute(attribute); + } + + key = lg_GetPrivateKey(obj); + if (key == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + switch (type) { + case CKA_KEY_TYPE: + /* handle legacy databases. In legacy databases key_type was stored + * in host order, with any leading zeros stripped off. Only key types + * under 0x1f (AES) were stored. We assume that any values which are + * either 1 byte long (big endian), or have byte[0] between 0 and + * 0x7f and bytes[1]-bytes[3] equal to '0' (little endian). All other + * values are assumed to be from the new database, which is always 4 + * bytes in network order */ + keyType=0; + keyString = key->u.rsa.coefficient.data; + keyTypeLen = key->u.rsa.coefficient.len; + + + /* + * Because of various endian and word lengths The database may have + * stored the keyType value in one of the following formats: + * (kt) <= 0x1f + * length data + * Big Endian, pre-3.9, all lengths: 1 (kt) + * Little Endian, pre-3.9, 32 bits: 4 (kt) 0 0 0 + * Little Endian, pre-3.9, 64 bits: 8 (kt) 0 0 0 0 0 0 0 + * All platforms, 3.9, 32 bits: 4 0 0 0 (kt) + * Big Endian, 3.9, 64 bits: 8 0 0 0 (kt) 0 0 0 0 + * Little Endian, 3.9, 64 bits: 8 0 0 0 0 0 0 0 (kt) + * All platforms, >= 3.9.1, all lengths: 4 (a) k1 k2 k3 + * where (a) is 0 or >= 0x80. currently (a) can only be 0. + */ + /* + * this key was written on a 64 bit platform with a using NSS 3.9 + * or earlier. Reduce the 64 bit possibilities above. When we are + * through, we will only have: + * + * Big Endian, pre-3.9, all lengths: 1 (kt) + * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 + * All platforms, 3.9, all lengths: 4 0 0 0 (kt) + * All platforms, => 3.9.1, all lengths: 4 (a) k1 k2 k3 + */ + if (keyTypeLen == 8) { + keyTypeStorage = *(PRUint32 *) keyString; + if (keyTypeStorage == 0) { + keyString += sizeof(PRUint32); + } + keyTypeLen = 4; + } + /* + * Now Handle: + * + * All platforms, 3.9, all lengths: 4 0 0 0 (kt) + * All platforms, => 3.9.1, all lengths: 4 (a) k1 k2 k3 + * + * NOTE: if kt == 0 or ak1k2k3 == 0, the test fails and + * we handle it as: + * + * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 + */ + if (keyTypeLen == sizeof(keyTypeStorage) && + (((keyString[0] & 0x80) == 0x80) || + !((keyString[1] == 0) && (keyString[2] == 0) + && (keyString[3] == 0))) ) { + PORT_Memcpy(&keyTypeStorage, keyString, sizeof(keyTypeStorage)); + keyType = (CK_KEY_TYPE) PR_ntohl(keyTypeStorage); + } else { + /* + * Now Handle: + * + * Big Endian, pre-3.9, all lengths: 1 (kt) + * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 + * -- KeyType == 0 all other cases ---: 4 0 0 0 0 + */ + keyType = (CK_KEY_TYPE) keyString[0] ; + } + return lg_ULongAttribute(attribute, type, keyType); + case CKA_VALUE: + return lg_CopyPrivAttribute(attribute,type,key->u.rsa.privateExponent.data, + key->u.rsa.privateExponent.len, obj->sdb); + case CKA_VALUE_LEN: + keyLen=key->u.rsa.privateExponent.len; + return lg_ULongAttribute(attribute,type, keyLen); + } + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute, SDB *sdbpw) +{ + unsigned char hash[SHA1_LENGTH]; + CK_KEY_TYPE keyType = CKK_RSA; + + switch (type) { + case CKA_KEY_TYPE: + return lg_ULongAttribute(attribute, type, keyType); + case CKA_ID: + SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len); + return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); + case CKA_DERIVE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_DECRYPT: + case CKA_SIGN: + case CKA_SIGN_RECOVER: + case CKA_UNWRAP: + return LG_CLONE_ATTR(attribute, type,lg_StaticTrueAttr); + case CKA_MODULUS: + return lg_CopyAttributeSigned(attribute,type,key->u.rsa.modulus.data, + key->u.rsa.modulus.len); + case CKA_PUBLIC_EXPONENT: + return lg_CopyAttributeSigned(attribute, type, + key->u.rsa.publicExponent.data, + key->u.rsa.publicExponent.len); + case CKA_PRIVATE_EXPONENT: + return lg_CopyPrivAttrSigned(attribute,type, + key->u.rsa.privateExponent.data, + key->u.rsa.privateExponent.len, sdbpw); + case CKA_PRIME_1: + return lg_CopyPrivAttrSigned(attribute, type, key->u.rsa.prime1.data, + key->u.rsa.prime1.len, sdbpw); + case CKA_PRIME_2: + return lg_CopyPrivAttrSigned(attribute, type, key->u.rsa.prime2.data, + key->u.rsa.prime2.len, sdbpw); + case CKA_EXPONENT_1: + return lg_CopyPrivAttrSigned(attribute, type, + key->u.rsa.exponent1.data, + key->u.rsa.exponent1.len, sdbpw); + case CKA_EXPONENT_2: + return lg_CopyPrivAttrSigned(attribute, type, + key->u.rsa.exponent2.data, + key->u.rsa.exponent2.len, sdbpw); + case CKA_COEFFICIENT: + return lg_CopyPrivAttrSigned(attribute, type, + key->u.rsa.coefficient.data, + key->u.rsa.coefficient.len, sdbpw); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindDSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute, SDB *sdbpw) +{ + unsigned char hash[SHA1_LENGTH]; + CK_KEY_TYPE keyType = CKK_DSA; + + switch (type) { + case CKA_KEY_TYPE: + return lg_ULongAttribute(attribute, type, keyType); + case CKA_ID: + SHA1_HashBuf(hash,key->u.dsa.publicValue.data, + key->u.dsa.publicValue.len); + return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); + case CKA_DERIVE: + case CKA_DECRYPT: + case CKA_SIGN_RECOVER: + case CKA_UNWRAP: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_SIGN: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_VALUE: + return lg_CopyPrivAttrSigned(attribute, type, + key->u.dsa.privateValue.data, + key->u.dsa.privateValue.len, sdbpw); + case CKA_PRIME: + return lg_CopyAttributeSigned(attribute, type, + key->u.dsa.params.prime.data, + key->u.dsa.params.prime.len); + case CKA_SUBPRIME: + return lg_CopyAttributeSigned(attribute, type, + key->u.dsa.params.subPrime.data, + key->u.dsa.params.subPrime.len); + case CKA_BASE: + return lg_CopyAttributeSigned(attribute, type, + key->u.dsa.params.base.data, + key->u.dsa.params.base.len); + case CKA_NETSCAPE_DB: + return lg_CopyAttributeSigned(attribute, type, + key->u.dsa.publicValue.data, + key->u.dsa.publicValue.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindDHPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute, SDB *sdbpw) +{ + unsigned char hash[SHA1_LENGTH]; + CK_KEY_TYPE keyType = CKK_DH; + + switch (type) { + case CKA_KEY_TYPE: + return lg_ULongAttribute(attribute, type, keyType); + case CKA_ID: + SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len); + return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); + case CKA_DERIVE: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_DECRYPT: + case CKA_SIGN: + case CKA_SIGN_RECOVER: + case CKA_UNWRAP: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_VALUE: + return lg_CopyPrivAttrSigned(attribute, type, + key->u.dh.privateValue.data, + key->u.dh.privateValue.len, sdbpw); + case CKA_PRIME: + return lg_CopyAttributeSigned(attribute, type, key->u.dh.prime.data, + key->u.dh.prime.len); + case CKA_BASE: + return lg_CopyAttributeSigned(attribute, type, key->u.dh.base.data, + key->u.dh.base.len); + case CKA_NETSCAPE_DB: + return lg_CopyAttributeSigned(attribute, type, + key->u.dh.publicValue.data, + key->u.dh.publicValue.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +#ifdef NSS_ENABLE_ECC +static CK_RV +lg_FindECPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute, SDB *sdbpw) +{ + unsigned char hash[SHA1_LENGTH]; + CK_KEY_TYPE keyType = CKK_EC; + + switch (type) { + case CKA_KEY_TYPE: + return lg_ULongAttribute(attribute, type, keyType); + case CKA_ID: + SHA1_HashBuf(hash,key->u.ec.publicValue.data,key->u.ec.publicValue.len); + return lg_CopyAttribute(attribute,type,hash,SHA1_LENGTH); + case CKA_DERIVE: + case CKA_SIGN: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_DECRYPT: + case CKA_SIGN_RECOVER: + case CKA_UNWRAP: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_VALUE: + return lg_CopyPrivAttrSigned(attribute, type, + key->u.ec.privateValue.data, + key->u.ec.privateValue.len, sdbpw); + case CKA_EC_PARAMS: + return lg_CopyAttributeSigned(attribute, type, + key->u.ec.ecParams.DEREncoding.data, + key->u.ec.ecParams.DEREncoding.len); + case CKA_NETSCAPE_DB: + return lg_CopyAttributeSigned(attribute, type, + key->u.ec.publicValue.data, + key->u.ec.publicValue.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} +#endif /* NSS_ENABLE_ECC */ + +static CK_RV +lg_FindPrivateKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + NSSLOWKEYPrivateKey *key; + char *label; + CK_RV crv; + + switch (type) { + case CKA_PRIVATE: + case CKA_SENSITIVE: + case CKA_ALWAYS_SENSITIVE: + case CKA_EXTRACTABLE: + case CKA_MODIFIABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_NEVER_EXTRACTABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_SUBJECT: + return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); + case CKA_LABEL: + label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey); + if (label == NULL) { + return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); + } + crv = lg_CopyAttribute(attribute,type,label,PORT_Strlen(label)); + PORT_Free(label); + return crv; + default: + break; + } + key = lg_GetPrivateKey(obj); + if (key == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + switch (key->keyType) { + case NSSLOWKEYRSAKey: + return lg_FindRSAPrivateKeyAttribute(key,type,attribute,obj->sdb); + case NSSLOWKEYDSAKey: + return lg_FindDSAPrivateKeyAttribute(key,type,attribute,obj->sdb); + case NSSLOWKEYDHKey: + return lg_FindDHPrivateKeyAttribute(key,type,attribute,obj->sdb); +#ifdef NSS_ENABLE_ECC + case NSSLOWKEYECKey: + return lg_FindECPrivateKeyAttribute(key,type,attribute,obj->sdb); +#endif /* NSS_ENABLE_ECC */ + default: + break; + } + + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindSMIMEAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + certDBEntrySMime *entry; + switch (type) { + case CKA_PRIVATE: + case CKA_MODIFIABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_NETSCAPE_EMAIL: + return lg_CopyAttribute(attribute,type,obj->dbKey.data, + obj->dbKey.len-1); + case CKA_NETSCAPE_SMIME_TIMESTAMP: + case CKA_SUBJECT: + case CKA_VALUE: + break; + default: + return lg_invalidAttribute(attribute); + } + entry = lg_getSMime(obj); + if (entry == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + switch (type) { + case CKA_NETSCAPE_SMIME_TIMESTAMP: + return lg_CopyAttribute(attribute,type,entry->optionsDate.data, + entry->optionsDate.len); + case CKA_SUBJECT: + return lg_CopyAttribute(attribute,type,entry->subjectName.data, + entry->subjectName.len); + case CKA_VALUE: + return lg_CopyAttribute(attribute,type,entry->smimeOptions.data, + entry->smimeOptions.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindTrustAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + NSSLOWCERTTrust *trust; + NSSLOWCERTCertDBHandle *certHandle; + NSSLOWCERTCertificate *cert; + unsigned char hash[SHA1_LENGTH]; + unsigned int trustFlags; + CK_RV crv; + + switch (type) { + case CKA_PRIVATE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_MODIFIABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_CERT_SHA1_HASH: + case CKA_CERT_MD5_HASH: + case CKA_TRUST_CLIENT_AUTH: + case CKA_TRUST_SERVER_AUTH: + case CKA_TRUST_EMAIL_PROTECTION: + case CKA_TRUST_CODE_SIGNING: + case CKA_TRUST_STEP_UP_APPROVED: + case CKA_ISSUER: + case CKA_SERIAL_NUMBER: + break; + default: + return lg_invalidAttribute(attribute); + } + certHandle = lg_getCertDB(obj->sdb); + if (!certHandle) { + return CKR_OBJECT_HANDLE_INVALID; + } + trust = lg_getTrust(obj, certHandle); + if (trust == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + switch (type) { + case CKA_CERT_SHA1_HASH: + SHA1_HashBuf(hash,trust->derCert->data,trust->derCert->len); + return lg_CopyAttribute(attribute, type, hash, SHA1_LENGTH); + case CKA_CERT_MD5_HASH: + MD5_HashBuf(hash,trust->derCert->data,trust->derCert->len); + return lg_CopyAttribute(attribute, type, hash, MD5_LENGTH); + case CKA_TRUST_CLIENT_AUTH: + trustFlags = trust->trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ? + trust->trust->sslFlags | CERTDB_TRUSTED_CA : 0 ; + goto trust; + case CKA_TRUST_SERVER_AUTH: + trustFlags = trust->trust->sslFlags; + goto trust; + case CKA_TRUST_EMAIL_PROTECTION: + trustFlags = trust->trust->emailFlags; + goto trust; + case CKA_TRUST_CODE_SIGNING: + trustFlags = trust->trust->objectSigningFlags; +trust: + if (trustFlags & CERTDB_TRUSTED_CA ) { + return lg_ULongAttribute(attribute, type, + CKT_NETSCAPE_TRUSTED_DELEGATOR); + } + if (trustFlags & CERTDB_TRUSTED) { + return lg_ULongAttribute(attribute, type, CKT_NETSCAPE_TRUSTED); + } + if (trustFlags & CERTDB_NOT_TRUSTED) { + return lg_ULongAttribute(attribute, type, CKT_NETSCAPE_UNTRUSTED); + } + if (trustFlags & CERTDB_TRUSTED_UNKNOWN) { + return lg_ULongAttribute(attribute, type, + CKT_NETSCAPE_TRUST_UNKNOWN); + } + if (trustFlags & CERTDB_VALID_CA) { + return lg_ULongAttribute(attribute, type, + CKT_NETSCAPE_VALID_DELEGATOR); + } + if (trustFlags & CERTDB_VALID_PEER) { + return lg_ULongAttribute(attribute, type, CKT_NETSCAPE_VALID); + } + return lg_ULongAttribute(attribute, type, CKT_NETSCAPE_MUST_VERIFY); + case CKA_TRUST_STEP_UP_APPROVED: + if (trust->trust->sslFlags & CERTDB_GOVT_APPROVED_CA) { + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + } else { + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + } + default: + break; + } + + + switch (type) { + case CKA_ISSUER: + cert = lg_getCert(obj, certHandle); + if (cert == NULL) break; + crv = lg_CopyAttribute(attribute,type,cert->derIssuer.data, + cert->derIssuer.len); + break; + case CKA_SERIAL_NUMBER: + cert = lg_getCert(obj, certHandle); + if (cert == NULL) break; + crv = lg_CopyAttribute(attribute,type,cert->derSN.data, + cert->derSN.len); + break; + default: + cert = NULL; + break; + } + if (cert) { + nsslowcert_DestroyCertificate(cert); + return crv; + } + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindCrlAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + certDBEntryRevocation *crl; + + switch (type) { + case CKA_PRIVATE: + case CKA_MODIFIABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_NETSCAPE_KRL: + return ((obj->handle == LG_TOKEN_KRL_HANDLE) + ? LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr) + : LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr)); + case CKA_SUBJECT: + return lg_CopyAttribute(attribute,type,obj->dbKey.data, + obj->dbKey.len); + case CKA_NETSCAPE_URL: + case CKA_VALUE: + break; + default: + return lg_invalidAttribute(attribute); + } + crl = lg_getCrl(obj); + if (!crl) { + return CKR_OBJECT_HANDLE_INVALID; + } + switch (type) { + case CKA_NETSCAPE_URL: + if (crl->url == NULL) { + return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); + } + return lg_CopyAttribute(attribute, type, crl->url, + PORT_Strlen(crl->url)+1); + case CKA_VALUE: + return lg_CopyAttribute(attribute, type, crl->derCrl.data, + crl->derCrl.len); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +static CK_RV +lg_FindCertAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE *attribute) +{ + NSSLOWCERTCertificate *cert; + NSSLOWCERTCertDBHandle *certHandle; + NSSLOWKEYPublicKey *pubKey; + unsigned char hash[SHA1_LENGTH]; + SECItem *item; + + switch (type) { + case CKA_PRIVATE: + return LG_CLONE_ATTR(attribute,type,lg_StaticFalseAttr); + case CKA_MODIFIABLE: + return LG_CLONE_ATTR(attribute,type,lg_StaticTrueAttr); + case CKA_CERTIFICATE_TYPE: + /* hardcoding X.509 into here */ + return lg_ULongAttribute(attribute, type, CKC_X_509); + case CKA_VALUE: + case CKA_ID: + case CKA_LABEL: + case CKA_SUBJECT: + case CKA_ISSUER: + case CKA_SERIAL_NUMBER: + case CKA_NETSCAPE_EMAIL: + break; + default: + return lg_invalidAttribute(attribute); + } + + certHandle = lg_getCertDB(obj->sdb); + if (certHandle == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + + cert = lg_getCert(obj, certHandle); + if (cert == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + switch (type) { + case CKA_VALUE: + return lg_CopyAttribute(attribute,type,cert->derCert.data, + cert->derCert.len); + case CKA_ID: + if (((cert->trust->sslFlags & CERTDB_USER) == 0) && + ((cert->trust->emailFlags & CERTDB_USER) == 0) && + ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) { + return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); + } + pubKey = nsslowcert_ExtractPublicKey(cert); + if (pubKey == NULL) break; + item = lg_GetPubItem(pubKey); + if (item == NULL) { + nsslowkey_DestroyPublicKey(pubKey); + break; + } + SHA1_HashBuf(hash,item->data,item->len); + /* item is imbedded in pubKey, just free the key */ + nsslowkey_DestroyPublicKey(pubKey); + return lg_CopyAttribute(attribute, type, hash, SHA1_LENGTH); + case CKA_LABEL: + return cert->nickname + ? lg_CopyAttribute(attribute, type, cert->nickname, + PORT_Strlen(cert->nickname)) + : LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); + case CKA_SUBJECT: + return lg_CopyAttribute(attribute,type,cert->derSubject.data, + cert->derSubject.len); + case CKA_ISSUER: + return lg_CopyAttribute(attribute,type,cert->derIssuer.data, + cert->derIssuer.len); + case CKA_SERIAL_NUMBER: + return lg_CopyAttribute(attribute,type,cert->derSN.data, + cert->derSN.len); + case CKA_NETSCAPE_EMAIL: + return (cert->emailAddr && cert->emailAddr[0]) + ? lg_CopyAttribute(attribute, type, cert->emailAddr, + PORT_Strlen(cert->emailAddr)) + : LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +CK_RV +lg_GetSingleAttribute(LGObjectCache *obj, CK_ATTRIBUTE *attribute) +{ + /* handle the common ones */ + CK_ATTRIBUTE_TYPE type = attribute->type; + switch (type) { + case CKA_CLASS: + return lg_ULongAttribute(attribute,type,obj->objclass); + case CKA_TOKEN: + return LG_CLONE_ATTR(attribute, type,lg_StaticTrueAttr); + case CKA_LABEL: + if ( (obj->objclass == CKO_CERTIFICATE) + || (obj->objclass == CKO_PRIVATE_KEY) + || (obj->objclass == CKO_PUBLIC_KEY) + || (obj->objclass == CKO_SECRET_KEY)) { + break; + } + return LG_CLONE_ATTR(attribute,type,lg_StaticNullAttr); + default: + break; + } + switch (obj->objclass) { + case CKO_CERTIFICATE: + return lg_FindCertAttribute(obj,type,attribute); + case CKO_NETSCAPE_CRL: + return lg_FindCrlAttribute(obj,type,attribute); + case CKO_NETSCAPE_TRUST: + return lg_FindTrustAttribute(obj,type,attribute); + case CKO_NETSCAPE_SMIME: + return lg_FindSMIMEAttribute(obj,type,attribute); + case CKO_PUBLIC_KEY: + return lg_FindPublicKeyAttribute(obj,type,attribute); + case CKO_PRIVATE_KEY: + return lg_FindPrivateKeyAttribute(obj,type,attribute); + case CKO_SECRET_KEY: + return lg_FindSecretKeyAttribute(obj,type,attribute); + default: + break; + } + return lg_invalidAttribute(attribute); +} + +/* + * Fill in the attribute template based on the data in the database. + */ +CK_RV +lg_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE handle, CK_ATTRIBUTE *templ, + CK_ULONG count) +{ + LGObjectCache *obj = lg_NewObjectCache(sdb, NULL, handle & ~LG_TOKEN_MASK); + CK_RV crv, crvCollect = CKR_OK; + int i; + + if (obj == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + + for (i=0; i < count; i++) { + crv = lg_GetSingleAttribute(obj, &templ[i]); + if (crvCollect == CKR_OK) crvCollect = crv; + } + + lg_DestroyObjectCache(obj); + return crvCollect; +} + +PRBool +lg_cmpAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attribute) +{ + unsigned char buf[LG_BUF_SPACE]; + CK_ATTRIBUTE testAttr; + unsigned char *tempBuf = NULL; + PRBool match = PR_TRUE; + CK_RV crv; + + /* we're going to compare 'attribute' with the actual attribute from + * the object. We'll use the length of 'attribute' to decide how much + * space we need to read the test attribute. If 'attribute' doesn't give + * enough space, then we know the values don't match and that will + * show up as ckr != CKR_OK */ + testAttr = *attribute; + testAttr.pValue = buf; + + /* if we don't have enough space, malloc it */ + if (attribute->ulValueLen > LG_BUF_SPACE) { + tempBuf = PORT_Alloc(attribute->ulValueLen); + if (!tempBuf) { + return PR_FALSE; + } + testAttr.pValue = tempBuf; + } + + /* get the attribute */ + crv = lg_GetSingleAttribute(obj, &testAttr); + /* if the attribute was read OK, compare it */ + if ((crv != CKR_OK) || (attribute->ulValueLen != testAttr.ulValueLen) || + (PORT_Memcmp(attribute->pValue,testAttr.pValue,testAttr.ulValueLen)!= 0)){ + /* something didn't match, this isn't the object we are looking for */ + match = PR_FALSE; + } + /* free the buffer we may have allocated */ + if (tempBuf) { + PORT_Free(tempBuf); + } + return match; +} + +PRBool +lg_tokenMatch(SDB *sdb, const SECItem *dbKey, CK_OBJECT_HANDLE class, + const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + PRBool match = PR_TRUE; + LGObjectCache *obj = lg_NewObjectCache(sdb, dbKey, class); + int i; + + if (obj == NULL) { + return PR_FALSE; + } + + for (i=0; i < count; i++) { + match = lg_cmpAttribute(obj, &templ[i]); + if (!match) { + break; + } + } + + /* done looking, free up our cache */ + lg_DestroyObjectCache(obj); + + /* if we get through the whole list without finding a mismatched attribute, + * then this object fits the criteria we are matching */ + return match; +} + +static CK_RV +lg_SetCertAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + const void *value, unsigned int len) +{ + 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 */ + if (type == CKA_NETSCAPE_EMAIL) { + return CKR_OK; + } + + certHandle = lg_getCertDB(obj->sdb); + if (certHandle == NULL) { + crv = CKR_TOKEN_WRITE_PROTECTED; + goto done; + } + + if ((type != CKA_LABEL) && (type != CKA_ID)) { + crv = CKR_ATTRIBUTE_READ_ONLY; + goto done; + } + + cert = lg_getCert(obj, certHandle); + if (cert == NULL) { + crv = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + + /* if the app is trying to set CKA_ID, it's probably because it just + * imported the key. Look to see if we need to set the CERTDB_USER bits. + */ + if (type == CKA_ID) { + if (((cert->trust->sslFlags & CERTDB_USER) == 0) && + ((cert->trust->emailFlags & CERTDB_USER) == 0) && + ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) { + NSSLOWKEYDBHandle *keyHandle; + + keyHandle = lg_getKeyDB(obj->sdb); + 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); + } + } + } + crv = CKR_OK; + goto done; + } + + /* must be CKA_LABEL */ + if (value != NULL) { + nickname = PORT_ZAlloc(len+1); + if (nickname == NULL) { + crv = CKR_HOST_MEMORY; + goto done; + } + PORT_Memcpy(nickname,value,len); + nickname[len] = 0; + } + rv = nsslowcert_AddPermNickname(certHandle, cert, nickname); + crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; + +done: + if (nickname) { + PORT_Free(nickname); + } + return crv; +} + +static CK_RV +lg_SetPrivateKeyAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, + const void *value, unsigned int len, + PRBool *writePrivate) +{ + 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 */ + if ((type == CKA_ID) || (type == CKA_SUBJECT)) { + return CKR_OK; + } + + keyHandle = lg_getKeyDB(obj->sdb); + if (keyHandle == NULL) { + crv = CKR_TOKEN_WRITE_PROTECTED; + goto done; + } + + privKey = lg_GetPrivateKeyWithDB(obj, keyHandle); + if (privKey == NULL) { + crv = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + + crv = CKR_ATTRIBUTE_READ_ONLY; + switch(type) { + case CKA_LABEL: + if (value != NULL) { + nickname = PORT_ZAlloc(len+1); + if (nickname == NULL) { + crv = CKR_HOST_MEMORY; + goto done; + } + PORT_Memcpy(nickname,value,len); + nickname[len] = 0; + } + rv = nsslowkey_UpdateNickname(keyHandle, privKey, &obj->dbKey, + nickname, obj->sdb); + crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; + break; + case CKA_VALUE: + case CKA_PRIVATE_EXPONENT: + case CKA_PRIME_1: + case CKA_PRIME_2: + case CKA_EXPONENT_1: + case CKA_EXPONENT_2: + case CKA_COEFFICIENT: + /* We aren't really changing these values, we are just triggering + * the database to update it's entry */ + *writePrivate = 1; + crv = CKR_OK; + break; + default: + crv = CKR_ATTRIBUTE_READ_ONLY; + break; + } +done: + if (nickname) { + PORT_Free(nickname); + } + return crv; +} + +static CK_RV +lg_SetTrustAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attr) +{ + unsigned int flags; + CK_TRUST trust; + NSSLOWCERTCertificate *cert; + NSSLOWCERTCertDBHandle *certHandle; + NSSLOWCERTCertTrust dbTrust; + SECStatus rv; + CK_RV crv; + + crv = lg_GetULongAttribute(attr->type, attr, 1, &trust); + if (crv != CKR_OK) { + return crv; + } + flags = lg_MapTrust(trust, (PRBool) (attr->type == CKA_TRUST_SERVER_AUTH)); + + certHandle = lg_getCertDB(obj->sdb); + + if (certHandle == NULL) { + crv = CKR_TOKEN_WRITE_PROTECTED; + goto done; + } + + cert = lg_getCert(obj, certHandle); + if (cert == NULL) { + crv = CKR_OBJECT_HANDLE_INVALID; + goto done; + } + dbTrust = *cert->trust; + + switch (attr->type) { + case CKA_TRUST_EMAIL_PROTECTION: + dbTrust.emailFlags = flags | + (cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS); + break; + case CKA_TRUST_CODE_SIGNING: + dbTrust.objectSigningFlags = flags | + (cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS); + break; + case CKA_TRUST_CLIENT_AUTH: + dbTrust.sslFlags = flags | (cert->trust->sslFlags & + (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CA)); + break; + case CKA_TRUST_SERVER_AUTH: + dbTrust.sslFlags = flags | (cert->trust->sslFlags & + (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CLIENT_CA)); + break; + default: + crv = CKR_ATTRIBUTE_READ_ONLY; + goto done; + } + + rv = nsslowcert_ChangeCertTrust(certHandle, cert, &dbTrust); + crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; +done: + return crv; +} + +static CK_RV +lg_SetSingleAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attr, + PRBool *writePrivate) +{ + CK_ATTRIBUTE attribLocal; + CK_RV crv; + + /* Make sure the attribute exists first */ + attribLocal.type = attr->type; + attribLocal.pValue = NULL; + attribLocal.ulValueLen = 0; + crv = lg_GetSingleAttribute(obj, &attribLocal); + if (crv != CKR_OK) { + return crv; + } + + /* if we are just setting it to the value we already have, + * allow it to happen. Let label setting go through so + * we have the opportunity to repair any database corruption. */ + if (attr->type != CKA_LABEL) { + if (lg_cmpAttribute(obj,attr)) { + return CKR_OK; + } + } + + crv = CKR_ATTRIBUTE_READ_ONLY; + switch (obj->objclass) { + case CKO_CERTIFICATE: + /* change NICKNAME, EMAIL, */ + crv = lg_SetCertAttribute(obj,attr->type, + attr->pValue,attr->ulValueLen); + break; + case CKO_NETSCAPE_CRL: + /* change URL */ + break; + case CKO_NETSCAPE_TRUST: + crv = lg_SetTrustAttribute(obj,attr); + break; + case CKO_PRIVATE_KEY: + case CKO_SECRET_KEY: + crv = lg_SetPrivateKeyAttribute(obj,attr->type, + attr->pValue,attr->ulValueLen, writePrivate); + break; + } + return crv; +} + +/* + * Fill in the attribute template based on the data in the database. + */ +CK_RV +lg_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE handle, + const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + LGObjectCache *obj = lg_NewObjectCache(sdb, NULL, handle & ~LG_TOKEN_MASK); + CK_RV crv, crvCollect = CKR_OK; + PRBool writePrivate = PR_FALSE; + int i; + + if (obj == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + + for (i=0; i < count; i++) { + crv = lg_SetSingleAttribute(obj, &templ[i], &writePrivate); + if (crvCollect == CKR_OK) crvCollect = crv; + } + + /* Write any collected changes out for private and secret keys. + * don't do the write for just the label */ + if (writePrivate) { + NSSLOWKEYPrivateKey *privKey = lg_GetPrivateKey(obj); + SECStatus rv = SECFailure; + char * label = lg_FindKeyNicknameByPublicKey(obj->sdb, &obj->dbKey); + + if (privKey) { + rv = nsslowkey_StoreKeyByPublicKey(lg_getKeyDB(sdb), privKey, + &obj->dbKey, label, sdb ); + } + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + } + } + + lg_DestroyObjectCache(obj); + return crvCollect; +} diff --git a/security/nss/lib/softoken/legacydb/lgcreate.c b/security/nss/lib/softoken/legacydb/lgcreate.c new file mode 100644 index 000000000..c3ab0781d --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lgcreate.c @@ -0,0 +1,955 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "secitem.h" +#include "pkcs11.h" +#include "lgdb.h" +#include "pcert.h" +#include "lowkeyi.h" +#include "blapi.h" +#include "secder.h" + +#include "keydbi.h" + +/* + * ******************** Object Creation Utilities *************************** + */ + +/* + * check the consistancy and initialize a Certificate Object + */ +static CK_RV +lg_createCertObject(SDB *sdb, CK_OBJECT_HANDLE *handle, + const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + SECItem derCert; + NSSLOWCERTCertificate *cert; + NSSLOWCERTCertTrust *trust = NULL; + NSSLOWCERTCertTrust userTrust = + { CERTDB_USER, CERTDB_USER, CERTDB_USER }; + NSSLOWCERTCertTrust defTrust = + { CERTDB_TRUSTED_UNKNOWN, + CERTDB_TRUSTED_UNKNOWN, CERTDB_TRUSTED_UNKNOWN }; + char *label = NULL; + char *email = NULL; + SECStatus rv; + PRBool inDB = PR_TRUE; + NSSLOWCERTCertDBHandle *certHandle = lg_getCertDB(sdb); + NSSLOWKEYDBHandle *keyHandle = NULL; + CK_CERTIFICATE_TYPE type; + const CK_ATTRIBUTE *attribute; + + /* we can't store any certs private */ + if (lg_isTrue(CKA_PRIVATE, templ, count)) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + /* We only support X.509 Certs for now */ + attribute = lg_FindAttribute(CKA_CERTIFICATE_TYPE, templ, count); + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; + type = *(CK_CERTIFICATE_TYPE *)attribute->pValue; + + if (type != CKC_X_509) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + /* X.509 Certificate */ + + + if (certHandle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + /* get the der cert */ + attribute = lg_FindAttribute(CKA_VALUE, templ, count); + if (!attribute) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + derCert.type = 0; + derCert.data = (unsigned char *)attribute->pValue; + derCert.len = attribute->ulValueLen ; + + label = lg_getString(CKA_LABEL, templ, count); + + cert = nsslowcert_FindCertByDERCert(certHandle, &derCert); + if (cert == NULL) { + cert = nsslowcert_DecodeDERCertificate(&derCert, label); + inDB = PR_FALSE; + } + if (cert == NULL) { + if (label) PORT_Free(label); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + keyHandle = lg_getKeyDB(sdb); + if (keyHandle) { + if (nsslowkey_KeyForCertExists(keyHandle,cert)) { + trust = &userTrust; + } + } + + if (!inDB) { + if (!trust) trust = &defTrust; + rv = nsslowcert_AddPermCert(certHandle, cert, label, trust); + } else { + rv = trust ? nsslowcert_ChangeCertTrust(certHandle,cert,trust) : + SECSuccess; + } + + if (label) PORT_Free(label); + + if (rv != SECSuccess) { + nsslowcert_DestroyCertificate(cert); + return CKR_DEVICE_ERROR; + } + + /* + * Add a NULL S/MIME profile if necessary. + */ + email = lg_getString(CKA_NETSCAPE_EMAIL, templ, count); + if (email) { + certDBEntrySMime *entry; + + entry = nsslowcert_ReadDBSMimeEntry(certHandle,email); + if (!entry) { + nsslowcert_SaveSMimeProfile(certHandle, email, + &cert->derSubject, NULL, NULL); + } else { + nsslowcert_DestroyDBEntry((certDBEntry *)entry); + } + PORT_Free(email); + } + *handle=lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_CERT); + nsslowcert_DestroyCertificate(cert); + + return CKR_OK; +} + +unsigned int +lg_MapTrust(CK_TRUST trust, PRBool clientAuth) +{ + unsigned int trustCA = clientAuth ? CERTDB_TRUSTED_CLIENT_CA : + CERTDB_TRUSTED_CA; + switch (trust) { + case CKT_NETSCAPE_TRUSTED: + return CERTDB_VALID_PEER|CERTDB_TRUSTED; + case CKT_NETSCAPE_TRUSTED_DELEGATOR: + return CERTDB_VALID_CA|trustCA; + case CKT_NETSCAPE_UNTRUSTED: + return CERTDB_NOT_TRUSTED; + case CKT_NETSCAPE_MUST_VERIFY: + return 0; + case CKT_NETSCAPE_VALID: /* implies must verify */ + return CERTDB_VALID_PEER; + case CKT_NETSCAPE_VALID_DELEGATOR: /* implies must verify */ + return CERTDB_VALID_CA; + default: + break; + } + return CERTDB_TRUSTED_UNKNOWN; +} + + +/* + * check the consistancy and initialize a Trust Object + */ +static CK_RV +lg_createTrustObject(SDB *sdb, CK_OBJECT_HANDLE *handle, + const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + const CK_ATTRIBUTE *issuer = NULL; + const CK_ATTRIBUTE *serial = NULL; + NSSLOWCERTCertificate *cert = NULL; + const CK_ATTRIBUTE *trust; + CK_TRUST sslTrust = CKT_NETSCAPE_TRUST_UNKNOWN; + CK_TRUST clientTrust = CKT_NETSCAPE_TRUST_UNKNOWN; + CK_TRUST emailTrust = CKT_NETSCAPE_TRUST_UNKNOWN; + CK_TRUST signTrust = CKT_NETSCAPE_TRUST_UNKNOWN; + CK_BBOOL stepUp; + NSSLOWCERTCertTrust dbTrust = { 0 }; + SECStatus rv; + NSSLOWCERTCertDBHandle *certHandle = lg_getCertDB(sdb); + NSSLOWCERTIssuerAndSN issuerSN; + + /* we can't store any certs private */ + if (lg_isTrue(CKA_PRIVATE, templ, count)) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + if (certHandle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + issuer = lg_FindAttribute(CKA_ISSUER, templ, count); + serial = lg_FindAttribute(CKA_SERIAL_NUMBER, templ, count); + + if (issuer && serial) { + issuerSN.derIssuer.data = (unsigned char *)issuer->pValue; + issuerSN.derIssuer.len = issuer->ulValueLen ; + + issuerSN.serialNumber.data = (unsigned char *)serial->pValue; + issuerSN.serialNumber.len = serial->ulValueLen ; + + cert = nsslowcert_FindCertByIssuerAndSN(certHandle,&issuerSN); + } + + if (cert == NULL) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + lg_GetULongAttribute(CKA_TRUST_SERVER_AUTH, templ, count, &sslTrust); + lg_GetULongAttribute(CKA_TRUST_CLIENT_AUTH, templ, count, &clientTrust); + lg_GetULongAttribute(CKA_TRUST_EMAIL_PROTECTION, templ, count, &emailTrust); + lg_GetULongAttribute(CKA_TRUST_CODE_SIGNING, templ, count, &signTrust); + stepUp = CK_FALSE; + trust = lg_FindAttribute(CKA_TRUST_STEP_UP_APPROVED, templ, count); + if (trust) { + if (trust->ulValueLen == sizeof(CK_BBOOL)) { + stepUp = *(CK_BBOOL*)trust->pValue; + } + } + + /* preserve certain old fields */ + if (cert->trust) { + dbTrust.sslFlags = cert->trust->sslFlags & CERTDB_PRESERVE_TRUST_BITS; + dbTrust.emailFlags= + cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS; + dbTrust.objectSigningFlags = + cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS; + } + + dbTrust.sslFlags |= lg_MapTrust(sslTrust,PR_FALSE); + dbTrust.sslFlags |= lg_MapTrust(clientTrust,PR_TRUE); + dbTrust.emailFlags |= lg_MapTrust(emailTrust,PR_FALSE); + dbTrust.objectSigningFlags |= lg_MapTrust(signTrust,PR_FALSE); + if (stepUp) { + dbTrust.sslFlags |= CERTDB_GOVT_APPROVED_CA; + } + + rv = nsslowcert_ChangeCertTrust(certHandle,cert,&dbTrust); + *handle=lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_TRUST); + nsslowcert_DestroyCertificate(cert); + if (rv != SECSuccess) { + return CKR_DEVICE_ERROR; + } + + return CKR_OK; +} + +/* + * check the consistancy and initialize a Trust Object + */ +static CK_RV +lg_createSMimeObject(SDB *sdb, CK_OBJECT_HANDLE *handle, + const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + SECItem derSubj,rawProfile,rawTime,emailKey; + SECItem *pRawProfile = NULL; + SECItem *pRawTime = NULL; + char *email = NULL; + const CK_ATTRIBUTE *subject = NULL, + *profile = NULL, + *time = NULL; + SECStatus rv; + NSSLOWCERTCertDBHandle *certHandle; + CK_RV ck_rv = CKR_OK; + + /* we can't store any certs private */ + if (lg_isTrue(CKA_PRIVATE,templ,count)) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + certHandle = lg_getCertDB(sdb); + if (certHandle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + /* lookup SUBJECT */ + subject = lg_FindAttribute(CKA_SUBJECT,templ,count); + PORT_Assert(subject); + if (!subject) { + ck_rv = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + + derSubj.data = (unsigned char *)subject->pValue; + derSubj.len = subject->ulValueLen ; + derSubj.type = 0; + + /* lookup VALUE */ + profile = lg_FindAttribute(CKA_VALUE,templ,count); + if (profile) { + rawProfile.data = (unsigned char *)profile->pValue; + rawProfile.len = profile->ulValueLen ; + rawProfile.type = siBuffer; + pRawProfile = &rawProfile; + } + + /* lookup Time */ + time = lg_FindAttribute(CKA_NETSCAPE_SMIME_TIMESTAMP,templ,count); + if (time) { + rawTime.data = (unsigned char *)time->pValue; + rawTime.len = time->ulValueLen ; + rawTime.type = siBuffer; + pRawTime = &rawTime; + } + + + email = lg_getString(CKA_NETSCAPE_EMAIL,templ,count); + if (!email) { + ck_rv = CKR_ATTRIBUTE_VALUE_INVALID; + goto loser; + } + + /* Store S/MIME Profile by SUBJECT */ + rv = nsslowcert_SaveSMimeProfile(certHandle, email, &derSubj, + pRawProfile,pRawTime); + if (rv != SECSuccess) { + ck_rv = CKR_DEVICE_ERROR; + goto loser; + } + emailKey.data = (unsigned char *)email; + emailKey.len = PORT_Strlen(email)+1; + + *handle = lg_mkHandle(sdb, &emailKey, LG_TOKEN_TYPE_SMIME); + +loser: + if (email) PORT_Free(email); + + return ck_rv; +} + +/* + * check the consistancy and initialize a Trust Object + */ +static CK_RV +lg_createCrlObject(SDB *sdb, CK_OBJECT_HANDLE *handle, + const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + PRBool isKRL = PR_FALSE; + SECItem derSubj,derCrl; + char *url = NULL; + const CK_ATTRIBUTE *subject,*crl; + SECStatus rv; + NSSLOWCERTCertDBHandle *certHandle; + + certHandle = lg_getCertDB(sdb); + + /* we can't store any private crls */ + if (lg_isTrue(CKA_PRIVATE,templ,count)) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + if (certHandle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + /* lookup SUBJECT */ + subject = lg_FindAttribute(CKA_SUBJECT,templ,count); + if (!subject) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + derSubj.data = (unsigned char *)subject->pValue; + derSubj.len = subject->ulValueLen ; + + /* lookup VALUE */ + crl = lg_FindAttribute(CKA_VALUE,templ,count); + PORT_Assert(crl); + if (!crl) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + derCrl.data = (unsigned char *)crl->pValue; + derCrl.len = crl->ulValueLen ; + + url = lg_getString(CKA_NETSCAPE_URL,templ,count); + isKRL = lg_isTrue(CKA_NETSCAPE_KRL,templ,count); + + /* Store CRL by SUBJECT */ + rv = nsslowcert_AddCrl(certHandle, &derCrl, &derSubj, url, isKRL); + + if (url) { + PORT_Free(url); + } + if (rv != SECSuccess) { + return CKR_DEVICE_ERROR; + } + + /* if we overwrote the existing CRL, poison the handle entry so we get + * a new object handle */ + (void) lg_poisonHandle(sdb, &derSubj, + isKRL ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL); + *handle = lg_mkHandle(sdb, &derSubj, + isKRL ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL); + + return CKR_OK; +} + +/* + * check the consistancy and initialize a Public Key Object + */ +static CK_RV +lg_createPublicKeyObject(SDB *sdb, CK_KEY_TYPE key_type, + CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + CK_ATTRIBUTE_TYPE pubKeyAttr = CKA_VALUE; + CK_RV crv; + NSSLOWKEYPrivateKey *priv; + SECItem pubKey; + NSSLOWKEYDBHandle *keyHandle = NULL; + + switch (key_type) { + case CKK_RSA: + pubKeyAttr = CKA_MODULUS; + break; +#ifdef NSS_ENABLE_ECC + case CKK_EC: + pubKeyAttr = CKA_EC_POINT; + break; +#endif /* NSS_ENABLE_ECC */ + case CKK_DSA: + case CKK_DH: + break; + default: + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + + crv = lg_Attribute2SSecItem(NULL,pubKeyAttr,templ,count,&pubKey); + if (crv != CKR_OK) return crv; + + PORT_Assert(pubKey.data); + keyHandle = lg_getKeyDB(sdb); + if (keyHandle == NULL) { + PORT_Free(pubKey.data); + return CKR_TOKEN_WRITE_PROTECTED; + } + if (keyHandle->version != 3) { + unsigned char buf[SHA1_LENGTH]; + SHA1_HashBuf(buf,pubKey.data,pubKey.len); + PORT_Memcpy(pubKey.data,buf,sizeof(buf)); + pubKey.len = sizeof(buf); + } + /* make sure the associated private key already exists */ + /* only works if we are logged in */ + priv = nsslowkey_FindKeyByPublicKey(keyHandle, &pubKey, sdb /*password*/); + if (priv == NULL) { + PORT_Free(pubKey.data); + return crv; + } + nsslowkey_DestroyPrivateKey(priv); + + *handle = lg_mkHandle(sdb, &pubKey, LG_TOKEN_TYPE_PUB); + PORT_Free(pubKey.data); + + return CKR_OK; +} + +/* make a private key from a verified object */ +static NSSLOWKEYPrivateKey * +lg_mkPrivKey(SDB *sdb, const CK_ATTRIBUTE *templ, CK_ULONG count, + CK_KEY_TYPE key_type, CK_RV *crvp) +{ + NSSLOWKEYPrivateKey *privKey; + PLArenaPool *arena; + CK_RV crv = CKR_OK; + SECStatus rv; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + *crvp = CKR_HOST_MEMORY; + return NULL; + } + + privKey = (NSSLOWKEYPrivateKey *) + PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey)); + if (privKey == NULL) { + PORT_FreeArena(arena,PR_FALSE); + *crvp = CKR_HOST_MEMORY; + return NULL; + } + + /* in future this would be a switch on key_type */ + privKey->arena = arena; + switch (key_type) { + case CKK_RSA: + privKey->keyType = NSSLOWKEYRSAKey; + crv=lg_Attribute2SSecItem(arena,CKA_MODULUS,templ,count, + &privKey->u.rsa.modulus); + if (crv != CKR_OK) break; + crv=lg_Attribute2SSecItem(arena,CKA_PUBLIC_EXPONENT,templ,count, + &privKey->u.rsa.publicExponent); + if (crv != CKR_OK) break; + crv=lg_PrivAttr2SSecItem(arena,CKA_PRIVATE_EXPONENT,templ,count, + &privKey->u.rsa.privateExponent, sdb); + if (crv != CKR_OK) break; + crv=lg_PrivAttr2SSecItem(arena,CKA_PRIME_1,templ,count, + &privKey->u.rsa.prime1, sdb); + if (crv != CKR_OK) break; + crv=lg_PrivAttr2SSecItem(arena,CKA_PRIME_2,templ,count, + &privKey->u.rsa.prime2, sdb); + if (crv != CKR_OK) break; + crv=lg_PrivAttr2SSecItem(arena,CKA_EXPONENT_1,templ,count, + &privKey->u.rsa.exponent1, sdb); + if (crv != CKR_OK) break; + crv=lg_PrivAttr2SSecItem(arena,CKA_EXPONENT_2,templ,count, + &privKey->u.rsa.exponent2, sdb); + if (crv != CKR_OK) break; + crv=lg_PrivAttr2SSecItem(arena,CKA_COEFFICIENT,templ,count, + &privKey->u.rsa.coefficient, sdb); + if (crv != CKR_OK) break; + rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version, + NSSLOWKEY_VERSION); + if (rv != SECSuccess) crv = CKR_HOST_MEMORY; + break; + + case CKK_DSA: + privKey->keyType = NSSLOWKEYDSAKey; + crv = lg_Attribute2SSecItem(arena,CKA_PRIME,templ,count, + &privKey->u.dsa.params.prime); + if (crv != CKR_OK) break; + crv = lg_Attribute2SSecItem(arena,CKA_SUBPRIME,templ,count, + &privKey->u.dsa.params.subPrime); + if (crv != CKR_OK) break; + crv = lg_Attribute2SSecItem(arena,CKA_BASE,templ,count, + &privKey->u.dsa.params.base); + if (crv != CKR_OK) break; + crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, + &privKey->u.dsa.privateValue, sdb); + if (crv != CKR_OK) break; + if (lg_hasAttribute(CKA_NETSCAPE_DB, templ,count)) { + crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, + &privKey->u.dsa.publicValue); + /* privKey was zero'd so public value is already set to NULL, 0 + * if we don't set it explicitly */ + } + break; + + case CKK_DH: + privKey->keyType = NSSLOWKEYDHKey; + crv = lg_Attribute2SSecItem(arena,CKA_PRIME,templ,count, + &privKey->u.dh.prime); + if (crv != CKR_OK) break; + crv = lg_Attribute2SSecItem(arena,CKA_BASE,templ,count, + &privKey->u.dh.base); + if (crv != CKR_OK) break; + crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, + &privKey->u.dh.privateValue, sdb); + if (crv != CKR_OK) break; + if (lg_hasAttribute(CKA_NETSCAPE_DB, templ, count)) { + crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, + &privKey->u.dh.publicValue); + /* privKey was zero'd so public value is already set to NULL, 0 + * if we don't set it explicitly */ + } + break; + +#ifdef NSS_ENABLE_ECC + case CKK_EC: + privKey->keyType = NSSLOWKEYECKey; + crv = lg_Attribute2SSecItem(arena, CKA_EC_PARAMS,templ,count, + &privKey->u.ec.ecParams.DEREncoding); + if (crv != CKR_OK) break; + + /* Fill out the rest of the ecParams structure + * based on the encoded params + */ + if (LGEC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding, + &privKey->u.ec.ecParams) != SECSuccess) { + crv = CKR_DOMAIN_PARAMS_INVALID; + break; + } + crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, + &privKey->u.ec.privateValue, sdb); + if (crv != CKR_OK) break; + if (lg_hasAttribute(CKA_NETSCAPE_DB,templ,count)) { + crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, + &privKey->u.ec.publicValue); + if (crv != CKR_OK) break; + /* privKey was zero'd so public value is already set to NULL, 0 + * if we don't set it explicitly */ + } + rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version, + NSSLOWKEY_EC_PRIVATE_KEY_VERSION); + if (rv != SECSuccess) crv = CKR_HOST_MEMORY; + break; +#endif /* NSS_ENABLE_ECC */ + + default: + crv = CKR_KEY_TYPE_INCONSISTENT; + break; + } + *crvp = crv; + if (crv != CKR_OK) { + PORT_FreeArena(arena,PR_FALSE); + return NULL; + } + return privKey; +} + +/* + * check the consistancy and initialize a Private Key Object + */ +static CK_RV +lg_createPrivateKeyObject(SDB *sdb, CK_KEY_TYPE key_type, + CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + NSSLOWKEYPrivateKey *privKey; + char *label; + SECStatus rv = SECSuccess; + CK_RV crv = CKR_DEVICE_ERROR; + SECItem pubKey; + NSSLOWKEYDBHandle *keyHandle = lg_getKeyDB(sdb); + + if (keyHandle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + privKey=lg_mkPrivKey(sdb, templ,count,key_type,&crv); + if (privKey == NULL) return crv; + label = lg_getString(CKA_LABEL,templ,count); + + crv = lg_Attribute2SSecItem(NULL,CKA_NETSCAPE_DB,templ,count,&pubKey); + if (crv != CKR_OK) { + crv = CKR_TEMPLATE_INCOMPLETE; + rv = SECFailure; + goto fail; + } +#ifdef notdef + if (keyHandle->version != 3) { + unsigned char buf[SHA1_LENGTH]; + SHA1_HashBuf(buf,pubKey.data,pubKey.len); + PORT_Memcpy(pubKey.data,buf,sizeof(buf)); + pubKey.len = sizeof(buf); + } +#endif + /* get the key type */ + if (key_type == CKK_RSA) { + rv = RSA_PrivateKeyCheck(&privKey->u.rsa); + if (rv == SECFailure) { + goto fail; + } + } + rv = nsslowkey_StoreKeyByPublicKey(keyHandle, privKey, &pubKey, + label, sdb /*->password*/); + +fail: + if (label) PORT_Free(label); + *handle = lg_mkHandle(sdb,&pubKey,LG_TOKEN_TYPE_PRIV); + if (pubKey.data) PORT_Free(pubKey.data); + nsslowkey_DestroyPrivateKey(privKey); + if (rv != SECSuccess) return crv; + + return CKR_OK; +} + + +#define LG_KEY_MAX_RETRIES 10 /* don't hang if we are having problems with the rng */ +#define LG_KEY_ID_SIZE 18 /* don't use either SHA1 or MD5 sizes */ +/* + * Secret keys must have a CKA_ID value to be stored in the database. This code + * will generate one if there wasn't one already. + */ +static CK_RV +lg_GenerateSecretCKA_ID(NSSLOWKEYDBHandle *handle, SECItem *id, char *label) +{ + unsigned int retries; + SECStatus rv = SECSuccess; + CK_RV crv = CKR_OK; + + id->data = NULL; + if (label) { + id->data = (unsigned char *)PORT_Strdup(label); + if (id->data == NULL) { + return CKR_HOST_MEMORY; + } + id->len = PORT_Strlen(label)+1; + if (!nsslowkey_KeyForIDExists(handle,id)) { + return CKR_OK; + } + PORT_Free(id->data); + id->data = NULL; + id->len = 0; + } + id->data = (unsigned char *)PORT_Alloc(LG_KEY_ID_SIZE); + if (id->data == NULL) { + return CKR_HOST_MEMORY; + } + id->len = LG_KEY_ID_SIZE; + + retries = 0; + do { + rv = RNG_GenerateGlobalRandomBytes(id->data,id->len); + } while (rv == SECSuccess && nsslowkey_KeyForIDExists(handle,id) && + (++retries <= LG_KEY_MAX_RETRIES)); + + if ((rv != SECSuccess) || (retries > LG_KEY_MAX_RETRIES)) { + crv = CKR_DEVICE_ERROR; /* random number generator is bad */ + PORT_Free(id->data); + id->data = NULL; + id->len = 0; + } + return crv; +} + + +static NSSLOWKEYPrivateKey *lg_mkSecretKeyRep(const CK_ATTRIBUTE *templ, + CK_ULONG count, CK_KEY_TYPE key_type, + SECItem *pubkey, SDB *sdbpw) +{ + NSSLOWKEYPrivateKey *privKey = 0; + PLArenaPool *arena = 0; + CK_KEY_TYPE keyType; + PRUint32 keyTypeStorage; + SECItem keyTypeItem; + CK_RV crv; + SECStatus rv; + static unsigned char derZero[1] = { 0 }; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { crv = CKR_HOST_MEMORY; goto loser; } + + privKey = (NSSLOWKEYPrivateKey *) + PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey)); + if (privKey == NULL) { crv = CKR_HOST_MEMORY; goto loser; } + + privKey->arena = arena; + + /* Secret keys are represented in the database as "fake" RSA keys. + * The RSA key is marked as a secret key representation by setting the + * public exponent field to 0, which is an invalid RSA exponent. + * The other fields are set as follows: + * modulus - CKA_ID value for the secret key + * private exponent - CKA_VALUE (the key itself) + * coefficient - CKA_KEY_TYPE, which indicates what encryption algorithm + * is used for the key. + * all others - set to integer 0 + */ + privKey->keyType = NSSLOWKEYRSAKey; + + /* The modulus is set to the key id of the symmetric key */ + crv = lg_Attribute2SecItem(arena, CKA_ID, templ, count, + &privKey->u.rsa.modulus); + if (crv != CKR_OK) goto loser; + + /* The public exponent is set to 0 length to indicate a special key */ + privKey->u.rsa.publicExponent.len = sizeof derZero; + privKey->u.rsa.publicExponent.data = derZero; + + /* The private exponent is the actual key value */ + crv = lg_PrivAttr2SecItem(arena, CKA_VALUE, templ, count, + &privKey->u.rsa.privateExponent, sdbpw); + if (crv != CKR_OK) goto loser; + + /* All other fields empty - needs testing */ + privKey->u.rsa.prime1.len = sizeof derZero; + privKey->u.rsa.prime1.data = derZero; + + privKey->u.rsa.prime2.len = sizeof derZero; + privKey->u.rsa.prime2.data = derZero; + + privKey->u.rsa.exponent1.len = sizeof derZero; + privKey->u.rsa.exponent1.data = derZero; + + privKey->u.rsa.exponent2.len = sizeof derZero; + privKey->u.rsa.exponent2.data = derZero; + + /* Coeficient set to KEY_TYPE */ + crv = lg_GetULongAttribute(CKA_KEY_TYPE, templ, count, &keyType); + if (crv != CKR_OK) goto loser; + /* on 64 bit platforms, we still want to store 32 bits of keyType (This is + * safe since the PKCS #11 defines for all types are 32 bits or less). */ + keyTypeStorage = (PRUint32) keyType; + keyTypeStorage = PR_htonl(keyTypeStorage); + keyTypeItem.data = (unsigned char *)&keyTypeStorage; + keyTypeItem.len = sizeof (keyTypeStorage); + rv = SECITEM_CopyItem(arena, &privKey->u.rsa.coefficient, &keyTypeItem); + if (rv != SECSuccess) { + crv = CKR_HOST_MEMORY; + goto loser; + } + + /* Private key version field set normally for compatibility */ + rv = DER_SetUInteger(privKey->arena, + &privKey->u.rsa.version, NSSLOWKEY_VERSION); + if (rv != SECSuccess) { crv = CKR_HOST_MEMORY; goto loser; } + +loser: + if (crv != CKR_OK) { + PORT_FreeArena(arena,PR_FALSE); + privKey = 0; + } + + return privKey; +} + +/* + * check the consistancy and initialize a Secret Key Object + */ +static CK_RV +lg_createSecretKeyObject(SDB *sdb, CK_KEY_TYPE key_type, + CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + CK_RV crv; + NSSLOWKEYPrivateKey *privKey = NULL; + NSSLOWKEYDBHandle *keyHandle = NULL; + SECItem pubKey; + char *label = NULL; + SECStatus rv = SECSuccess; + + pubKey.data = 0; + + /* If the object is a TOKEN object, store in the database */ + keyHandle = lg_getKeyDB(sdb); + + if (keyHandle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + label = lg_getString(CKA_LABEL,templ,count); + + crv = lg_Attribute2SecItem(NULL,CKA_ID,templ,count,&pubKey); + /* Should this be ID? */ + if (crv != CKR_OK) goto loser; + + /* if we don't have an ID, generate one */ + if (pubKey.len == 0) { + if (pubKey.data) { + PORT_Free(pubKey.data); + pubKey.data = NULL; + } + crv = lg_GenerateSecretCKA_ID(keyHandle, &pubKey, label); + if (crv != CKR_OK) goto loser; + } + + privKey = lg_mkSecretKeyRep(templ, count, key_type, &pubKey, sdb); + if (privKey == NULL) { + crv = CKR_HOST_MEMORY; + goto loser; + } + + rv = nsslowkey_StoreKeyByPublicKey(keyHandle, + privKey, &pubKey, label, sdb /*->password*/); + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + goto loser; + } + + *handle = lg_mkHandle(sdb, &pubKey, LG_TOKEN_TYPE_KEY); + +loser: + if (label) PORT_Free(label); + if (privKey) nsslowkey_DestroyPrivateKey(privKey); + if (pubKey.data) PORT_Free(pubKey.data); + + return crv; +} + +/* + * check the consistancy and initialize a Key Object + */ +static CK_RV +lg_createKeyObject(SDB *sdb, CK_OBJECT_CLASS objclass, + CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + CK_RV crv; + CK_KEY_TYPE key_type; + + /* get the key type */ + crv = lg_GetULongAttribute(CKA_KEY_TYPE, templ, count, &key_type); + if (crv != CKR_OK) { + return crv; + } + + switch (objclass) { + case CKO_PUBLIC_KEY: + return lg_createPublicKeyObject(sdb,key_type,handle,templ,count); + case CKO_PRIVATE_KEY: + return lg_createPrivateKeyObject(sdb,key_type,handle,templ,count); + case CKO_SECRET_KEY: + return lg_createSecretKeyObject(sdb,key_type,handle,templ,count); + default: + break; + } + return CKR_ATTRIBUTE_VALUE_INVALID; +} + +/* + * Parse the template and create an object stored in the DB that reflects. + * the object specified in the database. + */ +CK_RV +lg_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *handle, + const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + CK_RV crv; + CK_OBJECT_CLASS objclass; + + /* get the object class */ + crv = lg_GetULongAttribute(CKA_CLASS, templ, count, &objclass); + if (crv != CKR_OK) { + return crv; + } + + /* Now handle the specific object class. + */ + switch (objclass) { + case CKO_CERTIFICATE: + crv = lg_createCertObject(sdb,handle,templ,count); + break; + case CKO_NETSCAPE_TRUST: + crv = lg_createTrustObject(sdb,handle,templ,count); + break; + case CKO_NETSCAPE_CRL: + crv = lg_createCrlObject(sdb,handle,templ,count); + break; + case CKO_NETSCAPE_SMIME: + crv = lg_createSMimeObject(sdb,handle,templ,count); + break; + case CKO_PRIVATE_KEY: + case CKO_PUBLIC_KEY: + case CKO_SECRET_KEY: + crv = lg_createKeyObject(sdb,objclass,handle,templ,count); + break; + default: + crv = CKR_ATTRIBUTE_VALUE_INVALID; + break; + } + + return crv; +} + diff --git a/security/nss/lib/softoken/legacydb/lgdb.h b/security/nss/lib/softoken/legacydb/lgdb.h new file mode 100644 index 000000000..1c5744571 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lgdb.h @@ -0,0 +1,197 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Internal data structures and functions used by pkcs11.c + */ +#ifndef _LGDB_H_ +#define _LGDB_H_ 1 + +#include "nssilock.h" +#include "seccomon.h" +#include "secoidt.h" +#include "lowkeyti.h" +#include "pkcs11t.h" +#include "sdb.h" +#include "cdbhdl.h" + + +#define MULTIACCESS "multiaccess:" + + +/* machine dependent path stuff used by dbinit.c and pk11db.c */ +#ifdef macintosh +#define PATH_SEPARATOR ":" +#define SECMOD_DB "Security Modules" +#define CERT_DB_FMT "%sCertificates%s" +#define KEY_DB_FMT "%sKey Database%s" +#else +#define PATH_SEPARATOR "/" +#define SECMOD_DB "secmod.db" +#define CERT_DB_FMT "%scert%s.db" +#define KEY_DB_FMT "%skey%s.db" +#endif + +SEC_BEGIN_PROTOS + + +/* internal utility functions used by pkcs11.c */ +extern const CK_ATTRIBUTE *lg_FindAttribute(CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count); +extern CK_RV lg_Attribute2SecItem(PLArenaPool *,CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + SECItem *item); +extern CK_RV lg_Attribute2SSecItem(PLArenaPool *,CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + SECItem *item); +extern CK_RV lg_PrivAttr2SecItem(PLArenaPool *,CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + SECItem *item, SDB *sdbpw); +extern CK_RV lg_PrivAttr2SSecItem(PLArenaPool *,CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + SECItem *item, SDB *sdbpw); +extern CK_RV lg_GetULongAttribute(CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + CK_ULONG *out); +extern PRBool lg_hasAttribute(CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count); +extern PRBool lg_isTrue(CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count); +extern PRBool lg_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass); +extern char *lg_getString(CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count); +extern unsigned int lg_MapTrust(CK_TRUST trust, PRBool clientAuth); + +/* clear out all the existing object ID to database key mappings. + * used to reinit a token */ +extern CK_RV SFTK_ClearTokenKeyHashTable(SDB *sdb); + + +extern void lg_FreeSearch(SDBFind *search); + +NSSLOWCERTCertDBHandle *lg_getCertDB(SDB *sdb); +NSSLOWKEYDBHandle *lg_getKeyDB(SDB *sdb); + +const char *lg_EvaluateConfigDir(const char *configdir, char **domain); + + +/* + * object handle modifiers + */ +#define LG_TOKEN_MASK 0xc0000000L +#define LG_TOKEN_TYPE_MASK 0x38000000L +#define LG_TOKEN_TYPE_SHIFT 27 +/* keydb (high bit == 0) */ +#define LG_TOKEN_TYPE_PRIV 0x08000000L +#define LG_TOKEN_TYPE_PUB 0x10000000L +#define LG_TOKEN_TYPE_KEY 0x18000000L +/* certdb (high bit == 1) */ +#define LG_TOKEN_TYPE_TRUST 0x20000000L +#define LG_TOKEN_TYPE_CRL 0x28000000L +#define LG_TOKEN_TYPE_SMIME 0x30000000L +#define LG_TOKEN_TYPE_CERT 0x38000000L + +#define LG_TOKEN_KRL_HANDLE (LG_TOKEN_TYPE_CRL|1) + +#define LG_SEARCH_BLOCK_SIZE 10 +#define LG_BUF_SPACE 50 +#define LG_STRICT PR_FALSE + +/* + * token object utilities + */ +void lg_addHandle(SDBFind *search, CK_OBJECT_HANDLE handle); +PRBool lg_poisonHandle(SDB *sdb, SECItem *dbkey, CK_OBJECT_HANDLE handle); +PRBool lg_tokenMatch(SDB *sdb, const SECItem *dbKey, CK_OBJECT_HANDLE class, + const CK_ATTRIBUTE *templ, CK_ULONG count); +const SECItem *lg_lookupTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle); +CK_OBJECT_HANDLE lg_mkHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class); +SECStatus lg_deleteTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle); + +SECStatus lg_util_encrypt(PLArenaPool *arena, SDB *sdbpw, + SECItem *plainText, SECItem **cipherText); +SECStatus lg_util_decrypt(SDB *sdbpw, + SECItem *cipherText, SECItem **plainText); +PLHashTable *lg_GetHashTable(SDB *sdb); +void lg_DBLock(SDB *sdb); +void lg_DBUnlock(SDB *sdb); + +typedef void (*LGFreeFunc)(void *); + + +/* + * database functions + */ + +/* lg_FindObjectsInit initializes a search for token and session objects + * that match a template. */ +CK_RV lg_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, SDBFind **search); +/* lg_FindObjects continues a search for token and session objects + * that match a template, obtaining additional object handles. */ +CK_RV lg_FindObjects(SDB *sdb, SDBFind *search, + CK_OBJECT_HANDLE *phObject,CK_ULONG ulMaxObjectCount, + CK_ULONG *pulObjectCount); + +/* lg_FindObjectsFinal finishes a search for token and session objects. */ +CK_RV lg_FindObjectsFinal(SDB* lgdb, SDBFind *search); + +/* lg_CreateObject parses the template and create an object stored in the + * DB that reflects the object specified in the template. */ +CK_RV lg_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *handle, + const CK_ATTRIBUTE *templ, CK_ULONG count); + +CK_RV lg_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, + CK_ATTRIBUTE *template, CK_ULONG count); +CK_RV lg_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, + const CK_ATTRIBUTE *template, CK_ULONG count); +CK_RV lg_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id); + +CK_RV lg_Close(SDB *sdb); +CK_RV lg_Reset(SDB *sdb); + +/* + * The old database doesn't share and doesn't support + * transactions. + */ +CK_RV lg_Begin(SDB *sdb); +CK_RV lg_Commit(SDB *sdb); +CK_RV lg_Abort(SDB *sdb); +CK_RV lg_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry); +CK_RV lg_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry); + +SEC_END_PROTOS + +#endif /* _LGDB_H_ */ diff --git a/security/nss/lib/softoken/legacydb/lgdestroy.c b/security/nss/lib/softoken/legacydb/lgdestroy.c new file mode 100644 index 000000000..37db2e50e --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lgdestroy.c @@ -0,0 +1,144 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * Internal PKCS #11 functions. Should only be called by pkcs11.c + */ +#include "pkcs11.h" +#include "lgdb.h" +#include "pcert.h" +#include "lowkeyi.h" + +/* + * remove an object. + */ +CK_RV +lg_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id) +{ + CK_RV crv = CKR_OK; + SECStatus rv; + NSSLOWCERTCertificate *cert; + NSSLOWCERTCertTrust tmptrust; + PRBool isKrl; + NSSLOWKEYDBHandle *keyHandle; + NSSLOWCERTCertDBHandle *certHandle; + const SECItem *dbKey; + + object_id &= ~LG_TOKEN_MASK; + dbKey = lg_lookupTokenKeyByHandle(sdb,object_id); + if (dbKey == NULL) { + return CKR_OBJECT_HANDLE_INVALID; + } + + /* remove the objects from the real data base */ + switch (object_id & LG_TOKEN_TYPE_MASK) { + case LG_TOKEN_TYPE_PRIV: + case LG_TOKEN_TYPE_KEY: + /* KEYID is the public KEY for DSA and DH, and the MODULUS for + * RSA */ + keyHandle = lg_getKeyDB(sdb); + if (!keyHandle) { + crv = CKR_TOKEN_WRITE_PROTECTED; + break; + } + rv = nsslowkey_DeleteKey(keyHandle, dbKey); + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + } + break; + case LG_TOKEN_TYPE_PUB: + break; /* public keys only exist at the behest of the priv key */ + case LG_TOKEN_TYPE_CERT: + certHandle = lg_getCertDB(sdb); + if (!certHandle) { + crv = CKR_TOKEN_WRITE_PROTECTED; + break; + } + cert = nsslowcert_FindCertByKey(certHandle,dbKey); + if (cert == NULL) { + crv = CKR_DEVICE_ERROR; + break; + } + rv = nsslowcert_DeletePermCertificate(cert); + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + } + nsslowcert_DestroyCertificate(cert); + break; + case LG_TOKEN_TYPE_CRL: + certHandle = lg_getCertDB(sdb); + if (!certHandle) { + crv = CKR_TOKEN_WRITE_PROTECTED; + break; + } + isKrl = (PRBool) (object_id == LG_TOKEN_KRL_HANDLE); + rv = nsslowcert_DeletePermCRL(certHandle, dbKey, isKrl); + if (rv == SECFailure) crv = CKR_DEVICE_ERROR; + break; + case LG_TOKEN_TYPE_TRUST: + certHandle = lg_getCertDB(sdb); + if (!certHandle) { + crv = CKR_TOKEN_WRITE_PROTECTED; + break; + } + cert = nsslowcert_FindCertByKey(certHandle, dbKey); + if (cert == NULL) { + crv = CKR_DEVICE_ERROR; + break; + } + tmptrust = *cert->trust; + tmptrust.sslFlags &= CERTDB_PRESERVE_TRUST_BITS; + tmptrust.emailFlags &= CERTDB_PRESERVE_TRUST_BITS; + tmptrust.objectSigningFlags &= CERTDB_PRESERVE_TRUST_BITS; + tmptrust.sslFlags |= CERTDB_TRUSTED_UNKNOWN; + tmptrust.emailFlags |= CERTDB_TRUSTED_UNKNOWN; + tmptrust.objectSigningFlags |= CERTDB_TRUSTED_UNKNOWN; + rv = nsslowcert_ChangeCertTrust(certHandle, cert, &tmptrust); + if (rv != SECSuccess) crv = CKR_DEVICE_ERROR; + nsslowcert_DestroyCertificate(cert); + break; + default: + break; + } + lg_DBLock(sdb); + lg_deleteTokenKeyByHandle(sdb,object_id); + lg_DBUnlock(sdb); + + return crv; +} + + + diff --git a/security/nss/lib/softoken/legacydb/lgfind.c b/security/nss/lib/softoken/legacydb/lgfind.c new file mode 100644 index 000000000..b7029c7d5 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lgfind.c @@ -0,0 +1,941 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "secitem.h" +#include "pkcs11.h" +#include "lgdb.h" +#include "lowkeyi.h" +#include "pcert.h" +#include "blapi.h" + +#include "keydbi.h" + +/* + * This code maps PKCS #11 Finds to legacy database searches. This code + * was orginally in pkcs11.c in previous versions of NSS. + */ + +struct SDBFindStr { + CK_OBJECT_HANDLE *handles; + int size; + int index; + int array_size; +}; + + +/* + * free a search structure + */ +void +lg_FreeSearch(SDBFind *search) +{ + if (search->handles) { + PORT_Free(search->handles); + } + PORT_Free(search); +} + +void +lg_addHandle(SDBFind *search, CK_OBJECT_HANDLE handle) +{ + if (search->handles == NULL) { + return; + } + if (search->size >= search->array_size) { + search->array_size += LG_SEARCH_BLOCK_SIZE; + search->handles = (CK_OBJECT_HANDLE *) PORT_Realloc(search->handles, + sizeof(CK_OBJECT_HANDLE)* search->array_size); + if (search->handles == NULL) { + return; + } + } + search->handles[search->size] = handle; + search->size++; +} + +/* + * find any certs that may match the template and load them. + */ +#define LG_CERT 0x00000001 +#define LG_TRUST 0x00000002 +#define LG_CRL 0x00000004 +#define LG_SMIME 0x00000008 +#define LG_PRIVATE 0x00000010 +#define LG_PUBLIC 0x00000020 +#define LG_KEY 0x00000040 + +/* + * structure to collect key handles. + */ +typedef struct lgEntryDataStr { + SDB *sdb; + SDBFind *searchHandles; + const CK_ATTRIBUTE *template; + CK_ULONG templ_count; +} lgEntryData; + + +static SECStatus +lg_crl_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg) +{ + lgEntryData *crlData; + CK_OBJECT_HANDLE class_handle; + SDB *sdb; + + crlData = (lgEntryData *)arg; + sdb = crlData->sdb; + + class_handle = (type == certDBEntryTypeRevocation) ? LG_TOKEN_TYPE_CRL : + LG_TOKEN_KRL_HANDLE; + if (lg_tokenMatch(sdb, key, class_handle, + crlData->template, crlData->templ_count)) { + lg_addHandle(crlData->searchHandles, + lg_mkHandle(sdb,key,class_handle)); + } + return(SECSuccess); +} + +static void +lg_searchCrls(SDB *sdb, SECItem *derSubject, PRBool isKrl, + unsigned long classFlags, SDBFind *search, + const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) +{ + NSSLOWCERTCertDBHandle *certHandle = NULL; + + certHandle = lg_getCertDB(sdb); + if (certHandle == NULL) { + return; + } + if (derSubject->data != NULL) { + certDBEntryRevocation *crl = + nsslowcert_FindCrlByKey(certHandle, derSubject, isKrl); + + if (crl != NULL) { + lg_addHandle(search, lg_mkHandle(sdb, derSubject, + isKrl ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL)); + nsslowcert_DestroyDBEntry((certDBEntry *)crl); + } + } else { + lgEntryData crlData; + + /* traverse */ + crlData.sdb = sdb; + crlData.searchHandles = search; + crlData.template = pTemplate; + crlData.templ_count = ulCount; + nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeRevocation, + lg_crl_collect, (void *)&crlData); + nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeKeyRevocation, + lg_crl_collect, (void *)&crlData); + } +} + +/* + * structure to collect key handles. + */ +typedef struct lgKeyDataStr { + SDB *sdb; + NSSLOWKEYDBHandle *keyHandle; + SDBFind *searchHandles; + SECItem *id; + const CK_ATTRIBUTE *template; + CK_ULONG templ_count; + unsigned long classFlags; + PRBool strict; +} lgKeyData; + +static PRBool +isSecretKey(NSSLOWKEYPrivateKey *privKey) +{ + if (privKey->keyType == NSSLOWKEYRSAKey && + privKey->u.rsa.publicExponent.len == 1 && + privKey->u.rsa.publicExponent.data[0] == 0) + return PR_TRUE; + + return PR_FALSE; +} + + + +static SECStatus +lg_key_collect(DBT *key, DBT *data, void *arg) +{ + lgKeyData *keyData; + NSSLOWKEYPrivateKey *privKey = NULL; + SECItem tmpDBKey; + SDB *sdb; + unsigned long classFlags; + + keyData = (lgKeyData *)arg; + sdb = keyData->sdb; + classFlags = keyData->classFlags; + + tmpDBKey.data = key->data; + tmpDBKey.len = key->size; + tmpDBKey.type = siBuffer; + + PORT_Assert(keyData->keyHandle); + if (!keyData->strict && keyData->id) { + SECItem result; + PRBool haveMatch= PR_FALSE; + unsigned char hashKey[SHA1_LENGTH]; + result.data = hashKey; + result.len = sizeof(hashKey); + + if (keyData->id->len == 0) { + /* Make sure this isn't a LG_KEY */ + privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, + &tmpDBKey, keyData->sdb/*->password*/); + if (privKey) { + /* turn off the unneeded class flags */ + classFlags &= isSecretKey(privKey) ? ~(LG_PRIVATE|LG_PUBLIC) : + ~LG_KEY; + haveMatch = (PRBool) + ((classFlags & (LG_KEY|LG_PRIVATE|LG_PUBLIC)) != 0); + nsslowkey_DestroyPrivateKey(privKey); + } + } else { + SHA1_HashBuf( hashKey, key->data, key->size ); /* match id */ + haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result); + if (!haveMatch && ((unsigned char *)key->data)[0] == 0) { + /* This is a fix for backwards compatibility. The key + * database indexes private keys by the public key, and + * versions of NSS prior to 3.4 stored the public key as + * a signed integer. The public key is now treated as an + * unsigned integer, with no leading zero. In order to + * correctly compute the hash of an old key, it is necessary + * to fallback and detect the leading zero. + */ + SHA1_HashBuf(hashKey, + (unsigned char *)key->data + 1, key->size - 1); + haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result); + } + } + if (haveMatch) { + if (classFlags & LG_PRIVATE) { + lg_addHandle(keyData->searchHandles, + lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_PRIV)); + } + if (classFlags & LG_PUBLIC) { + lg_addHandle(keyData->searchHandles, + lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_PUB)); + } + if (classFlags & LG_KEY) { + lg_addHandle(keyData->searchHandles, + lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_KEY)); + } + } + return SECSuccess; + } + + privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, + keyData->sdb/*->password*/); + if ( privKey == NULL ) { + goto loser; + } + + if (isSecretKey(privKey)) { + if ((classFlags & LG_KEY) && + lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY, + keyData->template, keyData->templ_count)) { + lg_addHandle(keyData->searchHandles, + lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY)); + } + } else { + if ((classFlags & LG_PRIVATE) && + lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV, + keyData->template, keyData->templ_count)) { + lg_addHandle(keyData->searchHandles, + lg_mkHandle(keyData->sdb,&tmpDBKey,LG_TOKEN_TYPE_PRIV)); + } + if ((classFlags & LG_PUBLIC) && + lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB, + keyData->template, keyData->templ_count)) { + lg_addHandle(keyData->searchHandles, + lg_mkHandle(keyData->sdb, &tmpDBKey,LG_TOKEN_TYPE_PUB)); + } + } + +loser: + if ( privKey ) { + nsslowkey_DestroyPrivateKey(privKey); + } + return(SECSuccess); +} + +static void +lg_searchKeys(SDB *sdb, SECItem *key_id, + unsigned long classFlags, SDBFind *search, PRBool mustStrict, + const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) +{ + NSSLOWKEYDBHandle *keyHandle = NULL; + NSSLOWKEYPrivateKey *privKey; + lgKeyData keyData; + PRBool found = PR_FALSE; + + keyHandle = lg_getKeyDB(sdb); + if (keyHandle == NULL) { + return; + } + + if (key_id->data) { + privKey = nsslowkey_FindKeyByPublicKey(keyHandle, key_id, sdb); + if (privKey) { + if ((classFlags & LG_KEY) && isSecretKey(privKey)) { + lg_addHandle(search, + lg_mkHandle(sdb,key_id,LG_TOKEN_TYPE_KEY)); + found = PR_TRUE; + } + if ((classFlags & LG_PRIVATE) && !isSecretKey(privKey)) { + lg_addHandle(search, + lg_mkHandle(sdb,key_id,LG_TOKEN_TYPE_PRIV)); + found = PR_TRUE; + } + if ((classFlags & LG_PUBLIC) && !isSecretKey(privKey)) { + lg_addHandle(search, + lg_mkHandle(sdb,key_id,LG_TOKEN_TYPE_PUB)); + found = PR_TRUE; + } + nsslowkey_DestroyPrivateKey(privKey); + } + /* don't do the traversal if we have an up to date db */ + if (keyHandle->version != 3) { + 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) { + goto loser; + } + if (found) { + /* if we already found some keys, don't do the traversal */ + goto loser; + } + } + keyData.sdb = sdb; + keyData.keyHandle = keyHandle; + keyData.searchHandles = search; + keyData.id = key_id; + keyData.template = pTemplate; + keyData.templ_count = ulCount; + keyData.classFlags = classFlags; + keyData.strict = mustStrict ? mustStrict : LG_STRICT; + + nsslowkey_TraverseKeys(keyHandle, lg_key_collect, &keyData); + +loser: + return; +} + +/* + * structure to collect certs into + */ +typedef struct lgCertDataStr { + SDB *sdb; + int cert_count; + int max_cert_count; + NSSLOWCERTCertificate **certs; + const CK_ATTRIBUTE *template; + CK_ULONG templ_count; + unsigned long classFlags; + PRBool strict; +} lgCertData; + +/* + * collect all the certs from the traverse call. + */ +static SECStatus +lg_cert_collect(NSSLOWCERTCertificate *cert,void *arg) +{ + lgCertData *cd = (lgCertData *)arg; + + if (cert == NULL) { + return SECSuccess; + } + + if (cd->certs == NULL) { + return SECFailure; + } + + if (cd->strict) { + if ((cd->classFlags & LG_CERT) && !lg_tokenMatch(cd->sdb, + &cert->certKey, LG_TOKEN_TYPE_CERT, cd->template,cd->templ_count)) { + return SECSuccess; + } + if ((cd->classFlags & LG_TRUST) && !lg_tokenMatch(cd->sdb, + &cert->certKey, LG_TOKEN_TYPE_TRUST, + cd->template, cd->templ_count)) { + return SECSuccess; + } + } + + /* allocate more space if we need it. This should only happen in + * the general traversal case */ + if (cd->cert_count >= cd->max_cert_count) { + int size; + cd->max_cert_count += LG_SEARCH_BLOCK_SIZE; + size = cd->max_cert_count * sizeof (NSSLOWCERTCertificate *); + cd->certs = (NSSLOWCERTCertificate **)PORT_Realloc(cd->certs,size); + if (cd->certs == NULL) { + return SECFailure; + } + } + + cd->certs[cd->cert_count++] = nsslowcert_DupCertificate(cert); + return SECSuccess; +} + +/* provide impedence matching ... */ +static SECStatus +lg_cert_collect2(NSSLOWCERTCertificate *cert, SECItem *dymmy, void *arg) +{ + return lg_cert_collect(cert, arg); +} + +static void +lg_searchSingleCert(lgCertData *certData,NSSLOWCERTCertificate *cert) +{ + if (cert == NULL) { + return; + } + if (certData->strict && + !lg_tokenMatch(certData->sdb, &cert->certKey, LG_TOKEN_TYPE_CERT, + certData->template,certData->templ_count)) { + nsslowcert_DestroyCertificate(cert); + return; + } + certData->certs = (NSSLOWCERTCertificate **) + PORT_Alloc(sizeof (NSSLOWCERTCertificate *)); + if (certData->certs == NULL) { + nsslowcert_DestroyCertificate(cert); + return; + } + certData->certs[0] = cert; + certData->cert_count = 1; +} + +static void +lg_CertSetupData(lgCertData *certData,int count) +{ + certData->max_cert_count = count; + + if (certData->max_cert_count <= 0) { + return; + } + certData->certs = (NSSLOWCERTCertificate **) + PORT_Alloc( count * sizeof(NSSLOWCERTCertificate *)); + return; +} + +static void +lg_searchCertsAndTrust(SDB *sdb, SECItem *derCert, SECItem *name, + SECItem *derSubject, NSSLOWCERTIssuerAndSN *issuerSN, + SECItem *email, + unsigned long classFlags, SDBFind *handles, + const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) +{ + NSSLOWCERTCertDBHandle *certHandle = NULL; + lgCertData certData; + int i; + + certHandle = lg_getCertDB(sdb); + if (certHandle == NULL) return; + + certData.sdb = sdb; + certData.max_cert_count = 0; + certData.certs = NULL; + certData.cert_count = 0; + certData.template = pTemplate; + certData.templ_count = ulCount; + certData.classFlags = classFlags; + certData.strict = LG_STRICT; + + + /* + * Find the Cert. + */ + if (derCert->data != NULL) { + NSSLOWCERTCertificate *cert = + nsslowcert_FindCertByDERCert(certHandle,derCert); + lg_searchSingleCert(&certData,cert); + } else if (name->data != NULL) { + char *tmp_name = (char*)PORT_Alloc(name->len+1); + int count; + + if (tmp_name == NULL) { + return; + } + PORT_Memcpy(tmp_name,name->data,name->len); + tmp_name[name->len] = 0; + + count= nsslowcert_NumPermCertsForNickname(certHandle,tmp_name); + lg_CertSetupData(&certData,count); + nsslowcert_TraversePermCertsForNickname(certHandle,tmp_name, + lg_cert_collect, &certData); + PORT_Free(tmp_name); + } else if (derSubject->data != NULL) { + int count; + + count = nsslowcert_NumPermCertsForSubject(certHandle,derSubject); + lg_CertSetupData(&certData,count); + nsslowcert_TraversePermCertsForSubject(certHandle,derSubject, + lg_cert_collect, &certData); + } else if ((issuerSN->derIssuer.data != NULL) && + (issuerSN->serialNumber.data != NULL)) { + if (classFlags & LG_CERT) { + NSSLOWCERTCertificate *cert = + nsslowcert_FindCertByIssuerAndSN(certHandle,issuerSN); + + lg_searchSingleCert(&certData,cert); + } + if (classFlags & LG_TRUST) { + NSSLOWCERTTrust *trust = + nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN); + + if (trust) { + lg_addHandle(handles, + lg_mkHandle(sdb,&trust->dbKey,LG_TOKEN_TYPE_TRUST)); + nsslowcert_DestroyTrust(trust); + } + } + } else if (email->data != NULL) { + char *tmp_name = (char*)PORT_Alloc(email->len+1); + certDBEntrySMime *entry = NULL; + + if (tmp_name == NULL) { + return; + } + PORT_Memcpy(tmp_name,email->data,email->len); + tmp_name[email->len] = 0; + + entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name); + if (entry) { + int count; + SECItem *subjectName = &entry->subjectName; + + count = nsslowcert_NumPermCertsForSubject(certHandle, subjectName); + lg_CertSetupData(&certData,count); + nsslowcert_TraversePermCertsForSubject(certHandle, subjectName, + lg_cert_collect, &certData); + + nsslowcert_DestroyDBEntry((certDBEntry *)entry); + } + PORT_Free(tmp_name); + } else { + /* we aren't filtering the certs, we are working on all, so turn + * on the strict filters. */ + certData.strict = PR_TRUE; + lg_CertSetupData(&certData,LG_SEARCH_BLOCK_SIZE); + nsslowcert_TraversePermCerts(certHandle, lg_cert_collect2, &certData); + } + + /* + * build the handles + */ + for (i=0 ; i < certData.cert_count ; i++) { + NSSLOWCERTCertificate *cert = certData.certs[i]; + + /* if we filtered it would have been on the stuff above */ + if (classFlags & LG_CERT) { + lg_addHandle(handles, + lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_CERT)); + } + if ((classFlags & LG_TRUST) && nsslowcert_hasTrust(cert->trust)) { + lg_addHandle(handles, + lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_TRUST)); + } + nsslowcert_DestroyCertificate(cert); + } + + if (certData.certs) PORT_Free(certData.certs); + return; +} + +static SECStatus +lg_smime_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg) +{ + lgEntryData *smimeData; + SDB *sdb; + + smimeData = (lgEntryData *)arg; + sdb = smimeData->sdb; + + if (lg_tokenMatch(sdb, key, LG_TOKEN_TYPE_SMIME, + smimeData->template, smimeData->templ_count)) { + lg_addHandle(smimeData->searchHandles, + lg_mkHandle(sdb,key,LG_TOKEN_TYPE_SMIME)); + } + return(SECSuccess); +} + +static void +lg_searchSMime(SDB *sdb, SECItem *email, SDBFind *handles, + const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) +{ + NSSLOWCERTCertDBHandle *certHandle = NULL; + certDBEntrySMime *entry; + + certHandle = lg_getCertDB(sdb); + if (certHandle == NULL) return; + + if (email->data != NULL) { + char *tmp_name = (char*)PORT_Alloc(email->len+1); + + if (tmp_name == NULL) { + return; + } + PORT_Memcpy(tmp_name,email->data,email->len); + tmp_name[email->len] = 0; + + entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name); + if (entry) { + SECItem emailKey; + + emailKey.data = (unsigned char *)tmp_name; + emailKey.len = PORT_Strlen(tmp_name)+1; + emailKey.type = 0; + lg_addHandle(handles, + lg_mkHandle(sdb,&emailKey,LG_TOKEN_TYPE_SMIME)); + nsslowcert_DestroyDBEntry((certDBEntry *)entry); + } + PORT_Free(tmp_name); + } else { + /* traverse */ + lgEntryData smimeData; + + /* traverse */ + smimeData.sdb = sdb; + smimeData.searchHandles = handles; + smimeData.template = pTemplate; + smimeData.templ_count = ulCount; + nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeSMimeProfile, + lg_smime_collect, (void *)&smimeData); + } + return; +} + +static CK_RV +lg_searchTokenList(SDB *sdb, SDBFind *search, + const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) +{ + int i; + PRBool isKrl = PR_FALSE; + SECItem derCert = { siBuffer, NULL, 0 }; + SECItem derSubject = { siBuffer, NULL, 0 }; + SECItem name = { siBuffer, NULL, 0 }; + SECItem email = { siBuffer, NULL, 0 }; + SECItem key_id = { siBuffer, NULL, 0 }; + SECItem cert_sha1_hash = { siBuffer, NULL, 0 }; + SECItem cert_md5_hash = { siBuffer, NULL, 0 }; + NSSLOWCERTIssuerAndSN issuerSN = { + { siBuffer, NULL, 0 }, + { siBuffer, NULL, 0 } + }; + SECItem *copy = NULL; + CK_CERTIFICATE_TYPE certType; + CK_OBJECT_CLASS objectClass; + CK_RV crv; + unsigned long classFlags = + LG_CERT|LG_TRUST|LG_PRIVATE|LG_PUBLIC|LG_KEY|LG_SMIME|LG_CRL; + + if (lg_getCertDB(sdb) == NULL) { + classFlags = LG_PRIVATE|LG_KEY; + } else { + classFlags = LG_CERT|LG_TRUST|LG_PUBLIC|LG_SMIME|LG_CRL; + } + + /* + * look for things to search on token objects for. If the right options + * are specified, we can use them as direct indeces into the database + * (rather than using linear searches. We can also use the attributes to + * limit the kinds of objects we are searching for. Later we can use this + * array to filter the remaining objects more finely. + */ + for (i=0 ;classFlags && i < (int)ulCount; i++) { + + switch (pTemplate[i].type) { + case CKA_SUBJECT: + copy = &derSubject; + classFlags &= (LG_CERT|LG_PRIVATE|LG_PUBLIC|LG_SMIME|LG_CRL); + break; + case CKA_ISSUER: + copy = &issuerSN.derIssuer; + classFlags &= (LG_CERT|LG_TRUST); + break; + case CKA_SERIAL_NUMBER: + copy = &issuerSN.serialNumber; + classFlags &= (LG_CERT|LG_TRUST); + break; + case CKA_VALUE: + copy = &derCert; + classFlags &= (LG_CERT|LG_CRL|LG_SMIME); + break; + case CKA_LABEL: + copy = &name; + break; + case CKA_NETSCAPE_EMAIL: + copy = &email; + classFlags &= LG_SMIME|LG_CERT; + break; + case CKA_NETSCAPE_SMIME_TIMESTAMP: + classFlags &= LG_SMIME; + break; + case CKA_CLASS: + crv = lg_GetULongAttribute(CKA_CLASS,&pTemplate[i],1, &objectClass); + if (crv != CKR_OK) { + classFlags = 0; + break;; + } + switch (objectClass) { + case CKO_CERTIFICATE: + classFlags &= LG_CERT; + break; + case CKO_NETSCAPE_TRUST: + classFlags &= LG_TRUST; + break; + case CKO_NETSCAPE_CRL: + classFlags &= LG_CRL; + break; + case CKO_NETSCAPE_SMIME: + classFlags &= LG_SMIME; + break; + case CKO_PRIVATE_KEY: + classFlags &= LG_PRIVATE; + break; + case CKO_PUBLIC_KEY: + classFlags &= LG_PUBLIC; + break; + case CKO_SECRET_KEY: + classFlags &= LG_KEY; + break; + default: + classFlags = 0; + break; + } + break; + case CKA_PRIVATE: + if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { + classFlags = 0; + } + if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) { + classFlags &= (LG_PRIVATE|LG_KEY); + } else { + classFlags &= ~(LG_PRIVATE|LG_KEY); + } + break; + case CKA_SENSITIVE: + if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { + classFlags = 0; + } + if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) { + classFlags &= (LG_PRIVATE|LG_KEY); + } else { + classFlags = 0; + } + break; + case CKA_TOKEN: + if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { + classFlags = 0; + } + if (*((CK_BBOOL *)pTemplate[i].pValue) != CK_TRUE) { + classFlags = 0; + } + break; + case CKA_CERT_SHA1_HASH: + classFlags &= LG_TRUST; + copy = &cert_sha1_hash; break; + case CKA_CERT_MD5_HASH: + classFlags &= LG_TRUST; + copy = &cert_md5_hash; break; + case CKA_CERTIFICATE_TYPE: + crv = lg_GetULongAttribute(CKA_CLASS,&pTemplate[i],1,&certType); + if (crv != CKR_OK) { + classFlags = 0; + } + classFlags &= LG_CERT; + if (certType != CKC_X_509) { + classFlags = 0; + } + break; + case CKA_ID: + copy = &key_id; + classFlags &= (LG_CERT|LG_PRIVATE|LG_KEY|LG_PUBLIC); + break; + case CKA_NETSCAPE_KRL: + if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { + classFlags = 0; + } + classFlags &= LG_CRL; + isKrl = (PRBool)(*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE); + break; + case CKA_MODIFIABLE: + break; + case CKA_KEY_TYPE: + case CKA_DERIVE: + classFlags &= LG_PUBLIC|LG_PRIVATE|LG_KEY; + break; + case CKA_VERIFY_RECOVER: + classFlags &= LG_PUBLIC; + break; + case CKA_SIGN_RECOVER: + classFlags &= LG_PRIVATE; + break; + case CKA_ENCRYPT: + case CKA_VERIFY: + case CKA_WRAP: + classFlags &= LG_PUBLIC|LG_KEY; + break; + case CKA_DECRYPT: + case CKA_SIGN: + case CKA_UNWRAP: + case CKA_ALWAYS_SENSITIVE: + case CKA_EXTRACTABLE: + case CKA_NEVER_EXTRACTABLE: + classFlags &= LG_PRIVATE|LG_KEY; + break; + /* can't be a certificate if it doesn't match one of the above + * attributes */ + default: + classFlags = 0; + break; + } + if (copy) { + copy->data = (unsigned char*)pTemplate[i].pValue; + copy->len = pTemplate[i].ulValueLen; + } + copy = NULL; + } + + /* certs */ + if (classFlags & (LG_CERT|LG_TRUST)) { + lg_searchCertsAndTrust(sdb,&derCert,&name,&derSubject, + &issuerSN, &email,classFlags,search, + pTemplate, ulCount); + } + + /* keys */ + if (classFlags & (LG_PRIVATE|LG_PUBLIC|LG_KEY)) { + PRBool mustStrict = ((classFlags & LG_KEY) != 0) && (name.len != 0); + lg_searchKeys(sdb, &key_id, classFlags, search, + mustStrict, pTemplate, ulCount); + } + + /* crl's */ + if (classFlags & LG_CRL) { + lg_searchCrls(sdb, &derSubject, isKrl, classFlags, search, + pTemplate, ulCount); + } + /* Add S/MIME entry stuff */ + if (classFlags & LG_SMIME) { + lg_searchSMime(sdb, &email, search, pTemplate, ulCount); + } + return CKR_OK; +} + + +/* lg_FindObjectsInit initializes a search for token and session objects + * that match a template. */ +CK_RV lg_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *pTemplate, + CK_ULONG ulCount, SDBFind **retSearch) +{ + SDBFind *search; + CK_RV crv = CKR_OK; + + *retSearch = NULL; + + search = (SDBFind *)PORT_Alloc(sizeof(SDBFind)); + if (search == NULL) { + crv = CKR_HOST_MEMORY; + goto loser; + } + search->handles = (CK_OBJECT_HANDLE *) + PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * LG_SEARCH_BLOCK_SIZE); + if (search->handles == NULL) { + crv = CKR_HOST_MEMORY; + goto loser; + } + search->index = 0; + search->size = 0; + search->array_size = LG_SEARCH_BLOCK_SIZE; + /* FIXME - do we still need to get Login state? */ + + crv = lg_searchTokenList(sdb, search, pTemplate, ulCount); + if (crv != CKR_OK) { + goto loser; + } + + *retSearch = search; + return CKR_OK; + +loser: + if (search) { + lg_FreeSearch(search); + } + return crv; +} + + +/* lg_FindObjects continues a search for token and session objects + * that match a template, obtaining additional object handles. */ +CK_RV lg_FindObjects(SDB *sdb, SDBFind *search, + CK_OBJECT_HANDLE *phObject,CK_ULONG ulMaxObjectCount, + CK_ULONG *pulObjectCount) +{ + int transfer; + int left; + + *pulObjectCount = 0; + left = search->size - search->index; + transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount; + if (transfer > 0) { + PORT_Memcpy(phObject,&search->handles[search->index], + transfer*sizeof(CK_OBJECT_HANDLE_PTR)); + } else { + *phObject = CK_INVALID_HANDLE; + } + + search->index += transfer; + *pulObjectCount = transfer; + return CKR_OK; +} + +/* lg_FindObjectsFinal finishes a search for token and session objects. */ +CK_RV lg_FindObjectsFinal(SDB* lgdb, SDBFind *search) +{ + + if (search != NULL) { + lg_FreeSearch(search); + } + return CKR_OK; +} diff --git a/security/nss/lib/softoken/dbinit.c b/security/nss/lib/softoken/legacydb/lginit.c index 921af1568..ed5ec4a47 100644 --- a/security/nss/lib/softoken/dbinit.c +++ b/security/nss/lib/softoken/legacydb/lginit.c @@ -38,21 +38,20 @@ * ***** END LICENSE BLOCK ***** */ /* $Id$ */ -#include <ctype.h> -#include "seccomon.h" -#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" +#include "lgdb.h" + +typedef struct LGPrivateStr { + NSSLOWCERTCertDBHandle *certDB; + NSSLOWKEYDBHandle *keyDB; + PRLock *dbLock; + PLHashTable *hashTable; +} LGPrivate; static char * -sftk_certdb_name_cb(void *arg, int dbVersion) +lg_certdb_name_cb(void *arg, int dbVersion) { const char *configdir = (const char *)arg; const char *dbver; @@ -89,7 +88,7 @@ sftk_certdb_name_cb(void *arg, int dbVersion) } static char * -sftk_keydb_name_cb(void *arg, int dbVersion) +lg_keydb_name_cb(void *arg, int dbVersion) { const char *configdir = (const char *)arg; const char *dbver; @@ -121,7 +120,7 @@ sftk_keydb_name_cb(void *arg, int dbVersion) } const char * -sftk_EvaluateConfigDir(const char *configdir,char **appName) +lg_EvaluateConfigDir(const char *configdir,char **appName) { if (PORT_Strncmp(configdir, MULTIACCESS, sizeof(MULTIACCESS)-1) == 0) { char *cdir; @@ -143,171 +142,9 @@ sftk_EvaluateConfigDir(const char *configdir,char **appName) return configdir; } -static CK_RV -sftk_OpenCertDB(const char * configdir, const char *prefix, PRBool readOnly, - NSSLOWCERTCertDBHandle **certdbPtr) -{ - NSSLOWCERTCertDBHandle *certdb = NULL; - CK_RV crv = CKR_NETSCAPE_CERTDB_FAILED; - SECStatus rv; - char * name = NULL; - char * appName = NULL; - - if (prefix == NULL) { - prefix = ""; - } - - configdir = sftk_EvaluateConfigDir(configdir, &appName); - - name = PR_smprintf("%s" PATH_SEPARATOR "%s",configdir,prefix); - if (name == NULL) goto loser; - - certdb = (NSSLOWCERTCertDBHandle*)PORT_ZAlloc(sizeof(NSSLOWCERTCertDBHandle)); - 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); - if (rv == SECSuccess) { - crv = CKR_OK; - *certdbPtr = certdb; - certdb = NULL; - } -loser: - if (certdb) PR_Free(certdb); - if (name) PR_smprintf_free(name); - if (appName) PORT_Free(appName); - return crv; -} - -static CK_RV -sftk_OpenKeyDB(const char * configdir, const char *prefix, PRBool readOnly, - NSSLOWKEYDBHandle **keydbPtr) -{ - NSSLOWKEYDBHandle *keydb; - char * name = NULL; - char * appName = NULL; - - if (prefix == NULL) { - prefix = ""; - } - configdir = sftk_EvaluateConfigDir(configdir, &appName); - - name = PR_smprintf("%s" PATH_SEPARATOR "%s",configdir,prefix); - if (name == NULL) - return CKR_HOST_MEMORY; - keydb = nsslowkey_OpenKeyDB(readOnly, appName, prefix, - sftk_keydb_name_cb, (void *)name); - PR_smprintf_free(name); - if (appName) PORT_Free(appName); - if (keydb == NULL) - return CKR_NETSCAPE_KEYDB_FAILED; - *keydbPtr = keydb; - - return CKR_OK; -} - - -/* - * OK there are now lots of options here, lets go through them all: - * - * configdir - base directory where all the cert, key, and module datbases live. - * certPrefix - prefix added to the beginning of the cert database example: " - * "https-server1-" - * keyPrefix - prefix added to the beginning of the key database example: " - * "https-server1-" - * secmodName - name of the security module database (usually "secmod.db"). - * readOnly - Boolean: true if the databases are to be openned read only. - * nocertdb - Don't open the cert DB and key DB's, just initialize the - * Volatile certdb. - * nomoddb - Don't open the security module DB, just initialize the - * PKCS #11 module. - * forceOpen - Continue to force initializations even if the databases cannot - * be opened. - */ -CK_RV -sftk_DBInit(const char *configdir, const char *certPrefix, - const char *keyPrefix, PRBool readOnly, - PRBool noCertDB, PRBool noKeyDB, PRBool forceOpen, - NSSLOWCERTCertDBHandle **certdbPtr, NSSLOWKEYDBHandle **keydbPtr) -{ - CK_RV crv = CKR_OK; - - - if (!noCertDB) { - crv = sftk_OpenCertDB(configdir, certPrefix, readOnly, certdbPtr); - if (crv != CKR_OK) { - if (!forceOpen) goto loser; - crv = CKR_OK; - } - } - if (!noKeyDB) { - - crv = sftk_OpenKeyDB(configdir, keyPrefix, readOnly, keydbPtr); - if (crv != CKR_OK) { - if (!forceOpen) goto loser; - crv = CKR_OK; - } - } - - -loser: - return crv; -} - -NSSLOWCERTCertDBHandle * -sftk_getCertDB(SFTKSlot *slot) -{ - NSSLOWCERTCertDBHandle *certHandle; - - PZ_Lock(slot->slotLock); - certHandle = slot->certDB; - if (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) { - 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); - PORT_Free(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; -static rdbstatusfunc sftk_rdbstatusfunc = NULL; +static rdbfunc lg_rdbfunc = NULL; +static rdbstatusfunc lg_rdbstatusfunc = NULL; /* NOTE: SHLIB_SUFFIX is defined on the command line */ #define RDBLIB SHLIB_PREFIX"rdb."SHLIB_SUFFIX @@ -318,10 +155,10 @@ DB * rdbopen(const char *appName, const char *prefix, PRLibrary *lib; DB *db; - if (sftk_rdbfunc) { - db = (*sftk_rdbfunc)(appName,prefix,type,rdbmapflags(flags)); - if (!db && status && sftk_rdbstatusfunc) { - *status = (*sftk_rdbstatusfunc)(); + if (lg_rdbfunc) { + db = (*lg_rdbfunc)(appName,prefix,type,rdbmapflags(flags)); + if (!db && status && lg_rdbstatusfunc) { + *status = (*lg_rdbstatusfunc)(); } return db; } @@ -336,12 +173,12 @@ DB * rdbopen(const char *appName, const char *prefix, } /* get the entry points */ - sftk_rdbstatusfunc = (rdbstatusfunc) PR_FindFunctionSymbol(lib,"rdbstatus"); - sftk_rdbfunc = (rdbfunc) PR_FindFunctionSymbol(lib,"rdbopen"); - if (sftk_rdbfunc) { - db = (*sftk_rdbfunc)(appName,prefix,type,rdbmapflags(flags)); - if (!db && status && sftk_rdbstatusfunc) { - *status = (*sftk_rdbstatusfunc)(); + lg_rdbstatusfunc = (rdbstatusfunc) PR_FindSymbol(lib,"rdbstatus"); + lg_rdbfunc = (rdbfunc) PR_FindSymbol(lib,"rdbopen"); + if (lg_rdbfunc) { + db = (*lg_rdbfunc)(appName,prefix,type,rdbmapflags(flags)); + if (!db && status && lg_rdbstatusfunc) { + *status = (*lg_rdbstatusfunc)(); } return db; } @@ -382,7 +219,6 @@ rdbmapflags(int flags) { return 0; } - PRBool db_IsRDB(DB *db) { @@ -411,6 +247,71 @@ db_FinishTransaction(DB *db, PRBool abort) return rdb->xactdone(db, abort); } +static DB * +lg_getRawDB(SDB *sdb) +{ + NSSLOWCERTCertDBHandle *certDB; + NSSLOWKEYDBHandle *keyDB; + + certDB = lg_getCertDB(sdb); + if (certDB) { + return certDB->permCertDB; + } + keyDB = lg_getKeyDB(sdb); + if (keyDB) { + return keyDB->db; + } + return NULL; +} + +CK_RV +lg_Begin(SDB *sdb) +{ + DB *db = lg_getRawDB(sdb); + int ret; + + if (db == NULL) { + return CKR_GENERAL_ERROR; /* shouldn't happen */ + } + ret = db_BeginTransaction(db); + if (ret != 0) { + return CKR_GENERAL_ERROR; /* could happen */ + } + return CKR_OK; +} + +CK_RV +lg_Commit(SDB *sdb) +{ + DB *db = lg_getRawDB(sdb); + int ret; + + if (db == NULL) { + return CKR_GENERAL_ERROR; /* shouldn't happen */ + } + ret = db_FinishTransaction(db, PR_FALSE); + if (ret != 0) { + return CKR_GENERAL_ERROR; /* could happen */ + } + return CKR_OK; +} + +CK_RV +lg_Abort(SDB *sdb) +{ + DB *db = lg_getRawDB(sdb); + int ret; + + if (db == NULL) { + return CKR_GENERAL_ERROR; /* shouldn't happen */ + } + ret = db_FinishTransaction(db, PR_TRUE); + if (ret != 0) { + return CKR_GENERAL_ERROR; /* could happen */ + } + return CKR_OK; +} + int db_InitComplete(DB *db) { @@ -418,10 +319,10 @@ db_InitComplete(DB *db) if (db->type != DB_RDB) { return 0; } - /* we should have addes a version number to the RDBS structure. Since we + /* we should have added a version number to the RDBS structure. Since we * didn't, we detect that we have and 'extended' structure if the rdbstatus * func exists */ - if (!sftk_rdbstatusfunc) { + if (!lg_rdbstatusfunc) { return 0; } @@ -448,3 +349,296 @@ db_Copy(DB *dest,DB *src) return SECSuccess; } + +static CK_RV +lg_OpenCertDB(const char * configdir, const char *prefix, PRBool readOnly, + NSSLOWCERTCertDBHandle **certdbPtr) +{ + NSSLOWCERTCertDBHandle *certdb = NULL; + CK_RV crv = CKR_NETSCAPE_CERTDB_FAILED; + SECStatus rv; + char * name = NULL; + char * appName = NULL; + + if (prefix == NULL) { + prefix = ""; + } + + configdir = lg_EvaluateConfigDir(configdir, &appName); + + name = PR_smprintf("%s" PATH_SEPARATOR "%s",configdir,prefix); + if (name == NULL) goto loser; + + certdb = (NSSLOWCERTCertDBHandle*)PORT_ZAlloc(sizeof(NSSLOWCERTCertDBHandle)); + if (certdb == NULL) + goto loser; + + certdb->ref = 1; +/* fix when we get the DB in */ + rv = nsslowcert_OpenCertDB(certdb, readOnly, appName, prefix, + lg_certdb_name_cb, (void *)name, PR_FALSE); + if (rv == SECSuccess) { + crv = CKR_OK; + *certdbPtr = certdb; + certdb = NULL; + } +loser: + if (certdb) PR_Free(certdb); + if (name) PR_smprintf_free(name); + if (appName) PORT_Free(appName); + return crv; +} + +static CK_RV +lg_OpenKeyDB(const char * configdir, const char *prefix, PRBool readOnly, + NSSLOWKEYDBHandle **keydbPtr) +{ + NSSLOWKEYDBHandle *keydb; + char * name = NULL; + char * appName = NULL; + + if (prefix == NULL) { + prefix = ""; + } + configdir = lg_EvaluateConfigDir(configdir, &appName); + + name = PR_smprintf("%s" PATH_SEPARATOR "%s",configdir,prefix); + if (name == NULL) + return CKR_HOST_MEMORY; + keydb = nsslowkey_OpenKeyDB(readOnly, appName, prefix, + lg_keydb_name_cb, (void *)name); + PR_smprintf_free(name); + if (appName) PORT_Free(appName); + if (keydb == NULL) + return CKR_NETSCAPE_KEYDB_FAILED; + *keydbPtr = keydb; + + return CKR_OK; +} + +/* + * Accessors for the private parts of the sdb structure. + */ +void +lg_DBLock(SDB *sdb) +{ + LGPrivate *lgdb_p = (LGPrivate *)sdb->private; + PR_Lock(lgdb_p->dbLock); +} + +void +lg_DBUnlock(SDB *sdb) +{ + LGPrivate *lgdb_p = (LGPrivate *)sdb->private; + PR_Unlock(lgdb_p->dbLock); +} + +PLHashTable * +lg_GetHashTable(SDB *sdb) +{ + LGPrivate *lgdb_p = (LGPrivate *)sdb->private; + return lgdb_p->hashTable; +} + +NSSLOWCERTCertDBHandle * +lg_getCertDB(SDB *sdb) +{ + LGPrivate *lgdb_p = (LGPrivate *)sdb->private; + + return lgdb_p->certDB; +} + +NSSLOWKEYDBHandle * +lg_getKeyDB(SDB *sdb) +{ + LGPrivate *lgdb_p = (LGPrivate *)sdb->private; + + return lgdb_p->keyDB; +} + +CK_RV +lg_Close(SDB *sdb) +{ + LGPrivate *lgdb_p = (LGPrivate *)sdb->private; + if (lgdb_p) { + if (lgdb_p->certDB) { + nsslowcert_ClosePermCertDB(lgdb_p->certDB); + } else if (lgdb_p->keyDB) { + nsslowkey_CloseKeyDB(lgdb_p->keyDB); + } + if (lgdb_p->dbLock) { + PR_DestroyLock(lgdb_p->dbLock); + } + if (lgdb_p->hashTable) { + PL_HashTableDestroy(lgdb_p->hashTable); + } + PORT_Free(lgdb_p); + } + PORT_Free(sdb); + return CKR_OK; +} + +static PLHashNumber +lg_HashNumber(const void *key) +{ + return (PLHashNumber) key; +} + + +/* + * helper function to wrap a NSSLOWCERTCertDBHandle or a NSSLOWKEYDBHandle + * with and sdb structure. + */ +CK_RV +lg_init(SDB **pSdb, int flags, NSSLOWCERTCertDBHandle *certdbPtr, + NSSLOWKEYDBHandle *keydbPtr) +{ + SDB *sdb = NULL; + LGPrivate *lgdb_p = NULL; + CK_RV error = CKR_HOST_MEMORY; + + *pSdb = NULL; + sdb = (SDB *) PORT_Alloc(sizeof(SDB)); + if (sdb == NULL) { + goto loser; + } + lgdb_p = (LGPrivate *) PORT_Alloc(sizeof(LGPrivate)); + if (lgdb_p == NULL) { + goto loser; + } + /* invariant fields */ + lgdb_p->certDB = certdbPtr; + lgdb_p->keyDB = keydbPtr; + lgdb_p->dbLock = PR_NewLock(); + if (lgdb_p->dbLock == NULL) { + goto loser; + } + lgdb_p->hashTable = PL_NewHashTable(64, lg_HashNumber, PL_CompareValues, + SECITEM_HashCompare, NULL, 0); + if (lgdb_p->hashTable == NULL) { + goto loser; + } + + sdb->sdb_type = SDB_LEGACY; + sdb->sdb_flags = flags; + sdb->private = lgdb_p; + sdb->sdb_FindObjectsInit = lg_FindObjectsInit; + sdb->sdb_FindObjects = lg_FindObjects; + sdb->sdb_FindObjectsFinal = lg_FindObjectsFinal; + sdb->sdb_GetAttributeValue = lg_GetAttributeValue; + sdb->sdb_SetAttributeValue = lg_SetAttributeValue; + sdb->sdb_CreateObject = lg_CreateObject; + sdb->sdb_DestroyObject = lg_DestroyObject; + sdb->sdb_GetPWEntry = lg_GetPWEntry; + sdb->sdb_PutPWEntry = lg_PutPWEntry; + sdb->sdb_Begin = lg_Begin; + sdb->sdb_Commit = lg_Commit; + sdb->sdb_Abort = lg_Abort; + sdb->sdb_Close = lg_Reset; + sdb->sdb_Close = lg_Close; + + + *pSdb = sdb; + return CKR_OK; + +loser: + if (sdb) { + PORT_Free(sdb); + } + if (lgdb_p) { + if (lgdb_p->dbLock) { + PR_DestroyLock(lgdb_p->dbLock); + } + if (lgdb_p->hashTable) { + PL_HashTableDestroy(lgdb_p->hashTable); + } + PORT_Free(lgdb_p); + } + return error; + +} + +extern SECStatus secoid_Init(void); /* util *REALLY* needs + * to be a shared library */ +/* + * OK there are now lots of options here, lets go through them all: + * + * configdir - base directory where all the cert, key, and module datbases live. + * certPrefix - prefix added to the beginning of the cert database example: " + * "https-server1-" + * keyPrefix - prefix added to the beginning of the key database example: " + * "https-server1-" + * secmodName - name of the security module database (usually "secmod.db"). + * readOnly - Boolean: true if the databases are to be openned read only. + * nocertdb - Don't open the cert DB and key DB's, just initialize the + * Volatile certdb. + * nomoddb - Don't open the security module DB, just initialize the + * PKCS #11 module. + * forceOpen - Continue to force initializations even if the databases cannot + * be opened. + */ +CK_RV +legacy_Open(const char *configdir, const char *certPrefix, + const char *keyPrefix, int certVersion, int keyVersion, + int flags, SDB **certDB, SDB **keyDB) +{ + CK_RV crv = CKR_OK; + PRBool readOnly = (flags == SDB_RDONLY)? PR_TRUE: PR_FALSE; + + secoid_Init(); + nsslowcert_InitLocks(); + + if (keyDB) *keyDB = NULL; + if (certDB) *certDB = NULL; + + if (certDB) { + NSSLOWCERTCertDBHandle *certdbPtr; + + crv = lg_OpenCertDB(configdir, certPrefix, readOnly, &certdbPtr); + if (crv != CKR_OK) { + goto loser; + } + crv = lg_init(certDB, flags, certdbPtr, NULL); + if (crv != CKR_OK) { + nsslowcert_ClosePermCertDB(certdbPtr); + goto loser; + } + } + if (keyDB) { + NSSLOWKEYDBHandle *keydbPtr; + + crv = lg_OpenKeyDB(configdir, keyPrefix, readOnly, &keydbPtr); + if (crv != CKR_OK) { + goto loser; + } + crv = lg_init(keyDB, flags, NULL, keydbPtr); + if (crv != CKR_OK) { + nsslowkey_CloseKeyDB(keydbPtr); + goto loser; + } + if (certDB && *certDB) { + LGPrivate *lgdb_p = (LGPrivate *)(*certDB)->private; + lgdb_p->keyDB = keydbPtr; + } + } + +loser: + if (crv != CKR_OK) { + if (keyDB && *keyDB) { + lg_Close(*keyDB); + *keyDB = NULL; + } + if (certDB && *certDB) { + lg_Close(*certDB); + *certDB = NULL; + } + } + return crv; +} + +CK_RV +legacy_Shutdown(void) +{ + nsslowcert_DestroyFreeLists(); + nsslowcert_DestroyGlobalLocks(); +} diff --git a/security/nss/lib/softoken/legacydb/lgutil.c b/security/nss/lib/softoken/legacydb/lgutil.c new file mode 100644 index 000000000..3df08de09 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lgutil.c @@ -0,0 +1,424 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "lgdb.h" +#include "secerr.h" +#include "lgglue.h" + +/* + * ******************** Attribute Utilities ******************************* + */ + +/* + * look up and attribute structure from a type and Object structure. + * The returned attribute is referenced and needs to be freed when + * it is no longer needed. + */ +const CK_ATTRIBUTE * +lg_FindAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, + CK_ULONG count ) +{ + int i; + + for (i=0; i < count; i++) { + if (templ[i].type == type) { + return &templ[i]; + } + } + return NULL; +} + + +/* + * return true if object has attribute + */ +PRBool +lg_hasAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, + CK_ULONG count ) +{ + if (lg_FindAttribute(type, templ, count) == NULL) { + return PR_FALSE; + } + return PR_TRUE; +} + +/* + * copy an attribute into a SECItem. Secitem is allocated in the specified + * arena. + */ +CK_RV +lg_Attribute2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + SECItem *item) +{ + int len; + const CK_ATTRIBUTE *attribute; + + attribute = lg_FindAttribute(type, templ, count); + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; + len = attribute->ulValueLen; + + if (arena) { + item->data = (unsigned char *) PORT_ArenaAlloc(arena,len); + } else { + item->data = (unsigned char *) PORT_Alloc(len); + } + if (item->data == NULL) { + return CKR_HOST_MEMORY; + } + item->len = len; + PORT_Memcpy(item->data, attribute->pValue, len); + return CKR_OK; +} + + +/* + * copy an unsigned attribute into a SECItem. Secitem is allocated in + * the specified arena. + */ +CK_RV +lg_Attribute2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + SECItem *item) +{ + const CK_ATTRIBUTE *attribute; + item->data = NULL; + + attribute = lg_FindAttribute(type, templ, count); + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; + + (void)SECITEM_AllocItem(arena, item, attribute->ulValueLen); + if (item->data == NULL) { + return CKR_HOST_MEMORY; + } + PORT_Memcpy(item->data, attribute->pValue, item->len); + return CKR_OK; +} + +/* + * copy an unsigned attribute into a SECItem. Secitem is allocated in + * the specified arena. + */ +CK_RV +lg_PrivAttr2SSecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + SECItem *item, SDB *sdbpw) +{ + const CK_ATTRIBUTE *attribute; + SECItem epki, *dest = NULL; + SECStatus rv; + + item->data = NULL; + + attribute = lg_FindAttribute(type, templ, count); + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; + + epki.data = attribute->pValue; + epki.len = attribute->ulValueLen; + + rv = lg_util_decrypt(sdbpw, &epki, &dest); + if (rv != SECSuccess) { + return CKR_USER_NOT_LOGGED_IN; + } + (void)SECITEM_AllocItem(arena, item, dest->len); + if (item->data == NULL) { + SECITEM_FreeItem(dest, PR_TRUE); + return CKR_HOST_MEMORY; + } + + PORT_Memcpy(item->data, dest->data, item->len); + SECITEM_FreeItem(dest, PR_TRUE); + return CKR_OK; +} + +CK_RV +lg_PrivAttr2SecItem(PLArenaPool *arena, CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE *templ, CK_ULONG count, + SECItem *item, SDB *sdbpw) +{ + return lg_PrivAttr2SSecItem(arena, type, templ, count, item, sdbpw); +} + +/* + * this is only valid for CK_BBOOL type attributes. Return the state + * of that attribute. + */ +PRBool +lg_isTrue(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + const CK_ATTRIBUTE *attribute; + PRBool tok = PR_FALSE; + + attribute=lg_FindAttribute(type, templ, count); + if (attribute == NULL) { return PR_FALSE; } + tok = (PRBool)(*(CK_BBOOL *)attribute->pValue); + + return tok; +} + +/* + * return a null terminated string from attribute 'type'. This string + * is allocated and needs to be freed with PORT_Free() When complete. + */ +char * +lg_getString(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, CK_ULONG count) +{ + const CK_ATTRIBUTE *attribute; + char *label = NULL; + + attribute = lg_FindAttribute(type, templ, count); + if (attribute == NULL) return NULL; + + if (attribute->pValue != NULL) { + label = (char *) PORT_Alloc(attribute->ulValueLen+1); + if (label == NULL) { + return NULL; + } + + PORT_Memcpy(label,attribute->pValue, attribute->ulValueLen); + label[attribute->ulValueLen] = 0; + } + return label; +} + +CK_RV +lg_GetULongAttribute(CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE *templ, + CK_ULONG count, CK_ULONG *longData) +{ + const CK_ATTRIBUTE *attribute; + CK_ULONG value = 0; + const unsigned char *data; + int i; + + attribute = lg_FindAttribute(type, templ, count); + if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE; + + if (attribute->ulValueLen != sizeof(CK_ULONG)) { + return CKR_ATTRIBUTE_VALUE_INVALID; + } + data = (const unsigned char *)attribute->pValue; + for (i=0; i < 4; i++) { + value |= (CK_ULONG)(data[i]) << ((3-i)*8); + } + + *longData = value; + return CKR_OK; +} + +/* + * ******************** Object Utilities ******************************* + */ + +SECStatus +lg_deleteTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle) +{ + SECItem *item; + PRBool rem; + PLHashTable *hashTable= lg_GetHashTable(sdb); + + item = (SECItem *)PL_HashTableLookup(hashTable, (void *)handle); + rem = PL_HashTableRemove(hashTable,(void *)handle) ; + if (rem && item) { + SECITEM_FreeItem(item,PR_TRUE); + } + return rem ? SECSuccess : SECFailure; +} + +/* must be called holding lg_DBLock(sdb) */ +static SECStatus +lg_addTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle, SECItem *key) +{ + PLHashEntry *entry; + SECItem *item; + PLHashTable *hashTable= lg_GetHashTable(sdb); + + item = SECITEM_DupItem(key); + if (item == NULL) { + return SECFailure; + } + entry = PL_HashTableAdd(hashTable,(void *)handle,item); + if (entry == NULL) { + SECITEM_FreeItem(item,PR_TRUE); + return SECFailure; + } + return SECSuccess; +} + +/* must be called holding lg_DBLock(sdb) */ +const SECItem * +lg_lookupTokenKeyByHandle(SDB *sdb, CK_OBJECT_HANDLE handle) +{ + PLHashTable *hashTable= lg_GetHashTable(sdb); + return (const SECItem *)PL_HashTableLookup(hashTable, (void *)handle); +} + + +static PRIntn +lg_freeHashItem(PLHashEntry* entry, PRIntn index, void *arg) +{ + SECItem *item = (SECItem *)entry->value; + + SECITEM_FreeItem(item, PR_TRUE); + return HT_ENUMERATE_NEXT; +} + +CK_RV +LG_ClearTokenKeyHashTable(SDB *sdb) +{ + PLHashTable *hashTable; + lg_DBLock(sdb); + hashTable= lg_GetHashTable(sdb); + PL_HashTableEnumerateEntries(hashTable, lg_freeHashItem, NULL); + lg_DBLock(sdb); + return CKR_OK; +} + +/* + * handle Token Object stuff + */ +static void +lg_XORHash(unsigned char *key, unsigned char *dbkey, int len) +{ + int i; + + PORT_Memset(key, 0, 4); + + for (i=0; i < len-4; i += 4) { + key[0] ^= dbkey[i]; + key[1] ^= dbkey[i+1]; + key[2] ^= dbkey[i+2]; + key[3] ^= dbkey[i+3]; + } +} + +/* Make a token handle for an object and record it so we can find it again */ +CK_OBJECT_HANDLE +lg_mkHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class) +{ + unsigned char hashBuf[4]; + CK_OBJECT_HANDLE handle; + const SECItem *key; + + handle = class; + /* there is only one KRL, use a fixed handle for it */ + if (handle != LG_TOKEN_KRL_HANDLE) { + lg_XORHash(hashBuf,dbKey->data,dbKey->len); + handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | + (hashBuf[2] << 8) | hashBuf[3]; + handle = class | (handle & ~(LG_TOKEN_TYPE_MASK|LG_TOKEN_MASK)); + /* we have a CRL who's handle has randomly matched the reserved KRL + * handle, increment it */ + if (handle == LG_TOKEN_KRL_HANDLE) { + handle++; + } + } + + lg_DBLock(sdb); + while ((key = lg_lookupTokenKeyByHandle(sdb,handle)) != NULL) { + if (SECITEM_ItemsAreEqual(key,dbKey)) { + lg_DBUnlock(sdb); + return handle; + } + handle++; + } + lg_addTokenKeyByHandle(sdb,handle,dbKey); + lg_DBUnlock(sdb); + return handle; +} + +PRBool +lg_poisonHandle(SDB *sdb, SECItem *dbKey, CK_OBJECT_HANDLE class) +{ + unsigned char hashBuf[4]; + CK_OBJECT_HANDLE handle; + const SECItem *key; + + handle = class; + /* there is only one KRL, use a fixed handle for it */ + if (handle != LG_TOKEN_KRL_HANDLE) { + lg_XORHash(hashBuf,dbKey->data,dbKey->len); + handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | + (hashBuf[2] << 8) | hashBuf[3]; + handle = class | (handle & ~(LG_TOKEN_TYPE_MASK|LG_TOKEN_MASK)); + /* we have a CRL who's handle has randomly matched the reserved KRL + * handle, increment it */ + if (handle == LG_TOKEN_KRL_HANDLE) { + handle++; + } + } + lg_DBLock(sdb); + while ((key = lg_lookupTokenKeyByHandle(sdb,handle)) != NULL) { + if (SECITEM_ItemsAreEqual(key,dbKey)) { + key->data[0] ^= 0x80; + lg_DBUnlock(sdb); + return PR_TRUE; + } + handle++; + } + lg_DBUnlock(sdb); + return PR_FALSE; +} + +static LGEncryptFunc lg_encrypt_stub = NULL; +static LGDecryptFunc lg_decrypt_stub = NULL; + +void +legacy_SetCryptFunctions(LGEncryptFunc enc, LGDecryptFunc dec) +{ + lg_encrypt_stub = enc; + lg_decrypt_stub = dec; +} + +SECStatus lg_util_encrypt(PLArenaPool *arena, SDB *sdb, + SECItem *plainText, SECItem **cipherText) +{ + if (lg_encrypt_stub == NULL) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*lg_encrypt_stub)(arena, sdb, plainText, cipherText); +} + +SECStatus lg_util_decrypt(SDB *sdb, SECItem *cipherText, SECItem **plainText) +{ + if (lg_decrypt_stub == NULL) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*lg_decrypt_stub)(sdb, cipherText, plainText); +} + + diff --git a/security/nss/lib/softoken/lowcert.c b/security/nss/lib/softoken/legacydb/lowcert.c index 008687e52..6aa7e0960 100644 --- a/security/nss/lib/softoken/lowcert.c +++ b/security/nss/lib/softoken/legacydb/lowcert.c @@ -44,15 +44,11 @@ #include "seccomon.h" #include "secder.h" #include "nssilock.h" -#include "prmon.h" -#include "prtime.h" #include "lowkeyi.h" -#include "pcert.h" #include "secasn1.h" #include "secoid.h" #include "secerr.h" -#include "softoken.h" - +#include "pcert.h" static const SEC_ASN1Template nsslowcert_SubjectPublicKeyInfoTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWCERTSubjectPublicKeyInfo) }, @@ -112,26 +108,6 @@ prepare_low_dh_pub_key_for_asn1(NSSLOWKEYPublicKey *pubk) } /* - * Allow use of default cert database, so that apps(such as mozilla) don't - * have to pass the handle all over the place. - */ -static NSSLOWCERTCertDBHandle *default_pcert_db_handle = 0; - -void -nsslowcert_SetDefaultCertDB(NSSLOWCERTCertDBHandle *handle) -{ - default_pcert_db_handle = handle; - - return; -} - -NSSLOWCERTCertDBHandle * -nsslowcert_GetDefaultCertDB(void) -{ - return(default_pcert_db_handle); -} - -/* * simple cert decoder to avoid the cost of asn1 engine */ static unsigned char * @@ -211,7 +187,7 @@ nsslowcert_GetValidityFields(unsigned char *buf,int buf_length, static int nsslowcert_GetCertFields(unsigned char *cert,int cert_length, SECItem *issuer, SECItem *serial, SECItem *derSN, SECItem *subject, - SECItem *valid, SECItem *subjkey) + SECItem *valid, SECItem *subjkey, SECItem *extensions) { unsigned char *buf; unsigned int buf_length; @@ -269,10 +245,25 @@ nsslowcert_GetCertFields(unsigned char *cert,int cert_length, if (subjkey->data == NULL) return SECFailure; buf_length -= (subjkey->data-buf) + subjkey->len; buf = subjkey->data + subjkey->len; + + extensions->data = NULL; + extensions->len = 0; + while (buf_length > 0) { + /* EXTENSIONS */ + if (buf[0] == 0xa3) { + extensions->data = nsslowcert_dataStart(buf,buf_length, + &extensions->len, PR_FALSE, NULL); + break; + } + dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE,NULL); + if (dummy == NULL) return SECFailure; + buf_length -= (dummy - buf) + dummylen; + buf = dummy + dummylen; + } return SECSuccess; } -SECStatus +static SECStatus nsslowcert_GetCertTimes(NSSLOWCERTCertificate *c, PRTime *notBefore, PRTime *notAfter) { int rv; @@ -412,6 +403,196 @@ loser: } +static char * +nsslowcert_EmailName(SECItem *derDN, char *space, unsigned int len) +{ + unsigned char *buf; + unsigned int buf_length; + + /* unwrap outer sequence */ + buf=nsslowcert_dataStart(derDN->data,derDN->len,&buf_length,PR_FALSE,NULL); + if (buf == NULL) return NULL; + + /* Walk each RDN */ + while (buf_length > 0) { + unsigned char *rdn; + unsigned int rdn_length; + + /* grab next rdn */ + rdn=nsslowcert_dataStart(buf, buf_length, &rdn_length, PR_FALSE, NULL); + if (rdn == NULL) { return NULL; } + buf_length -= (rdn - buf) + rdn_length; + buf = rdn+rdn_length; + + while (rdn_length > 0) { + unsigned char *ava; + unsigned int ava_length; + unsigned char *oid; + unsigned int oid_length; + unsigned char *name; + unsigned int name_length; + SECItem oidItem; + SECOidTag type; + + /* unwrap the ava */ + ava=nsslowcert_dataStart(rdn, rdn_length, &ava_length, PR_FALSE, + NULL); + if (ava == NULL) return NULL; + rdn_length -= (ava-rdn)+ava_length; + rdn = ava + ava_length; + + oid=nsslowcert_dataStart(ava, ava_length, &oid_length, PR_FALSE, + NULL); + if (oid == NULL) { return NULL; } + ava_length -= (oid-ava)+oid_length; + ava = oid+oid_length; + + name=nsslowcert_dataStart(ava, ava_length, &name_length, PR_FALSE, + NULL); + if (oid == NULL) { return NULL; } + ava_length -= (name-ava)+name_length; + ava = name+name_length; + + oidItem.data = oid; + oidItem.len = oid_length; + type = SECOID_FindOIDTag(&oidItem); + if ((type == SEC_OID_PKCS9_EMAIL_ADDRESS) || + (type == SEC_OID_RFC1274_MAIL)) { + /* Email is supposed to be IA5String, so no + * translation necessary */ + char *emailAddr; + emailAddr = (char *)pkcs11_copyStaticData(name,name_length+1, + (unsigned char *)space,len); + if (emailAddr) { + emailAddr[name_length] = 0; + } + return emailAddr; + } + } + } + return NULL; +} + +static char * +nsslowcert_EmailAltName(NSSLOWCERTCertificate *cert, char *space, + unsigned int len) +{ + unsigned char *exts; + unsigned int exts_length; + + /* unwrap the sequence */ + exts = nsslowcert_dataStart(cert->extensions.data, cert->extensions.len, + &exts_length, PR_FALSE, NULL); + /* loop through extension */ + while (exts && exts_length > 0) { + unsigned char * ext; + unsigned int ext_length; + unsigned char *oid; + unsigned int oid_length; + unsigned char *nameList; + unsigned int nameList_length; + SECItem oidItem; + SECOidTag type; + + ext = nsslowcert_dataStart(exts, exts_length, &ext_length, + PR_FALSE, NULL); + if (ext == NULL) { break; } + exts_length -= (ext - exts) + ext_length; + exts = ext+ext_length; + + oid=nsslowcert_dataStart(ext, ext_length, &oid_length, PR_FALSE, NULL); + if (oid == NULL) { break; } + ext_length -= (oid - ext) + oid_length; + ext = oid+oid_length; + oidItem.data = oid; + oidItem.len = oid_length; + type = SECOID_FindOIDTag(&oidItem); + + /* get Alt Extension */ + if (type != SEC_OID_X509_SUBJECT_ALT_NAME) { + continue; + } + + /* skip passed the critical flag */ + if (ext[0] == 0x01) { /* BOOLEAN */ + unsigned char *dummy; + unsigned int dummy_length; + dummy = nsslowcert_dataStart(ext, ext_length, &dummy_length, + PR_FALSE, NULL); + if (dummy == NULL) { break; } + ext_length -= (dummy - ext) + dummy_length; + ext = dummy+dummy_length; + } + + + /* unwrap the name list */ + nameList = nsslowcert_dataStart(ext, ext_length, &nameList_length, + PR_FALSE, NULL); + if (nameList == NULL) { break; } + ext_length -= (nameList - ext) + nameList_length; + ext = nameList+nameList_length; + nameList = nsslowcert_dataStart(nameList, nameList_length, + &nameList_length, PR_FALSE, NULL); + /* loop through the name list */ + while (nameList && nameList_length > 0) { + unsigned char *thisName; + unsigned int thisName_length; + + thisName = nsslowcert_dataStart(nameList, nameList_length, + &thisName_length, PR_FALSE, NULL); + if (thisName == NULL) { break; } + if (nameList[0] == 0xa2) { /* DNS Name */ + SECItem dn; + char *emailAddr; + + dn.data = thisName; + dn.len = thisName_length; + emailAddr = nsslowcert_EmailName(&dn, space, len); + if (emailAddr) { + return emailAddr; + } + } + if (nameList[0] == 0x81) { /* RFC 822name */ + char *emailAddr; + emailAddr = (char *)pkcs11_copyStaticData(thisName, + thisName_length+1, (unsigned char *)space,len); + if (emailAddr) { + emailAddr[thisName_length] = 0; + } + return emailAddr; + } + nameList_length -= (thisName-nameList) + thisName_length; + nameList = thisName + thisName_length; + } + break; + } + return NULL; +} + +static char * +nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate *cert) +{ + char *emailAddr = NULL; + char *str; + + emailAddr = nsslowcert_EmailName(&cert->derSubject,cert->emailAddrSpace, + sizeof(cert->emailAddrSpace)); + /* couldn't find the email address in the DN, check the subject Alt name */ + if (!emailAddr && cert->extensions.data) { + emailAddr = nsslowcert_EmailAltName(cert, cert->emailAddrSpace, + sizeof(cert->emailAddrSpace)); + } + + + /* make it lower case */ + str = emailAddr; + while ( str && *str ) { + *str = tolower( *str ); + str++; + } + return emailAddr; + +} /* * take a DER certificate and decode it into a certificate structure @@ -438,7 +619,7 @@ nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname) /* decode the certificate info */ rv = nsslowcert_GetCertFields(cert->derCert.data, cert->derCert.len, &cert->derIssuer, &cert->serialNumber, &cert->derSN, &cert->derSubject, - &cert->validity, &cert->derSubjKeyInfo); + &cert->validity, &cert->derSubjKeyInfo, &cert->extensions); /* cert->subjectKeyID; x509v3 subject key identifier */ cert->subjectKeyID.data = NULL; @@ -470,11 +651,11 @@ nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname) if ( rv != SECSuccess ) { goto loser; } +#endif /* set the email address */ - cert->emailAddr = CERT_GetCertificateEmailAddress(cert); + cert->emailAddr = nsslowcert_GetCertificateEmailAddress(cert); -#endif cert->referenceCount = 1; @@ -527,7 +708,8 @@ nsslowcert_KeyFromDERCert(PRArenaPool *arena, SECItem *derCert, SECItem *key) PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey)); rv = nsslowcert_GetCertFields(derCert->data, derCert->len, - &certkey.derIssuer, &certkey.serialNumber, NULL, NULL, NULL, NULL); + &certkey.derIssuer, &certkey.serialNumber, NULL, NULL, + NULL, NULL, NULL); if ( rv ) { goto loser; @@ -623,7 +805,7 @@ nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate *cert) /* Fill out the rest of the ecParams structure * based on the encoded params */ - if (EC_FillParams(arena, &pubk->u.ec.ecParams.DEREncoding, + if (LGEC_FillParams(arena, &pubk->u.ec.ecParams.DEREncoding, &pubk->u.ec.ecParams) != SECSuccess) break; diff --git a/security/nss/lib/softoken/legacydb/lowkey.c b/security/nss/lib/softoken/legacydb/lowkey.c new file mode 100644 index 000000000..c9ed72e53 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lowkey.c @@ -0,0 +1,462 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "lowkeyi.h" +#include "secoid.h" +#include "secitem.h" +#include "secder.h" +#include "secasn1.h" +#include "secerr.h" + +static const SEC_ASN1Template nsslowkey_AttributeTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(NSSLOWKEYAttribute) }, + { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, + { SEC_ASN1_SET_OF, offsetof(NSSLOWKEYAttribute, attrValue), + SEC_AnyTemplate }, + { 0 } +}; + +static const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = { + { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate }, +}; +/* ASN1 Templates for new decoder/encoder */ +const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, + { SEC_ASN1_INTEGER, + offsetof(NSSLOWKEYPrivateKeyInfo,version) }, + { SEC_ASN1_INLINE, + offsetof(NSSLOWKEYPrivateKeyInfo,algorithm), + SECOID_AlgorithmIDTemplate }, + { SEC_ASN1_OCTET_STRING, + offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, + offsetof(NSSLOWKEYPrivateKeyInfo, attributes), + nsslowkey_SetOfAttributeTemplate }, + { 0 } +}; + +const SEC_ASN1Template nsslowkey_PQGParamsTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) }, + { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) }, + { SEC_ASN1_INTEGER, offsetof(PQGParams,subPrime) }, + { SEC_ASN1_INTEGER, offsetof(PQGParams,base) }, + { 0, } +}; + +const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.version) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.modulus) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.publicExponent) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.privateExponent) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime1) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.prime2) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent1) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.exponent2) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.rsa.coefficient) }, + { 0 } +}; + + +const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.publicValue) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.privateValue) }, + { 0, } +}; + +const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[] = { + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dsa.privateValue) }, +}; + +const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.publicValue) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.privateValue) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.base) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.prime) }, + { 0, } +}; + +#ifdef NSS_ENABLE_ECC + +/* XXX This is just a placeholder for later when we support + * generic curves and need full-blown support for parsing EC + * parameters. For now, we only support named curves in which + * EC params are simply encoded as an object ID and we don't + * use nsslowkey_ECParamsTemplate. + */ +const SEC_ASN1Template nsslowkey_ECParamsTemplate[] = { + { SEC_ASN1_CHOICE, offsetof(ECParams,type), NULL, sizeof(ECParams) }, + { SEC_ASN1_OBJECT_ID, offsetof(ECParams,curveOID), NULL, ec_params_named }, + { 0, } +}; + + +/* NOTE: The SECG specification allows the private key structure + * to contain curve parameters but recommends that they be stored + * in the PrivateKeyAlgorithmIdentifier field of the PrivateKeyInfo + * instead. + */ +const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, + { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.ec.version) }, + { SEC_ASN1_OCTET_STRING, + offsetof(NSSLOWKEYPrivateKey,u.ec.privateValue) }, + /* XXX The following template works for now since we only + * support named curves for which the parameters are + * encoded as an object ID. When we support generic curves, + * we'll need to define nsslowkey_ECParamsTemplate + */ +#if 1 + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | + SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0, + offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams.curveOID), + SEC_ObjectIDTemplate }, +#else + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | + SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0, + offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams), + nsslowkey_ECParamsTemplate }, +#endif + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | + SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 1, + offsetof(NSSLOWKEYPrivateKey,u.ec.publicValue), + SEC_BitStringTemplate }, + { 0, } +}; + + +/* + * smaller version of EC_FillParams. In this code, we only need + * oid and DER data. + */ +SECStatus +LGEC_FillParams(PRArenaPool *arena, const SECItem *encodedParams, + ECParams *params) +{ + SECOidTag tag; + SECItem oid = { siBuffer, NULL, 0}; + +#if EC_DEBUG + int i; + + printf("Encoded params in EC_DecodeParams: "); + for (i = 0; i < encodedParams->len; i++) { + printf("%02x:", encodedParams->data[i]); + } + printf("\n"); +#endif + + oid.len = encodedParams->len - 2; + oid.data = encodedParams->data + 2; + if ((encodedParams->data[0] != SEC_ASN1_OBJECT_ID) || + ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + return SECFailure; + } + + params->arena = arena; + + /* For named curves, fill out curveOID */ + params->curveOID.len = oid.len; + params->curveOID.data = (unsigned char *) PORT_ArenaAlloc(arena, oid.len); + if (params->curveOID.data == NULL) { + return SECFailure; + } + memcpy(params->curveOID.data, oid.data, oid.len); + + return SECSuccess; +} + +/* Copy all of the fields from srcParams into dstParams + */ +SECStatus +LGEC_CopyParams(PRArenaPool *arena, ECParams *dstParams, + const ECParams *srcParams) +{ + SECStatus rv = SECFailure; + + dstParams->arena = arena; + rv = SECITEM_CopyItem(arena, &dstParams->DEREncoding, + &srcParams->DEREncoding); + if (rv != SECSuccess) { + goto loser; + } + rv =SECITEM_CopyItem(arena, &dstParams->curveOID, + &srcParams->curveOID); + if (rv != SECSuccess) { + goto loser; + } + + return SECSuccess; + +loser: + return SECFailure; +} +#endif /* NSS_ENABLE_ECC */ +/* + * See bugzilla bug 125359 + * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints, + * all of the templates above that en/decode into integers must be converted + * from ASN.1's signed integer type. This is done by marking either the + * source or destination (encoding or decoding, respectively) type as + * siUnsignedInteger. + */ + +void +prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) +{ + key->u.rsa.modulus.type = siUnsignedInteger; + key->u.rsa.publicExponent.type = siUnsignedInteger; + key->u.rsa.privateExponent.type = siUnsignedInteger; + key->u.rsa.prime1.type = siUnsignedInteger; + key->u.rsa.prime2.type = siUnsignedInteger; + key->u.rsa.exponent1.type = siUnsignedInteger; + key->u.rsa.exponent2.type = siUnsignedInteger; + key->u.rsa.coefficient.type = siUnsignedInteger; +} + +void +prepare_low_pqg_params_for_asn1(PQGParams *params) +{ + params->prime.type = siUnsignedInteger; + params->subPrime.type = siUnsignedInteger; + params->base.type = siUnsignedInteger; +} + +void +prepare_low_dsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) +{ + key->u.dsa.publicValue.type = siUnsignedInteger; + key->u.dsa.privateValue.type = siUnsignedInteger; + key->u.dsa.params.prime.type = siUnsignedInteger; + key->u.dsa.params.subPrime.type = siUnsignedInteger; + key->u.dsa.params.base.type = siUnsignedInteger; +} + +void +prepare_low_dsa_priv_key_export_for_asn1(NSSLOWKEYPrivateKey *key) +{ + key->u.dsa.privateValue.type = siUnsignedInteger; +} + +void +prepare_low_dh_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) +{ + key->u.dh.prime.type = siUnsignedInteger; + key->u.dh.base.type = siUnsignedInteger; + key->u.dh.publicValue.type = siUnsignedInteger; + key->u.dh.privateValue.type = siUnsignedInteger; +} + +#ifdef NSS_ENABLE_ECC +void +prepare_low_ecparams_for_asn1(ECParams *params) +{ + params->DEREncoding.type = siUnsignedInteger; + params->curveOID.type = siUnsignedInteger; +} + +void +prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) +{ + key->u.ec.version.type = siUnsignedInteger; + key->u.ec.ecParams.DEREncoding.type = siUnsignedInteger; + key->u.ec.ecParams.curveOID.type = siUnsignedInteger; + key->u.ec.privateValue.type = siUnsignedInteger; + key->u.ec.publicValue.type = siUnsignedInteger; +} +#endif /* NSS_ENABLE_ECC */ + +void +nsslowkey_DestroyPrivateKey(NSSLOWKEYPrivateKey *privk) +{ + if (privk && privk->arena) { + PORT_FreeArena(privk->arena, PR_TRUE); + } +} + +void +nsslowkey_DestroyPublicKey(NSSLOWKEYPublicKey *pubk) +{ + if (pubk && pubk->arena) { + PORT_FreeArena(pubk->arena, PR_FALSE); + } +} +unsigned +nsslowkey_PublicModulusLen(NSSLOWKEYPublicKey *pubk) +{ + unsigned char b0; + + /* interpret modulus length as key strength... in + * fortezza that's the public key length */ + + switch (pubk->keyType) { + case NSSLOWKEYRSAKey: + b0 = pubk->u.rsa.modulus.data[0]; + return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1; + default: + break; + } + return 0; +} + +unsigned +nsslowkey_PrivateModulusLen(NSSLOWKEYPrivateKey *privk) +{ + + unsigned char b0; + + switch (privk->keyType) { + case NSSLOWKEYRSAKey: + b0 = privk->u.rsa.modulus.data[0]; + return b0 ? privk->u.rsa.modulus.len : privk->u.rsa.modulus.len - 1; + default: + break; + } + return 0; +} + +NSSLOWKEYPublicKey * +nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) +{ + NSSLOWKEYPublicKey *pubk; + PLArenaPool *arena; + + + arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + PORT_SetError (SEC_ERROR_NO_MEMORY); + return NULL; + } + + switch(privk->keyType) { + case NSSLOWKEYRSAKey: + case NSSLOWKEYNullKey: + pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof (NSSLOWKEYPublicKey)); + if (pubk != NULL) { + SECStatus rv; + + pubk->arena = arena; + pubk->keyType = privk->keyType; + if (privk->keyType == NSSLOWKEYNullKey) return pubk; + rv = SECITEM_CopyItem(arena, &pubk->u.rsa.modulus, + &privk->u.rsa.modulus); + if (rv == SECSuccess) { + rv = SECITEM_CopyItem (arena, &pubk->u.rsa.publicExponent, + &privk->u.rsa.publicExponent); + if (rv == SECSuccess) + return pubk; + } + } else { + PORT_SetError (SEC_ERROR_NO_MEMORY); + } + break; + case NSSLOWKEYDSAKey: + pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof(NSSLOWKEYPublicKey)); + if (pubk != NULL) { + SECStatus rv; + + pubk->arena = arena; + pubk->keyType = privk->keyType; + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue, + &privk->u.dsa.publicValue); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime, + &privk->u.dsa.params.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime, + &privk->u.dsa.params.subPrime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base, + &privk->u.dsa.params.base); + if (rv == SECSuccess) return pubk; + } + break; + case NSSLOWKEYDHKey: + pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof(NSSLOWKEYPublicKey)); + if (pubk != NULL) { + SECStatus rv; + + pubk->arena = arena; + pubk->keyType = privk->keyType; + rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue, + &privk->u.dh.publicValue); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, &pubk->u.dh.prime, + &privk->u.dh.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, &pubk->u.dh.base, + &privk->u.dh.base); + if (rv == SECSuccess) return pubk; + } + break; +#ifdef NSS_ENABLE_ECC + case NSSLOWKEYECKey: + pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof(NSSLOWKEYPublicKey)); + if (pubk != NULL) { + SECStatus rv; + + pubk->arena = arena; + pubk->keyType = privk->keyType; + rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, + &privk->u.ec.publicValue); + if (rv != SECSuccess) break; + pubk->u.ec.ecParams.arena = arena; + /* Copy the rest of the params */ + rv = LGEC_CopyParams(arena, &(pubk->u.ec.ecParams), + &(privk->u.ec.ecParams)); + if (rv == SECSuccess) return pubk; + } + break; +#endif /* NSS_ENABLE_ECC */ + /* No Fortezza in Low Key implementations (Fortezza keys aren't + * stored in our data base */ + default: + break; + } + + PORT_FreeArena (arena, PR_FALSE); + return NULL; +} + diff --git a/security/nss/lib/softoken/legacydb/lowkeyi.h b/security/nss/lib/softoken/legacydb/lowkeyi.h new file mode 100644 index 000000000..45359d4ef --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lowkeyi.h @@ -0,0 +1,198 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* $Id$ */ + +#ifndef _LOWKEYI_H_ +#define _LOWKEYI_H_ + +#include "prtypes.h" +#include "seccomon.h" +#include "secoidt.h" +#include "pcertt.h" +#include "lowkeyti.h" +#include "sdb.h" + +SEC_BEGIN_PROTOS + +/* + * See bugzilla bug 125359 + * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints, + * all of the templates above that en/decode into integers must be converted + * from ASN.1's signed integer type. This is done by marking either the + * source or destination (encoding or decoding, respectively) type as + * siUnsignedInteger. + */ +extern void prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key); +extern void prepare_low_pqg_params_for_asn1(PQGParams *params); +extern void prepare_low_dsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key); +extern void prepare_low_dsa_priv_key_export_for_asn1(NSSLOWKEYPrivateKey *key); +extern void prepare_low_dh_priv_key_for_asn1(NSSLOWKEYPrivateKey *key); +#ifdef NSS_ENABLE_ECC +extern void prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key); +extern void prepare_low_ecparams_for_asn1(ECParams *params); +#endif /* NSS_ENABLE_ECC */ + +typedef char * (* NSSLOWKEYDBNameFunc)(void *arg, int dbVersion); + +/* +** Open a key database. +*/ +extern NSSLOWKEYDBHandle *nsslowkey_OpenKeyDB(PRBool readOnly, + const char *domain, + const char *prefix, + NSSLOWKEYDBNameFunc namecb, + void *cbarg); + +/* +** Close the specified key database. +*/ +extern void nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle); + +/* + * Get the version number of the database + */ +extern int nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle); + +/* +** Delete a key from the database +*/ +extern SECStatus nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, + const SECItem *pubkey); + +/* +** Store a key in the database, indexed by its public key modulus. +** "pk" is the private key to store +** "f" is a the callback function for getting the password +** "arg" is the argument for the callback +*/ +extern SECStatus nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle, + NSSLOWKEYPrivateKey *pk, + SECItem *pubKeyData, + char *nickname, + SDB *sdb); + +/* does the key for this cert exist in the database filed by modulus */ +extern PRBool nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, + NSSLOWCERTCertificate *cert); +/* does a key with this ID already exist? */ +extern PRBool nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id); + +/* +** Destroy a private key object. +** "key" the object +** "freeit" if PR_TRUE then free the object as well as its sub-objects +*/ +extern void nsslowkey_DestroyPrivateKey(NSSLOWKEYPrivateKey *key); + +/* +** Destroy a public key object. +** "key" the object +** "freeit" if PR_TRUE then free the object as well as its sub-objects +*/ +extern void nsslowkey_DestroyPublicKey(NSSLOWKEYPublicKey *key); + +/* +** Return the modulus length of "pubKey". +*/ +extern unsigned int nsslowkey_PublicModulusLen(NSSLOWKEYPublicKey *pubKey); + + +/* +** Return the modulus length of "privKey". +*/ +extern unsigned int nsslowkey_PrivateModulusLen(NSSLOWKEYPrivateKey *privKey); + + +/* +** Convert a low private key "privateKey" into a public low key +*/ +extern NSSLOWKEYPublicKey + *nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privateKey); + + +SECStatus +nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle, + NSSLOWKEYPrivateKey *privkey, + SECItem *pubKeyData, + char *nickname, + SDB *sdb); + +/* Store key by modulus and specify an encryption algorithm to use. + * handle is the pointer to the key database, + * privkey is the private key to be stored, + * f and arg are the function and arguments to the callback + * to get a password, + * algorithm is the algorithm which the privKey is to be stored. + * A return of anything but SECSuccess indicates failure. + */ +extern SECStatus +nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, + NSSLOWKEYPrivateKey *privkey, + SECItem *pubKeyData, + char *nickname, + SDB *sdb, + PRBool update); + +/* Find key by modulus. This function is the inverse of store key + * by modulus. An attempt to locate the key with "modulus" is + * performed. If the key is found, the private key is returned, + * else NULL is returned. + * modulus is the modulus to locate + */ +extern NSSLOWKEYPrivateKey * +nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus, + SDB *sdb); + +extern char * +nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, + SECItem *modulus, SDB *sdb); + +#ifdef NSS_ENABLE_ECC +/* + * smaller version of EC_FillParams. In this code, we only need + * oid and DER data. + */ +SECStatus LGEC_FillParams(PRArenaPool *arena, const SECItem *encodedParams, + ECParams *params); + +/* Copy all of the fields from srcParams into dstParams */ +SECStatus LGEC_CopyParams(PRArenaPool *arena, ECParams *dstParams, + const ECParams *srcParams); +#endif +SEC_END_PROTOS + +#endif /* _LOWKEYI_H_ */ diff --git a/security/nss/lib/softoken/legacydb/lowkeyti.h b/security/nss/lib/softoken/legacydb/lowkeyti.h new file mode 100644 index 000000000..57f8105e3 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/lowkeyti.h @@ -0,0 +1,161 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef _LOWKEYTI_H_ +#define _LOWKEYTI_H_ 1 + +#include "blapit.h" +#include "prtypes.h" +#include "plarena.h" +#include "secitem.h" +#include "secasn1t.h" +#include "secoidt.h" + + +/* + * a key in/for the data base + */ +struct NSSLOWKEYDBKeyStr { + PLArenaPool *arena; + int version; + char *nickname; + SECItem salt; + SECItem derPK; +}; +typedef struct NSSLOWKEYDBKeyStr NSSLOWKEYDBKey; + +typedef struct NSSLOWKEYDBHandleStr NSSLOWKEYDBHandle; + +#ifdef NSS_USE_KEY4_DB +#define NSSLOWKEY_DB_FILE_VERSION 4 +#else +#define NSSLOWKEY_DB_FILE_VERSION 3 +#endif + +#define NSSLOWKEY_VERSION 0 /* what we *create* */ + +/* +** Typedef for callback to get a password "key". +*/ +extern const SEC_ASN1Template nsslowkey_PQGParamsTemplate[]; +extern const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[]; +extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[]; +extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[]; +extern const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[]; +extern const SEC_ASN1Template nsslowkey_DHPrivateKeyExportTemplate[]; +#ifdef NSS_ENABLE_ECC +#define NSSLOWKEY_EC_PRIVATE_KEY_VERSION 1 /* as per SECG 1 C.4 */ +extern const SEC_ASN1Template nsslowkey_ECParamsTemplate[]; +extern const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[]; +#endif /* NSS_ENABLE_ECC */ + +extern const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[]; +extern const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[]; + +/* + * PKCS #8 attributes + */ +struct NSSLOWKEYAttributeStr { + SECItem attrType; + SECItem *attrValue; +}; +typedef struct NSSLOWKEYAttributeStr NSSLOWKEYAttribute; + +/* +** A PKCS#8 private key info object +*/ +struct NSSLOWKEYPrivateKeyInfoStr { + PLArenaPool *arena; + SECItem version; + SECAlgorithmID algorithm; + SECItem privateKey; + NSSLOWKEYAttribute **attributes; +}; +typedef struct NSSLOWKEYPrivateKeyInfoStr NSSLOWKEYPrivateKeyInfo; +#define NSSLOWKEY_PRIVATE_KEY_INFO_VERSION 0 /* what we *create* */ + +/* +** A PKCS#8 private key info object +*/ +struct NSSLOWKEYEncryptedPrivateKeyInfoStr { + PLArenaPool *arena; + SECAlgorithmID algorithm; + SECItem encryptedData; +}; +typedef struct NSSLOWKEYEncryptedPrivateKeyInfoStr NSSLOWKEYEncryptedPrivateKeyInfo; + + +typedef enum { + NSSLOWKEYNullKey = 0, + NSSLOWKEYRSAKey = 1, + NSSLOWKEYDSAKey = 2, + NSSLOWKEYDHKey = 4, + NSSLOWKEYECKey = 5 +} NSSLOWKEYType; + +/* +** An RSA public key object. +*/ +struct NSSLOWKEYPublicKeyStr { + PLArenaPool *arena; + NSSLOWKEYType keyType ; + union { + RSAPublicKey rsa; + DSAPublicKey dsa; + DHPublicKey dh; + ECPublicKey ec; + } u; +}; +typedef struct NSSLOWKEYPublicKeyStr NSSLOWKEYPublicKey; + +/* +** Low Level private key object +** This is only used by the raw Crypto engines (crypto), keydb (keydb), +** and PKCS #11. Everyone else uses the high level key structure. +*/ +struct NSSLOWKEYPrivateKeyStr { + PLArenaPool *arena; + NSSLOWKEYType keyType; + union { + RSAPrivateKey rsa; + DSAPrivateKey dsa; + DHPrivateKey dh; + ECPrivateKey ec; + } u; +}; +typedef struct NSSLOWKEYPrivateKeyStr NSSLOWKEYPrivateKey; + +#endif /* _LOWKEYTI_H_ */ diff --git a/security/nss/lib/softoken/legacydb/manifest.mn b/security/nss/lib/softoken/legacydb/manifest.mn new file mode 100644 index 000000000..4c5fe7b95 --- /dev/null +++ b/security/nss/lib/softoken/legacydb/manifest.mn @@ -0,0 +1,68 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1994-2000 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +CORE_DEPTH = ../../../.. + +MODULE = nss + +REQUIRES = dbm + +LIBRARY_NAME = legacydb +LIBRARY_VERSION = 3 +MAPFILE = $(OBJDIR)/legacydb.def + +DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DSOFTOKEN_LIB_NAME=\"$(notdir $(SHARED_LIBRARY))\" + + +CSRCS = \ + dbmshim.c \ + keydb.c \ + lgattr.c \ + lgcreate.c \ + lgdestroy.c \ + lgfind.c \ + lginit.c \ + lgutil.c \ + lowcert.c \ + lowkey.c \ + pcertdb.c \ + pk11db.c \ + $(NULL) + +ifdef NSS_ENABLE_ECC +DEFINES += -DNSS_ENABLE_ECC +endif + diff --git a/security/nss/lib/softoken/pcert.h b/security/nss/lib/softoken/legacydb/pcert.h index d4314f634..68956abd6 100644 --- a/security/nss/lib/softoken/pcert.h +++ b/security/nss/lib/softoken/legacydb/pcert.h @@ -85,7 +85,7 @@ nsslowcert_FindCrlByKey(NSSLOWCERTCertDBHandle *handle, SECItem *crlKey, PRBool isKRL); SECStatus -nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle,SECItem *derName, +nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle,const SECItem *derName, PRBool isKRL); SECStatus nsslowcert_AddCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl , @@ -110,7 +110,7 @@ void nsslowcert_DestroyTrust(NSSLOWCERTTrust *Trust); * traversal. */ NSSLOWCERTCertificate * -nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey); +nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey); /* * Lookup trust for a certificate in the databases without locking @@ -120,7 +120,7 @@ nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey); * traversal. */ NSSLOWCERTTrust * -nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey); +nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey); /* ** Generate a certificate key from the issuer and serialnumber, then look it @@ -253,7 +253,7 @@ NSSLOWCERTCertificate * nsslowcert_CreateCert(void); certDBEntry * -nsslowcert_DecodeAnyDBEntry(SECItem *dbData, SECItem *dbKey, +nsslowcert_DecodeAnyDBEntry(SECItem *dbData, const SECItem *dbKey, certDBEntryType entryType, void *pdata); SEC_END_PROTOS diff --git a/security/nss/lib/softoken/pcertdb.c b/security/nss/lib/softoken/legacydb/pcertdb.c index a205ed71f..39c928f1e 100644 --- a/security/nss/lib/softoken/pcertdb.c +++ b/security/nss/lib/softoken/legacydb/pcertdb.c @@ -39,8 +39,6 @@ * * $Id$ */ -#include "prtime.h" - #include "lowkeyti.h" #include "pcert.h" #include "mcom_db.h" @@ -48,19 +46,9 @@ #include "secitem.h" #include "secder.h" -/* Call to SFTK_FreeSlot below */ - -#include "secasn1.h" -#include "secerr.h" -#include "nssilock.h" -#include "prmon.h" #include "nsslocks.h" -#include "base64.h" -#include "sechash.h" -#include "plhash.h" - -#include "cdbhdl.h" -#include "pkcs11i.h" +#include "secerr.h" +#include "lgdb.h" /* forward declaration */ NSSLOWCERTCertificate * @@ -198,7 +186,7 @@ nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert) * arg here so that it will be easy to make it per-cert in the future if * that turns out to be necessary. */ -void +static void nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert) { PORT_Assert(certTrustLock != NULL); @@ -210,7 +198,7 @@ nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert) /* * Free the cert trust lock */ -void +static void nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert) { PRStatus prstat; @@ -677,7 +665,7 @@ loser: * encode a database key for a cert record */ static SECStatus -EncodeDBCertKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey) +EncodeDBCertKey(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey) { unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN; if (arena) { @@ -701,7 +689,7 @@ loser: } static SECStatus -EncodeDBGenericKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey, +EncodeDBGenericKey(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey, certDBEntryType entryType) { /* @@ -1090,7 +1078,7 @@ DestroyCertEntryFreeList(void) * Read a certificate entry */ static certDBEntryCert * -ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey) +ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) { certDBEntryCert *entry; SECItem dbkey; @@ -1239,6 +1227,68 @@ loser: return(SECFailure); } +/* + * Create a new certDBEntryRevocation from existing data + */ +static certDBEntryRevocation * +NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags) +{ + certDBEntryRevocation *entry; + PRArenaPool *arena = NULL; + int nnlen; + + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE ); + + if ( !arena ) { + goto loser; + } + + entry = PORT_ArenaZNew(arena, certDBEntryRevocation); + if ( entry == NULL ) { + goto loser; + } + + /* fill in the dbRevolcation */ + entry->common.arena = arena; + entry->common.type = crlType; + entry->common.version = CERT_DB_FILE_VERSION; + entry->common.flags = flags; + + + entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len); + if ( !entry->derCrl.data ) { + goto loser; + } + + if (url) { + nnlen = PORT_Strlen(url) + 1; + entry->url = (char *)PORT_ArenaAlloc(arena, nnlen); + if ( !entry->url ) { + goto loser; + } + PORT_Memcpy(entry->url, url, nnlen); + } else { + entry->url = NULL; + } + + + entry->derCrl.len = derCrl->len; + PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len); + + return(entry); + +loser: + + /* allocation error, free arena and return */ + if ( arena ) { + PORT_FreeArena(arena, PR_FALSE); + } + + PORT_SetError(SEC_ERROR_NO_MEMORY); + return(0); +} + + static SECStatus WriteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry, SECItem *crlKey ) @@ -1282,7 +1332,7 @@ loser: * delete a crl entry */ static SECStatus -DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *crlKey, +DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *crlKey, certDBEntryType crlType) { SECItem dbkey; @@ -1696,7 +1746,7 @@ loser: } -SECStatus +static SECStatus EncodeDBSMimeEntry(certDBEntrySMime *entry, PRArenaPool *arena, SECItem *dbitem) { @@ -2218,7 +2268,7 @@ loser: static SECStatus DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry, - SECItem *derSubject) + const SECItem *derSubject) { unsigned int ncerts; PRArenaPool *arena; @@ -3311,10 +3361,7 @@ AddCertToPermDB(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTCertificate *cert, state = 2; /* "Change" handles if necessary */ - if (cert->dbhandle) { - sftk_freeCertDB(cert->dbhandle); - } - cert->dbhandle = nsslowcert_reference(handle); + cert->dbhandle = handle; /* add to or create new subject entry */ if ( subjectEntry ) { @@ -3977,12 +4024,6 @@ openNewCertDB(const char *appName, const char *prefix, const char *certdbname, return status == RDB_RETRY ? SECWouldBlock : SECFailure; } - rv = db_BeginTransaction(handle->permCertDB); - if (rv != SECSuccess) { - db_InitComplete(handle->permCertDB); - return SECFailure; - } - /* Verify version number; */ versionEntry = NewDBVersionEntry(0); if ( versionEntry == NULL ) { @@ -4020,7 +4061,6 @@ openNewCertDB(const char *appName, const char *prefix, const char *certdbname, loser: - db_FinishTransaction(handle->permCertDB,rv != SECSuccess); db_InitComplete(handle->permCertDB); return rv; } @@ -4159,10 +4199,6 @@ nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert) nsslowcert_LockDB(cert->dbhandle); - rv = db_BeginTransaction(cert->dbhandle->permCertDB); - if ( rv != SECSuccess ) { - goto loser; - } /* delete the records from the permanent database */ rv = DeletePermCert(cert); @@ -4170,9 +4206,6 @@ nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert) DestroyDBEntry((certDBEntry *)cert->dbEntry); cert->dbEntry = NULL; cert->trust = NULL; - - db_FinishTransaction(cert->dbhandle->permCertDB,rv != SECSuccess); -loser: nsslowcert_UnlockDB(cert->dbhandle); return(rv); @@ -4243,7 +4276,7 @@ DecodeACert(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry) goto loser; } - cert->dbhandle = nsslowcert_reference(handle); + cert->dbhandle = handle; cert->dbEntry = entry; cert->trust = &entry->trust; @@ -4291,13 +4324,13 @@ DestroyTrustFreeList(void) static NSSLOWCERTTrust * DecodeTrustEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry, - SECItem *dbKey) + const SECItem *dbKey) { NSSLOWCERTTrust *trust = CreateTrust(); if (trust == NULL) { return trust; } - trust->dbhandle = nsslowcert_reference(handle); + trust->dbhandle = handle; trust->dbEntry = entry; trust->dbKey.data = pkcs11_copyStaticData(dbKey->data,dbKey->len, trust->dbKeySpace, sizeof(trust->dbKeySpace)); @@ -4544,18 +4577,11 @@ nsslowcert_AddPermCert(NSSLOWCERTCertDBHandle *dbhandle, NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust) { SECStatus ret; - SECStatus rv; nsslowcert_LockDB(dbhandle); - rv = db_BeginTransaction(dbhandle->permCertDB); - if (rv != SECSuccess) { - nsslowcert_UnlockDB(dbhandle); - return SECFailure; - } ret = nsslowcert_UpdatePermCert(dbhandle, cert, nickname, trust); - db_FinishTransaction(dbhandle->permCertDB, ret != SECSuccess); nsslowcert_UnlockDB(dbhandle); return(ret); } @@ -4609,7 +4635,7 @@ nsslowcert_setDBVerify(NSSLOWCERTCertDBHandle *handle, PRBool value) * Lookup a certificate in the databases. */ static NSSLOWCERTCertificate * -FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey, PRBool lockdb) +FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb) { NSSLOWCERTCertificate *cert = NULL; certDBEntryCert *entry; @@ -4648,7 +4674,7 @@ loser: * Lookup a certificate in the databases. */ static NSSLOWCERTTrust * -FindTrustByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey, PRBool lockdb) +FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey, PRBool lockdb) { NSSLOWCERTTrust *trust = NULL; certDBEntryCert *entry; @@ -4691,7 +4717,7 @@ loser: * Lookup a certificate in the databases without locking */ NSSLOWCERTCertificate * -nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey) +nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) { return(FindCertByKey(handle, certKey, PR_FALSE)); } @@ -4700,7 +4726,7 @@ nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey) * Lookup a trust object in the databases without locking */ NSSLOWCERTTrust * -nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey) +nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey) { return(FindTrustByKey(handle, certKey, PR_FALSE)); } @@ -4931,9 +4957,6 @@ 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); @@ -4949,6 +4972,7 @@ DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb) } pkcs11_freeNickname(cert->nickname,cert->nicknameSpace); + pkcs11_freeNickname(cert->emailAddr,cert->emailAddrSpace); pkcs11_freeStaticData(cert->certKey.data,cert->certKeySpace); cert->certKey.data = NULL; cert->nickname = NULL; @@ -4967,15 +4991,10 @@ 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); } } @@ -5024,9 +5043,6 @@ nsslowcert_DestroyTrust(NSSLOWCERTTrust *trust) if ( entry ) { DestroyDBEntry((certDBEntry *)entry); } - if (trust->dbhandle) { - sftk_freeCertDB(trust->dbhandle); - } pkcs11_freeStaticData(trust->dbKey.data,trust->dbKeySpace); PORT_Memset(trust, 0, sizeof(*trust)); @@ -5109,23 +5125,22 @@ nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, SECItem *crlKey, char *url, PRBool isKRL) { SECStatus rv = SECFailure; - certDBEntryRevocation entry; + certDBEntryRevocation *entry = NULL; certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation : certDBEntryTypeRevocation; DeleteDBCrlEntry(handle, crlKey, crlType); /* Write the new entry into the data base */ - entry.common.arena = NULL; - entry.common.type = crlType; - entry.common.version = CERT_DB_FILE_VERSION; - entry.common.flags = 0; + entry = NewDBCrlEntry(derCrl, url, crlType, 0); + if (entry == NULL) goto done; - entry.derCrl.data = derCrl->data; - entry.derCrl.len = derCrl->len; - entry.url = url; - - rv = WriteDBCrlEntry(handle, &entry, crlKey); + rv = WriteDBCrlEntry(handle, entry, crlKey); + if (rv != SECSuccess) goto done; +done: + if (entry) { + DestroyDBEntry((certDBEntry *)entry); + } return rv; } @@ -5135,33 +5150,23 @@ nsslowcert_AddCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, { SECStatus rv; - rv = db_BeginTransaction(handle->permCertDB); - if (rv != SECSuccess) { - return SECFailure; - } rv = nsslowcert_UpdateCrl(handle, derCrl, crlKey, url, isKRL); - db_FinishTransaction(handle->permCertDB, rv != SECSuccess); return rv; } SECStatus -nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle, SECItem *derName, +nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle, const SECItem *derName, PRBool isKRL) { SECStatus rv; certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation : certDBEntryTypeRevocation; - rv = db_BeginTransaction(handle->permCertDB); - if (rv != SECSuccess) { - return SECFailure; - } rv = DeleteDBCrlEntry(handle, derName, crlType); if (rv != SECSuccess) goto done; done: - db_FinishTransaction(handle->permCertDB, rv != SECSuccess); return rv; } @@ -5248,15 +5253,10 @@ nsslowcert_SaveSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, char *emailAddr, { SECStatus rv = SECFailure;; - rv = db_BeginTransaction(dbhandle->permCertDB); - if (rv != SECSuccess) { - return SECFailure; - } rv = nsslowcert_UpdateSMimeProfile(dbhandle, emailAddr, derSubject, emailProfile, profileTime); - db_FinishTransaction(dbhandle->permCertDB, rv != SECSuccess); return(rv); } @@ -5288,7 +5288,7 @@ nsslowcert_DestroyGlobalLocks(void) } certDBEntry * -nsslowcert_DecodeAnyDBEntry(SECItem *dbData, SECItem *dbKey, +nsslowcert_DecodeAnyDBEntry(SECItem *dbData, const SECItem *dbKey, certDBEntryType entryType, void *pdata) { PLArenaPool *arena = NULL; diff --git a/security/nss/lib/softoken/pcertt.h b/security/nss/lib/softoken/legacydb/pcertt.h index 848fe69e9..476a2d079 100644 --- a/security/nss/lib/softoken/pcertt.h +++ b/security/nss/lib/softoken/legacydb/pcertt.h @@ -146,6 +146,7 @@ struct NSSLOWCERTCertificateStr { SECItem validity; certDBEntryCert *dbEntry; /* database entry struct */ SECItem subjectKeyID; /* x509v3 subject key identifier */ + SECItem extensions; char *nickname; char *emailAddr; NSSLOWCERTCertTrust *trust; @@ -156,6 +157,7 @@ struct NSSLOWCERTCertificateStr { int referenceCount; char nicknameSpace[200]; + char emailAddrSpace[200]; unsigned char certKeySpace[512]; }; diff --git a/security/nss/lib/softoken/pk11db.c b/security/nss/lib/softoken/legacydb/pk11db.c index 6bbe2ab4f..f85a0a6c3 100644 --- a/security/nss/lib/softoken/pk11db.c +++ b/security/nss/lib/softoken/legacydb/pk11db.c @@ -40,266 +40,12 @@ */ #include "pk11pars.h" -#include "pkcs11i.h" +#include "lgdb.h" #include "mcom_db.h" -#include "cdbhdl.h" #include "secerr.h" #define FREE_CLEAR(p) if (p) { PORT_Free(p); p = NULL; } -static void -secmod_parseTokenFlags(char *tmp, sftk_token_parameters *parsed) { - parsed->readOnly = secmod_argHasFlag("flags","readOnly",tmp); - parsed->noCertDB = secmod_argHasFlag("flags","noCertDB",tmp); - parsed->noKeyDB = secmod_argHasFlag("flags","noKeyDB",tmp); - parsed->forceOpen = secmod_argHasFlag("flags","forceOpen",tmp); - parsed->pwRequired = secmod_argHasFlag("flags","passwordRequired",tmp); - parsed->optimizeSpace = secmod_argHasFlag("flags","optimizeSpace",tmp); - return; -} - -static void -secmod_parseFlags(char *tmp, sftk_parameters *parsed) { - parsed->noModDB = secmod_argHasFlag("flags","noModDB",tmp); - parsed->readOnly = secmod_argHasFlag("flags","readOnly",tmp); - /* keep legacy interface working */ - parsed->noCertDB = secmod_argHasFlag("flags","noCertDB",tmp); - parsed->forceOpen = secmod_argHasFlag("flags","forceOpen",tmp); - parsed->pwRequired = secmod_argHasFlag("flags","passwordRequired",tmp); - parsed->optimizeSpace = secmod_argHasFlag("flags","optimizeSpace",tmp); - return; -} - -CK_RV -secmod_parseTokenParameters(char *param, sftk_token_parameters *parsed) -{ - int next; - char *tmp = NULL; - char *index; - index = secmod_argStrip(param); - - while (*index) { - SECMOD_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;) - SECMOD_HANDLE_STRING_ARG(index,parsed->certPrefix,"certPrefix=",;) - SECMOD_HANDLE_STRING_ARG(index,parsed->keyPrefix,"keyPrefix=",;) - SECMOD_HANDLE_STRING_ARG(index,parsed->tokdes,"tokenDescription=",;) - SECMOD_HANDLE_STRING_ARG(index,parsed->slotdes,"slotDescription=",;) - SECMOD_HANDLE_STRING_ARG(index,tmp,"minPWLen=", - if (tmp) { parsed->minPW=atoi(tmp); }) - SECMOD_HANDLE_STRING_ARG(index,tmp,"flags=", - if (tmp) { secmod_parseTokenFlags(param,parsed); }) - SECMOD_HANDLE_FINAL_ARG(index) - } - if (tmp) - PORT_Free(tmp); - return CKR_OK; -} - -static void -secmod_parseTokens(char *tokenParams, sftk_parameters *parsed) -{ - char *tokenIndex; - sftk_token_parameters *tokens = NULL; - int i=0,count = 0,next; - - if ((tokenParams == NULL) || (*tokenParams == 0)) return; - - /* first count the number of slots */ - for (tokenIndex = secmod_argStrip(tokenParams); *tokenIndex; - tokenIndex = secmod_argStrip(secmod_argSkipParameter(tokenIndex))) { - count++; - } - - /* get the data structures */ - tokens = (sftk_token_parameters *) - PORT_ZAlloc(count*sizeof(sftk_token_parameters)); - if (tokens == NULL) return; - - for (tokenIndex = secmod_argStrip(tokenParams), i = 0; - *tokenIndex && i < count ; i++ ) { - char *name; - name = secmod_argGetName(tokenIndex,&next); - tokenIndex += next; - - tokens[i].slotID = secmod_argDecodeNumber(name); - 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; - if (args) { - secmod_parseTokenParameters(args,&tokens[i]); - PORT_Free(args); - } - } - if (name) PORT_Free(name); - tokenIndex = secmod_argStrip(tokenIndex); - } - parsed->token_count = i; - parsed->tokens = tokens; - return; -} - -CK_RV -secmod_parseParameters(char *param, sftk_parameters *parsed, PRBool isFIPS) -{ - int next; - char *tmp = NULL; - char *index; - char *certPrefix = NULL, *keyPrefix = NULL; - char *tokdes = NULL, *ptokdes = NULL; - char *slotdes = NULL, *pslotdes = NULL; - char *fslotdes = NULL, *fpslotdes = NULL; - char *minPW = NULL; - index = secmod_argStrip(param); - - PORT_Memset(parsed, 0, sizeof(sftk_parameters)); - - while (*index) { - SECMOD_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;) - SECMOD_HANDLE_STRING_ARG(index,parsed->secmodName,"secmod=",;) - SECMOD_HANDLE_STRING_ARG(index,parsed->man,"manufacturerID=",;) - SECMOD_HANDLE_STRING_ARG(index,parsed->libdes,"libraryDescription=",;) - /* constructed values, used so legacy interfaces still work */ - SECMOD_HANDLE_STRING_ARG(index,certPrefix,"certPrefix=",;) - SECMOD_HANDLE_STRING_ARG(index,keyPrefix,"keyPrefix=",;) - SECMOD_HANDLE_STRING_ARG(index,tokdes,"cryptoTokenDescription=",;) - SECMOD_HANDLE_STRING_ARG(index,ptokdes,"dbTokenDescription=",;) - SECMOD_HANDLE_STRING_ARG(index,slotdes,"cryptoSlotDescription=",;) - SECMOD_HANDLE_STRING_ARG(index,pslotdes,"dbSlotDescription=",;) - SECMOD_HANDLE_STRING_ARG(index,fslotdes,"FIPSSlotDescription=",;) - SECMOD_HANDLE_STRING_ARG(index,fpslotdes,"FIPSTokenDescription=",;) - SECMOD_HANDLE_STRING_ARG(index,minPW,"minPWLen=",;) - - SECMOD_HANDLE_STRING_ARG(index,tmp,"flags=", - if (tmp) { secmod_parseFlags(param,parsed); }) - SECMOD_HANDLE_STRING_ARG(index,tmp,"tokens=", - if (tmp) { secmod_parseTokens(tmp,parsed); }) - SECMOD_HANDLE_FINAL_ARG(index) - } - if (tmp) - PORT_Free(tmp); - if (parsed->tokens == NULL) { - int count = isFIPS ? 1 : 2; - int index = count-1; - sftk_token_parameters *tokens = NULL; - - tokens = (sftk_token_parameters *) - PORT_ZAlloc(count*sizeof(sftk_token_parameters)); - if (tokens == NULL) { - goto loser; - } - parsed->tokens = tokens; - parsed->token_count = count; - tokens[index].slotID = isFIPS ? FIPS_SLOT_ID : PRIVATE_KEY_SLOT_ID; - tokens[index].certPrefix = certPrefix; - tokens[index].keyPrefix = keyPrefix; - tokens[index].minPW = minPW ? atoi(minPW) : 0; - tokens[index].readOnly = parsed->readOnly; - tokens[index].noCertDB = parsed->noCertDB; - tokens[index].noKeyDB = parsed->noCertDB; - tokens[index].forceOpen = parsed->forceOpen; - tokens[index].pwRequired = parsed->pwRequired; - tokens[index].optimizeSpace = parsed->optimizeSpace; - tokens[0].optimizeSpace = parsed->optimizeSpace; - certPrefix = NULL; - keyPrefix = NULL; - if (isFIPS) { - tokens[index].tokdes = fslotdes; - tokens[index].slotdes = fpslotdes; - fslotdes = NULL; - fpslotdes = NULL; - } else { - tokens[index].tokdes = ptokdes; - tokens[index].slotdes = pslotdes; - tokens[0].slotID = NETSCAPE_SLOT_ID; - tokens[0].tokdes = tokdes; - tokens[0].slotdes = slotdes; - tokens[0].noCertDB = PR_TRUE; - tokens[0].noKeyDB = PR_TRUE; - ptokdes = NULL; - pslotdes = NULL; - tokdes = NULL; - slotdes = NULL; - } - } - -loser: - FREE_CLEAR(certPrefix); - FREE_CLEAR(keyPrefix); - FREE_CLEAR(tokdes); - FREE_CLEAR(ptokdes); - FREE_CLEAR(slotdes); - FREE_CLEAR(pslotdes); - FREE_CLEAR(fslotdes); - FREE_CLEAR(fpslotdes); - FREE_CLEAR(minPW); - return CKR_OK; -} - -void -secmod_freeParams(sftk_parameters *params) -{ - int i; - - for (i=0; i < params->token_count; i++) { - FREE_CLEAR(params->tokens[i].configdir); - FREE_CLEAR(params->tokens[i].certPrefix); - FREE_CLEAR(params->tokens[i].keyPrefix); - FREE_CLEAR(params->tokens[i].tokdes); - FREE_CLEAR(params->tokens[i].slotdes); - } - - FREE_CLEAR(params->configdir); - FREE_CLEAR(params->secmodName); - FREE_CLEAR(params->man); - FREE_CLEAR(params->libdes); - FREE_CLEAR(params->tokens); -} - - -char * -secmod_getSecmodName(char *param, char **appName, char **filename,PRBool *rw) -{ - int next; - char *configdir = NULL; - char *secmodName = NULL; - char *value = NULL; - char *save_params = param; - const char *lconfigdir = NULL; - param = secmod_argStrip(param); - - - while (*param) { - SECMOD_HANDLE_STRING_ARG(param,configdir,"configDir=",;) - SECMOD_HANDLE_STRING_ARG(param,secmodName,"secmod=",;) - SECMOD_HANDLE_FINAL_ARG(param) - } - - *rw = PR_TRUE; - if (secmod_argHasFlag("flags","readOnly",save_params) || - secmod_argHasFlag("flags","noModDB",save_params)) *rw = PR_FALSE; - - if (!secmodName || *secmodName == '\0') { - if (secmodName) PORT_Free(secmodName); - secmodName = PORT_Strdup(SECMOD_DB); - } - *filename = secmodName; - - if (configdir) { - lconfigdir = sftk_EvaluateConfigDir(configdir, appName); - } - - if (lconfigdir) { - value = PR_smprintf("%s" PATH_SEPARATOR "%s",lconfigdir,secmodName); - } else { - value = PR_smprintf("%s",secmodName); - } - if (configdir) PORT_Free(configdir); - return value; -} - /* Construct a database key for a given module */ static SECStatus secmod_MakeKey(DBT *key, char * module) { int len = 0; @@ -768,8 +514,6 @@ loser: return NULL; } - - static DB * secmod_OpenDB(const char *appName, const char *filename, const char *dbName, PRBool readOnly, PRBool update) @@ -862,13 +606,16 @@ secmod_addEscape(const char *string, char quote) return newString; } +SECStatus legacy_AddSecmodDB(const char *appName, const char *filename, + const char *dbname, char *module, PRBool rw); + #define SECMOD_STEP 10 #define SFTK_DEFAULT_INTERNAL_INIT "library= name=\"NSS Internal PKCS #11 Module\" parameters=\"%s\" NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={%s askpw=any timeout=30})\"" /* * Read all the existing modules in */ char ** -secmod_ReadPermDB(const char *appName, const char *filename, +legacy_ReadSecmodDB(const char *appName, const char *filename, const char *dbname, char *params, PRBool rw) { DBT key,data; @@ -924,7 +671,7 @@ done: if (pkcs11db) { secmod_CloseDB(pkcs11db); } else if (moduleList[0] && rw) { - secmod_AddPermDB(appName,filename,dbname,moduleList[0], rw) ; + legacy_AddSecmodDB(appName,filename,dbname,moduleList[0], rw) ; } if (!moduleList[0]) { PORT_Free(moduleList); @@ -934,7 +681,7 @@ done: } SECStatus -secmod_ReleasePermDBData(const char *appName, const char *filename, +legacy_ReleaseSecmodDBData(const char *appName, const char *filename, const char *dbname, char **moduleSpecList, PRBool rw) { if (moduleSpecList) { @@ -951,7 +698,7 @@ secmod_ReleasePermDBData(const char *appName, const char *filename, * Delete a module from the Data Base */ SECStatus -secmod_DeletePermDB(const char *appName, const char *filename, +legacy_DeleteSecmodDB(const char *appName, const char *filename, const char *dbname, char *args, PRBool rw) { DBT key; @@ -987,7 +734,7 @@ done: * Add a module to the Data base */ SECStatus -secmod_AddPermDB(const char *appName, const char *filename, +legacy_AddSecmodDB(const char *appName, const char *filename, const char *dbname, char *module, PRBool rw) { DBT key,data; diff --git a/security/nss/lib/softoken/lgglue.c b/security/nss/lib/softoken/lgglue.c new file mode 100644 index 000000000..a20a1804f --- /dev/null +++ b/security/nss/lib/softoken/lgglue.c @@ -0,0 +1,341 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * The following code handles the storage of PKCS 11 modules used by the + * NSS. This file is written to abstract away how the modules are + * stored so we can deside that later. + */ +#include "sftkdb.h" +#include "sdb.h" +#include "prsystem.h" +#include "prprf.h" +#include "lgglue.h" +#include "secerr.h" + +static LGOpenFunc legacy_glue_open = NULL; +static LGReadSecmodFunc legacy_glue_readSecmod = NULL; +static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL; +static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL; +static LGAddSecmodFunc legacy_glue_addSecmod = NULL; +static LGShutdownFunc legacy_glue_shutdown = NULL; + +/* + * The following 3 functions duplicate the work done by bl_LoadLibrary. + * We should make bl_LoadLibrary a global and replace the call to + * sftkdb_LoadLibrary(const char *libname) with it. + */ +#ifdef XP_UNIX +#include <unistd.h> +#define LG_MAX_LINKS 20 +static char * +sftkdb_resolvePath(const char *orig) +{ + int count = 0; + int len =0; + int ret = -1; + char *resolved = NULL; + char *source = NULL; + + len = 1025; /* MAX PATH +1*/ + if (strlen(orig)+1 > len) { + /* PATH TOO LONG */ + return NULL; + } + resolved = PORT_Alloc(len); + if (!resolved) { + return NULL; + } + source = PORT_Alloc(len); + if (!source) { + goto loser; + } + PORT_Strcpy(source, orig); + /* Walk down all the links */ + while ( count++ < LG_MAX_LINKS) { + char *tmp; + /* swap our previous sorce out with resolved */ + /* read it */ + ret = readlink(source, resolved, len-1); + if (ret < 0) { + break; + } + resolved[ret] = 0; + tmp = source; source = resolved; resolved = tmp; + } + if (count > 1) { + ret = 0; + } +loser: + if (resolved) { + PORT_Free(resolved); + } + if (ret < 0) { + if (source) { + PORT_Free(source); + source = NULL; + } + } + return source; +} + +#endif + +static PRLibrary * +sftkdb_LoadFromPath(const char *path, const char *libname) +{ + char *c; + int pathLen, nameLen, fullPathLen; + char *fullPathName = NULL; + PRLibSpec libSpec; + PRLibrary *lib = NULL; + + + /* strip of our parent's library name */ + c = strrchr(path, PR_GetDirectorySeparator()); + if (!c) { + return NULL; /* invalid path */ + } + pathLen = (c-path)+1; + nameLen = strlen(libname); + fullPathLen = pathLen + nameLen +1; + fullPathName = (char *)PORT_Alloc(fullPathLen); + if (fullPathName == NULL) { + return NULL; /* memory allocation error */ + } + PORT_Memcpy(fullPathName, path, pathLen); + PORT_Memcpy(fullPathName+pathLen, libname, nameLen); + fullPathName[fullPathLen-1] = 0; + + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = fullPathName; + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); + PORT_Free(fullPathName); + return lib; +} + +static PRLibrary * +sftkdb_LoadLibrary(const char *libname) +{ + PRLibrary *lib = NULL; + PRFuncPtr fn_addr; + char *parentLibPath = NULL; + + fn_addr = (PRFuncPtr) &sftkdb_LoadLibrary; + parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr); + + if (!parentLibPath) { + goto done; + } + + lib = sftkdb_LoadFromPath(parentLibPath, libname); +#ifdef XP_UNIX + /* handle symbolic link case */ + if (!lib) { + char *trueParentLibPath = sftkdb_resolvePath(parentLibPath); + if (!trueParentLibPath) { + goto done; + } + lib = sftkdb_LoadFromPath(trueParentLibPath, libname); + PORT_Free(trueParentLibPath); + } +#endif + PORT_Free(parentLibPath); + +done: + /* still couldn't load it, try the generic path */ + if (!lib) { + PRLibSpec libSpec; + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = libname; + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); + } + return lib; +} + +static PRLibrary *legacy_glue_lib = NULL; +static SECStatus +sftkdbLoad_Legacy() +{ + PRLibrary *lib = NULL; + LGSetCryptFunc setCryptFunction = NULL; + + if (legacy_glue_lib) { + return SECSuccess; + } + + lib = sftkdb_LoadLibrary(SHLIB_PREFIX"legacydb"SHLIB_VERSION"."SHLIB_SUFFIX); + if (lib == NULL) { + return SECFailure; + } + + legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open"); + legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib, + "legacy_ReadSecmodDB"); + legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib, + "legacy_ReleaseSecmodDBData"); + legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib, + "legacy_DeleteSecmodDB"); + legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, + "legacy_AddSecmodDB"); + legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib, + "legacy_Shutdown"); + setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib, + "legacy_SetCryptFunctions"); + + if (!legacy_glue_open || !legacy_glue_readSecmod || + !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || + !legacy_glue_addSecmod || !setCryptFunction) { + PR_UnloadLibrary(lib); + return SECFailure; + } + setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub); + legacy_glue_lib = lib; + return SECSuccess; +} + +CK_RV +sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix, + int certVersion, int keyVersion, int flags, + SDB **certDB, SDB **keyDB) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return CKR_GENERAL_ERROR; + } + if (!legacy_glue_open) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*legacy_glue_open)(dir, certPrefix, keyPrefix, + certVersion, keyVersion, + flags, certDB, keyDB); +} + +char ** +sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, + const char *dbname, char *params, PRBool rw) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return NULL; + } + if (!legacy_glue_readSecmod) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw); +} + +SECStatus +sftkdbCall_ReleaseSecmodDBData(const char *appName, + const char *filename, const char *dbname, + char **moduleSpecList, PRBool rw) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return rv; + } + if (!legacy_glue_releaseSecmod) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*legacy_glue_releaseSecmod)(appName, filename, dbname, + moduleSpecList, rw); +} + +SECStatus +sftkdbCall_DeleteSecmodDB(const char *appName, + const char *filename, const char *dbname, + char *args, PRBool rw) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return rv; + } + if (!legacy_glue_deleteSecmod) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw); +} + +SECStatus +sftkdbCall_AddSecmodDB(const char *appName, + const char *filename, const char *dbname, + char *module, PRBool rw) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return rv; + } + if (!legacy_glue_addSecmod) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw); +} + +CK_RV +sftkdbCall_Shutdown(void) +{ + CK_RV crv = CKR_OK; + if (legacy_glue_lib) { + return CKR_OK; + } + if (legacy_glue_shutdown) { + crv = (*legacy_glue_shutdown)(); + } + PR_UnloadLibrary(legacy_glue_lib); + legacy_glue_lib = NULL; + legacy_glue_open = NULL; + legacy_glue_readSecmod = NULL; + legacy_glue_releaseSecmod = NULL; + legacy_glue_deleteSecmod = NULL; + legacy_glue_addSecmod = NULL; + return crv; +} + + diff --git a/security/nss/lib/softoken/lgglue.h b/security/nss/lib/softoken/lgglue.h new file mode 100644 index 000000000..8ced909d3 --- /dev/null +++ b/security/nss/lib/softoken/lgglue.h @@ -0,0 +1,92 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This code defines the glue layer between softoken and the legacy DB library + */ +#include "sdb.h" + +/* + * function prototypes for the callbacks into softoken from the legacyDB + */ + +typedef SECStatus (*LGEncryptFunc)(PRArenaPool *arena, SDB *sdb, + SECItem *plainText, SECItem **cipherText); +typedef SECStatus (*LGDecryptFunc)(SDB *sdb, SECItem *cipherText, + SECItem **plainText); + +/* + * function prototypes for the exported functions. + */ +typedef CK_RV (*LGOpenFunc) (const char *dir, const char *certPrefix, + const char *keyPrefix, + int certVersion, int keyVersion, int flags, + SDB **certDB, SDB **keyDB); +typedef char ** (*LGReadSecmodFunc)(const char *appName, + const char *filename, + const char *dbname, char *params, PRBool rw); +typedef SECStatus (*LGReleaseSecmodFunc)(const char *appName, + const char *filename, + const char *dbname, char **params, PRBool rw); +typedef SECStatus (*LGDeleteSecmodFunc)(const char *appName, + const char *filename, + const char *dbname, char *params, PRBool rw); +typedef SECStatus (*LGAddSecmodFunc)(const char *appName, + const char *filename, + const char *dbname, char *params, PRBool rw); +typedef SECStatus (*LGShutdownFunc)(void); +typedef void (*LGSetCryptFunc)(LGEncryptFunc, LGDecryptFunc); + + +/* + * Softoken Glue Functions + */ +CK_RV sftkdbCall_open(const char *dir, const char *certPrefix, + const char *keyPrefix, + int certVersion, int keyVersion, int flags, + SDB **certDB, SDB **keyDB); +char ** sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, + const char *dbname, char *params, PRBool rw); +SECStatus sftkdbCall_ReleaseSecmodDBData(const char *appName, + const char *filename, const char *dbname, + char **moduleSpecList, PRBool rw); +SECStatus sftkdbCall_DeleteSecmodDB(const char *appName, + const char *filename, const char *dbname, + char *args, PRBool rw); +SECStatus sftkdbCall_AddSecmodDB(const char *appName, + const char *filename, const char *dbname, + char *module, PRBool rw); +CK_RV sftkdbCall_Shutdown(void); + diff --git a/security/nss/lib/softoken/lowkey.c b/security/nss/lib/softoken/lowkey.c index 9c984b4d3..8772d024d 100644 --- a/security/nss/lib/softoken/lowkey.c +++ b/security/nss/lib/softoken/lowkey.c @@ -40,15 +40,41 @@ #include "secder.h" #include "base64.h" #include "secasn1.h" -#include "pcert.h" #include "secerr.h" #ifdef NSS_ENABLE_ECC -extern SECStatus EC_CopyParams(PRArenaPool *arena, - ECParams *dstParams, - const ECParams *srcParams); +#include "softoken.h" #endif +const SEC_ASN1Template nsslowkey_AttributeTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(NSSLOWKEYAttribute) }, + { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, + { SEC_ASN1_SET_OF, offsetof(NSSLOWKEYAttribute, attrValue), + SEC_AnyTemplate }, + { 0 } +}; + +const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = { + { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate }, +}; +/* ASN1 Templates for new decoder/encoder */ +const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, + { SEC_ASN1_INTEGER, + offsetof(NSSLOWKEYPrivateKeyInfo,version) }, + { SEC_ASN1_INLINE, + offsetof(NSSLOWKEYPrivateKeyInfo,algorithm), + SECOID_AlgorithmIDTemplate }, + { SEC_ASN1_OCTET_STRING, + offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, + offsetof(NSSLOWKEYPrivateKeyInfo, attributes), + nsslowkey_SetOfAttributeTemplate }, + { 0 } +}; + const SEC_ASN1Template nsslowkey_PQGParamsTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) }, { SEC_ASN1_INTEGER, offsetof(PQGParams,prime) }, diff --git a/security/nss/lib/softoken/lowkeyi.h b/security/nss/lib/softoken/lowkeyi.h index b32a0f0af..9c13bfa10 100644 --- a/security/nss/lib/softoken/lowkeyi.h +++ b/security/nss/lib/softoken/lowkeyi.h @@ -42,7 +42,6 @@ #include "prtypes.h" #include "seccomon.h" #include "secoidt.h" -#include "pcertt.h" #include "lowkeyti.h" SEC_BEGIN_PROTOS @@ -65,89 +64,6 @@ extern void prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key); extern void prepare_low_ecparams_for_asn1(ECParams *params); #endif /* NSS_ENABLE_ECC */ -typedef char * (* NSSLOWKEYDBNameFunc)(void *arg, int dbVersion); - -/* -** Open a key database. -*/ -extern NSSLOWKEYDBHandle *nsslowkey_OpenKeyDB(PRBool readOnly, - const char *domain, - const char *prefix, - NSSLOWKEYDBNameFunc namecb, - void *cbarg); - - -/* - * Clear out all the keys in the existing database - */ -extern SECStatus nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle); - -/* -** Close the specified key database. -*/ -extern void nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle); - -/* - * Get the version number of the database - */ -extern int nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle); - -/* -** Support a default key database. -*/ -extern void nsslowkey_SetDefaultKeyDB(NSSLOWKEYDBHandle *handle); -extern NSSLOWKEYDBHandle *nsslowkey_GetDefaultKeyDB(void); - -/* set the alg id of the key encryption algorithm */ -extern void nsslowkey_SetDefaultKeyDBAlg(SECOidTag alg); - -/* - * given a password and salt, produce a hash of the password - */ -extern SECItem *nsslowkey_HashPassword(char *pw, SECItem *salt); - -/* - * Derive the actual password value for a key database from the - * password string value. The derivation uses global salt value - * stored in the key database. - */ -extern SECItem * -nsslowkey_DeriveKeyDBPassword(NSSLOWKEYDBHandle *handle, char *pw); - -/* -** Delete a key from the database -*/ -extern SECStatus nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, - SECItem *pubkey); - -/* -** Store a key in the database, indexed by its public key modulus. -** "pk" is the private key to store -** "f" is a the callback function for getting the password -** "arg" is the argument for the callback -*/ -extern SECStatus nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle, - NSSLOWKEYPrivateKey *pk, - SECItem *pubKeyData, - char *nickname, - SECItem *arg); - -/* does the key for this cert exist in the database filed by modulus */ -extern PRBool nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, - NSSLOWCERTCertificate *cert); -/* does a key with this ID already exist? */ -extern PRBool nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id); - - -extern SECStatus nsslowkey_HasKeyDBPassword(NSSLOWKEYDBHandle *handle); -extern SECStatus nsslowkey_SetKeyDBPassword(NSSLOWKEYDBHandle *handle, - SECItem *pwitem); -extern SECStatus nsslowkey_CheckKeyDBPassword(NSSLOWKEYDBHandle *handle, - SECItem *pwitem); -extern SECStatus nsslowkey_ChangeKeyDBPassword(NSSLOWKEYDBHandle *handle, - SECItem *oldpwitem, - SECItem *newpwitem); - /* ** Destroy a private key object. ** "key" the object @@ -180,88 +96,6 @@ extern unsigned int nsslowkey_PrivateModulusLen(NSSLOWKEYPrivateKey *privKey); extern NSSLOWKEYPublicKey *nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privateKey); -/* - * Set the Key Database password. - * handle is a handle to the key database - * pwitem is the new password - * algorithm is the algorithm by which the key database - * password is to be encrypted. - * On failure, SECFailure is returned, otherwise SECSuccess is - * returned. - */ -extern SECStatus -nsslowkey_SetKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, - SECItem *pwitem, - SECOidTag algorithm); - -/* Check the key database password. - * handle is a handle to the key database - * pwitem is the suspect password - * algorithm is the algorithm by which the key database - * password is to be encrypted. - * The password is checked against plaintext to see if it is the - * actual password. If it is not, SECFailure is returned. - */ -extern SECStatus -nsslowkey_CheckKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, - SECItem *pwitem, - SECOidTag algorithm); - -/* Change the key database password and/or algorithm by which - * the password is stored with. - * handle is a handle to the key database - * old_pwitem is the current password - * new_pwitem is the new password - * old_algorithm is the algorithm by which the key database - * password is currently encrypted. - * new_algorithm is the algorithm with which the new password - * is to be encrypted. - * A return of anything but SECSuccess indicates failure. - */ -extern SECStatus -nsslowkey_ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, - SECItem *oldpwitem, SECItem *newpwitem, - SECOidTag old_algorithm); - -SECStatus -nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle, - NSSLOWKEYPrivateKey *privkey, - SECItem *pubKeyData, - char *nickname, - SECItem *arg); - -/* Store key by modulus and specify an encryption algorithm to use. - * handle is the pointer to the key database, - * privkey is the private key to be stored, - * f and arg are the function and arguments to the callback - * to get a password, - * algorithm is the algorithm which the privKey is to be stored. - * A return of anything but SECSuccess indicates failure. - */ -extern SECStatus -nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, - NSSLOWKEYPrivateKey *privkey, - SECItem *pubKeyData, - char *nickname, - SECItem *arg, - SECOidTag algorithm, - PRBool update); - -/* Find key by modulus. This function is the inverse of store key - * by modulus. An attempt to locate the key with "modulus" is - * performed. If the key is found, the private key is returned, - * else NULL is returned. - * modulus is the modulus to locate - */ -extern NSSLOWKEYPrivateKey * -nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus, - SECItem *arg); - -extern char * -nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, - SECItem *modulus, SECItem *pwitem); - - /* Make a copy of a low private key in it's own arena. * a return of NULL indicates an error. */ diff --git a/security/nss/lib/softoken/lowkeyti.h b/security/nss/lib/softoken/lowkeyti.h index 5423bdb7a..15bb9730a 100644 --- a/security/nss/lib/softoken/lowkeyti.h +++ b/security/nss/lib/softoken/lowkeyti.h @@ -43,31 +43,6 @@ #include "secitem.h" #include "secasn1t.h" #include "secoidt.h" -/*#include "secmodt.h" -#include "pkcs11t.h" */ - - -/* - * a key in/for the data base - */ -struct NSSLOWKEYDBKeyStr { - PLArenaPool *arena; - int version; - char *nickname; - SECItem salt; - SECItem derPK; -}; -typedef struct NSSLOWKEYDBKeyStr NSSLOWKEYDBKey; - -typedef struct NSSLOWKEYDBHandleStr NSSLOWKEYDBHandle; - -#ifdef NSS_USE_KEY4_DB -#define NSSLOWKEY_DB_FILE_VERSION 4 -#else -#define NSSLOWKEY_DB_FILE_VERSION 3 -#endif - -#define NSSLOWKEY_VERSION 0 /* what we *create* */ /* ** Typedef for callback to get a password "key". @@ -109,17 +84,6 @@ struct NSSLOWKEYPrivateKeyInfoStr { typedef struct NSSLOWKEYPrivateKeyInfoStr NSSLOWKEYPrivateKeyInfo; #define NSSLOWKEY_PRIVATE_KEY_INFO_VERSION 0 /* what we *create* */ -/* -** A PKCS#8 private key info object -*/ -struct NSSLOWKEYEncryptedPrivateKeyInfoStr { - PLArenaPool *arena; - SECAlgorithmID algorithm; - SECItem encryptedData; -}; -typedef struct NSSLOWKEYEncryptedPrivateKeyInfoStr NSSLOWKEYEncryptedPrivateKeyInfo; - - typedef enum { NSSLOWKEYNullKey = 0, NSSLOWKEYRSAKey = 1, diff --git a/security/nss/lib/softoken/manifest.mn b/security/nss/lib/softoken/manifest.mn index 5df3a4517..a3d2f995f 100644 --- a/security/nss/lib/softoken/manifest.mn +++ b/security/nss/lib/softoken/manifest.mn @@ -37,6 +37,7 @@ CORE_DEPTH = ../../.. MODULE = nss +DIRS = legacydb REQUIRES = dbm @@ -44,7 +45,7 @@ LIBRARY_NAME = softokn LIBRARY_VERSION = 3 MAPFILE = $(OBJDIR)/softokn.def -DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DSOFTOKEN_LIB_NAME=\"$(notdir $(SHARED_LIBRARY))\" +DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DSOFTOKEN_LIB_NAME=\"$(notdir $(SHARED_LIBRARY))\" -DSHLIB_VERSION=\"$(LIBRARY_VERSION)\" EXPORTS = \ @@ -54,37 +55,35 @@ EXPORTS = \ pkcs11t.h \ pkcs11n.h \ pkcs11u.h \ + sdb.h \ + sftkdbt.h \ $(NULL) PRIVATE_EXPORTS = \ + lgglue.h \ pk11pars.h \ pkcs11ni.h \ - lowkeyi.h \ - lowkeyti.h \ - pcertt.h \ softoken.h \ softoknt.h \ softkver.h \ $(NULL) CSRCS = \ - dbinit.c \ - dbmshim.c \ ecdecode.c \ fipsaudt.c \ fipstest.c \ fipstokn.c \ - keydb.c \ - lowcert.c \ + lgglue.c \ lowkey.c \ lowpbe.c \ padbuf.c \ - pcertdb.c \ - pk11db.c \ pkcs11.c \ pkcs11c.c \ pkcs11u.c \ rsawrapr.c \ + sdb.c \ + sftkdb.c \ + sftkpars.c \ softkver.c \ tlsprf.c \ $(NULL) @@ -93,3 +92,7 @@ ifdef NSS_ENABLE_ECC DEFINES += -DNSS_ENABLE_ECC endif +ifdef SQLITE_UNSAFE_THREADS +DEFINES += -DSQLITE_UNSAFE_THREADS +endif + diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index eba10bf63..49e703ee1 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.c @@ -61,15 +61,14 @@ #include "blapi.h" #include "secder.h" #include "secport.h" -#include "pcert.h" #include "secrng.h" +#include "nss.h" +#include "prtypes.h" +#include "nspr.h" #include "softkver.h" -#include "keydbi.h" - -#ifdef DEBUG -#include "cdbhdl.h" -#endif +#include "sftkdb.h" +#include "sftkpars.h" /* * ******************** Static data ******************************* @@ -86,7 +85,7 @@ static char libraryDescription_space[33]; * failure so that there are at most 60 login attempts per minute. */ static PRIntervalTime loginWaitTime; -static PRUint32 minSessionObjectHandle = 1U; +static PRUint32 minSessionObjectHandle = 1U; #define __PASTE(x,y) x##y @@ -353,12 +352,12 @@ static const struct mechanismList mechanisms[] = { {CKM_AES_MAC_GENERAL, {16, 32, CKF_SN_VR}, PR_TRUE}, {CKM_AES_CBC_PAD, {16, 32, CKF_EN_DE_WR_UN}, PR_TRUE}, /* ------------------------- Camellia Operations --------------------- */ - {CKM_CAMELLIA_KEY_GEN, {16, 32, CKF_GENERATE}, PR_TRUE}, - {CKM_CAMELLIA_ECB, {16, 32, CKF_EN_DE_WR_UN}, PR_TRUE}, - {CKM_CAMELLIA_CBC, {16, 32, CKF_EN_DE_WR_UN}, PR_TRUE}, - {CKM_CAMELLIA_MAC, {16, 32, CKF_SN_VR}, PR_TRUE}, - {CKM_CAMELLIA_MAC_GENERAL, {16, 32, CKF_SN_VR}, PR_TRUE}, - {CKM_CAMELLIA_CBC_PAD, {16, 32, CKF_EN_DE_WR_UN}, PR_TRUE}, + {CKM_CAMELLIA_KEY_GEN, {16, 32, CKF_GENERATE}, PR_TRUE}, + {CKM_CAMELLIA_ECB, {16, 32, CKF_EN_DE_WR_UN}, PR_TRUE}, + {CKM_CAMELLIA_CBC, {16, 32, CKF_EN_DE_WR_UN}, PR_TRUE}, + {CKM_CAMELLIA_MAC, {16, 32, CKF_SN_VR}, PR_TRUE}, + {CKM_CAMELLIA_MAC_GENERAL, {16, 32, CKF_SN_VR}, PR_TRUE}, + {CKM_CAMELLIA_CBC_PAD, {16, 32, CKF_EN_DE_WR_UN}, PR_TRUE}, /* ------------------------- Hashing Operations ----------------------- */ {CKM_MD2, {0, 0, CKF_DIGEST}, PR_FALSE}, {CKM_MD2_HMAC, {1, 128, CKF_SN_VR}, PR_TRUE}, @@ -538,22 +537,13 @@ sftk_configure(const char *man, const char *libdes) * see if the key DB password is enabled */ static PRBool -sftk_hasNullPassword(NSSLOWKEYDBHandle *keydb,SECItem **pwitem) +sftk_hasNullPassword(SFTKDBHandle *keydb) { PRBool pwenabled; - + pwenabled = PR_FALSE; - *pwitem = NULL; - if (nsslowkey_HasKeyDBPassword (keydb) == SECSuccess) { - *pwitem = nsslowkey_HashPassword("", keydb->global_salt); - if ( *pwitem ) { - if (nsslowkey_CheckKeyDBPassword (keydb, *pwitem) == SECSuccess) { - pwenabled = PR_TRUE; - } else { - SECITEM_ZfreeItem(*pwitem, PR_TRUE); - *pwitem = NULL; - } - } + if (sftkdb_HasPasswordSet(keydb) == SECSuccess) { + return (sftkdb_CheckPassword(keydb, "") == SECSuccess); } return pwenabled; @@ -661,124 +651,19 @@ sftk_handleCertObject(SFTKSession *session,SFTKObject *object) if (sftk_isTrue(object,CKA_TOKEN)) { SFTKSlot *slot = session->slot; - SECItem derCert; - NSSLOWCERTCertificate *cert; - NSSLOWCERTCertTrust *trust = NULL; - NSSLOWCERTCertTrust userTrust = - { CERTDB_USER, CERTDB_USER, CERTDB_USER }; - NSSLOWCERTCertTrust defTrust = - { CERTDB_TRUSTED_UNKNOWN, - CERTDB_TRUSTED_UNKNOWN, CERTDB_TRUSTED_UNKNOWN }; - char *label = NULL; - char *email = NULL; - SECStatus rv; - PRBool inDB = PR_TRUE; - NSSLOWCERTCertDBHandle *certHandle = sftk_getCertDB(slot); - NSSLOWKEYDBHandle *keyHandle = NULL; + SFTKDBHandle *certHandle = sftk_getCertDB(slot); if (certHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } - /* get the der cert */ - attribute = sftk_FindAttribute(object,CKA_VALUE); - PORT_Assert(attribute); - if (!attribute) { - sftk_freeCertDB(certHandle); - return CKR_ATTRIBUTE_VALUE_INVALID; - } - - derCert.type = 0; - derCert.data = (unsigned char *)attribute->attrib.pValue; - derCert.len = attribute->attrib.ulValueLen ; - - label = sftk_getString(object,CKA_LABEL); - - 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; - } - - 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(certHandle, cert, label, trust); - } else { - rv = trust ? nsslowcert_ChangeCertTrust(certHandle,cert,trust) : - SECSuccess; - } - - if (label) PORT_Free(label); - sftk_FreeAttribute(attribute); - - if (rv != SECSuccess) { - sftk_freeCertDB(certHandle); - nsslowcert_DestroyCertificate(cert); - return CKR_DEVICE_ERROR; - } - - /* - * Add a NULL S/MIME profile if necessary. - */ - email = sftk_getString(object,CKA_NETSCAPE_EMAIL); - if (email) { - certDBEntrySMime *entry; - - entry = nsslowcert_ReadDBSMimeEntry(certHandle,email); - if (!entry) { - 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); + crv = sftkdb_write(certHandle, object, &object->handle); + sftk_freeDB(certHandle); + return crv; } return CKR_OK; } - -unsigned int -sftk_MapTrust(CK_TRUST trust, PRBool clientAuth) -{ - unsigned int trustCA = clientAuth ? CERTDB_TRUSTED_CLIENT_CA : - CERTDB_TRUSTED_CA; - switch (trust) { - case CKT_NETSCAPE_TRUSTED: - return CERTDB_VALID_PEER|CERTDB_TRUSTED; - case CKT_NETSCAPE_TRUSTED_DELEGATOR: - return CERTDB_VALID_CA|trustCA; - case CKT_NETSCAPE_UNTRUSTED: - return CERTDB_NOT_TRUSTED; - case CKT_NETSCAPE_MUST_VERIFY: - return 0; - case CKT_NETSCAPE_VALID: /* implies must verify */ - return CERTDB_VALID_PEER; - case CKT_NETSCAPE_VALID_DELEGATOR: /* implies must verify */ - return CERTDB_VALID_CA; - default: - break; - } - return CERTDB_TRUSTED_UNKNOWN; -} - /* * check the consistancy and initialize a Trust Object @@ -786,8 +671,6 @@ sftk_MapTrust(CK_TRUST trust, PRBool clientAuth) static CK_RV sftk_handleTrustObject(SFTKSession *session,SFTKObject *object) { - NSSLOWCERTIssuerAndSN issuerSN; - /* we can't store any certs private */ if (sftk_isTrue(object,CKA_PRIVATE)) { return CKR_ATTRIBUTE_VALUE_INVALID; @@ -809,109 +692,16 @@ sftk_handleTrustObject(SFTKSession *session,SFTKObject *object) if (sftk_isTrue(object,CKA_TOKEN)) { SFTKSlot *slot = session->slot; - SFTKAttribute *issuer = NULL; - SFTKAttribute *serial = NULL; - NSSLOWCERTCertificate *cert = NULL; - SFTKAttribute *trust; - CK_TRUST sslTrust = CKT_NETSCAPE_TRUST_UNKNOWN; - CK_TRUST clientTrust = CKT_NETSCAPE_TRUST_UNKNOWN; - CK_TRUST emailTrust = CKT_NETSCAPE_TRUST_UNKNOWN; - CK_TRUST signTrust = CKT_NETSCAPE_TRUST_UNKNOWN; - CK_BBOOL stepUp; - NSSLOWCERTCertTrust dbTrust = { 0 }; - SECStatus rv; - NSSLOWCERTCertDBHandle *certHandle = sftk_getCertDB(slot); + SFTKDBHandle *certHandle = sftk_getCertDB(slot); + CK_RV crv; if (certHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } - issuer = sftk_FindAttribute(object,CKA_ISSUER); - serial = sftk_FindAttribute(object,CKA_SERIAL_NUMBER); - - PORT_Assert(issuer && serial); - if (issuer && serial) { - issuerSN.derIssuer.data = (unsigned char *)issuer->attrib.pValue; - issuerSN.derIssuer.len = issuer->attrib.ulValueLen ; - - issuerSN.serialNumber.data = (unsigned char *)serial->attrib.pValue; - issuerSN.serialNumber.len = serial->attrib.ulValueLen ; - - cert = nsslowcert_FindCertByIssuerAndSN(certHandle,&issuerSN); - } - if (issuer) sftk_FreeAttribute(issuer); - if (serial) sftk_FreeAttribute(serial); - - if (cert == NULL) { - sftk_freeCertDB(certHandle); - return CKR_ATTRIBUTE_VALUE_INVALID; - } - - trust = sftk_FindAttribute(object,CKA_TRUST_SERVER_AUTH); - if (trust) { - if (trust->attrib.ulValueLen == sizeof(CK_TRUST)) { - PORT_Memcpy(&sslTrust,trust->attrib.pValue, sizeof(sslTrust)); - } - sftk_FreeAttribute(trust); - } - trust = sftk_FindAttribute(object,CKA_TRUST_CLIENT_AUTH); - if (trust) { - if (trust->attrib.ulValueLen == sizeof(CK_TRUST)) { - PORT_Memcpy(&clientTrust,trust->attrib.pValue, - sizeof(clientTrust)); - } - sftk_FreeAttribute(trust); - } - trust = sftk_FindAttribute(object,CKA_TRUST_EMAIL_PROTECTION); - if (trust) { - if (trust->attrib.ulValueLen == sizeof(CK_TRUST)) { - PORT_Memcpy(&emailTrust,trust->attrib.pValue, - sizeof(emailTrust)); - } - sftk_FreeAttribute(trust); - } - trust = sftk_FindAttribute(object,CKA_TRUST_CODE_SIGNING); - if (trust) { - if (trust->attrib.ulValueLen == sizeof(CK_TRUST)) { - PORT_Memcpy(&signTrust,trust->attrib.pValue, - sizeof(signTrust)); - } - sftk_FreeAttribute(trust); - } - stepUp = CK_FALSE; - trust = sftk_FindAttribute(object,CKA_TRUST_STEP_UP_APPROVED); - if (trust) { - if (trust->attrib.ulValueLen == sizeof(CK_BBOOL)) { - stepUp = *(CK_BBOOL*)trust->attrib.pValue; - } - sftk_FreeAttribute(trust); - } - - /* preserve certain old fields */ - if (cert->trust) { - dbTrust.sslFlags = - cert->trust->sslFlags & CERTDB_PRESERVE_TRUST_BITS; - dbTrust.emailFlags= - cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS; - dbTrust.objectSigningFlags = - cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS; - } - - dbTrust.sslFlags |= sftk_MapTrust(sslTrust,PR_FALSE); - dbTrust.sslFlags |= sftk_MapTrust(clientTrust,PR_TRUE); - dbTrust.emailFlags |= sftk_MapTrust(emailTrust,PR_FALSE); - dbTrust.objectSigningFlags |= sftk_MapTrust(signTrust,PR_FALSE); - if (stepUp) { - dbTrust.sslFlags |= CERTDB_GOVT_APPROVED_CA; - } - - 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; - } + crv = sftkdb_write(certHandle, object, &object->handle); + sftk_freeDB(certHandle); + return crv; } return CKR_OK; @@ -939,16 +729,8 @@ sftk_handleSMimeObject(SFTKSession *session,SFTKObject *object) if (sftk_isTrue(object,CKA_TOKEN)) { SFTKSlot *slot = session->slot; - SECItem derSubj,rawProfile,rawTime,emailKey; - SECItem *pRawProfile = NULL; - SECItem *pRawTime = NULL; - char *email = NULL; - SFTKAttribute *subject = NULL, - *profile = NULL, - *time = NULL; - SECStatus rv; - NSSLOWCERTCertDBHandle *certHandle; - CK_RV ck_rv = CKR_OK; + SFTKDBHandle *certHandle; + CK_RV crv; PORT_Assert(slot); if (slot == NULL) { @@ -960,63 +742,9 @@ sftk_handleSMimeObject(SFTKSession *session,SFTKObject *object) return CKR_TOKEN_WRITE_PROTECTED; } - /* lookup SUBJECT */ - subject = sftk_FindAttribute(object,CKA_SUBJECT); - PORT_Assert(subject); - if (!subject) { - ck_rv = CKR_ATTRIBUTE_VALUE_INVALID; - goto loser; - } - - derSubj.data = (unsigned char *)subject->attrib.pValue; - derSubj.len = subject->attrib.ulValueLen ; - derSubj.type = 0; - - /* lookup VALUE */ - profile = sftk_FindAttribute(object,CKA_VALUE); - if (profile) { - rawProfile.data = (unsigned char *)profile->attrib.pValue; - rawProfile.len = profile->attrib.ulValueLen ; - rawProfile.type = siBuffer; - pRawProfile = &rawProfile; - } - - /* lookup Time */ - time = sftk_FindAttribute(object,CKA_NETSCAPE_SMIME_TIMESTAMP); - if (time) { - rawTime.data = (unsigned char *)time->attrib.pValue; - rawTime.len = time->attrib.ulValueLen ; - rawTime.type = siBuffer; - pRawTime = &rawTime; - } - - - email = sftk_getString(object,CKA_NETSCAPE_EMAIL); - if (!email) { - ck_rv = CKR_ATTRIBUTE_VALUE_INVALID; - goto loser; - } - - /* Store CRL by SUBJECT */ - rv = nsslowcert_SaveSMimeProfile(certHandle, email, &derSubj, - pRawProfile,pRawTime); - if (rv != SECSuccess) { - ck_rv = CKR_DEVICE_ERROR; - goto loser; - } - emailKey.data = (unsigned char *)email; - emailKey.len = PORT_Strlen(email)+1; - - object->handle = sftk_mkHandle(slot, &emailKey, SFTK_TOKEN_TYPE_SMIME); - -loser: - sftk_freeCertDB(certHandle); - if (subject) sftk_FreeAttribute(subject); - if (profile) sftk_FreeAttribute(profile); - if (time) sftk_FreeAttribute(time); - if (email) PORT_Free(email); - - return ck_rv; + crv = sftkdb_write(certHandle, object, &object->handle); + sftk_freeDB(certHandle); + return crv; } return CKR_OK; @@ -1044,61 +772,16 @@ sftk_handleCrlObject(SFTKSession *session,SFTKObject *object) if (sftk_isTrue(object,CKA_TOKEN)) { SFTKSlot *slot = session->slot; - PRBool isKRL = PR_FALSE; - SECItem derSubj,derCrl; - char *url = NULL; - SFTKAttribute *subject,*crl; - SECStatus rv; - NSSLOWCERTCertDBHandle *certHandle; - - PORT_Assert(slot); - certHandle = sftk_getCertDB(slot); + SFTKDBHandle *certHandle = sftk_getCertDB(slot); + CK_RV crv; if (certHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } - /* lookup SUBJECT */ - subject = sftk_FindAttribute(object,CKA_SUBJECT); - PORT_Assert(subject); - if (!subject) { - sftk_freeCertDB(certHandle); - return CKR_ATTRIBUTE_VALUE_INVALID; - } - - derSubj.data = (unsigned char *)subject->attrib.pValue; - derSubj.len = subject->attrib.ulValueLen ; - - /* lookup VALUE */ - crl = sftk_FindAttribute(object,CKA_VALUE); - PORT_Assert(crl); - derCrl.data = (unsigned char *)crl->attrib.pValue; - derCrl.len = crl->attrib.ulValueLen ; - - - url = sftk_getString(object,CKA_NETSCAPE_URL); - isKRL = sftk_isTrue(object,CKA_NETSCAPE_KRL); - - /* Store CRL by SUBJECT */ - rv = nsslowcert_AddCrl(certHandle, &derCrl, &derSubj, url, isKRL); - sftk_freeCertDB(certHandle); - - if (url) { - PORT_Free(url); - } - sftk_FreeAttribute(crl); - if (rv != SECSuccess) { - sftk_FreeAttribute(subject); - return CKR_DEVICE_ERROR; - } - - /* if we overwrote the existing CRL, poison the handle entry so we get - * a new object handle */ - (void) sftk_poisonHandle(slot, &derSubj, - isKRL ? SFTK_TOKEN_KRL_HANDLE : SFTK_TOKEN_TYPE_CRL); - object->handle = sftk_mkHandle(slot, &derSubj, - isKRL ? SFTK_TOKEN_KRL_HANDLE : SFTK_TOKEN_TYPE_CRL); - sftk_FreeAttribute(subject); + crv = sftkdb_write(certHandle, object, &object->handle); + sftk_freeDB(certHandle); + return crv; } return CKR_OK; @@ -1218,37 +901,15 @@ sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object, if (sftk_isTrue(object,CKA_TOKEN)) { SFTKSlot *slot = session->slot; - NSSLOWKEYPrivateKey *priv; - SECItem pubKey; - NSSLOWKEYDBHandle *keyHandle = NULL; - - crv = sftk_Attribute2SSecItem(NULL,&pubKey,object,pubKeyAttr); - if (crv != CKR_OK) return crv; + SFTKDBHandle *certHandle = sftk_getCertDB(slot); - PORT_Assert(pubKey.data); - keyHandle = sftk_getKeyDB(slot); - if (keyHandle == NULL) { - PORT_Free(pubKey.data); + if (certHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } - if (keyHandle->version != 3) { - unsigned char buf[SHA1_LENGTH]; - SHA1_HashBuf(buf,pubKey.data,pubKey.len); - PORT_Memcpy(pubKey.data,buf,sizeof(buf)); - pubKey.len = sizeof(buf); - } - /* make sure the associated private key already exists */ - /* only works if we are logged in */ - priv = nsslowkey_FindKeyByPublicKey(keyHandle, &pubKey, slot->password); - sftk_freeKeyDB(keyHandle); - if (priv == NULL) { - PORT_Free(pubKey.data); - return crv; - } - nsslowkey_DestroyPrivateKey(priv); - object->handle = sftk_mkHandle(slot, &pubKey, SFTK_TOKEN_TYPE_PUB); - PORT_Free(pubKey.data); + crv = sftkdb_write(certHandle, object, &object->handle); + sftk_freeDB(certHandle); + return crv; } return CKR_OK; @@ -1313,10 +974,6 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE if ( !sftk_hasAttribute(object, CKA_SUBPRIME)) { return CKR_TEMPLATE_INCOMPLETE; } - if (sftk_isTrue(object,CKA_TOKEN) && - !sftk_hasAttribute(object, CKA_NETSCAPE_DB)) { - return CKR_TEMPLATE_INCOMPLETE; - } sign = CK_TRUE; /* fall through */ case CKK_DH: @@ -1341,10 +998,6 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE if ( !sftk_hasAttribute(object, CKA_VALUE)) { return CKR_TEMPLATE_INCOMPLETE; } - if (sftk_isTrue(object,CKA_TOKEN) && - !sftk_hasAttribute(object, CKA_NETSCAPE_DB)) { - return CKR_TEMPLATE_INCOMPLETE; - } encrypt = CK_FALSE; sign = CK_TRUE; recover = CK_FALSE; @@ -1384,65 +1037,26 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE if (sftk_isTrue(object,CKA_TOKEN)) { SFTKSlot *slot = session->slot; - NSSLOWKEYPrivateKey *privKey; - char *label; - SECStatus rv = SECSuccess; - CK_RV crv = CKR_DEVICE_ERROR; - SECItem pubKey; - NSSLOWKEYDBHandle *keyHandle = sftk_getKeyDB(slot); + SFTKDBHandle *keyHandle = sftk_getKeyDB(slot); + CK_RV crv; if (keyHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } - privKey=sftk_mkPrivKey(object,key_type,&crv); - if (privKey == NULL) return crv; - label = sftk_getString(object,CKA_LABEL); - - crv = sftk_Attribute2SSecItem(NULL,&pubKey,object,CKA_NETSCAPE_DB); - if (crv != CKR_OK) { - crv = CKR_TEMPLATE_INCOMPLETE; - rv = SECFailure; - goto fail; - } - if (keyHandle->version != 3) { - unsigned char buf[SHA1_LENGTH]; - SHA1_HashBuf(buf,pubKey.data,pubKey.len); - PORT_Memcpy(pubKey.data,buf,sizeof(buf)); - pubKey.len = sizeof(buf); - } - - if (key_type == CKK_RSA) { - rv = RSA_PrivateKeyCheck(&privKey->u.rsa); - if (rv == SECFailure) { - goto fail; - } - } - 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 crv; + crv = sftkdb_write(keyHandle, object, &object->handle); + sftk_freeDB(keyHandle); + return crv; } else { object->objectInfo = sftk_mkPrivKey(object,key_type,&crv); if (object->objectInfo == NULL) return crv; object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey; - /* now NULL out the sensitive attributes */ - /* remove nulled out attributes for session objects. these only - * applied to rsa private keys anyway (other private keys did not - * get their attributes NULL'ed out */ } return CKR_OK; } /* forward declare the DES formating function for handleSecretKey */ void sftk_FormatDESKey(unsigned char *key, int length); -static NSSLOWKEYPrivateKey *sftk_mkSecretKeyRep(SFTKObject *object); /* Validate secret key data, and set defaults */ static CK_RV @@ -1535,57 +1149,6 @@ validateSecretKey(SFTKSession *session, SFTKObject *object, return crv; } -#define SFTK_KEY_MAX_RETRIES 10 /* don't hang if we are having problems with the rng */ -#define SFTK_KEY_ID_SIZE 18 /* don't use either SHA1 or MD5 sizes */ -/* - * Secret keys must have a CKA_ID value to be stored in the database. This code - * will generate one if there wasn't one already. - */ -static CK_RV -sftk_GenerateSecretCKA_ID(NSSLOWKEYDBHandle *handle, SECItem *id, char *label) -{ - unsigned int retries; - SECStatus rv = SECSuccess; - CK_RV crv = CKR_OK; - - id->data = NULL; - if (label) { - id->data = (unsigned char *)PORT_Strdup(label); - if (id->data == NULL) { - return CKR_HOST_MEMORY; - } - id->len = PORT_Strlen(label)+1; - if (!nsslowkey_KeyForIDExists(handle,id)) { - return CKR_OK; - } - PORT_Free(id->data); - id->data = NULL; - id->len = 0; - } - id->data = (unsigned char *)PORT_Alloc(SFTK_KEY_ID_SIZE); - if (id->data == NULL) { - return CKR_HOST_MEMORY; - } - id->len = SFTK_KEY_ID_SIZE; - - retries = 0; - do { - rv = RNG_GenerateGlobalRandomBytes(id->data,id->len); - } while (rv == SECSuccess && nsslowkey_KeyForIDExists(handle,id) && - (++retries <= SFTK_KEY_MAX_RETRIES)); - - if ((rv != SECSuccess) || (retries > SFTK_KEY_MAX_RETRIES)) { - if (rv != SECSuccess) { - sftk_fatalError = PR_TRUE; - } - crv = CKR_DEVICE_ERROR; /* random number generator is bad */ - PORT_Free(id->data); - id->data = NULL; - id->len = 0; - } - return crv; -} - /* * check the consistancy and initialize a Secret Key Object */ @@ -1594,12 +1157,6 @@ sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object, CK_KEY_TYPE key_type, PRBool isFIPS) { CK_RV crv; - NSSLOWKEYPrivateKey *privKey = NULL; - NSSLOWKEYDBHandle *keyHandle = NULL; - SECItem pubKey; - char *label = NULL; - - pubKey.data = 0; /* First validate and set defaults */ crv = validateSecretKey(session, object, key_type, isFIPS); @@ -1608,53 +1165,19 @@ sftk_handleSecretKeyObject(SFTKSession *session,SFTKObject *object, /* If the object is a TOKEN object, store in the database */ if (sftk_isTrue(object,CKA_TOKEN)) { SFTKSlot *slot = session->slot; - SECStatus rv = SECSuccess; - keyHandle = sftk_getKeyDB(slot); + SFTKDBHandle *keyHandle = sftk_getKeyDB(slot); + CK_RV crv; if (keyHandle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } - label = sftk_getString(object,CKA_LABEL); - - crv = sftk_Attribute2SecItem(NULL, &pubKey, object, CKA_ID); - /* Should this be ID? */ - if (crv != CKR_OK) goto loser; - - /* if we don't have an ID, generate one */ - if (pubKey.len == 0) { - if (pubKey.data) { - PORT_Free(pubKey.data); - pubKey.data = NULL; - } - 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); - if (privKey == NULL) { - crv = CKR_HOST_MEMORY; - goto loser; - } - - rv = nsslowkey_StoreKeyByPublicKey(keyHandle, - privKey, &pubKey, label, slot->password); - if (rv != SECSuccess) { - crv = CKR_DEVICE_ERROR; - goto loser; - } - - object->handle = sftk_mkHandle(slot,&pubKey,SFTK_TOKEN_TYPE_KEY); + crv = sftkdb_write(keyHandle, object, &object->handle); + sftk_freeDB(keyHandle); + return crv; } loser: - if (keyHandle) sftk_freeKeyDB(keyHandle); - if (label) PORT_Free(label); - if (privKey) nsslowkey_DestroyPrivateKey(privKey); - if (pubKey.data) PORT_Free(pubKey.data); return crv; } @@ -2071,7 +1594,7 @@ sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp) CK_RV crv = CKR_OK; SECStatus rv; - PORT_Assert(!sftk_isToken(object->handle)); + /*PORT_Assert(!sftk_isToken(object->handle)); */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { *crvp = CKR_HOST_MEMORY; @@ -2116,7 +1639,7 @@ sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp) CKA_COEFFICIENT); if (crv != CKR_OK) break; rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version, - NSSLOWKEY_VERSION); + NSSLOWKEY_PRIVATE_KEY_INFO_VERSION); if (rv != SECSuccess) crv = CKR_HOST_MEMORY; break; @@ -2221,6 +1744,7 @@ sftk_GetPrivKey(SFTKObject *object,CK_KEY_TYPE key_type, CK_RV *crvp) return (NSSLOWKEYPrivateKey *)object->objectInfo; } +#ifdef notdef if (sftk_isToken(object->handle)) { /* grab it from the data base */ SFTKTokenObject *to = sftk_narrowToTokenObject(object); @@ -2231,6 +1755,9 @@ sftk_GetPrivKey(SFTKObject *object,CK_KEY_TYPE key_type, CK_RV *crvp) } else { priv = sftk_mkPrivKey(object, key_type, crvp); } +#else + priv = sftk_mkPrivKey(object, key_type, crvp); +#endif object->objectInfo = priv; object->infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey; return priv; @@ -2296,104 +1823,6 @@ sftk_IsWeakKey(unsigned char *key,CK_KEY_TYPE key_type) } -/* make a fake private key representing a symmetric key */ -static NSSLOWKEYPrivateKey * -sftk_mkSecretKeyRep(SFTKObject *object) -{ - NSSLOWKEYPrivateKey *privKey = 0; - PLArenaPool *arena = 0; - CK_KEY_TYPE keyType; - PRUint32 keyTypeStorage; - SECItem keyTypeItem; - CK_RV crv; - SECStatus rv; - static unsigned char derZero[1] = { 0 }; - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { crv = CKR_HOST_MEMORY; goto loser; } - - privKey = (NSSLOWKEYPrivateKey *) - PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey)); - if (privKey == NULL) { crv = CKR_HOST_MEMORY; goto loser; } - - privKey->arena = arena; - - /* Secret keys are represented in the database as "fake" RSA keys. The RSA key - * is marked as a secret key representation by setting the public exponent field - * to 0, which is an invalid RSA exponent. The other fields are set as follows: - * modulus - CKA_ID value for the secret key - * private exponent - CKA_VALUE (the key itself) - * coefficient - CKA_KEY_TYPE, which indicates what encryption algorithm - * is used for the key. - * all others - set to integer 0 - */ - privKey->keyType = NSSLOWKEYRSAKey; - - /* The modulus is set to the key id of the symmetric key */ - crv=sftk_Attribute2SecItem(arena,&privKey->u.rsa.modulus,object,CKA_ID); - if (crv != CKR_OK) goto loser; - - /* The public exponent is set to 0 length to indicate a special key */ - privKey->u.rsa.publicExponent.len = sizeof derZero; - privKey->u.rsa.publicExponent.data = derZero; - - /* The private exponent is the actual key value */ - crv=sftk_Attribute2SecItem(arena,&privKey->u.rsa.privateExponent,object,CKA_VALUE); - if (crv != CKR_OK) goto loser; - - /* All other fields empty - needs testing */ - privKey->u.rsa.prime1.len = sizeof derZero; - privKey->u.rsa.prime1.data = derZero; - - privKey->u.rsa.prime2.len = sizeof derZero; - privKey->u.rsa.prime2.data = derZero; - - privKey->u.rsa.exponent1.len = sizeof derZero; - privKey->u.rsa.exponent1.data = derZero; - - privKey->u.rsa.exponent2.len = sizeof derZero; - privKey->u.rsa.exponent2.data = derZero; - - /* Coeficient set to KEY_TYPE */ - crv = sftk_GetULongAttribute(object, CKA_KEY_TYPE, &keyType); - if (crv != CKR_OK) goto loser; - /* on 64 bit platforms, we still want to store 32 bits of keyType (This is - * safe since the PKCS #11 defines for all types are 32 bits or less). */ - keyTypeStorage = (PRUint32) keyType; - keyTypeStorage = PR_htonl(keyTypeStorage); - keyTypeItem.data = (unsigned char *)&keyTypeStorage; - keyTypeItem.len = sizeof (keyTypeStorage); - rv = SECITEM_CopyItem(arena, &privKey->u.rsa.coefficient, &keyTypeItem); - if (rv != SECSuccess) { - crv = CKR_HOST_MEMORY; - goto loser; - } - - /* Private key version field set normally for compatibility */ - rv = DER_SetUInteger(privKey->arena, - &privKey->u.rsa.version, NSSLOWKEY_VERSION); - if (rv != SECSuccess) { crv = CKR_HOST_MEMORY; goto loser; } - -loser: - if (crv != CKR_OK) { - PORT_FreeArena(arena,PR_FALSE); - privKey = 0; - } - - return privKey; -} - -static PRBool -isSecretKey(NSSLOWKEYPrivateKey *privKey) -{ - if (privKey->keyType == NSSLOWKEYRSAKey && - privKey->u.rsa.publicExponent.len == 1 && - privKey->u.rsa.publicExponent.data[0] == 0) - return PR_TRUE; - - return PR_FALSE; -} - /********************************************************************** * * Start of PKCS 11 functions @@ -2565,56 +1994,6 @@ 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) -{ - sftkDBs *param = (sftkDBs *)arg; - NSSLOWCERTCertTrust trust = *cert->trust; - - if (param->keyHandle && - nsslowkey_KeyForCertExists(param->keyHandle,cert)) { - trust.sslFlags |= CERTDB_USER; - trust.emailFlags |= CERTDB_USER; - trust.objectSigningFlags |= CERTDB_USER; - } else { - trust.sslFlags &= ~CERTDB_USER; - trust.emailFlags &= ~CERTDB_USER; - trust.objectSigningFlags &= ~CERTDB_USER; - } - - if (PORT_Memcmp(&trust,cert->trust, sizeof (trust)) != 0) { - 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(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 */ - sftkDBs param; - param.certHandle = certHandle; - param.keyHandle = keyHandle; - - nsslowcert_TraversePermCerts(certHandle, sftk_set_user, ¶m); - - return; -} - /* * ths function has all the common initialization that happens whenever we @@ -2663,8 +2042,8 @@ SFTK_SlotReInit(SFTKSlot *slot, sizeof(slot->tokDescription)); if ((!params->noCertDB) || (!params->noKeyDB)) { - NSSLOWCERTCertDBHandle * certHandle = NULL; - NSSLOWKEYDBHandle *keyHandle = NULL; + SFTKDBHandle * certHandle = NULL; + SFTKDBHandle *keyHandle = NULL; crv = sftk_DBInit(params->configdir ? params->configdir : configdir, params->certPrefix, params->keyPrefix, params->readOnly, params->noCertDB, params->noKeyDB, params->forceOpen, @@ -2673,16 +2052,13 @@ SFTK_SlotReInit(SFTKSlot *slot, 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); + (PRBool)!sftk_hasNullPassword(slot->keyDB); if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) { slot->minimumPinLen = params->minPW; } @@ -2794,16 +2170,21 @@ loser: static CK_RV sft_CloseAllSession(SFTKSlot *slot) { - SECItem *pw = NULL; SFTKSession *session; unsigned int i; + SFTKDBHandle *handle; + /* first log out the card */ + handle = sftk_getKeyDB(slot); PZ_Lock(slot->slotLock); - pw = slot->password; slot->isLoggedIn = PR_FALSE; - slot->password = NULL; + if (handle) { + sftkdb_ClearPassword(handle); + } PZ_Unlock(slot->slotLock); - if (pw) SECITEM_ZfreeItem(pw, PR_TRUE); + if (handle) { + sftk_freeDB(handle); + } /* now close all the current sessions */ /* NOTE: If you try to open new sessions before NSC_CloseAllSessions @@ -2852,8 +2233,8 @@ static CK_RV sft_CloseAllSession(SFTKSlot *slot) static void sftk_DBShutdown(SFTKSlot *slot) { - NSSLOWCERTCertDBHandle *certHandle; - NSSLOWKEYDBHandle *keyHandle; + SFTKDBHandle *certHandle; + SFTKDBHandle *keyHandle; PZ_Lock(slot->slotLock); certHandle = slot->certDB; slot->certDB = NULL; @@ -2861,12 +2242,10 @@ sftk_DBShutdown(SFTKSlot *slot) slot->keyDB = NULL; PZ_Unlock(slot->slotLock); if (certHandle) { - PORT_Assert(certHandle->ref == 1 || slot->slotID > FIPS_SLOT_ID); - sftk_freeCertDB(certHandle); + sftk_freeDB(certHandle); } if (keyHandle) { - PORT_Assert(keyHandle->ref == 1 || slot->slotID > FIPS_SLOT_ID); - sftk_freeKeyDB(keyHandle); + sftk_freeDB(keyHandle); } } @@ -2961,26 +2340,27 @@ NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args) char *secmod = NULL; char *appName = NULL; char *filename = NULL; + SDBType dbType = SDB_LEGACY; PRBool rw; static char *success="Success"; char **rvstr = NULL; - secmod = secmod_getSecmodName(parameters,&appName,&filename, &rw); + secmod = sftk_getSecmodName(parameters, &dbType, &appName,&filename, &rw); switch (function) { case SECMOD_MODULE_DB_FUNCTION_FIND: - rvstr = secmod_ReadPermDB(appName,filename,secmod,(char *)parameters,rw); + rvstr = sftkdb_ReadSecmodDB(dbType,appName,filename,secmod,(char *)parameters,rw); break; case SECMOD_MODULE_DB_FUNCTION_ADD: - rvstr = (secmod_AddPermDB(appName,filename,secmod,(char *)args,rw) + rvstr = (sftkdb_AddSecmodDB(dbType,appName,filename,secmod,(char *)args,rw) == SECSuccess) ? &success: NULL; break; case SECMOD_MODULE_DB_FUNCTION_DEL: - rvstr = (secmod_DeletePermDB(appName,filename,secmod,(char *)args,rw) + rvstr = (sftkdb_DeleteSecmodDB(dbType,appName,filename,secmod,(char *)args,rw) == SECSuccess) ? &success: NULL; break; case SECMOD_MODULE_DB_FUNCTION_RELEASE: - rvstr = (secmod_ReleasePermDBData(appName,filename,secmod, + rvstr = (sftkdb_ReleaseSecmodDBData(dbType, appName,filename,secmod, (char **)args,rw) == SECSuccess) ? &success: NULL; break; } @@ -3074,12 +2454,6 @@ CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS) } RNG_SystemInfoForRNG(); - rv = nsslowcert_InitLocks(); - if (rv != SECSuccess) { - crv = CKR_DEVICE_ERROR; - return crv; - } - /* NOTE: * we should be getting out mutexes from this list, not statically binding @@ -3088,8 +2462,6 @@ CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS) */ /* initialize the key and cert db's */ - nsslowkey_SetDefaultKeyDBAlg - (SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC); if (init_args && (!(init_args->flags & CKF_OS_LOCKING_OK))) { if (init_args->CreateMutex && init_args->DestroyMutex && init_args->LockMutex && init_args->UnlockMutex) { @@ -3112,7 +2484,7 @@ CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS) if ((init_args && init_args->LibraryParameters)) { sftk_parameters paramStrings; - crv = secmod_parseParameters + crv = sftk_parseParameters ((char *)init_args->LibraryParameters, ¶mStrings, isFIPS); if (crv != CKR_OK) { return crv; @@ -3145,7 +2517,7 @@ CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS) } } loser: - secmod_freeParams(¶mStrings); + sftk_freeParams(¶mStrings); } if (CKR_OK == crv) { sftk_InitFreeLists(); @@ -3184,8 +2556,7 @@ CK_RV nsc_CommonFinalize (CK_VOID_PTR pReserved, PRBool isFIPS) } sftk_CleanupFreeLists(); - nsslowcert_DestroyFreeLists(); - nsslowcert_DestroyGlobalLocks(); + sftkdb_Shutdown(); /* This function does not discard all our previously aquired entropy. */ RNG_RNGShutdown(); @@ -3286,21 +2657,12 @@ CK_RV NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) * been changed underneath us. */ static PRBool -sftk_checkNeedLogin(SFTKSlot *slot, NSSLOWKEYDBHandle *keyHandle) +sftk_checkNeedLogin(SFTKSlot *slot, SFTKDBHandle *keyHandle) { - if (slot->password) { - SECStatus rv; - rv = nsslowkey_CheckKeyDBPassword(keyHandle,slot->password); - if ( rv == SECSuccess) { - return slot->needLogin; - } else { - SECITEM_FreeItem(slot->password, PR_TRUE); - slot->password = NULL; - slot->isLoggedIn = PR_FALSE; - } + if (sftkdb_PWCached(keyHandle) == SECSuccess) { + return slot->needLogin; } - slot->needLogin = - (PRBool)!sftk_hasNullPassword(keyHandle,&slot->password); + slot->needLogin = (PRBool)!sftk_hasNullPassword(keyHandle); return (slot->needLogin); } @@ -3308,8 +2670,8 @@ sftk_checkNeedLogin(SFTKSlot *slot, NSSLOWKEYDBHandle *keyHandle) * the system. */ CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo) { - SFTKSlot *slot; - NSSLOWKEYDBHandle *handle; + SFTKSlot *slot; + SFTKDBHandle *handle; if (!nsc_init && !nsf_init) return CKR_CRYPTOKI_NOT_INITIALIZED; slot = sftk_SlotFromID(slotID, PR_FALSE); @@ -3348,7 +2710,7 @@ CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo) * (3) Finally we have an initialized password whicn is not NULL, and * we will need to prompt for it. */ - if (nsslowkey_HasKeyDBPassword(handle) == SECFailure) { + if (sftkdb_HasPasswordSet(handle) == SECFailure) { pInfo->flags |= CKF_LOGIN_REQUIRED; } else if (!sftk_checkNeedLogin(slot,handle)) { pInfo->flags |= CKF_USER_PIN_INITIALIZED; @@ -3361,9 +2723,14 @@ CK_RV NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo) pInfo->ulFreePublicMemory = 1; pInfo->ulTotalPrivateMemory = 1; pInfo->ulFreePrivateMemory = 1; +#ifdef SHDB_FIXME pInfo->hardwareVersion.major = CERT_DB_FILE_VERSION; pInfo->hardwareVersion.minor = handle->version; - sftk_freeKeyDB(handle); +else + pInfo->hardwareVersion.major = 0; + pInfo->hardwareVersion.minor = 0; +#endif + sftk_freeDB(handle); } /* * CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED how CKF_TOKEN_INITIALIZED @@ -3468,31 +2835,12 @@ CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op) return CKR_MECHANISM_INVALID; } - -static SECStatus -sftk_TurnOffUser(NSSLOWCERTCertificate *cert, SECItem *k, void *arg) -{ - NSSLOWCERTCertTrust trust; - SECStatus rv; - - rv = nsslowcert_GetCertTrust(cert,&trust); - if (rv == SECSuccess && ((trust.emailFlags & CERTDB_USER) || - (trust.sslFlags & CERTDB_USER) || - (trust.objectSigningFlags & CERTDB_USER))) { - trust.emailFlags &= ~CERTDB_USER; - trust.sslFlags &= ~CERTDB_USER; - trust.objectSigningFlags &= ~CERTDB_USER; - nsslowcert_ChangeCertTrust(cert->dbhandle,cert,&trust); - } - return SECSuccess; -} - /* 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, PR_FALSE); - NSSLOWKEYDBHandle *handle; - NSSLOWCERTCertDBHandle *certHandle; + SFTKDBHandle *handle; + SFTKDBHandle *certHandle; SECStatus rv; unsigned int i; SFTKObject *object; @@ -3534,8 +2882,8 @@ CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin, return CKR_TOKEN_WRITE_PROTECTED; } - rv = nsslowkey_ResetKeyDB(handle); - sftk_freeKeyDB(handle); + rv = sftkdb_ResetKeyDB(handle); + sftk_freeDB(handle); if (rv != SECSuccess) { return CKR_DEVICE_ERROR; } @@ -3544,8 +2892,7 @@ CK_RV NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin, certHandle = sftk_getCertDB(slot); if (certHandle == NULL) return CKR_OK; - nsslowcert_TraversePermCerts(certHandle,sftk_TurnOffUser, NULL); - sftk_freeCertDB(certHandle); + sftk_freeDB(certHandle); return CKR_OK; /*is this the right function for not implemented*/ } @@ -3557,8 +2904,7 @@ CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession, { SFTKSession *sp = NULL; SFTKSlot *slot; - NSSLOWKEYDBHandle *handle = NULL; - SECItem *newPin; + SFTKDBHandle *handle = NULL; char newPinStr[SFTK_MAX_PIN+1]; SECStatus rv; CK_RV crv = CKR_SESSION_HANDLE_INVALID; @@ -3599,34 +2945,27 @@ CK_RV NSC_InitPIN(CK_SESSION_HANDLE hSession, goto loser; } - if (nsslowkey_HasKeyDBPassword(handle) != SECFailure) { + if (sftkdb_HasPasswordSet(handle) != SECFailure) { crv = CKR_DEVICE_ERROR; goto loser; } /* convert to null terminated string */ - PORT_Memcpy(newPinStr,pPin,ulPinLen); + PORT_Memcpy(newPinStr, pPin, ulPinLen); newPinStr[ulPinLen] = 0; /* build the hashed pins which we pass around */ - newPin = nsslowkey_HashPassword(newPinStr,handle->global_salt); - PORT_Memset(newPinStr,0,sizeof(newPinStr)); /* change the data base */ - rv = nsslowkey_SetKeyDBPassword(handle,newPin); - sftk_freeKeyDB(handle); + rv = sftkdb_ChangePassword(handle, NULL, newPinStr); + sftk_freeDB(handle); handle = NULL; /* Now update our local copy of the pin */ if (rv == SECSuccess) { - if (slot->password) { - SECITEM_ZfreeItem(slot->password, PR_TRUE); - } - slot->password = newPin; if (ulPinLen == 0) slot->needLogin = PR_FALSE; return CKR_OK; } - SECITEM_ZfreeItem(newPin, PR_TRUE); crv = CKR_PIN_INCORRECT; loser: @@ -3634,7 +2973,7 @@ loser: sftk_FreeSession(sp); } if (handle) { - sftk_freeKeyDB(handle); + sftk_freeDB(handle); } return crv; } @@ -3647,9 +2986,7 @@ CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, { SFTKSession *sp = NULL; SFTKSlot *slot; - NSSLOWKEYDBHandle *handle = NULL; - SECItem *newPin; - SECItem *oldPin; + SFTKDBHandle *handle = NULL; char newPinStr[SFTK_MAX_PIN+1],oldPinStr[SFTK_MAX_PIN+1]; SECStatus rv; CK_RV crv = CKR_SESSION_HANDLE_INVALID; @@ -3696,16 +3033,10 @@ CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, PORT_Memcpy(oldPinStr,pOldPin,ulOldLen); oldPinStr[ulOldLen] = 0; - /* build the hashed pins which we pass around */ - newPin = nsslowkey_HashPassword(newPinStr,handle->global_salt); - oldPin = nsslowkey_HashPassword(oldPinStr,handle->global_salt); - PORT_Memset(newPinStr,0,sizeof(newPinStr)); - PORT_Memset(oldPinStr,0,sizeof(oldPinStr)); - /* change the data base password */ PR_Lock(slot->pwCheckLock); - rv = nsslowkey_ChangeKeyDBPassword(handle,oldPin,newPin); - sftk_freeKeyDB(handle); + rv = sftkdb_ChangePassword(handle, oldPinStr, newPinStr); + sftk_freeDB(handle); handle = NULL; if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) { PR_Sleep(loginWaitTime); @@ -3713,23 +3044,17 @@ CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, PR_Unlock(slot->pwCheckLock); /* Now update our local copy of the pin */ - SECITEM_ZfreeItem(oldPin, PR_TRUE); if (rv == SECSuccess) { - if (slot->password) { - SECITEM_ZfreeItem(slot->password, PR_TRUE); - } - slot->password = newPin; slot->needLogin = (PRBool)(ulNewLen != 0); return CKR_OK; } - SECITEM_ZfreeItem(newPin, PR_TRUE); crv = CKR_PIN_INCORRECT; loser: if (sp) { sftk_FreeSession(sp); } if (handle) { - sftk_freeKeyDB(handle); + sftk_freeDB(handle); } return crv; } @@ -3791,7 +3116,6 @@ CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession) { SFTKSlot *slot; SFTKSession *session; - SECItem *pw = NULL; PRBool sessionFound; PZLock *lock; @@ -3812,20 +3136,25 @@ CK_RV NSC_CloseSession(CK_SESSION_HANDLE hSession) PZ_Unlock(lock); if (sessionFound) { + SFTKDBHandle *handle; + handle = sftk_getKeyDB(slot); PZ_Lock(slot->slotLock); if (--slot->sessionCount == 0) { - pw = slot->password; slot->isLoggedIn = PR_FALSE; - slot->password = NULL; + if (handle) { + sftkdb_ClearPassword(handle); + } } PZ_Unlock(slot->slotLock); + if (handle) { + sftk_freeDB(handle); + } if (session->info.flags & CKF_RW_SESSION) { PR_AtomicDecrement(&slot->rwSessionCount); } } sftk_FreeSession(session); - if (pw) SECITEM_ZfreeItem(pw, PR_TRUE); return CKR_OK; } @@ -3863,11 +3192,10 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, { SFTKSlot *slot; SFTKSession *session; - NSSLOWKEYDBHandle *handle; + SFTKDBHandle *handle; CK_FLAGS sessionFlags; SECStatus rv; CK_RV crv; - SECItem *pin; char pinStr[SFTK_MAX_PIN+1]; @@ -3910,7 +3238,7 @@ 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. */ - rv = nsslowkey_HasKeyDBPassword(handle); + rv = sftkdb_HasPasswordSet(handle); if (rv == SECFailure) { /* allow SSO's to log in only if there is not password on the * key database */ @@ -3919,15 +3247,12 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, || (slot->slotID == FIPS_SLOT_ID)) { /* should this be a fixed password? */ if (ulPinLen == 0) { - SECItem *pw; + sftkdb_ClearPassword(handle); PZ_Lock(slot->slotLock); - pw = slot->password; - slot->password = NULL; slot->isLoggedIn = PR_TRUE; slot->ssoLoggedIn = (PRBool)(userType == CKU_SO); PZ_Unlock(slot->slotLock); sftk_update_all_states(slot); - SECITEM_ZfreeItem(pw,PR_TRUE); crv = CKR_OK; goto done; } @@ -3946,39 +3271,28 @@ CK_RV NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, /* build the hashed pins which we pass around */ - pin = nsslowkey_HashPassword(pinStr,handle->global_salt); - if (pin == NULL) { - crv = CKR_HOST_MEMORY; - goto done; - } - PR_Lock(slot->pwCheckLock); - rv = nsslowkey_CheckKeyDBPassword(handle,pin); - sftk_freeKeyDB(handle); + rv = sftkdb_CheckPassword(handle,pinStr); + sftk_freeDB(handle); handle = NULL; if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) { PR_Sleep(loginWaitTime); } PR_Unlock(slot->pwCheckLock); if (rv == SECSuccess) { - SECItem *tmp; PZ_Lock(slot->slotLock); - tmp = slot->password; slot->isLoggedIn = PR_TRUE; - slot->password = pin; PZ_Unlock(slot->slotLock); - if (tmp) SECITEM_ZfreeItem(tmp, PR_TRUE); /* update all sessions */ sftk_update_all_states(slot); return CKR_OK; } - SECITEM_ZfreeItem(pin, PR_TRUE); crv = CKR_PIN_INCORRECT; done: if (handle) { - sftk_freeKeyDB(handle); + sftk_freeDB(handle); } return crv; } @@ -3988,7 +3302,7 @@ CK_RV NSC_Logout(CK_SESSION_HANDLE hSession) { SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); SFTKSession *session; - SECItem *pw = NULL; + SFTKDBHandle *handle; if (slot == NULL) { return CKR_SESSION_HANDLE_INVALID; @@ -4000,13 +3314,17 @@ CK_RV NSC_Logout(CK_SESSION_HANDLE hSession) if (!slot->isLoggedIn) return CKR_USER_NOT_LOGGED_IN; + handle = sftk_getKeyDB(slot); PZ_Lock(slot->slotLock); - pw = slot->password; slot->isLoggedIn = PR_FALSE; slot->ssoLoggedIn = PR_FALSE; - slot->password = NULL; + if (handle) { + sftkdb_ClearPassword(handle); + } PZ_Unlock(slot->slotLock); - if (pw) SECITEM_ZfreeItem(pw, PR_TRUE); + if (handle) { + sftk_freeDB(handle); + } sftk_update_all_states(slot); return CKR_OK; @@ -4051,7 +3369,7 @@ static CK_RV sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class, return CKR_TEMPLATE_INCOMPLETE; } paramString = (char *)attribute->attrib.pValue; - crv = secmod_parseParameters(paramString, ¶mStrings, isFIPS); + crv = sftk_parseParameters(paramString, ¶mStrings, isFIPS); if (crv != CKR_OK) { goto loser; } @@ -4098,7 +3416,7 @@ static CK_RV sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class, goto loser; } loser: - secmod_freeParams(¶mStrings); + sftk_freeParams(¶mStrings); sftk_FreeAttribute(attribute); return crv; @@ -4292,6 +3610,43 @@ CK_RV NSC_GetAttributeValue(CK_SESSION_HANDLE hSession, return CKR_SESSION_HANDLE_INVALID; } + /* short circuit everything for token objects */ + if (sftk_isToken(hObject)) { + SFTKSlot *slot = sftk_SlotFromSession(session); + SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, hObject); + SFTKDBHandle *keydb = NULL; + + if (dbHandle == NULL) { + sftk_FreeSession(session); + return CKR_OBJECT_HANDLE_INVALID; + } + + crv = sftkdb_GetAttributeValue(dbHandle, hObject, pTemplate, ulCount); + + /* make sure we don't export any sensitive information */ + keydb = sftk_getKeyDB(slot); + if (dbHandle == keydb) { + for (i=0; i < (int) ulCount; i++) { + if (sftk_isSensitive(pTemplate[i].type,CKO_PRIVATE_KEY)) { + crv = CKR_ATTRIBUTE_SENSITIVE; + if (pTemplate[i].pValue && (pTemplate[i].ulValueLen!= -1)){ + PORT_Memset(pTemplate[i].pValue, 0, + pTemplate[i].ulValueLen); + } + pTemplate[i].ulValueLen = -1; + } + } + } + + sftk_FreeSession(session); + sftk_freeDB(dbHandle); + if (keydb) { + sftk_freeDB(keydb); + } + return crv; + } + + /* handle the session object */ object = sftk_ObjectFromHandle(hObject,session); sftk_FreeSession(session); if (object == NULL) { @@ -4420,746 +3775,164 @@ CK_RV NSC_SetAttributeValue (CK_SESSION_HANDLE hSession, return crv; } -/* - * find any certs that may match the template and load them. - */ -#define NSC_CERT 0x00000001 -#define NSC_TRUST 0x00000002 -#define NSC_CRL 0x00000004 -#define NSC_SMIME 0x00000008 -#define NSC_PRIVATE 0x00000010 -#define NSC_PUBLIC 0x00000020 -#define NSC_KEY 0x00000040 - -/* - * structure to collect key handles. - */ -typedef struct sftkCrlDataStr { - SFTKSlot *slot; - SFTKSearchResults *searchHandles; - CK_ATTRIBUTE *template; - CK_ULONG templ_count; -} sftkCrlData; - - -static SECStatus -sftk_crl_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg) -{ - sftkCrlData *crlData; - CK_OBJECT_HANDLE class_handle; - SFTKSlot *slot; - - crlData = (sftkCrlData *)arg; - slot = crlData->slot; - - class_handle = (type == certDBEntryTypeRevocation) ? SFTK_TOKEN_TYPE_CRL : - SFTK_TOKEN_KRL_HANDLE; - if (sftk_tokenMatch(slot, key, class_handle, - crlData->template, crlData->templ_count)) { - sftk_addHandle(crlData->searchHandles, - sftk_mkHandle(slot,key,class_handle)); - } - return(SECSuccess); -} - -static void -sftk_searchCrls(SFTKSlot *slot, SECItem *derSubject, PRBool isKrl, - unsigned long classFlags, SFTKSearchResults *search, - CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) +static CK_RV +sftk_expandSearchList(SFTKSearchResults *search, int count) { - NSSLOWCERTCertDBHandle *certHandle = NULL; - - certHandle = sftk_getCertDB(slot); - if (certHandle == NULL) { - return; - } - if (derSubject->data != NULL) { - certDBEntryRevocation *crl = - nsslowcert_FindCrlByKey(certHandle, derSubject, isKrl); - - if (crl != NULL) { - sftk_addHandle(search, sftk_mkHandle(slot, derSubject, - isKrl ? SFTK_TOKEN_KRL_HANDLE : SFTK_TOKEN_TYPE_CRL)); - nsslowcert_DestroyDBEntry((certDBEntry *)crl); - } - } else { - sftkCrlData crlData; - - /* traverse */ - crlData.slot = slot; - crlData.searchHandles = search; - crlData.template = pTemplate; - crlData.templ_count = ulCount; - nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeRevocation, - sftk_crl_collect, (void *)&crlData); - nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeKeyRevocation, - sftk_crl_collect, (void *)&crlData); - } - sftk_freeCertDB(certHandle); + search->array_size += count; + search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles, + sizeof(CK_OBJECT_HANDLE)*search->array_size); + return search->handles ? CKR_OK : CKR_HOST_MEMORY; } -/* - * structure to collect key handles. - */ -typedef struct sftkKeyDataStr { - SFTKSlot *slot; - NSSLOWKEYDBHandle *keyHandle; - SFTKSearchResults *searchHandles; - SECItem *id; - CK_ATTRIBUTE *template; - CK_ULONG templ_count; - unsigned long classFlags; - PRBool isLoggedIn; - PRBool strict; -} sftkKeyData; - -static SECStatus -sftk_key_collect(DBT *key, DBT *data, void *arg) -{ - sftkKeyData *keyData; - NSSLOWKEYPrivateKey *privKey = NULL; - SECItem tmpDBKey; - SFTKSlot *slot; - - keyData = (sftkKeyData *)arg; - slot = keyData->slot; - - tmpDBKey.data = key->data; - tmpDBKey.len = key->size; - tmpDBKey.type = siBuffer; - - PORT_Assert(keyData->keyHandle); - if (!keyData->strict && keyData->id) { - SECItem result; - PRBool haveMatch= PR_FALSE; - unsigned char hashKey[SHA1_LENGTH]; - result.data = hashKey; - result.len = sizeof(hashKey); - - if (keyData->id->len == 0) { - /* Make sure this isn't a NSC_KEY */ - privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, - &tmpDBKey, keyData->slot->password); - if (privKey) { - haveMatch = isSecretKey(privKey) ? - (PRBool)(keyData->classFlags & NSC_KEY) != 0: - (PRBool)(keyData->classFlags & - (NSC_PRIVATE|NSC_PUBLIC)) != 0; - nsslowkey_DestroyPrivateKey(privKey); - } - } else { - SHA1_HashBuf( hashKey, key->data, key->size ); /* match id */ - haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result); - if (!haveMatch && ((unsigned char *)key->data)[0] == 0) { - /* This is a fix for backwards compatibility. The key - * database indexes private keys by the public key, and - * versions of NSS prior to 3.4 stored the public key as - * a signed integer. The public key is now treated as an - * unsigned integer, with no leading zero. In order to - * correctly compute the hash of an old key, it is necessary - * to fallback and detect the leading zero. - */ - SHA1_HashBuf(hashKey, - (unsigned char *)key->data + 1, key->size - 1); - haveMatch = SECITEM_ItemsAreEqual(keyData->id,&result); - } - } - if (haveMatch) { - if (keyData->classFlags & NSC_PRIVATE) { - sftk_addHandle(keyData->searchHandles, - sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_PRIV)); - } - if (keyData->classFlags & NSC_PUBLIC) { - sftk_addHandle(keyData->searchHandles, - sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_PUB)); - } - if (keyData->classFlags & NSC_KEY) { - sftk_addHandle(keyData->searchHandles, - sftk_mkHandle(slot,&tmpDBKey,SFTK_TOKEN_TYPE_KEY)); - } - } - return SECSuccess; - } - privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, - keyData->slot->password); - if ( privKey == NULL ) { - goto loser; - } - - if (isSecretKey(privKey)) { - if ((keyData->classFlags & NSC_KEY) && - sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_KEY, - keyData->template, keyData->templ_count)) { - sftk_addHandle(keyData->searchHandles, - sftk_mkHandle(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_KEY)); - } - } else { - if ((keyData->classFlags & NSC_PRIVATE) && - sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_PRIV, - keyData->template, keyData->templ_count)) { - sftk_addHandle(keyData->searchHandles, - sftk_mkHandle(keyData->slot,&tmpDBKey,SFTK_TOKEN_TYPE_PRIV)); - } - if ((keyData->classFlags & NSC_PUBLIC) && - sftk_tokenMatch(keyData->slot, &tmpDBKey, SFTK_TOKEN_TYPE_PUB, - keyData->template, keyData->templ_count)) { - sftk_addHandle(keyData->searchHandles, - sftk_mkHandle(keyData->slot, &tmpDBKey,SFTK_TOKEN_TYPE_PUB)); - } - } - -loser: - if ( privKey ) { - nsslowkey_DestroyPrivateKey(privKey); - } - return(SECSuccess); -} - -static void -sftk_searchKeys(SFTKSlot *slot, SECItem *key_id, PRBool isLoggedIn, - unsigned long classFlags, SFTKSearchResults *search, PRBool mustStrict, - CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount) +static CK_RV +sftk_searchDatabase(SFTKDBHandle *handle, SFTKSearchResults *search, + const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) { - NSSLOWKEYDBHandle *keyHandle = NULL; - NSSLOWKEYPrivateKey *privKey; - sftkKeyData keyData; - PRBool found = PR_FALSE; + CK_RV crv; + int objectListSize = search->array_size-search->size; + CK_OBJECT_HANDLE *array = &search->handles[search->size]; + SDBFind *find; + CK_ULONG count; - keyHandle = sftk_getKeyDB(slot); - if (keyHandle == NULL) { - return; - } + crv = sftkdb_FindObjectsInit(handle, pTemplate, ulCount, &find); + if (crv != CKR_OK) + return crv; + do { + crv = sftkdb_FindObjects(handle, find, array, objectListSize, &count); + if ((crv != CKR_OK) || (count == 0)) + break; + search->size += count; + objectListSize -= count; + if (objectListSize > 0) + break; + crv = sftk_expandSearchList(search,NSC_SEARCH_BLOCK_SIZE); + objectListSize = NSC_SEARCH_BLOCK_SIZE; + array = &search->handles[search->size]; + } while (crv == CKR_OK); + sftkdb_FindObjectsFinal(handle, find); - if (key_id->data) { - privKey = nsslowkey_FindKeyByPublicKey(keyHandle, key_id, slot->password); - if (privKey) { - if ((classFlags & NSC_KEY) && isSecretKey(privKey)) { - sftk_addHandle(search, - sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_KEY)); - found = PR_TRUE; - } - if ((classFlags & NSC_PRIVATE) && !isSecretKey(privKey)) { - sftk_addHandle(search, - sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_PRIV)); - found = PR_TRUE; - } - if ((classFlags & NSC_PUBLIC) && !isSecretKey(privKey)) { - sftk_addHandle(search, - sftk_mkHandle(slot,key_id,SFTK_TOKEN_TYPE_PUB)); - found = PR_TRUE; - } - nsslowkey_DestroyPrivateKey(privKey); - } - /* don't do the traversal if we have an up to date db */ - if (keyHandle->version != 3) { - 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) { - goto loser; - } - if (found) { - /* if we already found some keys, don't do the traversal */ - goto loser; - } - } - keyData.slot = slot; - keyData.keyHandle = keyHandle; - keyData.searchHandles = search; - keyData.id = key_id; - keyData.template = pTemplate; - keyData.templ_count = ulCount; - keyData.isLoggedIn = isLoggedIn; - keyData.classFlags = classFlags; - keyData.strict = mustStrict ? mustStrict : NSC_STRICT; - - nsslowkey_TraverseKeys(keyHandle, sftk_key_collect, &keyData); -loser: - sftk_freeKeyDB(keyHandle); - + return crv; } -/* - * structure to collect certs into +/* softoken used to search the SMimeEntries automatically instead of + * doing this in pk11wrap. This code should really be up in + * pk11wrap so that it will work with other tokens other than softoken. */ -typedef struct sftkCertDataStr { - SFTKSlot *slot; - int cert_count; - int max_cert_count; - NSSLOWCERTCertificate **certs; - CK_ATTRIBUTE *template; - CK_ULONG templ_count; - unsigned long classFlags; - PRBool strict; -} sftkCertData; - -/* - * collect all the certs from the traverse call. - */ -static SECStatus -sftk_cert_collect(NSSLOWCERTCertificate *cert,void *arg) +CK_RV +sftk_emailhack(SFTKSlot *slot, SFTKDBHandle *handle, + SFTKSearchResults *search, CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) { - sftkCertData *cd = (sftkCertData *)arg; + PRBool isCert = PR_FALSE; + int emailIndex = -1; + int i; + SFTKSearchResults smime_search; + CK_ATTRIBUTE smime_template[2]; + CK_OBJECT_CLASS smime_class = CKO_NETSCAPE_SMIME; + SFTKAttribute *attribute = NULL; + SFTKObject *object = NULL; + CK_RV crv = CKR_OK; - if (cert == NULL) { - return SECSuccess; - } - if (cd->certs == NULL) { - return SECFailure; - } + smime_search.handles = NULL; /* paranoia, some one is bound to add a goto + * loser before this gets initialized */ - if (cd->strict) { - if ((cd->classFlags & NSC_CERT) && !sftk_tokenMatch(cd->slot, - &cert->certKey, SFTK_TOKEN_TYPE_CERT, cd->template,cd->templ_count)) { - return SECSuccess; - } - if ((cd->classFlags & NSC_TRUST) && !sftk_tokenMatch(cd->slot, - &cert->certKey, SFTK_TOKEN_TYPE_TRUST, - cd->template, cd->templ_count)) { - return SECSuccess; + /* see if we are looking for email certs */ + for (i=0; i < ulCount; i++) { + if (pTemplate[i].type == CKA_CLASS) { + if ((pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS) || + (*(CK_OBJECT_CLASS *)pTemplate[i].pValue) != CKO_CERTIFICATE)) { + /* not a cert, skip out */ + break; + } + isCert = PR_TRUE; + } else if (pTemplate[i].type == CKA_NETSCAPE_EMAIL) { + emailIndex = i; + } + if (isCert && (emailIndex != -1)) break; } - /* allocate more space if we need it. This should only happen in - * the general traversal case */ - if (cd->cert_count >= cd->max_cert_count) { - int size; - cd->max_cert_count += NSC_CERT_BLOCK_SIZE; - size = cd->max_cert_count * sizeof (NSSLOWCERTCertificate *); - cd->certs = (NSSLOWCERTCertificate **)PORT_Realloc(cd->certs,size); - if (cd->certs == NULL) { - return SECFailure; - } + if (!isCert || (emailIndex == -1)) { + return CKR_OK; } - cd->certs[cd->cert_count++] = nsslowcert_DupCertificate(cert); - return SECSuccess; -} - -/* provide impedence matching ... */ -static SECStatus -sftk_cert_collect2(NSSLOWCERTCertificate *cert, SECItem *dymmy, void *arg) -{ - return sftk_cert_collect(cert, arg); -} + /* we are doing a cert and email search, find the SMimeEntry */ + smime_template[0].type = CKA_CLASS; + smime_template[0].pValue = &smime_class; + smime_template[0].ulValueLen = sizeof(smime_class); + smime_template[1] = pTemplate[emailIndex]; -static void -sftk_searchSingleCert(sftkCertData *certData,NSSLOWCERTCertificate *cert) -{ - if (cert == NULL) { - return; - } - if (certData->strict && - !sftk_tokenMatch(certData->slot, &cert->certKey, SFTK_TOKEN_TYPE_CERT, - certData->template,certData->templ_count)) { - nsslowcert_DestroyCertificate(cert); - return; + smime_search.handles = (CK_OBJECT_HANDLE *) + PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE); + if (smime_search.handles == NULL) { + crv = CKR_HOST_MEMORY; + goto loser; } - certData->certs = (NSSLOWCERTCertificate **) - PORT_Alloc(sizeof (NSSLOWCERTCertificate *)); - if (certData->certs == NULL) { - nsslowcert_DestroyCertificate(cert); - return; + smime_search.index = 0; + smime_search.size = 0; + smime_search.array_size = NSC_SEARCH_BLOCK_SIZE; + + crv = sftk_searchDatabase(handle, &smime_search, smime_template, 2); + if (crv != CKR_OK || smime_search.size == 0) { + goto loser; } - certData->certs[0] = cert; - certData->cert_count = 1; -} - -static void -sftk_CertSetupData(sftkCertData *certData,int count) -{ - certData->max_cert_count = count; - if (certData->max_cert_count <= 0) { - return; + /* get the SMime subject */ + object = sftk_NewTokenObject(slot, NULL, smime_search.handles[0]); + if (object == NULL) { + crv = CKR_HOST_MEMORY; /* is there any other reason for this failure? */ + goto loser; + } + attribute = sftk_FindAttribute(object,CKA_SUBJECT); + if (attribute == NULL) { + crv = CKR_ATTRIBUTE_TYPE_INVALID; + goto loser; } - certData->certs = (NSSLOWCERTCertificate **) - PORT_Alloc( count * sizeof(NSSLOWCERTCertificate *)); - return; -} - -static void -sftk_searchCertsAndTrust(SFTKSlot *slot, SECItem *derCert, SECItem *name, - SECItem *derSubject, NSSLOWCERTIssuerAndSN *issuerSN, - SECItem *email, - unsigned long classFlags, SFTKSearchResults *handles, - CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) -{ - NSSLOWCERTCertDBHandle *certHandle = NULL; - sftkCertData certData; - int i; - - certHandle = sftk_getCertDB(slot); - if (certHandle == NULL) return; - - certData.slot = slot; - certData.max_cert_count = 0; - certData.certs = NULL; - certData.cert_count = 0; - certData.template = pTemplate; - certData.templ_count = ulCount; - certData.classFlags = classFlags; - certData.strict = NSC_STRICT; - - - /* - * Find the Cert. - */ - if (derCert->data != NULL) { - NSSLOWCERTCertificate *cert = - nsslowcert_FindCertByDERCert(certHandle,derCert); - sftk_searchSingleCert(&certData,cert); - } else if (name->data != NULL) { - char *tmp_name = (char*)PORT_Alloc(name->len+1); - int count; - - if (tmp_name == NULL) { - return; - } - PORT_Memcpy(tmp_name,name->data,name->len); - tmp_name[name->len] = 0; - - count= nsslowcert_NumPermCertsForNickname(certHandle,tmp_name); - sftk_CertSetupData(&certData,count); - nsslowcert_TraversePermCertsForNickname(certHandle,tmp_name, - sftk_cert_collect, &certData); - PORT_Free(tmp_name); - } else if (derSubject->data != NULL) { - int count; - - count = nsslowcert_NumPermCertsForSubject(certHandle,derSubject); - sftk_CertSetupData(&certData,count); - nsslowcert_TraversePermCertsForSubject(certHandle,derSubject, - sftk_cert_collect, &certData); - } else if ((issuerSN->derIssuer.data != NULL) && - (issuerSN->serialNumber.data != NULL)) { - if (classFlags & NSC_CERT) { - NSSLOWCERTCertificate *cert = - nsslowcert_FindCertByIssuerAndSN(certHandle,issuerSN); - - sftk_searchSingleCert(&certData,cert); - } - if (classFlags & NSC_TRUST) { - NSSLOWCERTTrust *trust = - nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN); - - if (trust) { - sftk_addHandle(handles, - sftk_mkHandle(slot,&trust->dbKey,SFTK_TOKEN_TYPE_TRUST)); - nsslowcert_DestroyTrust(trust); - } - } - } else if (email->data != NULL) { - char *tmp_name = (char*)PORT_Alloc(email->len+1); - certDBEntrySMime *entry = NULL; - - if (tmp_name == NULL) { - return; - } - PORT_Memcpy(tmp_name,email->data,email->len); - tmp_name[email->len] = 0; - - entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name); - if (entry) { - int count; - SECItem *subjectName = &entry->subjectName; - count = nsslowcert_NumPermCertsForSubject(certHandle, subjectName); - sftk_CertSetupData(&certData,count); - nsslowcert_TraversePermCertsForSubject(certHandle, subjectName, - sftk_cert_collect, &certData); + /* now find the certs with that subject */ + pTemplate[emailIndex] = attribute->attrib; + /* now add the appropriate certs to the search list */ + crv = sftk_searchDatabase(handle, search, pTemplate, ulCount); + pTemplate[emailIndex] = smime_template[1]; /* restore the user's template*/ - nsslowcert_DestroyDBEntry((certDBEntry *)entry); - } - PORT_Free(tmp_name); - } else { - /* we aren't filtering the certs, we are working on all, so turn - * on the strict filters. */ - certData.strict = PR_TRUE; - sftk_CertSetupData(&certData,NSC_CERT_BLOCK_SIZE); - nsslowcert_TraversePermCerts(certHandle, sftk_cert_collect2, &certData); +loser: + if (attribute) { + sftk_FreeAttribute(attribute); } - sftk_freeCertDB(certHandle); - - /* - * build the handles - */ - for (i=0 ; i < certData.cert_count ; i++) { - NSSLOWCERTCertificate *cert = certData.certs[i]; - - /* if we filtered it would have been on the stuff above */ - if (classFlags & NSC_CERT) { - sftk_addHandle(handles, - sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_CERT)); - } - if ((classFlags & NSC_TRUST) && nsslowcert_hasTrust(cert->trust)) { - sftk_addHandle(handles, - sftk_mkHandle(slot,&cert->certKey,SFTK_TOKEN_TYPE_TRUST)); - } - nsslowcert_DestroyCertificate(cert); + if (object) { + sftk_FreeObject(object); } - - if (certData.certs) PORT_Free(certData.certs); - return; -} - -static void -sftk_searchSMime(SFTKSlot *slot, SECItem *email, SFTKSearchResults *handles, - CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) -{ - NSSLOWCERTCertDBHandle *certHandle = NULL; - certDBEntrySMime *entry; - - 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); - tmp_name[email->len] = 0; - - entry = nsslowcert_ReadDBSMimeEntry(certHandle,tmp_name); - if (entry) { - SECItem emailKey; - - emailKey.data = (unsigned char *)tmp_name; - emailKey.len = PORT_Strlen(tmp_name)+1; - emailKey.type = 0; - sftk_addHandle(handles, - sftk_mkHandle(slot,&emailKey,SFTK_TOKEN_TYPE_SMIME)); - nsslowcert_DestroyDBEntry((certDBEntry *)entry); - } - PORT_Free(tmp_name); + if (smime_search.handles) { + PORT_Free(smime_search.handles); } - sftk_freeCertDB(certHandle); - return; + + return crv; } + static CK_RV sftk_searchTokenList(SFTKSlot *slot, SFTKSearchResults *search, - CK_ATTRIBUTE *pTemplate, CK_LONG ulCount, - PRBool *tokenOnly, PRBool isLoggedIn) + CK_ATTRIBUTE *pTemplate, CK_LONG ulCount, + PRBool *tokenOnly, PRBool isLoggedIn) { - int i; - PRBool isKrl = PR_FALSE; - SECItem derCert = { siBuffer, NULL, 0 }; - SECItem derSubject = { siBuffer, NULL, 0 }; - SECItem name = { siBuffer, NULL, 0 }; - SECItem email = { siBuffer, NULL, 0 }; - SECItem key_id = { siBuffer, NULL, 0 }; - SECItem cert_sha1_hash = { siBuffer, NULL, 0 }; - SECItem cert_md5_hash = { siBuffer, NULL, 0 }; - NSSLOWCERTIssuerAndSN issuerSN = { - { siBuffer, NULL, 0 }, - { siBuffer, NULL, 0 } - }; - SECItem *copy = NULL; - unsigned long classFlags = - NSC_CERT|NSC_TRUST|NSC_PRIVATE|NSC_PUBLIC|NSC_KEY|NSC_SMIME|NSC_CRL; - - /* if we aren't logged in, don't look for private or secret keys */ - if (!isLoggedIn) { - classFlags &= ~(NSC_PRIVATE|NSC_KEY); - } - - /* - * look for things to search on token objects for. If the right options - * are specified, we can use them as direct indeces into the database - * (rather than using linear searches. We can also use the attributes to - * limit the kinds of objects we are searching for. Later we can use this - * array to filter the remaining objects more finely. - */ - for (i=0 ;classFlags && i < (int)ulCount; i++) { - - switch (pTemplate[i].type) { - case CKA_SUBJECT: - copy = &derSubject; - classFlags &= (NSC_CERT|NSC_PRIVATE|NSC_PUBLIC|NSC_SMIME|NSC_CRL); - break; - case CKA_ISSUER: - copy = &issuerSN.derIssuer; - classFlags &= (NSC_CERT|NSC_TRUST); - break; - case CKA_SERIAL_NUMBER: - copy = &issuerSN.serialNumber; - classFlags &= (NSC_CERT|NSC_TRUST); - break; - case CKA_VALUE: - copy = &derCert; - classFlags &= (NSC_CERT|NSC_CRL|NSC_SMIME); - break; - case CKA_LABEL: - copy = &name; - break; - case CKA_NETSCAPE_EMAIL: - copy = &email; - classFlags &= NSC_SMIME|NSC_CERT; - break; - case CKA_NETSCAPE_SMIME_TIMESTAMP: - classFlags &= NSC_SMIME; - break; - case CKA_CLASS: - if (pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS)) { - classFlags = 0; - break;; - } - switch (*((CK_OBJECT_CLASS *)pTemplate[i].pValue)) { - case CKO_CERTIFICATE: - classFlags &= NSC_CERT; - break; - case CKO_NETSCAPE_TRUST: - classFlags &= NSC_TRUST; - break; - case CKO_NETSCAPE_CRL: - classFlags &= NSC_CRL; - break; - case CKO_NETSCAPE_SMIME: - classFlags &= NSC_SMIME; - break; - case CKO_PRIVATE_KEY: - classFlags &= NSC_PRIVATE; - break; - case CKO_PUBLIC_KEY: - classFlags &= NSC_PUBLIC; - break; - case CKO_SECRET_KEY: - classFlags &= NSC_KEY; - break; - default: - classFlags = 0; - break; - } - break; - case CKA_PRIVATE: - if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { - classFlags = 0; - } - if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) { - classFlags &= (NSC_PRIVATE|NSC_KEY); - } else { - classFlags &= ~(NSC_PRIVATE|NSC_KEY); - } - break; - case CKA_SENSITIVE: - if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { - classFlags = 0; - } - if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) { - classFlags &= (NSC_PRIVATE|NSC_KEY); - } else { - classFlags = 0; - } - break; - case CKA_TOKEN: - if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { - classFlags = 0; - } - if (*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE) { - *tokenOnly = PR_TRUE; - } else { - classFlags = 0; - } - break; - case CKA_CERT_SHA1_HASH: - classFlags &= NSC_TRUST; - copy = &cert_sha1_hash; break; - case CKA_CERT_MD5_HASH: - classFlags &= NSC_TRUST; - copy = &cert_md5_hash; break; - case CKA_CERTIFICATE_TYPE: - if (pTemplate[i].ulValueLen != sizeof(CK_CERTIFICATE_TYPE)) { - classFlags = 0; - } - classFlags &= NSC_CERT; - if (*((CK_CERTIFICATE_TYPE *)pTemplate[i].pValue) != CKC_X_509) { - classFlags = 0; - } - break; - case CKA_ID: - copy = &key_id; - classFlags &= (NSC_CERT|NSC_PRIVATE|NSC_KEY|NSC_PUBLIC); - break; - case CKA_NETSCAPE_KRL: - if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL)) { - classFlags = 0; - } - classFlags &= NSC_CRL; - isKrl = (PRBool)(*((CK_BBOOL *)pTemplate[i].pValue) == CK_TRUE); - break; - case CKA_MODIFIABLE: - break; - case CKA_KEY_TYPE: - case CKA_DERIVE: - classFlags &= NSC_PUBLIC|NSC_PRIVATE|NSC_KEY; - break; - case CKA_VERIFY_RECOVER: - classFlags &= NSC_PUBLIC; - break; - case CKA_SIGN_RECOVER: - classFlags &= NSC_PRIVATE; - break; - case CKA_ENCRYPT: - case CKA_VERIFY: - case CKA_WRAP: - classFlags &= NSC_PUBLIC|NSC_KEY; - break; - case CKA_DECRYPT: - case CKA_SIGN: - case CKA_UNWRAP: - case CKA_ALWAYS_SENSITIVE: - case CKA_EXTRACTABLE: - case CKA_NEVER_EXTRACTABLE: - classFlags &= NSC_PRIVATE|NSC_KEY; - break; - /* can't be a certificate if it doesn't match one of the above - * attributes */ - default: - classFlags = 0; - break; - } - if (copy) { - copy->data = (unsigned char*)pTemplate[i].pValue; - copy->len = pTemplate[i].ulValueLen; - } - copy = NULL; - } - - - /* certs */ - if (classFlags & (NSC_CERT|NSC_TRUST)) { - sftk_searchCertsAndTrust(slot,&derCert,&name,&derSubject, - &issuerSN, &email,classFlags,search, - pTemplate, ulCount); - } + CK_RV crv; + CK_RV crv2; + SFTKDBHandle *certHandle = sftk_getCertDB(slot); - /* keys */ - if (classFlags & (NSC_PRIVATE|NSC_PUBLIC|NSC_KEY)) { - PRBool mustStrict = ((classFlags & NSC_KEY) != 0) && (name.len != 0); - sftk_searchKeys(slot, &key_id, isLoggedIn, classFlags, search, - mustStrict, pTemplate, ulCount); - } + crv = sftk_searchDatabase(certHandle, search, pTemplate, ulCount); + crv2 = sftk_emailhack(slot, certHandle, search, pTemplate, ulCount); + if (crv == CKR_OK) crv2 = crv; + sftk_freeDB(certHandle); - /* crl's */ - if (classFlags & NSC_CRL) { - sftk_searchCrls(slot, &derSubject, isKrl, classFlags, search, - pTemplate, ulCount); - } - /* Add S/MIME entry stuff */ - if (classFlags & NSC_SMIME) { - sftk_searchSMime(slot, &email, search, pTemplate, ulCount); + if (crv == CKR_OK && isLoggedIn) { + SFTKDBHandle *keyHandle = sftk_getKeyDB(slot); + crv = sftk_searchDatabase(keyHandle, search, pTemplate, ulCount); + sftk_freeDB(keyHandle); } - return CKR_OK; + return crv; } - /* NSC_FindObjectsInit initializes a search for token and session objects * that match a template. */ @@ -5207,8 +3980,8 @@ CK_RV NSC_FindObjectsInit(CK_SESSION_HANDLE hSession, /* build list of found objects in the session */ if (!tokenOnly) { crv = sftk_searchObjectList(search, slot->sessObjHashTable, - slot->sessObjHashSize, slot->objectLock, - pTemplate, ulCount, isLoggedIn); + slot->sessObjHashSize, slot->objectLock, + pTemplate, ulCount, isLoggedIn); } if (crv != CKR_OK) { goto loser; diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index cfd1e7cb0..df149a9ea 100644 --- a/security/nss/lib/softoken/pkcs11c.c +++ b/security/nss/lib/softoken/pkcs11c.c @@ -59,7 +59,6 @@ #include "pkcs11.h" #include "pkcs11i.h" #include "lowkeyi.h" -#include "pcert.h" #include "sechash.h" #include "secder.h" #include "secdig.h" @@ -71,7 +70,6 @@ #include "secasn1.h" #include "secerr.h" -#include "pcert.h" #include "ssl3prot.h" /* for SSL3_RANDOM_LENGTH */ #include "prprf.h" @@ -97,8 +95,6 @@ static void sftk_Null(void *data, PRBool freeit) } #ifdef NSS_ENABLE_ECC -extern SECStatus EC_DecodeParams(const SECItem *encodedParams, - ECParams **ecparams); #ifdef EC_DEBUG #define SEC_PRINT(str1, str2, num, sitem) \ printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \ diff --git a/security/nss/lib/softoken/pkcs11i.h b/security/nss/lib/softoken/pkcs11i.h index 8abc03ed8..71b0ccce3 100644 --- a/security/nss/lib/softoken/pkcs11i.h +++ b/security/nss/lib/softoken/pkcs11i.h @@ -44,7 +44,8 @@ #include "secoidt.h" #include "lowkeyti.h" #include "pkcs11t.h" -#include "pcertt.h" + +#include "sftkdbt.h" /* @@ -348,7 +349,6 @@ struct SFTKSlotStr { 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 */ @@ -357,8 +357,8 @@ struct SFTKSlotStr { PRBool DB_loaded; /* per load */ PRBool readOnly; /* per load */ PRBool optimizeSpace; /* invariant */ - NSSLOWCERTCertDBHandle *certDB; /* per load */ - NSSLOWKEYDBHandle *keyDB; /* per load */ + SFTKDBHandle *certDB; /* per load */ + SFTKDBHandle *keyDB; /* per load */ int minimumPinLen; /* per load */ PRInt32 sessionIDCount; /* atomically incremented */ /* (preserved) */ @@ -367,7 +367,7 @@ struct SFTKSlotStr { int sessionCount; /* variable - reset */ PRInt32 rwSessionCount; /* set by atomic operations */ /* (reset) */ - PRUint32 sessionObjectHandleCount; /* variable - preserved */ + int sessionObjectHandleCount;/* variable - perserved */ int index; /* invariant */ PLHashTable *tokObjHashTable; /* invariant */ SFTKObject **sessObjHashTable; /* variable - reset */ @@ -650,53 +650,13 @@ extern void sftk_FormatDESKey(unsigned char *key, int length); extern PRBool sftk_CheckDESKey(unsigned char *key); extern PRBool sftk_IsWeakKey(unsigned char *key,CK_KEY_TYPE key_type); -extern CK_RV secmod_parseParameters(char *param, sftk_parameters *parsed, - PRBool isFIPS); -extern void secmod_freeParams(sftk_parameters *params); -extern char *secmod_getSecmodName(char *params, char **domain, - char **filename, PRBool *rw); -extern char ** secmod_ReadPermDB(const char *domain, const char *filename, - const char *dbname, char *params, PRBool rw); -extern SECStatus secmod_DeletePermDB(const char *domain, const char *filename, - const char *dbname, char *args, PRBool rw); -extern SECStatus secmod_AddPermDB(const char *domain, const char *filename, - const char *dbname, char *module, PRBool rw); -extern SECStatus secmod_ReleasePermDBData(const char *domain, - const char *filename, const char *dbname, char **specList, PRBool rw); /* mechanism allows this operation */ extern CK_RV sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op); -/* - * OK there are now lots of options here, lets go through them all: - * - * configdir - base directory where all the cert, key, and module datbases live. - * certPrefix - prefix added to the beginning of the cert database example: " - * "https-server1-" - * keyPrefix - prefix added to the beginning of the key database example: " - * "https-server1-" - * secmodName - name of the security module database (usually "secmod.db"). - * readOnly - Boolean: true if the databases are to be openned read only. - * nocertdb - Don't open the cert DB and key DB's, just initialize the - * Volatile certdb. - * nomoddb - Don't open the security module DB, just initialize the - * PKCS #11 module. - * forceOpen - Continue to force initializations even if the databases cannot - * be opened. - */ -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); -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); - /* * narrow objects */ @@ -709,10 +669,6 @@ SFTKTokenObject * sftk_narrowToTokenObject(SFTKObject *); void sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle); PRBool sftk_poisonHandle(SFTKSlot *slot, SECItem *dbkey, CK_OBJECT_HANDLE handle); -PRBool sftk_tokenMatch(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class, - CK_ATTRIBUTE_PTR theTemplate,int count); -CK_OBJECT_HANDLE sftk_mkHandle(SFTKSlot *slot, - SECItem *dbKey, CK_OBJECT_HANDLE class); SFTKObject * sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle); SFTKTokenObject *sftk_convertSessionToToken(SFTKObject *so); diff --git a/security/nss/lib/softoken/pkcs11n.h b/security/nss/lib/softoken/pkcs11n.h index b1dce6c12..6167c01b5 100644 --- a/security/nss/lib/softoken/pkcs11n.h +++ b/security/nss/lib/softoken/pkcs11n.h @@ -50,10 +50,10 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; */ /* - * NSSCK_VENDOR_NETSCAPE + * NSSCK_VENDOR_NSS * * Cryptoki reserves the high half of all the number spaces for - * vendor-defined use. I'd like to keep all of our Netscape- + * vendor-defined use. I'd like to keep all of our NSS- * specific values together, but not in the oh-so-obvious * 0x80000001, 0x80000002, etc. area. So I've picked an offset, * and constructed values for the beginnings of our spaces. @@ -61,54 +61,56 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; * Note that some "historical" Netscape values don't fall within * this range. */ -#define NSSCK_VENDOR_NETSCAPE 0x4E534350 /* NSCP */ +#define NSSCK_VENDOR_NSS 0x4E534350 /* NSCP */ /* - * Netscape-defined object classes + * NSS-defined object classes * */ -#define CKO_NETSCAPE (CKO_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) +#define CKO_NSS (CKO_VENDOR_DEFINED|NSSCK_VENDOR_NSS) + +#define CKO_NSS_CRL (CKO_NSS + 1) +#define CKO_NSS_SMIME (CKO_NSS + 2) +#define CKO_NSS_TRUST (CKO_NSS + 3) +#define CKO_NSS_BUILTIN_ROOT_LIST (CKO_NSS + 4) +#define CKO_NSS_NEWSLOT (CKO_NSS + 5) +#define CKO_NSS_DELSLOT (CKO_NSS + 6) -#define CKO_NETSCAPE_CRL (CKO_NETSCAPE + 1) -#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 + * NSS-defined key types * */ -#define CKK_NETSCAPE (CKK_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) +#define CKK_NSS (CKK_VENDOR_DEFINED|NSSCK_VENDOR_NSS) -#define CKK_NETSCAPE_PKCS8 (CKK_NETSCAPE + 1) +#define CKK_NSS_PKCS8 (CKK_NSS + 1) /* - * Netscape-defined certificate types + * NSS-defined certificate types * */ -#define CKC_NETSCAPE (CKC_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) +#define CKC_NSS (CKC_VENDOR_DEFINED|NSSCK_VENDOR_NSS) /* - * Netscape-defined object attributes + * NSS-defined object attributes * */ -#define CKA_NETSCAPE (CKA_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) - -#define CKA_NETSCAPE_URL (CKA_NETSCAPE + 1) -#define CKA_NETSCAPE_EMAIL (CKA_NETSCAPE + 2) -#define CKA_NETSCAPE_SMIME_INFO (CKA_NETSCAPE + 3) -#define CKA_NETSCAPE_SMIME_TIMESTAMP (CKA_NETSCAPE + 4) -#define CKA_NETSCAPE_PKCS8_SALT (CKA_NETSCAPE + 5) -#define CKA_NETSCAPE_PASSWORD_CHECK (CKA_NETSCAPE + 6) -#define CKA_NETSCAPE_EXPIRES (CKA_NETSCAPE + 7) -#define CKA_NETSCAPE_KRL (CKA_NETSCAPE + 8) - -#define CKA_NETSCAPE_PQG_COUNTER (CKA_NETSCAPE + 20) -#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) +#define CKA_NSS (CKA_VENDOR_DEFINED|NSSCK_VENDOR_NSS) + +#define CKA_NSS_URL (CKA_NSS + 1) +#define CKA_NSS_EMAIL (CKA_NSS + 2) +#define CKA_NSS_SMIME_INFO (CKA_NSS + 3) +#define CKA_NSS_SMIME_TIMESTAMP (CKA_NSS + 4) +#define CKA_NSS_PKCS8_SALT (CKA_NSS + 5) +#define CKA_NSS_PASSWORD_CHECK (CKA_NSS + 6) +#define CKA_NSS_EXPIRES (CKA_NSS + 7) +#define CKA_NSS_KRL (CKA_NSS + 8) + +#define CKA_NSS_PQG_COUNTER (CKA_NSS + 20) +#define CKA_NSS_PQG_SEED (CKA_NSS + 21) +#define CKA_NSS_PQG_H (CKA_NSS + 22) +#define CKA_NSS_PQG_SEED_BITS (CKA_NSS + 23) +#define CKA_NSS_MODULE_SPEC (CKA_NSS + 24) +#define CKA_NSS_OVERRIDE_EXTENSIONS (CKA_NSS + 25) /* * Trust attributes: @@ -117,7 +119,7 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; * put them all in one place. */ -#define CKA_TRUST (CKA_NETSCAPE + 0x2000) +#define CKA_TRUST (CKA_NSS + 0x2000) /* "Usage" key information */ #define CKA_TRUST_DIGITAL_SIGNATURE (CKA_TRUST + 1) @@ -142,7 +144,7 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; #define CKA_CERT_SHA1_HASH (CKA_TRUST + 100) #define CKA_CERT_MD5_HASH (CKA_TRUST + 101) -/* Netscape trust stuff */ +/* NSS trust stuff */ /* XXX fgmr new ones here-- step-up, etc. */ /* HISTORICAL: define used to pass in the database key for DSA private keys */ @@ -150,13 +152,13 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; #define CKA_NETSCAPE_TRUST 0x80000001L /* - * Netscape-defined crypto mechanisms + * NSS-defined crypto mechanisms * */ -#define CKM_NETSCAPE (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) +#define CKM_NSS (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NSS) -#define CKM_NETSCAPE_AES_KEY_WRAP (CKM_NETSCAPE + 1) -#define CKM_NETSCAPE_AES_KEY_WRAP_PAD (CKM_NETSCAPE + 2) +#define CKM_NSS_AES_KEY_WRAP (CKM_NSS + 1) +#define CKM_NSS_AES_KEY_WRAP_PAD (CKM_NSS + 2) /* * HISTORICAL: @@ -178,13 +180,13 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; #define CKM_TLS_PRF_GENERAL 0x80000373L /* - * Netscape-defined return values + * NSS-defined return values * */ -#define CKR_NETSCAPE (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) +#define CKR_NSS (CKM_VENDOR_DEFINED|NSSCK_VENDOR_NSS) -#define CKR_NETSCAPE_CERTDB_FAILED (CKR_NETSCAPE + 1) -#define CKR_NETSCAPE_KEYDB_FAILED (CKR_NETSCAPE + 2) +#define CKR_NSS_CERTDB_FAILED (CKR_NSS + 1) +#define CKR_NSS_KEYDB_FAILED (CKR_NSS + 2) /* * Trust info @@ -192,7 +194,7 @@ static const char CKT_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$"; * This isn't part of the Cryptoki standard (yet), so I'm putting * all the definitions here. Some of this would move to nssckt.h * if trust info were made part of the standard. In view of this - * possibility, I'm putting my (Netscape) values in the netscape + * possibility, I'm putting my (NSS) values in the NSS * vendor space, like everything else. */ @@ -201,22 +203,55 @@ typedef CK_ULONG CK_TRUST; /* The following trust types are defined: */ #define CKT_VENDOR_DEFINED 0x80000000 -#define CKT_NETSCAPE (CKT_VENDOR_DEFINED|NSSCK_VENDOR_NETSCAPE) +#define CKT_NSS (CKT_VENDOR_DEFINED|NSSCK_VENDOR_NSS) /* If trust goes standard, these'll probably drop out of vendor space. */ -#define CKT_NETSCAPE_TRUSTED (CKT_NETSCAPE + 1) -#define CKT_NETSCAPE_TRUSTED_DELEGATOR (CKT_NETSCAPE + 2) -#define CKT_NETSCAPE_UNTRUSTED (CKT_NETSCAPE + 3) -#define CKT_NETSCAPE_MUST_VERIFY (CKT_NETSCAPE + 4) -#define CKT_NETSCAPE_TRUST_UNKNOWN (CKT_NETSCAPE + 5) /* default */ +#define CKT_NSS_TRUSTED (CKT_NSS + 1) +#define CKT_NSS_TRUSTED_DELEGATOR (CKT_NSS + 2) +#define CKT_NSS_UNTRUSTED (CKT_NSS + 3) +#define CKT_NSS_MUST_VERIFY (CKT_NSS + 4) +#define CKT_NSS_TRUST_UNKNOWN (CKT_NSS + 5) /* default */ /* - * These may well remain Netscape-specific; I'm only using them + * These may well remain NSS-specific; I'm only using them * to cache resolution data. */ -#define CKT_NETSCAPE_VALID (CKT_NETSCAPE + 10) -#define CKT_NETSCAPE_VALID_DELEGATOR (CKT_NETSCAPE + 11) - +#define CKT_NSS_VALID (CKT_NSS + 10) +#define CKT_NSS_VALID_DELEGATOR (CKT_NSS + 11) + +/* don't leave old programs in a lurch just yet, give them the old NETSCAPE + * synonym */ +#define CKO_NETSCAPE_CRL CKO_NSS_CRL +#define CKO_NETSCAPE_SMIME CKO_NSS_SMIME +#define CKO_NETSCAPE_TRUST CKO_NSS_TRUST +#define CKO_NETSCAPE_BUILTIN_ROOT_LIST CKO_NSS_BUILTIN_ROOT_LIST +#define CKO_NETSCAPE_NEWSLOT CKO_NSS_NEWSLOT +#define CKO_NETSCAPE_DELSLOT CKO_NSS_DELSLOT +#define CKK_NETSCAPE_PKCS8 CKK_NSS_PKCS8 +#define CKA_NETSCAPE_URL CKA_NSS_URL +#define CKA_NETSCAPE_EMAIL CKA_NSS_EMAIL +#define CKA_NETSCAPE_SMIME_INFO CKA_NSS_SMIME_INFO +#define CKA_NETSCAPE_SMIME_TIMESTAMP CKA_NSS_SMIME_TIMESTAMP +#define CKA_NETSCAPE_PKCS8_SALT CKA_NSS_PKCS8_SALT +#define CKA_NETSCAPE_PASSWORD_CHECK CKA_NSS_PASSWORD_CHECK +#define CKA_NETSCAPE_EXPIRES CKA_NSS_EXPIRES +#define CKA_NETSCAPE_KRL CKA_NSS_KRL +#define CKA_NETSCAPE_PQG_COUNTER CKA_NSS_PQG_COUNTER +#define CKA_NETSCAPE_PQG_SEED CKA_NSS_PQG_SEED +#define CKA_NETSCAPE_PQG_H CKA_NSS_PQG_H +#define CKA_NETSCAPE_PQG_SEED_BITS CKA_NSS_PQG_SEED_BITS +#define CKA_NETSCAPE_MODULE_SPEC CKA_NSS_MODULE_SPEC +#define CKM_NETSCAPE_AES_KEY_WRAP CKM_NSS_AES_KEY_WRAP +#define CKM_NETSCAPE_AES_KEY_WRAP_PAD CKM_NSS_AES_KEY_WRAP_PAD +#define CKR_NETSCAPE_CERTDB_FAILED CKR_NSS_CERTDB_FAILED +#define CKR_NETSCAPE_KEYDB_FAILED CKR_NSS_KEYDB_FAILED +#define CKT_NETSCAPE_TRUSTED CKT_NSS_TRUSTED +#define CKT_NETSCAPE_TRUSTED_DELEGATOR CKT_NSS_TRUSTED_DELEGATOR +#define CKT_NETSCAPE_UNTRUSTED CKT_NSS_UNTRUSTED +#define CKT_NETSCAPE_MUST_VERIFY CKT_NSS_MUST_VERIFY +#define CKT_NETSCAPE_TRUST_UNKNOWN CKT_NSS_TRUST_UNKNOWN +#define CKT_NETSCAPE_VALID CKT_NSS_VALID +#define CKT_NETSCAPE_VALID_DELEGATOR CKT_NSS_VALID_DELEGATOR /* * These are not really PKCS #11 values specifically. They are the 'loadable' diff --git a/security/nss/lib/softoken/pkcs11t.h b/security/nss/lib/softoken/pkcs11t.h index 1eef6bf61..7f8009e40 100644 --- a/security/nss/lib/softoken/pkcs11t.h +++ b/security/nss/lib/softoken/pkcs11t.h @@ -912,12 +912,12 @@ typedef CK_ULONG CK_MECHANISM_TYPE; #define CKM_TWOFISH_CBC 0x00001093 /* Camellia is proposed for v2.20 Amendment 3 */ -#define CKM_CAMELLIA_KEY_GEN 0x00000550 -#define CKM_CAMELLIA_ECB 0x00000551 -#define CKM_CAMELLIA_CBC 0x00000552 -#define CKM_CAMELLIA_MAC 0x00000553 +#define CKM_CAMELLIA_KEY_GEN 0x00000550 +#define CKM_CAMELLIA_ECB 0x00000551 +#define CKM_CAMELLIA_CBC 0x00000552 +#define CKM_CAMELLIA_MAC 0x00000553 #define CKM_CAMELLIA_MAC_GENERAL 0x00000554 -#define CKM_CAMELLIA_CBC_PAD 0x00000555 +#define CKM_CAMELLIA_CBC_PAD 0x00000555 #define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556 #define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557 diff --git a/security/nss/lib/softoken/pkcs11u.c b/security/nss/lib/softoken/pkcs11u.c index a575bd13f..5e64cac95 100644 --- a/security/nss/lib/softoken/pkcs11u.c +++ b/security/nss/lib/softoken/pkcs11u.c @@ -39,13 +39,12 @@ */ #include "pkcs11.h" #include "pkcs11i.h" -#include "pcertt.h" #include "lowkeyi.h" -#include "pcert.h" #include "secasn1.h" #include "blapi.h" #include "secerr.h" #include "prnetdb.h" /* for PR_ntohl */ +#include "sftkdb.h" /* * ******************** Attribute Utilities ******************************* @@ -107,59 +106,6 @@ sftk_NewAttribute(SFTKObject *object, return attribute; } -static SFTKAttribute * -sftk_NewTokenAttribute(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, - CK_ULONG len, PRBool copy) -{ - SFTKAttribute *attribute; - - attribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute)); - - if (attribute == NULL) return NULL; - attribute->attrib.type = type; - attribute->handle = type; - attribute->next = attribute->prev = NULL; - attribute->freeAttr = PR_TRUE; - attribute->freeData = PR_FALSE; - attribute->attrib.type = type; - if (!copy) { - attribute->attrib.pValue = value; - attribute->attrib.ulValueLen = len; - return attribute; - } - - if (value) { - if (len <= ATTR_SPACE) { - attribute->attrib.pValue = attribute->space; - } else { - attribute->attrib.pValue = PORT_Alloc(len); - attribute->freeData = PR_TRUE; - } - if (attribute->attrib.pValue == NULL) { - PORT_Free(attribute); - return NULL; - } - PORT_Memcpy(attribute->attrib.pValue,value,len); - attribute->attrib.ulValueLen = len; - } else { - attribute->attrib.pValue = NULL; - attribute->attrib.ulValueLen = 0; - } - return attribute; -} - -static SFTKAttribute * -sftk_NewTokenAttributeSigned(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, - CK_ULONG len, PRBool copy) -{ - unsigned char * dval = (unsigned char *)value; - if (*dval == 0) { - dval++; - len--; - } - return sftk_NewTokenAttribute(type,dval,len,copy); -} - /* * Free up all the memory associated with an attribute. Reference count * must be zero to call this. @@ -191,1157 +137,60 @@ sftk_FreeAttribute(SFTKAttribute *attribute) } } -#define SFTK_DEF_ATTRIBUTE(value,len) \ - { NULL, NULL, PR_FALSE, PR_FALSE, 0, { 0, value, len } } - -#define SFTK_CLONE_ATTR(type, staticAttr) \ - sftk_NewTokenAttribute( type, staticAttr.attrib.pValue, \ - staticAttr.attrib.ulValueLen, PR_FALSE) - -CK_BBOOL sftk_staticTrueValue = CK_TRUE; -CK_BBOOL sftk_staticFalseValue = CK_FALSE; -static const SFTKAttribute sftk_StaticTrueAttr = - SFTK_DEF_ATTRIBUTE(&sftk_staticTrueValue,sizeof(sftk_staticTrueValue)); -static const SFTKAttribute sftk_StaticFalseAttr = - SFTK_DEF_ATTRIBUTE(&sftk_staticFalseValue,sizeof(sftk_staticFalseValue)); -static const SFTKAttribute sftk_StaticNullAttr = SFTK_DEF_ATTRIBUTE(NULL,0); -char sftk_StaticOneValue = 1; -static const SFTKAttribute sftk_StaticOneAttr = - SFTK_DEF_ATTRIBUTE(&sftk_StaticOneValue,sizeof(sftk_StaticOneValue)); - -CK_CERTIFICATE_TYPE sftk_staticX509Value = CKC_X_509; -static const SFTKAttribute sftk_StaticX509Attr = - SFTK_DEF_ATTRIBUTE(&sftk_staticX509Value, sizeof(sftk_staticX509Value)); -CK_TRUST sftk_staticTrustedValue = CKT_NETSCAPE_TRUSTED; -CK_TRUST sftk_staticTrustedDelegatorValue = CKT_NETSCAPE_TRUSTED_DELEGATOR; -CK_TRUST sftk_staticValidDelegatorValue = CKT_NETSCAPE_VALID_DELEGATOR; -CK_TRUST sftk_staticUnTrustedValue = CKT_NETSCAPE_UNTRUSTED; -CK_TRUST sftk_staticTrustUnknownValue = CKT_NETSCAPE_TRUST_UNKNOWN; -CK_TRUST sftk_staticValidPeerValue = CKT_NETSCAPE_VALID; -CK_TRUST sftk_staticMustVerifyValue = CKT_NETSCAPE_MUST_VERIFY; -static const SFTKAttribute sftk_StaticTrustedAttr = - SFTK_DEF_ATTRIBUTE(&sftk_staticTrustedValue, - sizeof(sftk_staticTrustedValue)); -static const SFTKAttribute sftk_StaticTrustedDelegatorAttr = - SFTK_DEF_ATTRIBUTE(&sftk_staticTrustedDelegatorValue, - sizeof(sftk_staticTrustedDelegatorValue)); -static const SFTKAttribute sftk_StaticValidDelegatorAttr = - SFTK_DEF_ATTRIBUTE(&sftk_staticValidDelegatorValue, - sizeof(sftk_staticValidDelegatorValue)); -static const SFTKAttribute sftk_StaticUnTrustedAttr = - SFTK_DEF_ATTRIBUTE(&sftk_staticUnTrustedValue, - sizeof(sftk_staticUnTrustedValue)); -static const SFTKAttribute sftk_StaticTrustUnknownAttr = - SFTK_DEF_ATTRIBUTE(&sftk_staticTrustUnknownValue, - sizeof(sftk_staticTrustUnknownValue)); -static const SFTKAttribute sftk_StaticValidPeerAttr = - SFTK_DEF_ATTRIBUTE(&sftk_staticValidPeerValue, - sizeof(sftk_staticValidPeerValue)); -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; - } - if (object->obj.objectInfo) { - return (certDBEntrySMime *)object->obj.objectInfo; - } - - 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; -} - -static certDBEntryRevocation * -sftk_getCrl(SFTKTokenObject *object) -{ - certDBEntryRevocation *crl; - PRBool isKrl; - NSSLOWCERTCertDBHandle *certHandle; - - if (object->obj.objclass != CKO_NETSCAPE_CRL) { - return NULL; - } - if (object->obj.objectInfo) { - return (certDBEntryRevocation *)object->obj.objectInfo; - } - - isKrl = (PRBool) (object->obj.handle == SFTK_TOKEN_KRL_HANDLE); - 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, NSSLOWCERTCertDBHandle *certHandle) -{ - NSSLOWCERTCertificate *cert; - CK_OBJECT_CLASS objClass = object->obj.objclass; - - if ((objClass != CKO_CERTIFICATE) && (objClass != CKO_NETSCAPE_TRUST)) { - return NULL; - } - if (objClass == CKO_CERTIFICATE && object->obj.objectInfo) { - return (NSSLOWCERTCertificate *)object->obj.objectInfo; - } - cert = nsslowcert_FindCertByKey(certHandle, &object->dbKey); - if (objClass == CKO_CERTIFICATE) { - object->obj.objectInfo = (void *)cert; - object->obj.infoFree = (SFTKFree) nsslowcert_DestroyCertificate ; - } - return cert; -} - -static NSSLOWCERTTrust * -sftk_getTrust(SFTKTokenObject *object) -{ - NSSLOWCERTTrust *trust; - NSSLOWCERTCertDBHandle *certHandle; - - if (object->obj.objclass != CKO_NETSCAPE_TRUST) { - return NULL; - } - if (object->obj.objectInfo) { - return (NSSLOWCERTTrust *)object->obj.objectInfo; - } - 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; -} - -static NSSLOWKEYPublicKey * -sftk_GetPublicKey(SFTKTokenObject *object) -{ - NSSLOWKEYPublicKey *pubKey; - NSSLOWKEYPrivateKey *privKey; - - if (object->obj.objclass != CKO_PUBLIC_KEY) { - return NULL; - } - if (object->obj.objectInfo) { - return (NSSLOWKEYPublicKey *)object->obj.objectInfo; - } - privKey = sftk_FindKeyByPublicKey(object->obj.slot, &object->dbKey); - if (privKey == NULL) { - return NULL; - } - pubKey = nsslowkey_ConvertToPublicKey(privKey); - nsslowkey_DestroyPrivateKey(privKey); - object->obj.objectInfo = (void *) pubKey; - object->obj.infoFree = (SFTKFree) nsslowkey_DestroyPublicKey ; - 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_GetPrivateKeyWithDB(SFTKTokenObject *object, NSSLOWKEYDBHandle *keyHandle) -{ - NSSLOWKEYPrivateKey *privKey; - - if ((object->obj.objclass != CKO_PRIVATE_KEY) && - (object->obj.objclass != CKO_SECRET_KEY)) { - return NULL; - } - if (object->obj.objectInfo) { - return (NSSLOWKEYPrivateKey *)object->obj.objectInfo; - } - privKey = nsslowkey_FindKeyByPublicKey(keyHandle, &object->dbKey, - object->obj.slot->password); - if (privKey == NULL) { - return NULL; - } - object->obj.objectInfo = (void *) privKey; - object->obj.infoFree = (SFTKFree) nsslowkey_DestroyPrivateKey ; - 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 - * should include this comment. - */ -static SECItem * -sftk_GetPubItem(NSSLOWKEYPublicKey *pubKey) { - SECItem *pubItem = NULL; - /* get value to compare from the cert's public key */ - switch ( pubKey->keyType ) { - case NSSLOWKEYRSAKey: - pubItem = &pubKey->u.rsa.modulus; - break; - case NSSLOWKEYDSAKey: - pubItem = &pubKey->u.dsa.publicValue; - break; - case NSSLOWKEYDHKey: - pubItem = &pubKey->u.dh.publicValue; - break; -#ifdef NSS_ENABLE_ECC - case NSSLOWKEYECKey: - pubItem = &pubKey->u.ec.publicValue; - break; -#endif /* NSS_ENABLE_ECC */ - default: - break; - } - return pubItem; -} - -static const SEC_ASN1Template sftk_SerialTemplate[] = { - { SEC_ASN1_INTEGER, offsetof(NSSLOWCERTCertificate,serialNumber) }, - { 0 } -}; - -static SFTKAttribute * -sftk_FindRSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type) -{ - unsigned char hash[SHA1_LENGTH]; - CK_KEY_TYPE keyType = CKK_RSA; - - switch (type) { - case CKA_KEY_TYPE: - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE); - case CKA_ID: - SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len); - return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE); - case CKA_DERIVE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_ENCRYPT: - case CKA_VERIFY: - case CKA_VERIFY_RECOVER: - case CKA_WRAP: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_MODULUS: - return sftk_NewTokenAttributeSigned(type,key->u.rsa.modulus.data, - key->u.rsa.modulus.len, PR_FALSE); - case CKA_PUBLIC_EXPONENT: - return sftk_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data, - key->u.rsa.publicExponent.len, PR_FALSE); - default: - break; - } - return NULL; -} - -static SFTKAttribute * -sftk_FindDSAPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type) -{ - unsigned char hash[SHA1_LENGTH]; - CK_KEY_TYPE keyType = CKK_DSA; - - switch (type) { - case CKA_KEY_TYPE: - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE); - case CKA_ID: - SHA1_HashBuf(hash,key->u.dsa.publicValue.data, - key->u.dsa.publicValue.len); - return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE); - case CKA_DERIVE: - case CKA_ENCRYPT: - case CKA_VERIFY_RECOVER: - case CKA_WRAP: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_VERIFY: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_VALUE: - return sftk_NewTokenAttributeSigned(type,key->u.dsa.publicValue.data, - key->u.dsa.publicValue.len, PR_FALSE); - case CKA_PRIME: - return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data, - key->u.dsa.params.prime.len, PR_FALSE); - case CKA_SUBPRIME: - return sftk_NewTokenAttributeSigned(type, - key->u.dsa.params.subPrime.data, - key->u.dsa.params.subPrime.len, PR_FALSE); - case CKA_BASE: - return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.base.data, - key->u.dsa.params.base.len, PR_FALSE); - default: - break; - } - return NULL; -} - -static SFTKAttribute * -sftk_FindDHPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type) -{ - unsigned char hash[SHA1_LENGTH]; - CK_KEY_TYPE keyType = CKK_DH; - - switch (type) { - case CKA_KEY_TYPE: - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE); - case CKA_ID: - SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len); - return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE); - case CKA_DERIVE: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_ENCRYPT: - case CKA_VERIFY: - case CKA_VERIFY_RECOVER: - case CKA_WRAP: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_VALUE: - return sftk_NewTokenAttributeSigned(type,key->u.dh.publicValue.data, - key->u.dh.publicValue.len, PR_FALSE); - case CKA_PRIME: - return sftk_NewTokenAttributeSigned(type,key->u.dh.prime.data, - key->u.dh.prime.len, PR_FALSE); - case CKA_BASE: - return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data, - key->u.dh.base.len, PR_FALSE); - default: - break; - } - return NULL; -} - -#ifdef NSS_ENABLE_ECC -static SFTKAttribute * -sftk_FindECPublicKeyAttribute(NSSLOWKEYPublicKey *key, CK_ATTRIBUTE_TYPE type) -{ - unsigned char hash[SHA1_LENGTH]; - CK_KEY_TYPE keyType = CKK_EC; - - switch (type) { - case CKA_KEY_TYPE: - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE); - case CKA_ID: - SHA1_HashBuf(hash, key->u.ec.publicValue.data, - key->u.ec.publicValue.len); - return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE); - case CKA_DERIVE: - case CKA_VERIFY: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_ENCRYPT: - case CKA_VERIFY_RECOVER: - case CKA_WRAP: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_EC_PARAMS: - /* XXX Why is the last arg PR_FALSE? */ - return sftk_NewTokenAttributeSigned(type, - key->u.ec.ecParams.DEREncoding.data, - key->u.ec.ecParams.DEREncoding.len, - PR_FALSE); - case CKA_EC_POINT: - /* XXX Why is the last arg PR_FALSE? */ - return sftk_NewTokenAttributeSigned(type,key->u.ec.publicValue.data, - key->u.ec.publicValue.len, PR_FALSE); - default: - break; - } - return NULL; -} -#endif /* NSS_ENABLE_ECC */ - - -static SFTKAttribute * -sftk_FindPublicKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) -{ - NSSLOWKEYPublicKey *key; - SFTKAttribute *att = NULL; - char *label; - - switch (type) { - case CKA_PRIVATE: - case CKA_SENSITIVE: - case CKA_ALWAYS_SENSITIVE: - case CKA_NEVER_EXTRACTABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_MODIFIABLE: - case CKA_EXTRACTABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_LABEL: - label = sftk_FindKeyNicknameByPublicKey(object->obj.slot, - &object->dbKey); - if (label == NULL) { - return SFTK_CLONE_ATTR(type,sftk_StaticOneAttr); - } - att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE); - PORT_Free(label); - return att; - default: - break; - } - - key = sftk_GetPublicKey(object); - if (key == NULL) { - return NULL; - } - - switch (key->keyType) { - case NSSLOWKEYRSAKey: - return sftk_FindRSAPublicKeyAttribute(key,type); - case NSSLOWKEYDSAKey: - return sftk_FindDSAPublicKeyAttribute(key,type); - case NSSLOWKEYDHKey: - return sftk_FindDHPublicKeyAttribute(key,type); -#ifdef NSS_ENABLE_ECC - case NSSLOWKEYECKey: - return sftk_FindECPublicKeyAttribute(key,type); -#endif /* NSS_ENABLE_ECC */ - default: - break; - } - - return NULL; -} - -static SFTKAttribute * -sftk_FindSecretKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) -{ - NSSLOWKEYPrivateKey *key; - char *label; - unsigned char *keyString; - SFTKAttribute *att; - int keyTypeLen; - CK_ULONG keyLen; - CK_KEY_TYPE keyType; - PRUint32 keyTypeStorage; - - switch (type) { - case CKA_PRIVATE: - case CKA_SENSITIVE: - case CKA_ALWAYS_SENSITIVE: - case CKA_EXTRACTABLE: - case CKA_DERIVE: - case CKA_ENCRYPT: - case CKA_DECRYPT: - case CKA_SIGN: - case CKA_VERIFY: - case CKA_WRAP: - case CKA_UNWRAP: - case CKA_MODIFIABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_NEVER_EXTRACTABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_LABEL: - label = sftk_FindKeyNicknameByPublicKey(object->obj.slot, - &object->dbKey); - if (label == NULL) { - return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); - } - att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE); - PORT_Free(label); - return att; - case CKA_KEY_TYPE: - case CKA_VALUE_LEN: - case CKA_VALUE: - break; - default: - return NULL; - } - - key = sftk_GetPrivateKey(object); - if (key == NULL) { - return NULL; - } - switch (type) { - case CKA_KEY_TYPE: - /* handle legacy databases. In legacy databases key_type was stored - * in host order, with any leading zeros stripped off. Only key types - * under 0x1f (AES) were stored. We assume that any values which are - * either 1 byte long (big endian), or have byte[0] between 0 and - * 0x7f and bytes[1]-bytes[3] equal to '0' (little endian). All other - * values are assumed to be from the new database, which is always 4 - * bytes in network order */ - keyType=0; - keyString = key->u.rsa.coefficient.data; - keyTypeLen = key->u.rsa.coefficient.len; - - - /* - * Because of various endian and word lengths The database may have - * stored the keyType value in one of the following formats: - * (kt) <= 0x1f - * length data - * Big Endian, pre-3.9, all lengths: 1 (kt) - * Little Endian, pre-3.9, 32 bits: 4 (kt) 0 0 0 - * Little Endian, pre-3.9, 64 bits: 8 (kt) 0 0 0 0 0 0 0 - * All platforms, 3.9, 32 bits: 4 0 0 0 (kt) - * Big Endian, 3.9, 64 bits: 8 0 0 0 (kt) 0 0 0 0 - * Little Endian, 3.9, 64 bits: 8 0 0 0 0 0 0 0 (kt) - * All platforms, >= 3.9.1, all lengths: 4 (a) k1 k2 k3 - * where (a) is 0 or >= 0x80. currently (a) can only be 0. - */ - /* - * this key was written on a 64 bit platform with a using NSS 3.9 - * or earlier. Reduce the 64 bit possibilities above. We were are - * through, we will only have: - * - * Big Endian, pre-3.9, all lengths: 1 (kt) - * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 - * All platforms, 3.9, all lengths: 4 0 0 0 (kt) - * All platforms, => 3.9.1, all lengths: 4 (a) k1 k2 k3 - */ - if (keyTypeLen == 8) { - keyTypeStorage = *(PRUint32 *) keyString; - if (keyTypeStorage == 0) { - keyString += sizeof(PRUint32); - } - keyTypeLen = 4; - } - /* - * Now Handle: - * - * All platforms, 3.9, all lengths: 4 0 0 0 (kt) - * All platforms, => 3.9.1, all lengths: 4 (a) k1 k2 k3 - * - * NOTE: if kt == 0 or ak1k2k3 == 0, the test fails and - * we handle it as: - * - * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 - */ - if (keyTypeLen == sizeof(keyTypeStorage) && - (((keyString[0] & 0x80) == 0x80) || - !((keyString[1] == 0) && (keyString[2] == 0) - && (keyString[3] == 0))) ) { - PORT_Memcpy(&keyTypeStorage, keyString, sizeof(keyTypeStorage)); - keyType = (CK_KEY_TYPE) PR_ntohl(keyTypeStorage); - } else { - /* - * Now Handle: - * - * Big Endian, pre-3.9, all lengths: 1 (kt) - * Little Endian, pre-3.9, all lengths: 4 (kt) 0 0 0 - * -- KeyType == 0 all other cases ---: 4 0 0 0 0 - */ - keyType = (CK_KEY_TYPE) keyString[0] ; - } - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType),PR_TRUE); - case CKA_VALUE: - return sftk_NewTokenAttribute(type,key->u.rsa.privateExponent.data, - key->u.rsa.privateExponent.len, PR_FALSE); - case CKA_VALUE_LEN: - keyLen=key->u.rsa.privateExponent.len; - return sftk_NewTokenAttribute(type, &keyLen, sizeof(CK_ULONG), PR_TRUE); - } - - return NULL; -} - -static SFTKAttribute * -sftk_FindRSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, - CK_ATTRIBUTE_TYPE type) -{ - unsigned char hash[SHA1_LENGTH]; - CK_KEY_TYPE keyType = CKK_RSA; - - switch (type) { - case CKA_KEY_TYPE: - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE); - case CKA_ID: - SHA1_HashBuf(hash,key->u.rsa.modulus.data,key->u.rsa.modulus.len); - return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE); - case CKA_DERIVE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_DECRYPT: - case CKA_SIGN: - case CKA_SIGN_RECOVER: - case CKA_UNWRAP: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_MODULUS: - return sftk_NewTokenAttributeSigned(type,key->u.rsa.modulus.data, - key->u.rsa.modulus.len, PR_FALSE); - case CKA_PUBLIC_EXPONENT: - return sftk_NewTokenAttributeSigned(type,key->u.rsa.publicExponent.data, - key->u.rsa.publicExponent.len, PR_FALSE); - case CKA_PRIVATE_EXPONENT: - return sftk_NewTokenAttributeSigned(type, - key->u.rsa.privateExponent.data, - key->u.rsa.privateExponent.len, PR_FALSE); - case CKA_PRIME_1: - return sftk_NewTokenAttributeSigned(type, key->u.rsa.prime1.data, - key->u.rsa.prime1.len, PR_FALSE); - case CKA_PRIME_2: - return sftk_NewTokenAttributeSigned(type, key->u.rsa.prime2.data, - key->u.rsa.prime2.len, PR_FALSE); - case CKA_EXPONENT_1: - return sftk_NewTokenAttributeSigned(type, key->u.rsa.exponent1.data, - key->u.rsa.exponent1.len, PR_FALSE); - case CKA_EXPONENT_2: - return sftk_NewTokenAttributeSigned(type, key->u.rsa.exponent2.data, - key->u.rsa.exponent2.len, PR_FALSE); - case CKA_COEFFICIENT: - return sftk_NewTokenAttributeSigned(type, key->u.rsa.coefficient.data, - key->u.rsa.coefficient.len, PR_FALSE); - default: - break; - } - return NULL; -} - -static SFTKAttribute * -sftk_FindDSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, - CK_ATTRIBUTE_TYPE type) -{ - unsigned char hash[SHA1_LENGTH]; - CK_KEY_TYPE keyType = CKK_DSA; - - switch (type) { - case CKA_KEY_TYPE: - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE); - case CKA_ID: - SHA1_HashBuf(hash,key->u.dsa.publicValue.data, - key->u.dsa.publicValue.len); - return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE); - case CKA_DERIVE: - case CKA_DECRYPT: - case CKA_SIGN_RECOVER: - case CKA_UNWRAP: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_SIGN: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_VALUE: - return sftk_NewTokenAttributeSigned(type, key->u.dsa.privateValue.data, - key->u.dsa.privateValue.len, PR_FALSE); - case CKA_PRIME: - return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.prime.data, - key->u.dsa.params.prime.len, PR_FALSE); - case CKA_SUBPRIME: - return sftk_NewTokenAttributeSigned(type, - key->u.dsa.params.subPrime.data, - key->u.dsa.params.subPrime.len, PR_FALSE); - case CKA_BASE: - return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.base.data, - key->u.dsa.params.base.len, PR_FALSE); - case CKA_NETSCAPE_DB: - return sftk_NewTokenAttributeSigned(type, - key->u.dsa.publicValue.data, - key->u.dsa.publicValue.len, - PR_FALSE); - default: - break; - } - return NULL; -} - -static SFTKAttribute * -sftk_FindDHPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type) -{ - unsigned char hash[SHA1_LENGTH]; - CK_KEY_TYPE keyType = CKK_DH; - - switch (type) { - case CKA_KEY_TYPE: - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE); - case CKA_ID: - SHA1_HashBuf(hash,key->u.dh.publicValue.data,key->u.dh.publicValue.len); - return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE); - case CKA_DERIVE: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_DECRYPT: - case CKA_SIGN: - case CKA_SIGN_RECOVER: - case CKA_UNWRAP: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_VALUE: - return sftk_NewTokenAttributeSigned(type,key->u.dh.privateValue.data, - key->u.dh.privateValue.len, PR_FALSE); - case CKA_PRIME: - return sftk_NewTokenAttributeSigned(type,key->u.dh.prime.data, - key->u.dh.prime.len, PR_FALSE); - case CKA_BASE: - return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data, - key->u.dh.base.len, PR_FALSE); - case CKA_NETSCAPE_DB: - return sftk_NewTokenAttributeSigned(type, - key->u.dh.publicValue.data, - key->u.dh.publicValue.len, - PR_FALSE); - default: - break; - } - return NULL; -} - -#ifdef NSS_ENABLE_ECC -static SFTKAttribute * -sftk_FindECPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type) -{ - unsigned char hash[SHA1_LENGTH]; - CK_KEY_TYPE keyType = CKK_EC; - - switch (type) { - case CKA_KEY_TYPE: - return sftk_NewTokenAttribute(type,&keyType,sizeof(keyType), PR_TRUE); - case CKA_ID: - SHA1_HashBuf(hash,key->u.ec.publicValue.data,key->u.ec.publicValue.len); - return sftk_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE); - case CKA_DERIVE: - case CKA_SIGN: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_DECRYPT: - case CKA_SIGN_RECOVER: - case CKA_UNWRAP: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_VALUE: - return sftk_NewTokenAttributeSigned(type, key->u.ec.privateValue.data, - key->u.ec.privateValue.len, PR_FALSE); - case CKA_EC_PARAMS: - /* XXX Why is the last arg PR_FALSE? */ - return sftk_NewTokenAttributeSigned(type, - key->u.ec.ecParams.DEREncoding.data, - key->u.ec.ecParams.DEREncoding.len, - PR_FALSE); - case CKA_NETSCAPE_DB: - return sftk_NewTokenAttributeSigned(type, - key->u.ec.publicValue.data, - key->u.ec.publicValue.len, - PR_FALSE); - default: - break; - } - return NULL; -} -#endif /* NSS_ENABLE_ECC */ - -static SFTKAttribute * -sftk_FindPrivateKeyAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) -{ - NSSLOWKEYPrivateKey *key; - char *label; - SFTKAttribute *att; - - switch (type) { - case CKA_PRIVATE: - case CKA_SENSITIVE: - case CKA_ALWAYS_SENSITIVE: - case CKA_EXTRACTABLE: - case CKA_MODIFIABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_NEVER_EXTRACTABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_SUBJECT: - return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); - case CKA_LABEL: - label = sftk_FindKeyNicknameByPublicKey(object->obj.slot, - &object->dbKey); - if (label == NULL) { - return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); - } - att = sftk_NewTokenAttribute(type,label,PORT_Strlen(label), PR_TRUE); - PORT_Free(label); - return att; - default: - break; - } - key = sftk_GetPrivateKey(object); - if (key == NULL) { - return NULL; - } - switch (key->keyType) { - case NSSLOWKEYRSAKey: - return sftk_FindRSAPrivateKeyAttribute(key,type); - case NSSLOWKEYDSAKey: - return sftk_FindDSAPrivateKeyAttribute(key,type); - case NSSLOWKEYDHKey: - return sftk_FindDHPrivateKeyAttribute(key,type); -#ifdef NSS_ENABLE_ECC - case NSSLOWKEYECKey: - return sftk_FindECPrivateKeyAttribute(key,type); -#endif /* NSS_ENABLE_ECC */ - default: - break; - } - - return NULL; -} - -static SFTKAttribute * -sftk_FindSMIMEAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) -{ - certDBEntrySMime *entry; - switch (type) { - case CKA_PRIVATE: - case CKA_MODIFIABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_NETSCAPE_EMAIL: - return sftk_NewTokenAttribute(type,object->dbKey.data, - object->dbKey.len-1, PR_FALSE); - case CKA_NETSCAPE_SMIME_TIMESTAMP: - case CKA_SUBJECT: - case CKA_VALUE: - break; - default: - return NULL; - } - entry = sftk_getSMime(object); - if (entry == NULL) { - return NULL; - } - switch (type) { - case CKA_NETSCAPE_SMIME_TIMESTAMP: - return sftk_NewTokenAttribute(type,entry->optionsDate.data, - entry->optionsDate.len, PR_FALSE); - case CKA_SUBJECT: - return sftk_NewTokenAttribute(type,entry->subjectName.data, - entry->subjectName.len, PR_FALSE); - case CKA_VALUE: - return sftk_NewTokenAttribute(type,entry->smimeOptions.data, - entry->smimeOptions.len, PR_FALSE); - default: - break; - } - return NULL; -} - -static SFTKAttribute * -sftk_FindTrustAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) -{ - NSSLOWCERTTrust *trust; - unsigned char hash[SHA1_LENGTH]; - unsigned int trustFlags; - - switch (type) { - case CKA_PRIVATE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_MODIFIABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_CERT_SHA1_HASH: - case CKA_CERT_MD5_HASH: - case CKA_TRUST_CLIENT_AUTH: - case CKA_TRUST_SERVER_AUTH: - case CKA_TRUST_EMAIL_PROTECTION: - case CKA_TRUST_CODE_SIGNING: - case CKA_TRUST_STEP_UP_APPROVED: - break; - default: - return NULL; - } - trust = sftk_getTrust(object); - if (trust == NULL) { - return NULL; - } - switch (type) { - case CKA_CERT_SHA1_HASH: - SHA1_HashBuf(hash,trust->derCert->data,trust->derCert->len); - return sftk_NewTokenAttribute(type, hash, SHA1_LENGTH, PR_TRUE); - case CKA_CERT_MD5_HASH: - MD5_HashBuf(hash,trust->derCert->data,trust->derCert->len); - return sftk_NewTokenAttribute(type, hash, MD5_LENGTH, PR_TRUE); - case CKA_TRUST_CLIENT_AUTH: - trustFlags = trust->trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ? - trust->trust->sslFlags | CERTDB_TRUSTED_CA : 0 ; - goto trust; - case CKA_TRUST_SERVER_AUTH: - trustFlags = trust->trust->sslFlags; - goto trust; - case CKA_TRUST_EMAIL_PROTECTION: - trustFlags = trust->trust->emailFlags; - goto trust; - case CKA_TRUST_CODE_SIGNING: - trustFlags = trust->trust->objectSigningFlags; -trust: - if (trustFlags & CERTDB_TRUSTED_CA ) { - return SFTK_CLONE_ATTR(type,sftk_StaticTrustedDelegatorAttr); - } - if (trustFlags & CERTDB_TRUSTED) { - return SFTK_CLONE_ATTR(type,sftk_StaticTrustedAttr); - } - if (trustFlags & CERTDB_NOT_TRUSTED) { - return SFTK_CLONE_ATTR(type,sftk_StaticUnTrustedAttr); - } - if (trustFlags & CERTDB_TRUSTED_UNKNOWN) { - return SFTK_CLONE_ATTR(type,sftk_StaticTrustUnknownAttr); - } - if (trustFlags & CERTDB_VALID_CA) { - return SFTK_CLONE_ATTR(type,sftk_StaticValidDelegatorAttr); - } - if (trustFlags & CERTDB_VALID_PEER) { - return SFTK_CLONE_ATTR(type,sftk_StaticValidPeerAttr); - } - return SFTK_CLONE_ATTR(type,sftk_StaticMustVerifyAttr); - case CKA_TRUST_STEP_UP_APPROVED: - if (trust->trust->sslFlags & CERTDB_GOVT_APPROVED_CA) { - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - } else { - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - } - default: - break; - } - -#ifdef notdef - switch (type) { - case CKA_ISSUER: - cert = sftk_getCertObject(object); - if (cert == NULL) break; - attr = sftk_NewTokenAttribute(type,cert->derIssuer.data, - cert->derIssuer.len, PR_FALSE); - - case CKA_SERIAL_NUMBER: - cert = sftk_getCertObject(object); - if (cert == NULL) break; - item = SEC_ASN1EncodeItem(NULL,NULL,cert,sftk_SerialTemplate); - if (item == NULL) break; - attr = sftk_NewTokenAttribute(type, item->data, item->len, PR_TRUE); - SECITEM_FreeItem(item,PR_TRUE); - } - if (cert) { - NSSLOWCERTDestroyCertificate(cert); - return attr; - } -#endif - return NULL; -} - -static SFTKAttribute * -sftk_FindCrlAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) +static SFTKAttribute * +sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type) { - certDBEntryRevocation *crl; + SFTKAttribute *myattribute = NULL; + SFTKDBHandle *dbHandle = NULL; + CK_RV crv; - switch (type) { - case CKA_PRIVATE: - case CKA_MODIFIABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_NETSCAPE_KRL: - return ((object->obj.handle == SFTK_TOKEN_KRL_HANDLE) - ? SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr) - : SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr)); - case CKA_SUBJECT: - return sftk_NewTokenAttribute(type,object->dbKey.data, - object->dbKey.len, PR_FALSE); - case CKA_NETSCAPE_URL: - case CKA_VALUE: - break; - default: - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return NULL; - } - crl = sftk_getCrl(object); - if (!crl) { - return NULL; - } - switch (type) { - case CKA_NETSCAPE_URL: - if (crl->url == NULL) { - return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); - } - return sftk_NewTokenAttribute(type, crl->url, - PORT_Strlen(crl->url)+1, PR_TRUE); - case CKA_VALUE: - return sftk_NewTokenAttribute(type, crl->derCrl.data, - crl->derCrl.len, PR_FALSE); - default: - break; + myattribute = (SFTKAttribute*)PORT_Alloc(sizeof(SFTKAttribute)); + if (myattribute == NULL) { + goto loser; } - return NULL; -} -static SFTKAttribute * -sftk_FindCertAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) -{ - NSSLOWCERTCertificate *cert; - NSSLOWCERTCertDBHandle *certHandle; - NSSLOWKEYPublicKey *pubKey; - unsigned char hash[SHA1_LENGTH]; - SECItem *item; + dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle); - switch (type) { - case CKA_PRIVATE: - return SFTK_CLONE_ATTR(type,sftk_StaticFalseAttr); - case CKA_MODIFIABLE: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_CERTIFICATE_TYPE: - /* hardcoding X.509 into here */ - return SFTK_CLONE_ATTR(type,sftk_StaticX509Attr); - case CKA_VALUE: - case CKA_ID: - case CKA_LABEL: - case CKA_SUBJECT: - case CKA_ISSUER: - case CKA_SERIAL_NUMBER: - case CKA_NETSCAPE_EMAIL: - break; - default: - return NULL; - } + myattribute->handle = type; + myattribute->attrib.type = type; + myattribute->attrib.pValue = myattribute->space; + myattribute->attrib.ulValueLen = ATTR_SPACE; + myattribute->next = myattribute->prev = NULL; + myattribute->freeAttr = PR_TRUE; + myattribute->freeData = PR_FALSE; - certHandle = sftk_getCertDB(object->obj.slot); - if (certHandle == NULL) { - return NULL; - } + crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, + &myattribute->attrib, 1); - cert = sftk_getCert(object, certHandle); - sftk_freeCertDB(certHandle); - if (cert == NULL) { - return NULL; - } - switch (type) { - case CKA_VALUE: - return sftk_NewTokenAttribute(type,cert->derCert.data, - cert->derCert.len,PR_FALSE); - case CKA_ID: - if (((cert->trust->sslFlags & CERTDB_USER) == 0) && - ((cert->trust->emailFlags & CERTDB_USER) == 0) && - ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) { - return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); + /* attribute is bigger than our attribute space buffer, malloc it */ + if (crv == CKR_BUFFER_TOO_SMALL) { + myattribute->attrib.pValue = NULL; + crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, + &myattribute->attrib, 1); + if (crv != CKR_OK) { + goto loser; } - pubKey = nsslowcert_ExtractPublicKey(cert); - if (pubKey == NULL) break; - item = sftk_GetPubItem(pubKey); - if (item == NULL) { - nsslowkey_DestroyPublicKey(pubKey); - break; + myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen); + if (myattribute->attrib.pValue == NULL) { + crv = CKR_HOST_MEMORY; + goto loser; } - SHA1_HashBuf(hash,item->data,item->len); - /* item is imbedded in pubKey, just free the key */ - nsslowkey_DestroyPublicKey(pubKey); - return sftk_NewTokenAttribute(type, hash, SHA1_LENGTH, PR_TRUE); - case CKA_LABEL: - return cert->nickname - ? sftk_NewTokenAttribute(type, cert->nickname, - PORT_Strlen(cert->nickname), PR_FALSE) - : SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); - case CKA_SUBJECT: - return sftk_NewTokenAttribute(type,cert->derSubject.data, - cert->derSubject.len, PR_FALSE); - case CKA_ISSUER: - return sftk_NewTokenAttribute(type,cert->derIssuer.data, - cert->derIssuer.len, PR_FALSE); - case CKA_SERIAL_NUMBER: - return sftk_NewTokenAttribute(type,cert->derSN.data, - cert->derSN.len, PR_FALSE); - case CKA_NETSCAPE_EMAIL: - return (cert->emailAddr && cert->emailAddr[0]) - ? sftk_NewTokenAttribute(type, cert->emailAddr, - PORT_Strlen(cert->emailAddr), PR_FALSE) - : SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); - default: - break; + myattribute->freeData = PR_TRUE; + crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, + &myattribute->attrib, 1); + } +loser: + if (dbHandle) { + sftk_freeDB(dbHandle); } - return NULL; -} - -static SFTKAttribute * -sftk_FindTokenAttribute(SFTKTokenObject *object,CK_ATTRIBUTE_TYPE type) -{ - /* handle the common ones */ - switch (type) { - case CKA_CLASS: - return sftk_NewTokenAttribute(type,&object->obj.objclass, - sizeof(object->obj.objclass),PR_FALSE); - case CKA_TOKEN: - return SFTK_CLONE_ATTR(type,sftk_StaticTrueAttr); - case CKA_LABEL: - if ( (object->obj.objclass == CKO_CERTIFICATE) - || (object->obj.objclass == CKO_PRIVATE_KEY) - || (object->obj.objclass == CKO_PUBLIC_KEY) - || (object->obj.objclass == CKO_SECRET_KEY)) { - break; + if (crv != CKR_OK) { + if (myattribute) { + myattribute->attrib.ulValueLen = 0; + sftk_FreeAttribute(myattribute); + myattribute = NULL; } - return SFTK_CLONE_ATTR(type,sftk_StaticNullAttr); - default: - break; - } - switch (object->obj.objclass) { - case CKO_CERTIFICATE: - return sftk_FindCertAttribute(object,type); - case CKO_NETSCAPE_CRL: - return sftk_FindCrlAttribute(object,type); - case CKO_NETSCAPE_TRUST: - return sftk_FindTrustAttribute(object,type); - case CKO_NETSCAPE_SMIME: - return sftk_FindSMIMEAttribute(object,type); - case CKO_PUBLIC_KEY: - return sftk_FindPublicKeyAttribute(object,type); - case CKO_PRIVATE_KEY: - return sftk_FindPrivateKeyAttribute(object,type); - case CKO_SECRET_KEY: - return sftk_FindSecretKeyAttribute(object,type); - default: - break; } - PORT_Assert(0); - return NULL; + return myattribute; } /* @@ -1434,9 +283,22 @@ sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type, } PRBool -sftk_hasAttributeToken(SFTKTokenObject *object) +sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type) { - return PR_FALSE; + CK_ATTRIBUTE template; + CK_RV crv; + SFTKDBHandle *dbHandle; + + dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle); + template.type = type; + template.pValue = NULL; + template.ulValueLen = 0; + + crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1); + sftk_freeDB(dbHandle); + + /* attribute is bigger than our attribute space buffer, malloc it */ + return (crv == CKR_OK) ? PR_TRUE : PR_FALSE; } /* @@ -1449,7 +311,7 @@ sftk_hasAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type) SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); if (sessObject == NULL) { - return sftk_hasAttributeToken(sftk_narrowToTokenObject(object)); + return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type); } PZ_Lock(sessObject->attributeLock); @@ -1563,254 +425,35 @@ sftk_nullAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type) sftk_FreeAttribute(attribute); } -static CK_RV -sftk_SetCertAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, - void *value, unsigned int len) -{ - 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 */ - if (type == CKA_NETSCAPE_EMAIL) { - return CKR_OK; - } - - certHandle = sftk_getCertDB(to->obj.slot); - if (certHandle == NULL) { - crv = CKR_TOKEN_WRITE_PROTECTED; - goto done; - } - - if ((type != CKA_LABEL) && (type != CKA_ID)) { - crv = CKR_ATTRIBUTE_READ_ONLY; - goto done; - } - - cert = sftk_getCert(to, certHandle); - if (cert == NULL) { - crv = CKR_OBJECT_HANDLE_INVALID; - goto done; - } - - /* if the app is trying to set CKA_ID, it's probably because it just - * imported the key. Look to see if we need to set the CERTDB_USER bits. - */ - if (type == CKA_ID) { - if (((cert->trust->sslFlags & CERTDB_USER) == 0) && - ((cert->trust->emailFlags & CERTDB_USER) == 0) && - ((cert->trust->objectSigningFlags & CERTDB_USER) == 0)) { - SFTKSlot *slot = to->obj.slot; - 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); - } - } - crv = CKR_OK; - goto done; - } - - /* must be CKA_LABEL */ - if (value != NULL) { - nickname = PORT_ZAlloc(len+1); - if (nickname == NULL) { - crv = CKR_HOST_MEMORY; - goto done; - } - PORT_Memcpy(nickname,value,len); - nickname[len] = 0; - } - rv = nsslowcert_AddPermNickname(certHandle, cert, nickname); - crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; - -done: - if (nickname) { - PORT_Free(nickname); - } - if (certHandle) { - sftk_freeCertDB(certHandle); - } - return crv; -} - -static CK_RV -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 */ - if ((type == CKA_ID) || (type == CKA_SUBJECT)) { - return CKR_OK; - } - - keyHandle = sftk_getKeyDB(to->obj.slot); - if (keyHandle == NULL) { - crv = CKR_TOKEN_WRITE_PROTECTED; - goto done; - } - if (type != CKA_LABEL) { - crv = CKR_ATTRIBUTE_READ_ONLY; - goto done; - } - - privKey = sftk_GetPrivateKeyWithDB(to, keyHandle); - if (privKey == NULL) { - crv = CKR_OBJECT_HANDLE_INVALID; - goto done; - } - if (value != NULL) { - nickname = PORT_ZAlloc(len+1); - if (nickname == NULL) { - crv = CKR_HOST_MEMORY; - goto done; - } - PORT_Memcpy(nickname,value,len); - nickname[len] = 0; - } - rv = nsslowkey_UpdateNickname(keyHandle, privKey, &to->dbKey, - nickname, to->obj.slot->password); - crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; -done: - if (nickname) { - PORT_Free(nickname); - } - if (keyHandle) { - sftk_freeKeyDB(keyHandle); - } - return crv; -} - -static CK_RV -sftk_SetTrustAttribute(SFTKTokenObject *to, CK_ATTRIBUTE_TYPE type, - void *value, unsigned int len) -{ - unsigned int flags; - CK_TRUST trust; - NSSLOWCERTCertificate *cert; - NSSLOWCERTCertDBHandle *certHandle; - NSSLOWCERTCertTrust dbTrust; - SECStatus rv; - CK_RV crv; - - if (len != sizeof (CK_TRUST)) { - return CKR_ATTRIBUTE_VALUE_INVALID; - } - trust = *(CK_TRUST *)value; - flags = sftk_MapTrust(trust, (PRBool) (type == CKA_TRUST_SERVER_AUTH)); - - certHandle = sftk_getCertDB(to->obj.slot); - - if (certHandle == NULL) { - crv = CKR_TOKEN_WRITE_PROTECTED; - goto done; - } - - cert = sftk_getCert(to, certHandle); - if (cert == NULL) { - crv = CKR_OBJECT_HANDLE_INVALID; - goto done; - } - dbTrust = *cert->trust; - - switch (type) { - case CKA_TRUST_EMAIL_PROTECTION: - dbTrust.emailFlags = flags | - (cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS); - break; - case CKA_TRUST_CODE_SIGNING: - dbTrust.objectSigningFlags = flags | - (cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS); - break; - case CKA_TRUST_CLIENT_AUTH: - dbTrust.sslFlags = flags | (cert->trust->sslFlags & - (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CA)); - break; - case CKA_TRUST_SERVER_AUTH: - dbTrust.sslFlags = flags | (cert->trust->sslFlags & - (CERTDB_PRESERVE_TRUST_BITS|CERTDB_TRUSTED_CLIENT_CA)); - break; - default: - crv = CKR_ATTRIBUTE_READ_ONLY; - goto done; - } - - rv = nsslowcert_ChangeCertTrust(certHandle, cert, &dbTrust); - crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; -done: - if (certHandle) { - sftk_freeCertDB(certHandle); - } - return crv; -} static CK_RV sftk_forceTokenAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, void *value, unsigned int len) { - SFTKAttribute *attribute; + CK_ATTRIBUTE attribute; + SFTKDBHandle *dbHandle = NULL; SFTKTokenObject *to = sftk_narrowToTokenObject(object); - CK_RV crv = CKR_ATTRIBUTE_READ_ONLY; + CK_RV crv; PORT_Assert(to); if (to == NULL) { return CKR_DEVICE_ERROR; } - /* if we are just setting it to the value we already have, - * allow it to happen. Let label setting go through so - * we have the opportunity to repair any database corruption. */ - attribute=sftk_FindAttribute(object,type); - PORT_Assert(attribute); - if (!attribute) { - return CKR_ATTRIBUTE_TYPE_INVALID; + dbHandle = sftk_getDBForTokenObject(object->slot, object->handle); - } - if ((type != CKA_LABEL) && (attribute->attrib.ulValueLen == len) && - PORT_Memcmp(attribute->attrib.pValue,value,len) == 0) { - sftk_FreeAttribute(attribute); - return CKR_OK; - } + attribute.type = type; + attribute.pValue = value; + attribute.ulValueLen = len; - switch (object->objclass) { - case CKO_CERTIFICATE: - /* change NICKNAME, EMAIL, */ - crv = sftk_SetCertAttribute(to,type,value,len); - break; - case CKO_NETSCAPE_CRL: - /* change URL */ - break; - case CKO_NETSCAPE_TRUST: - crv = sftk_SetTrustAttribute(to,type,value,len); - break; - case CKO_PRIVATE_KEY: - case CKO_SECRET_KEY: - crv = sftk_SetPrivateKeyAttribute(to,type,value,len); - break; - } - sftk_FreeAttribute(attribute); + crv = sftkdb_SetAttributeValue(dbHandle, object->handle, + &attribute, 1); + sftk_freeDB(dbHandle); return crv; } /* - * force an attribute to a spaecif value. + * force an attribute to a specifc value. */ CK_RV sftk_forceAttribute(SFTKObject *object,CK_ATTRIBUTE_TYPE type, void *value, @@ -2087,44 +730,6 @@ sftk_AddAttributeType(SFTKObject *object,CK_ATTRIBUTE_TYPE type,void *valPtr, * ******************** Object Utilities ******************************* */ -static SECStatus -sftk_deleteTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle) -{ - SECItem *item; - PRBool rem; - - item = (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)handle); - rem = PL_HashTableRemove(slot->tokObjHashTable,(void *)handle) ; - if (rem && item) { - SECITEM_FreeItem(item,PR_TRUE); - } - 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; - } - entry = PL_HashTableAdd(slot->tokObjHashTable,(void *)handle,item); - if (entry == NULL) { - SECITEM_FreeItem(item,PR_TRUE); - return SECFailure; - } - return SECSuccess; -} - /* must be called holding sftk_tokenKeyLock(slot) */ static SECItem * sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle) @@ -2213,7 +818,8 @@ sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list, */ PRBool optimizeSpace = isSessionObject && ((SFTKSessionObject *)object)->optimizeSpace; - if (!optimizeSpace && (list->count < MAX_OBJECT_LIST_SIZE)) { + if (object->refLock && !optimizeSpace + && (list->count < MAX_OBJECT_LIST_SIZE)) { PZ_Lock(list->lock); object->next = list->head; list->head = object; @@ -2226,8 +832,10 @@ sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list, PZ_DestroyLock(so->attributeLock); so->attributeLock = NULL; } - PZ_DestroyLock(object->refLock); - object->refLock = NULL; + if (object->refLock) { + PZ_DestroyLock(object->refLock); + object->refLock = NULL; + } PORT_Free(object); } @@ -2501,10 +1109,6 @@ sftk_DeleteObject(SFTKSession *session, SFTKObject *object) SFTKSessionObject *so = sftk_narrowToSessionObject(object); SFTKTokenObject *to = sftk_narrowToTokenObject(object); CK_RV crv = CKR_OK; - SECStatus rv; - NSSLOWCERTCertificate *cert; - NSSLOWCERTCertTrust tmptrust; - PRBool isKrl; PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize); /* Handle Token case */ @@ -2519,88 +1123,11 @@ sftk_DeleteObject(SFTKSession *session, SFTKObject *object) sftkqueue_clear_deleted_element(object); sftk_FreeObject(object); /* reduce it's reference count */ } else { - NSSLOWKEYDBHandle *keyHandle; - NSSLOWCERTCertDBHandle *certHandle; + SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle); PORT_Assert(to); - /* remove the objects from the real data base */ - switch (object->handle & SFTK_TOKEN_TYPE_MASK) { - case SFTK_TOKEN_TYPE_PRIV: - case SFTK_TOKEN_TYPE_KEY: - /* KEYID is the public KEY for DSA and DH, and the MODULUS for - * RSA */ - 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: - 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; - } - 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(certHandle, &to->dbKey, isKrl); - sftk_freeCertDB(certHandle); - if (rv == SECFailure) crv = CKR_DEVICE_ERROR; - break; - case SFTK_TOKEN_TYPE_TRUST: - 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; - } - tmptrust = *cert->trust; - tmptrust.sslFlags &= CERTDB_PRESERVE_TRUST_BITS; - tmptrust.emailFlags &= CERTDB_PRESERVE_TRUST_BITS; - tmptrust.objectSigningFlags &= CERTDB_PRESERVE_TRUST_BITS; - tmptrust.sslFlags |= CERTDB_TRUSTED_UNKNOWN; - tmptrust.emailFlags |= CERTDB_TRUSTED_UNKNOWN; - tmptrust.objectSigningFlags |= CERTDB_TRUSTED_UNKNOWN; - rv = nsslowcert_ChangeCertTrust(certHandle, cert, &tmptrust); - sftk_freeCertDB(certHandle); - if (rv != SECSuccess) crv = CKR_DEVICE_ERROR; - nsslowcert_DestroyCertificate(cert); - break; - default: - break; - } - sftk_tokenKeyLock(object->slot); - sftk_deleteTokenKeyByHandle(object->slot,object->handle); - sftk_tokenKeyUnlock(object->slot); + crv = sftkdb_DestroyObject(handle, object->handle); + sftk_freeDB(handle); } return crv; } @@ -3265,93 +1792,6 @@ sftk_FreeSession(SFTKSession *session) if (destroy) sftk_DestroySession(session); } -/* - * handle Token Object stuff - */ -static void -sftk_XORHash(unsigned char *key, unsigned char *dbkey, int len) -{ - int i; - - PORT_Memset(key, 0, 4); - - for (i=0; i < len-4; i += 4) { - key[0] ^= dbkey[i]; - key[1] ^= dbkey[i+1]; - key[2] ^= dbkey[i+2]; - key[3] ^= dbkey[i+3]; - } -} - -/* Make a token handle for an object and record it so we can find it again */ -CK_OBJECT_HANDLE -sftk_mkHandle(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class) -{ - unsigned char hashBuf[4]; - CK_OBJECT_HANDLE handle; - SECItem *key; - - handle = class; - /* there is only one KRL, use a fixed handle for it */ - if (handle != SFTK_TOKEN_KRL_HANDLE) { - sftk_XORHash(hashBuf,dbKey->data,dbKey->len); - handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | - (hashBuf[2] << 8) | hashBuf[3]; - handle = SFTK_TOKEN_MAGIC | class | - (handle & ~(SFTK_TOKEN_TYPE_MASK|SFTK_TOKEN_MASK)); - /* we have a CRL who's handle has randomly matched the reserved KRL - * handle, increment it */ - if (handle == SFTK_TOKEN_KRL_HANDLE) { - handle++; - } - } - - sftk_tokenKeyLock(slot); - while ((key = sftk_lookupTokenKeyByHandle(slot,handle)) != NULL) { - if (SECITEM_ItemsAreEqual(key,dbKey)) { - sftk_tokenKeyUnlock(slot); - return handle; - } - handle++; - } - sftk_addTokenKeyByHandle(slot,handle,dbKey); - sftk_tokenKeyUnlock(slot); - return handle; -} - -PRBool -sftk_poisonHandle(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class) -{ - unsigned char hashBuf[4]; - CK_OBJECT_HANDLE handle; - SECItem *key; - - handle = class; - /* there is only one KRL, use a fixed handle for it */ - if (handle != SFTK_TOKEN_KRL_HANDLE) { - sftk_XORHash(hashBuf,dbKey->data,dbKey->len); - handle = (hashBuf[0] << 24) | (hashBuf[1] << 16) | - (hashBuf[2] << 8) | hashBuf[3]; - handle = SFTK_TOKEN_MAGIC | class | - (handle & ~(SFTK_TOKEN_TYPE_MASK|SFTK_TOKEN_MASK)); - /* we have a CRL who's handle has randomly matched the reserved KRL - * handle, increment it */ - if (handle == SFTK_TOKEN_KRL_HANDLE) { - handle++; - } - } - sftk_tokenKeyLock(slot); - while ((key = sftk_lookupTokenKeyByHandle(slot,handle)) != NULL) { - if (SECITEM_ItemsAreEqual(key,dbKey)) { - key->data[0] ^= 0x80; - sftk_tokenKeyUnlock(slot); - return PR_TRUE; - } - handle++; - } - sftk_tokenKeyUnlock(slot); - return PR_FALSE; -} void sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle) @@ -3371,13 +1811,22 @@ sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle) search->size++; } -static const CK_OBJECT_HANDLE sftk_classArray[] = { - 0, CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, CKO_SECRET_KEY, - CKO_NETSCAPE_TRUST, CKO_NETSCAPE_CRL, CKO_NETSCAPE_SMIME, - CKO_CERTIFICATE }; +static CK_RV +handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle, + CK_OBJECT_CLASS *objClass) +{ + SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle); + CK_ATTRIBUTE objClassTemplate; + CK_RV crv; -#define handleToClass(handle) \ - sftk_classArray[((handle & SFTK_TOKEN_TYPE_MASK))>>28] + *objClass = CKO_DATA; + objClassTemplate.type = CKA_CLASS; + objClassTemplate.pValue = objClass; + objClassTemplate.ulValueLen = sizeof(*objClass); + crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1); + sftk_freeDB(dbHandle); + return crv; +} SFTKObject * sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle) @@ -3385,7 +1834,7 @@ sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle) SFTKObject *object = NULL; SFTKTokenObject *tokObject = NULL; PRBool hasLocks = PR_FALSE; - SECStatus rv; + CK_RV crv; object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0, PR_FALSE); @@ -3394,26 +1843,16 @@ sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle) } tokObject = (SFTKTokenObject *) object; - object->objclass = handleToClass(handle); object->handle = handle; + /* every object must have a class, if we can't get it, the object + * doesn't exist */ + crv = handleToClass(slot, handle, &object->objclass); + if (crv != CKR_OK) { + goto loser; + } object->slot = slot; object->objectInfo = NULL; object->infoFree = NULL; - if (dbKey == NULL) { - sftk_tokenKeyLock(slot); - dbKey = sftk_lookupTokenKeyByHandle(slot,handle); - if (dbKey == NULL) { - sftk_tokenKeyUnlock(slot); - goto loser; - } - rv = SECITEM_CopyItem(NULL,&tokObject->dbKey,dbKey); - sftk_tokenKeyUnlock(slot); - } else { - rv = SECITEM_CopyItem(NULL,&tokObject->dbKey,dbKey); - } - if (rv != SECSuccess) { - goto loser; - } if (!hasLocks) { object->refLock = PZ_NewLock(nssILockRefLock); } @@ -3431,23 +1870,6 @@ loser: } -PRBool -sftk_tokenMatch(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE class, - CK_ATTRIBUTE_PTR theTemplate,int count) -{ - SFTKObject *object; - PRBool ret; - - object = sftk_NewTokenObject(slot,dbKey,SFTK_TOKEN_MASK|class); - if (object == NULL) { - return PR_FALSE; - } - - ret = sftk_objectMatch(object,theTemplate,count); - sftk_FreeObject(object); - return ret; -} - SFTKTokenObject * sftk_convertSessionToToken(SFTKObject *obj) { @@ -3474,7 +1896,6 @@ sftk_convertSessionToToken(SFTKObject *obj) } return to; - } SFTKSessionObject * diff --git a/security/nss/lib/softoken/sdb.c b/security/nss/lib/softoken/sdb.c new file mode 100644 index 000000000..2642a991d --- /dev/null +++ b/security/nss/lib/softoken/sdb.c @@ -0,0 +1,1518 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Red Hat, Inc. + * + * The Initial Developer of the Original Code is + * Red Hat, Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Relyea (rrelyea@redhat.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This file implements PKCS 11 on top of our existing security modules + * + * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. + * This implementation has two slots: + * slot 1 is our generic crypto support. It does not require login. + * It supports Public Key ops, and all they bulk ciphers and hashes. + * It can also support Private Key ops for imported Private keys. It does + * not have any token storage. + * slot 2 is our private key support. It requires a login before use. It + * can store Private Keys and Certs as token objects. Currently only private + * keys and their associated Certificates are saved on the token. + * + * In this implementation, session objects are only visible to the session + * that created or generated them. + */ + +#include "sdb.h" +#include "pkcs11t.h" +#include "seccomon.h" +#include <sqlite3.h> +#include "prthread.h" +#include "prio.h" +#include "stdio.h" + +#include "prlock.h" + +#ifdef SQLITE_UNSAFE_THREADS +/* + * SQLite can be compiled to be thread safe or not. + * turn on SQLITE_UNSAFE_THREADS if the OS does not support + * a thread safe version of sqlite. + */ +static PRLock *sqlite_lock = NULL; + +#define LOCK_SQLITE() PR_Lock(sqlite_lock); +#define UNLOCK_SQLITE() PR_Unlock(sqlite_lock); +#else +#define LOCK_SQLITE() +#define UNLOCK_SQLITE() +#endif + +typedef enum { + SDB_CERT = 1, + SDB_KEY = 2 +} sdbDataType; + +struct SDBPrivateStr { + char *sqlDBName; /* invarient, path to this database */ + sqlite3 *sqlXactDB; /* protected by lock, current transaction db*/ + PRThread *sqlXactThread; /* protected by lock, + * current transaiction thred*/ + sdbDataType type; /* invariant, database type */ + char *table; /* invariant, SQL table which contains the db */ + PRLock *lock; /* invariant, lock to protect sqlXact* fields*/ +}; + +typedef struct SDBPrivateStr SDBPrivate; + +/* + * known attributes + */ +static const CK_ATTRIBUTE_TYPE known_attributes[] = { + CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, + CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, + CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, + CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, + CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, + CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, + CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, + CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, + CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, + CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, + CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, + CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, + CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, + CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, + CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, + CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, + CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, + CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, + CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, + CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, + CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, + CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NETSCAPE_URL, CKA_NETSCAPE_EMAIL, + CKA_NETSCAPE_SMIME_INFO, CKA_NETSCAPE_SMIME_TIMESTAMP, + CKA_NETSCAPE_PKCS8_SALT, CKA_NETSCAPE_PASSWORD_CHECK, CKA_NETSCAPE_EXPIRES, + CKA_NETSCAPE_KRL, CKA_NETSCAPE_PQG_COUNTER, CKA_NETSCAPE_PQG_SEED, + CKA_NETSCAPE_PQG_H, CKA_NETSCAPE_PQG_SEED_BITS, CKA_NETSCAPE_MODULE_SPEC, + CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, + CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, + CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, + CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, + CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, + CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, + CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, + CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS +}; + +static int known_attributes_size= sizeof(known_attributes)/ + sizeof(known_attributes[0]); + +/* Magic for an explicit NULL. NOTE: ideally this should be + * out of band data. Since it's not completely out of band, pick + * a value that has no meaning to any existing PKCS #11 attributes. + * This value is 1) not a valid string (imbedded '\0'). 2) not a U_LONG + * or a normal key (too short). 3) not a bool (too long). 4) not an RSA + * public exponent (too many bits). + */ +const unsigned char SQLITE_EXPLICIT_NULL[] = { 0xa5, 0x0, 0x5a }; +#define SQLITE_EXPLICIT_NULL_LEN 3 + +/* + * determine when we've completed our tasks + */ +#define MAX_RETRIES 10 +static int +sdb_done(int err, int *count) +{ + /* allow as many rows as the database wants to give */ + if (err == SQLITE_ROW) { + *count = 0; + return 0; + } + if (err != SQLITE_BUSY) { + return 1; + } + /* err == SQLITE_BUSY, Dont' retry forever in this case */ + if (++(*count) >= MAX_RETRIES) { + return 1; + } + return 0; +} + +/* + * Map SQL_LITE errors to PKCS #11 errors as best we can. + */ +static int +sdb_mapSQLError(sdbDataType type, int sqlerr) +{ + switch (sqlerr) { + /* good matches */ + case SQLITE_OK: + case SQLITE_DONE: + return CKR_OK; + case SQLITE_NOMEM: + return CKR_HOST_MEMORY; + case SQLITE_READONLY: + return CKR_TOKEN_WRITE_PROTECTED; + /* close matches */ + case SQLITE_AUTH: + case SQLITE_PERM: + /*return CKR_USER_NOT_LOGGED_IN; */ + case SQLITE_CANTOPEN: + case SQLITE_NOTFOUND: + /* NSS distiguishes between failure to open the cert and the key db */ + return type == SDB_CERT ? + CKR_NETSCAPE_CERTDB_FAILED : CKR_NETSCAPE_KEYDB_FAILED; + case SQLITE_IOERR: + return CKR_DEVICE_ERROR; + default: + break; + } + return CKR_GENERAL_ERROR; +} + +/* + * sqlite3 cannot share handles across threads, in general. + * PKCS #11 modules can be called thread, so we need to constantly open and + * close the sqlite database. + * + * The one exception is transactions. When we are in a transaction, we must + * use the same database pointer for that entire transation. In this case + * we save the transaction database and use it for all accesses on the + * transaction thread. Other threads still get their own database. + * + * There can only be once active transaction on the database at a time. + */ +static CK_RV +sdb_openDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB) +{ +#ifdef SQLITE_THREAD_SHARE_DB + *sqlDB = sdb_p->sqlXactDB; + return CKR_OK; +#else + + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + + char *dbname = sdb_p->sqlDBName; + sdbDataType type = sdb_p->type; + + *sqlDB = NULL; + + PR_Lock(sdb_p->lock); + + /* We're in a transaction, use the transaction DB */ + if ((sdb_p->sqlXactDB) && (sdb_p->sqlXactThread == PR_GetCurrentThread())) { + *sqlDB =sdb_p->sqlXactDB; + /* only one thread can get here, safe to unlock */ + PR_Unlock(sdb_p->lock); + return CKR_OK; + } + + /* we're and independent operation, get our own db handle */ + PR_Unlock(sdb_p->lock); + + sqlerr = sqlite3_open(dbname, sqlDB); + if (sqlerr != SQLITE_OK) { + error = sdb_mapSQLError(type, sqlerr); + goto loser; + } + + sqlerr = sqlite3_busy_timeout(*sqlDB, 1000); + if (sqlerr != CKR_OK) { + error = sdb_mapSQLError(type, sqlerr); + goto loser; + } + return error; + +loser: + if (*sqlDB) { + sqlite3_close(*sqlDB); + *sqlDB = NULL; + } + return error; +#endif +} + +/* down with the local database, free it if we allocated it, otherwise + * free unlock our use the the transaction database */ +static CK_RV +sdb_closeDBLocal(SDBPrivate *sdb_p, sqlite3 *sqlDB) +{ +#ifndef SQLITE_THREAD_SHARE_DB + if (sdb_p->sqlXactDB != sqlDB) { + sqlite3_close(sqlDB); + } +#endif + return CKR_OK; +} + +struct SDBFindStr { + sqlite3 *sqlDB; + sqlite3_stmt *findstmt; +}; + + +#define FIND_OBJECTS_CMD "SELECT ALL * FROM %s WHERE %s;" +#define FIND_OBJECTS_ALL_CMD "SELECT ALL * FROM %s;" +CK_RV +sdb_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *template, CK_ULONG count, + SDBFind **find) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = NULL; + char *newStr, *findStr = NULL; + sqlite3_stmt *findstmt = NULL; + char *join=""; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + int i; + + LOCK_SQLITE() + *find = NULL; + error = sdb_openDBLocal(sdb_p, &sqlDB); + if (error != CKR_OK) { + goto loser; + } + + findStr = sqlite3_mprintf(""); + for (i=0; findStr && i < count; i++) { + newStr = sqlite3_mprintf("%s%sa%x=$DATA%d", findStr, join, + template[i].type, i); + join=" AND "; + sqlite3_free(findStr); + findStr = newStr; + } + + if (findStr == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + + if (count == 0) { + newStr = sqlite3_mprintf(FIND_OBJECTS_ALL_CMD, sdb_p->table); + } else { + newStr = sqlite3_mprintf(FIND_OBJECTS_CMD, sdb_p->table, findStr); + } + sqlite3_free(findStr); + if (newStr == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + sqlerr = sqlite3_prepare(sqlDB, newStr, -1, &findstmt, NULL); + sqlite3_free(newStr); + for (i=0; sqlerr == SQLITE_OK && i < count; i++) { + sqlerr = sqlite3_bind_blob(findstmt, i+1, template[i].pValue, + template[i].ulValueLen, SQLITE_TRANSIENT); + } + if (sqlerr == SQLITE_OK) { + *find = PORT_New(SDBFind); + if (*find == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + (*find)->findstmt = findstmt; + (*find)->sqlDB = sqlDB; + UNLOCK_SQLITE() + return CKR_OK; + } + error = sdb_mapSQLError(sdb_p->type, sqlerr); + +loser: + if (findstmt) { + sqlite3_finalize(findstmt); + } + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + UNLOCK_SQLITE() + return error; +} + + +CK_RV +sdb_FindObjects(SDB *sdb, SDBFind *sdbFind, CK_OBJECT_HANDLE *object, + CK_ULONG arraySize, CK_ULONG *count) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3_stmt *stmt = sdbFind->findstmt; + int sqlerr = SQLITE_OK; + int retry = 0; + + *count = 0; + + if (arraySize == 0) { + return CKR_OK; + } + LOCK_SQLITE() + + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + if (sqlerr == SQLITE_ROW) { + /* only care about the id */ + *object++= sqlite3_column_int(stmt, 0); + arraySize--; + (*count)++; + } + } while (!sdb_done(sqlerr,&retry) && (arraySize > 0)); + + /* we only have some of the objects, there is probably more, + * set the sqlerr to an OK value so we return CKR_OK */ + if (sqlerr == SQLITE_ROW && arraySize == 0) { + sqlerr = SQLITE_DONE; + } + UNLOCK_SQLITE() + + return sdb_mapSQLError(sdb_p->type, sqlerr); +} + +CK_RV +sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3_stmt *stmt = sdbFind->findstmt; + sqlite3 *sqlDB = sdbFind->sqlDB; + int sqlerr = SQLITE_OK; + + LOCK_SQLITE() + if (stmt) { + sqlite3_reset(stmt); + sqlerr = sqlite3_finalize(stmt); + } + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + PORT_Free(sdbFind); + + UNLOCK_SQLITE() + return sdb_mapSQLError(sdb_p->type, sqlerr); +} + +#define GET_ATTRIBUTE_CMD "SELECT ALL %s FROM %s WHERE id=$ID;" +CK_RV +sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id, + CK_ATTRIBUTE *template, CK_ULONG count) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = NULL; + sqlite3_stmt *stmt = NULL; + char *getStr = NULL; + char *newStr = NULL; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + int found = 0; + int retry = 0; + int i; + + getStr = sqlite3_mprintf(""); + for (i=0; getStr && i < count; i++) { + if (i==0) { + newStr = sqlite3_mprintf("a%x", template[i].type); + } else { + newStr = sqlite3_mprintf("%s, a%x", getStr, template[i].type); + } + sqlite3_free(getStr); + getStr = newStr; + } + + if (getStr == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + + newStr = sqlite3_mprintf(GET_ATTRIBUTE_CMD, getStr, sdb_p->table); + sqlite3_free(getStr); + getStr = NULL; + if (newStr == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + /* open a new db if necessary */ + error = sdb_openDBLocal(sdb_p,&sqlDB); + if (error != CKR_OK) { + goto loser; + } + sqlerr = sqlite3_prepare(sqlDB, newStr, -1, &stmt, NULL); + if (sqlerr != SQLITE_OK) { goto loser; } + sqlerr = sqlite3_bind_int(stmt, 1, object_id); + if (sqlerr != SQLITE_OK) { goto loser; } + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + if (sqlerr == SQLITE_ROW) { + for (i=0; i < count; i++) { + int column = i; + int blobSize; + const char *blobData; + + blobSize = sqlite3_column_bytes(stmt, column); + blobData = sqlite3_column_blob(stmt, column); + if (blobData == NULL) { + template[i].ulValueLen = -1; + error = CKR_ATTRIBUTE_TYPE_INVALID; + continue; + } + /* If the blob equals our explicit NULL value, then the + * attribute is a NULL. */ + if ((blobSize == SQLITE_EXPLICIT_NULL_LEN) && + (PORT_Memcmp(blobData, SQLITE_EXPLICIT_NULL, + SQLITE_EXPLICIT_NULL_LEN) == 0)) { + blobSize = 0; + } + if (template[i].pValue) { + if (template[i].ulValueLen < blobSize) { + template[i].ulValueLen = -1; + error = CKR_BUFFER_TOO_SMALL; + continue; + } + PORT_Memcpy(template[i].pValue, blobData, blobSize); + } + template[i].ulValueLen = blobSize; + } + found = 1; + } + } while (!sdb_done(sqlerr,&retry)); + +loser: + /* fix up the error if necessary */ + if (error == CKR_OK) { + error = sdb_mapSQLError(sdb_p->type, sqlerr); + if (!found && error == CKR_OK) { + error = CKR_OBJECT_HANDLE_INVALID; + } + } + if (newStr) { + sqlite3_free(newStr); + } + + if (stmt) { + sqlite3_reset(stmt); + sqlite3_finalize(stmt); + } + + /* if we had to open a new database, free it now */ + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + return error; +} + +CK_RV +sdb_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, + CK_ATTRIBUTE *template, CK_ULONG count) +{ + CK_RV crv; + + if (count == 0) { + return CKR_OK; + } + + LOCK_SQLITE() + crv = sdb_GetAttributeValueNoLock(sdb, object_id, template, count); + UNLOCK_SQLITE() + return crv; +} + +#define SET_ATTRIBUTE_CMD "UPDATE %s SET %s WHERE id=$ID;" +CK_RV +sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, + const CK_ATTRIBUTE *template, CK_ULONG count) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = NULL; + sqlite3_stmt *stmt = NULL; + char *setStr = NULL; + char *newStr = NULL; + int sqlerr = SQLITE_OK; + int retry = 0; + CK_RV error = CKR_OK; + int i; + + if (sdb->sdb_flags == SDB_RDONLY) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + if (count == 0) { + return CKR_OK; + } + + LOCK_SQLITE() + setStr = sqlite3_mprintf(""); + for (i=0; setStr && i < count; i++) { + if (i==0) { + sqlite3_free(setStr); + setStr = sqlite3_mprintf("a%x=$VALUE%d", + template[i].type, i); + continue; + } + newStr = sqlite3_mprintf("%s,a%x=$VALUE%d", setStr, + template[i].type, i); + sqlite3_free(setStr); + setStr = newStr; + } + newStr = NULL; + + if (setStr == NULL) { + return CKR_HOST_MEMORY; + } + newStr = sqlite3_mprintf(SET_ATTRIBUTE_CMD, sdb_p->table, setStr); + sqlite3_free(setStr); + if (newStr == NULL) { + UNLOCK_SQLITE() + return CKR_HOST_MEMORY; + } + error = sdb_openDBLocal(sdb_p, &sqlDB); + if (error != CKR_OK) { + goto loser; + } + sqlerr = sqlite3_prepare(sqlDB, newStr, -1, &stmt, NULL); + if (sqlerr != SQLITE_OK) goto loser; + for (i=0; i < count; i++) { + if (template[i].ulValueLen != 0) { + sqlerr = sqlite3_bind_blob(stmt, i+1, template[i].pValue, + template[i].ulValueLen, SQLITE_STATIC); + } else { + sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL, + SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); + } + if (sqlerr != SQLITE_OK) goto loser; + } + sqlerr = sqlite3_bind_int(stmt, i+1, object_id); + if (sqlerr != SQLITE_OK) goto loser; + + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + } while (!sdb_done(sqlerr,&retry)); + +loser: + if (newStr) { + sqlite3_free(newStr); + } + if (error == CKR_OK) { + error = sdb_mapSQLError(sdb_p->type, sqlerr); + } + + if (stmt) { + sqlite3_reset(stmt); + sqlite3_finalize(stmt); + } + + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + + UNLOCK_SQLITE() + return error; +} + +/* + * check to see if a candidate object handle already exists. + */ +static PRBool +sdb_objectExists(SDB *sdb, CK_OBJECT_HANDLE candidate) +{ + CK_RV crv; + CK_ATTRIBUTE template = { CKA_LABEL, NULL, 0 }; + + crv = sdb_GetAttributeValueNoLock(sdb,candidate,&template, 1); + if (crv == CKR_OBJECT_HANDLE_INVALID) { + return PR_FALSE; + } + return PR_TRUE; +} + +/* + * if we're here, we are in a transaction, so it's safe + * to examine the current state of the database + */ +static CK_OBJECT_HANDLE +sdb_getObjectId(SDB *sdb) +{ + CK_OBJECT_HANDLE candidate; + static CK_OBJECT_HANDLE next_obj = CK_INVALID_HANDLE; + int count; + /* + * get an initial object handle to use + */ + if (next_obj == CK_INVALID_HANDLE) { + PRTime time; + time = PR_Now(); + + next_obj = (CK_OBJECT_HANDLE)(time & 0x3fffffffL); + } + candidate = next_obj++; + /* detect that we've looped through all the handles... */ + for (count = 0; count < 0x40000000; count++, candidate = next_obj++) { + /* mask off excess bits */ + candidate &= 0x3fffffff; + /* if we hit zero, go to the next entry */ + if (candidate == CK_INVALID_HANDLE) { + continue; + } + /* make sure we aren't already using */ + if (!sdb_objectExists(sdb, candidate)) { + /* this one is free */ + return candidate; + } + } + + /* no handle is free, fail */ + return CK_INVALID_HANDLE; +} + +#define CREATE_CMD "INSERT INTO %s (id%s) VALUES($ID%s);" +CK_RV +sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id, + const CK_ATTRIBUTE *template, CK_ULONG count) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = NULL; + sqlite3_stmt *stmt = NULL; + char *columnStr = NULL; + char *valueStr = NULL; + char *newStr = NULL; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + CK_OBJECT_HANDLE this_object; + int retry = 0; + int i; + + if (sdb->sdb_flags == SDB_RDONLY) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + LOCK_SQLITE() + if ((*object_id != CK_INVALID_HANDLE) && + !sdb_objectExists(sdb, *object_id)) { + this_object = *object_id; + } else { + this_object = sdb_getObjectId(sdb); + } + if (this_object == CK_INVALID_HANDLE) { + UNLOCK_SQLITE(); + return CKR_HOST_MEMORY; + } + columnStr = sqlite3_mprintf(""); + valueStr = sqlite3_mprintf(""); + *object_id = this_object; + for (i=0; columnStr && valueStr && i < count; i++) { + newStr = sqlite3_mprintf("%s,a%x", columnStr, template[i].type); + sqlite3_free(columnStr); + columnStr = newStr; + newStr = sqlite3_mprintf("%s,$VALUE%d", valueStr, i); + sqlite3_free(valueStr); + valueStr = newStr; + } + newStr = NULL; + if ((columnStr == NULL) || (valueStr == NULL)) { + if (columnStr) { + sqlite3_free(columnStr); + } + if (valueStr) { + sqlite3_free(valueStr); + } + UNLOCK_SQLITE() + return CKR_HOST_MEMORY; + } + newStr = sqlite3_mprintf(CREATE_CMD, sdb_p->table, columnStr, valueStr); + sqlite3_free(columnStr); + sqlite3_free(valueStr); + error = sdb_openDBLocal(sdb_p, &sqlDB); + if (error != CKR_OK) { + goto loser; + } + sqlerr = sqlite3_prepare(sqlDB, newStr, -1, &stmt, NULL); + if (sqlerr != SQLITE_OK) goto loser; + sqlerr = sqlite3_bind_int(stmt, 1, *object_id); + if (sqlerr != SQLITE_OK) goto loser; + for (i=0; i < count; i++) { + if (template[i].ulValueLen) { + sqlerr = sqlite3_bind_blob(stmt, i+2, template[i].pValue, + template[i].ulValueLen, SQLITE_STATIC); + } else { + sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL, + SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); + } + if (sqlerr != SQLITE_OK) goto loser; + } + + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + } while (!sdb_done(sqlerr,&retry)); + +loser: + if (newStr) { + sqlite3_free(newStr); + } + if (error == CKR_OK) { + error = sdb_mapSQLError(sdb_p->type, sqlerr); + } + + if (stmt) { + sqlite3_reset(stmt); + sqlite3_finalize(stmt); + } + + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + UNLOCK_SQLITE() + + return error; +} + +#define DESTROY_CMD "DELETE FROM %s WHERE (id=$ID);" +CK_RV +sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = NULL; + sqlite3_stmt *stmt = NULL; + char *newStr = NULL; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + int retry = 0; + + if (sdb->sdb_flags == SDB_RDONLY) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + LOCK_SQLITE() + error = sdb_openDBLocal(sdb_p, &sqlDB); + if (error != CKR_OK) { + goto loser; + } + newStr = sqlite3_mprintf(DESTROY_CMD, sdb_p->table); + if (newStr == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + sqlerr =sqlite3_prepare(sqlDB, newStr, -1, &stmt, NULL); + sqlite3_free(newStr); + if (sqlerr != SQLITE_OK) goto loser; + sqlerr =sqlite3_bind_int(stmt, 1, object_id); + if (sqlerr != SQLITE_OK) goto loser; + + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + } while (!sdb_done(sqlerr,&retry)); + +loser: + if (error == CKR_OK) { + error = sdb_mapSQLError(sdb_p->type, sqlerr); + } + + if (stmt) { + sqlite3_reset(stmt); + sqlite3_finalize(stmt); + } + + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + + UNLOCK_SQLITE() + return error; +} + +#define BEGIN_CMD "BEGIN IMMEDIATE TRANSACTION;" +/* + * start a transaction. + * + * We need to open a new database, then store that new database into + * the private data structure. We open the database first, then use locks + * to protect storing the data to prevent deadlocks. + */ +CK_RV +sdb_Begin(SDB *sdb) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = NULL; + sqlite3_stmt *stmt = NULL; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + int retry = 0; + + + if (sdb->sdb_flags == SDB_RDONLY) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + + LOCK_SQLITE() +#ifdef SQLITE_THREAD_SHARE_DB + sqlDB = sdb_p->sqlXactDB; +#else + /* get a new version that we will use for the entire transaction */ + sqlerr = sqlite3_open(sdb_p->sqlDBName, &sqlDB); + if (sqlerr != SQLITE_OK) { + goto loser; + } +#endif + + sqlerr = sqlite3_busy_timeout(sqlDB, 1000); + if (sqlerr != CKR_OK) { + goto loser; + } + + sqlerr =sqlite3_prepare(sqlDB, BEGIN_CMD, -1, &stmt, NULL); + + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + } while (!sdb_done(sqlerr,&retry)); + + if (stmt) { + sqlite3_reset(stmt); + sqlite3_finalize(stmt); + } + +loser: + error = sdb_mapSQLError(sdb_p->type, sqlerr); + +#ifndef SQLITE_THREAD_SHARE_DB + /* we are starting a new transaction, + * and if we succeeded, then save this database for the rest of + * our transaction */ + if (error == CKR_OK) { + /* we hold a 'BEGIN TRANSACTION' and a sdb_p->lock. At this point + * sdb_p->sqlXactDB MUST be null */ + PR_Lock(sdb_p->lock); + PORT_Assert(sdb_p->sqlXactDB == NULL); + sdb_p->sqlXactDB = sqlDB; + sdb_p->sqlXactThread = PR_GetCurrentThread(); + PR_Unlock(sdb_p->lock); + } else { + /* we failed to start our transaction, + * free any databases we openned. */ + if (sqlDB) { + sqlite3_close(sqlDB); + } + } +#endif + + UNLOCK_SQLITE() + return error; +} + +/* + * Complete a transaction. Basically undo everything we did in begin. + * There are 2 flavors Abort and Commit. Basically the only differerence between + * these 2 are what the database will show. (no change in to former, change in + * the latter). + */ +static CK_RV +sdb_complete(SDB *sdb, const char *cmd) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = NULL; + sqlite3_stmt *stmt = NULL; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + int retry = 0; + + + if (sdb->sdb_flags == SDB_RDONLY) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + +#ifndef SQLITE_THREAD_SHARE_DB + /* We must have a transation database, or we shouldn't have arrived here */ + PR_Lock(sdb_p->lock); + PORT_Assert(sdb_p->sqlXactDB); + if (sdb_p->sqlXactDB == NULL) { + PR_Unlock(sdb_p->lock); + return CKR_GENERAL_ERROR; /* shouldn't happen */ + } + PORT_Assert( sdb_p->sqlXactThread == PR_GetCurrentThread()); + if ( sdb_p->sqlXactThread != PR_GetCurrentThread()) { + PR_Unlock(sdb_p->lock); + return CKR_GENERAL_ERROR; /* shouldn't happen */ + } + sqlDB = sdb_p->sqlXactDB; + sdb_p->sqlXactDB = NULL; /* no one else can get to this DB, + * safe to unlock */ + sdb_p->sqlXactThread = NULL; + PR_Unlock(sdb_p->lock); +#else + sqlDB = sdb_p->sqlXactDB; +#endif + + sqlerr =sqlite3_prepare(sqlDB, cmd, -1, &stmt, NULL); + + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + } while (!sdb_done(sqlerr,&retry)); + + /* Pending BEGIN TRANSACTIONS Can move forward at this point. */ + + if (stmt) { + sqlite3_reset(stmt); + sqlite3_finalize(stmt); + } + + error = sdb_mapSQLError(sdb_p->type, sqlerr); + +#ifndef SQLITE_THREAD_SHARE_DB + /* We just finished a transaction. + * Free the database, and remove it from the list */ + sqlite3_close(sqlDB); +#endif + + return error; +} + +#define COMMIT_CMD "COMMIT TRANSACTION;" +CK_RV +sdb_Commit(SDB *sdb) +{ + CK_RV crv; + LOCK_SQLITE() + crv = sdb_complete(sdb,COMMIT_CMD); + UNLOCK_SQLITE() + return crv; +} + +#define ROLLBACK_CMD "ROLLBACK TRANSACTION;" +CK_RV +sdb_Abort(SDB *sdb) +{ + CK_RV crv; + LOCK_SQLITE() + crv = sdb_complete(sdb,ROLLBACK_CMD); + UNLOCK_SQLITE() + return crv; +} + +#define GET_PW_CMD "SELECT ALL * FROM password WHERE id='password';" +CK_RV +sdb_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = sdb_p->sqlXactDB; + sqlite3_stmt *stmt = NULL; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + int found = 0; + int retry = 0; + + /* only Key databases have password entries */ + if (sdb_p->type != SDB_KEY) { + return CKR_OBJECT_HANDLE_INVALID; + } + + LOCK_SQLITE() + error = sdb_openDBLocal(sdb_p, &sqlDB); + if (error != CKR_OK) { + goto loser; + } + + sqlerr = sqlite3_prepare(sqlDB, GET_PW_CMD, -1, &stmt, NULL); + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + if (sqlerr == SQLITE_ROW) { + const char *blobData; + entry->salt.data = entry->data; + entry->salt.len = sqlite3_column_bytes(stmt, 1); + if (entry->salt.len > sizeof(entry->data)) { + error = CKR_BUFFER_TOO_SMALL; + continue; + } + blobData = sqlite3_column_blob(stmt, 1); + PORT_Memcpy(entry->salt.data,blobData, entry->salt.len); + entry->value.data = &entry->data[entry->salt.len]; + entry->value.len = sqlite3_column_bytes(stmt, 2); + if ((entry->value.len+entry->salt.len) > sizeof(entry->data)) { + error = CKR_BUFFER_TOO_SMALL; + continue; + } + blobData = sqlite3_column_blob(stmt, 2); + PORT_Memcpy(entry->value.data,blobData, entry->value.len); + found = 1; + } + } while (!sdb_done(sqlerr,&retry)); + +loser: + /* fix up the error if necessary */ + if (error == CKR_OK) { + error = sdb_mapSQLError(sdb_p->type, sqlerr); + if (!found && error == CKR_OK) { + error = CKR_OBJECT_HANDLE_INVALID; + } + } + + if (stmt) { + sqlite3_reset(stmt); + sqlite3_finalize(stmt); + } + + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + UNLOCK_SQLITE() + + return error; +} + +static int tableExists(sqlite3 *sqlDB, const char *tableName); +#define PW_CREATE_TABLE_CMD \ + "CREATE TABLE password (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, salt, value);" +#define PW_CREATE_CMD \ + "INSERT INTO password (id,salt,value) VALUES('password',$SALT,$VALUE);" +CK_RV +sdb_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = sdb_p->sqlXactDB; + sqlite3_stmt *stmt = NULL; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + int retry = 0; + + /* only Key databases have password entries */ + if (sdb_p->type != SDB_KEY) { + return CKR_OBJECT_HANDLE_INVALID; + } + + LOCK_SQLITE() + error = sdb_openDBLocal(sdb_p, &sqlDB); + if (error != CKR_OK) { + goto loser; + } + + if (!tableExists(sqlDB, "password")) { + sqlerr = sqlite3_exec(sqlDB, PW_CREATE_TABLE_CMD, NULL, 0, NULL); + if (sqlerr != SQLITE_OK) goto loser; + } + sqlerr = sqlite3_prepare(sqlDB, PW_CREATE_CMD, -1, &stmt, NULL); + if (sqlerr != SQLITE_OK) goto loser; + sqlerr = sqlite3_bind_blob(stmt, 1, entry->salt.data, + entry->salt.len, SQLITE_STATIC); + if (sqlerr != SQLITE_OK) goto loser; + sqlerr = sqlite3_bind_blob(stmt, 2, entry->value.data, + entry->value.len, SQLITE_STATIC); + if (sqlerr != SQLITE_OK) goto loser; + + do { + sqlerr = sqlite3_step(stmt); + if (sqlerr == SQLITE_BUSY) { + PR_Sleep(5); + } + } while (!sdb_done(sqlerr,&retry)); + +loser: + /* fix up the error if necessary */ + if (error == CKR_OK) { + error = sdb_mapSQLError(sdb_p->type, sqlerr); + } + + if (stmt) { + sqlite3_reset(stmt); + sqlite3_finalize(stmt); + } + + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + UNLOCK_SQLITE() + + return error; +} + +#define RESET_CMD "DROP TABLE IF EXISTS %s;" +CK_RV +sdb_Reset(SDB *sdb) +{ + SDBPrivate *sdb_p = sdb->private; + sqlite3 *sqlDB = NULL; + char *newStr; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + + /* only Key databases can be reset */ + if (sdb_p->type != SDB_KEY) { + return CKR_OBJECT_HANDLE_INVALID; + } + + LOCK_SQLITE() + error = sdb_openDBLocal(sdb_p, &sqlDB); + if (error != CKR_OK) { + goto loser; + } + + /* delete the key table */ + newStr = sqlite3_mprintf(RESET_CMD, sdb_p->table); + if (newStr == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); + sqlite3_free(newStr); + + if (sqlerr != SQLITE_OK) goto loser; + + /* delete the password entry table */ + sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS password;", + NULL, 0, NULL); + +loser: + /* fix up the error if necessary */ + if (error == CKR_OK) { + error = sdb_mapSQLError(sdb_p->type, sqlerr); + } + + if (sqlDB) { + sdb_closeDBLocal(sdb_p, sqlDB) ; + } + + UNLOCK_SQLITE() + return error; +} + + +CK_RV +sdb_Close(SDB *sdb) +{ + SDBPrivate *sdb_p = sdb->private; + int sqlerr = SQLITE_OK; + sdbDataType type = sdb_p->type; + + /* sqlerr = sqlite3_close(sqlDB); */ + PORT_Free(sdb_p->sqlDBName); + free(sdb_p); + free(sdb); + return sdb_mapSQLError(type, sqlerr); +} + + +/* + * functions to support open + */ + +#define CHECK_TABLE_CMD "SELECT ALL * FROM %s LIMIT 0;" +/* return 1 if sqlDB contains table 'tableName */ +static int tableExists(sqlite3 *sqlDB, const char *tableName) +{ + char * cmd = sqlite3_mprintf(CHECK_TABLE_CMD, tableName); + int sqlerr = SQLITE_OK; + + if (cmd == NULL) { + return 0; + } + + sqlerr = sqlite3_exec(sqlDB, cmd, NULL, 0, 0); + sqlite3_free(cmd); + + return (sqlerr == SQLITE_OK) ? 1 : 0; +} + +/* + * initialize a single database + */ +#define INIT_CMD \ + "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)" +#define ALTER_CMD \ + "ALTER TABLE %s ADD COLUMN a%x" + + +CK_RV +sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, + int *newInit, int flags, SDB **pSdb) +{ + int i; + char *initStr = NULL; + char *newStr; + int inTransaction = 0; + SDB *sdb = NULL; + SDBPrivate *sdb_p = NULL; + sqlite3 *sqlDB = NULL; + int sqlerr = SQLITE_OK; + CK_RV error = CKR_OK; + + *pSdb = NULL; + *inUpdate = 0; + + /* sqlite3 doesn't have a flag to specify that we want to + * open the database read only. If the db doesn't exist, + * sqlite3 will always create it. + */ + LOCK_SQLITE(); + if ((flags == SDB_RDONLY) && PR_Access(dbname, PR_ACCESS_EXISTS)) { + error = sdb_mapSQLError(type, SQLITE_CANTOPEN); + goto loser; + } + sqlerr = sqlite3_open(dbname, &sqlDB); + if (sqlerr != SQLITE_OK) { + error = sdb_mapSQLError(type, sqlerr); + goto loser; + } + + sqlerr = sqlite3_busy_timeout(sqlDB, 1000); + if (sqlerr != CKR_OK) { + error = sdb_mapSQLError(type, sqlerr); + goto loser; + } + + if (flags != SDB_RDONLY) { + sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL); + if (sqlerr != SQLITE_OK) { + error = sdb_mapSQLError(type, sqlerr); + goto loser; + } + inTransaction = 1; + } + if (!tableExists(sqlDB,table)) { + *newInit = 1; + if (flags != SDB_CREATE) { + error = sdb_mapSQLError(type, SQLITE_CANTOPEN); + goto loser; + } + initStr = sqlite3_mprintf(""); + for (i=0; initStr && i < known_attributes_size; i++) { + newStr = sqlite3_mprintf("%s, a%x",initStr, known_attributes[i]); + sqlite3_free(initStr); + initStr = newStr; + } + if (initStr == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + newStr = sqlite3_mprintf(INIT_CMD, table, initStr); + sqlite3_free(initStr); + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); + sqlite3_free(newStr); + if (sqlerr != SQLITE_OK) { + error = sdb_mapSQLError(type, sqlerr); + goto loser; + } + } else { + /* if the nssInit table exists, then someone else is initing the + * nss database. We don't want to complete the open until the init + * is completed. */ + if (tableExists(sqlDB,"nssInUpdate")) { + *inUpdate = 1; + } + } + sdb = (SDB *) malloc(sizeof(SDB)); + sdb_p = (SDBPrivate *) malloc(sizeof(SDBPrivate)); + /* invariant fields */ + sdb_p->sqlDBName = PORT_Strdup(dbname); + sdb_p->type = type; + sdb_p->table = table; + sdb_p->lock = PR_NewLock(); + /* these fields are protected by the lock */ + sdb_p->sqlXactDB = NULL; + sdb_p->sqlXactThread = NULL; + sdb->private = sdb_p; + sdb->sdb_type = SDB_SQL; + sdb->sdb_flags = flags; + sdb->sdb_FindObjectsInit = sdb_FindObjectsInit; + sdb->sdb_FindObjects = sdb_FindObjects; + sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal; + sdb->sdb_GetAttributeValue = sdb_GetAttributeValue; + sdb->sdb_SetAttributeValue = sdb_SetAttributeValue; + sdb->sdb_CreateObject = sdb_CreateObject; + sdb->sdb_DestroyObject = sdb_DestroyObject; + sdb->sdb_GetPWEntry = sdb_GetPWEntry; + sdb->sdb_PutPWEntry = sdb_PutPWEntry; + sdb->sdb_Begin = sdb_Begin; + sdb->sdb_Commit = sdb_Commit; + sdb->sdb_Abort = sdb_Abort; + sdb->sdb_Close = sdb_Close; + + if (inTransaction) { + sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL); + if (sqlerr != SQLITE_OK) { + error = sdb_mapSQLError(sdb_p->type, sqlerr); + goto loser; + } + inTransaction = 0; + } + if (*inUpdate) { + while (tableExists(sqlDB,"nssInit")) { + PR_Sleep(5); + } + } +#ifdef SQLITE_THREAD_SHARE_DB + sdb_p->sqlXactDB = sqlDB; +#else + /* sqlite3 cannot share sqlDB references across threads, open the + * db only when we need to read or update it (sigh) */ + sqlite3_close(sqlDB); +#endif + + *pSdb = sdb; + UNLOCK_SQLITE(); + return CKR_OK; + +loser: + /* lots of stuff to do */ + if (inTransaction) { + sqlite3_exec(sqlDB, ROLLBACK_CMD, NULL, 0, NULL); + } + if (sdb) { + free(sdb); + } + if (sdb_p) { + free(sdb_p); + } + if (sqlDB) { + sqlite3_close(sqlDB); + } + UNLOCK_SQLITE(); + return error; + +} + +static char *sdb_BuildFileName(const char * directory, + const char *prefix, const char *type, + int version, int flags) +{ + char *dbname = NULL; + /* build the full dbname */ + dbname = sqlite3_mprintf("%s/%s%s%d.db",directory, prefix, type, version); + return dbname; +} + +/* sdbopen */ +CK_RV +s_open(const char *directory, const char *certPrefix, const char *keyPrefix, + int cert_version, int key_version, int flags, + SDB **certdb, SDB **keydb, int *newInit) +{ + char *cert = sdb_BuildFileName(directory, certPrefix, + "cert", cert_version, flags); + char *key = sdb_BuildFileName(directory, keyPrefix, + "key", key_version, flags); + CK_RV error = CKR_OK; + int inUpdate; + + *certdb = NULL; + *keydb = NULL; + *newInit = 0; + +#ifdef SQLITE_UNSAFE_THREADS + if (sqlite_lock == NULL) { + sqlite_lock = PR_NewLock(); + if (sqlite_lock == NULL) { + error = CKR_HOST_MEMORY; + goto loser; + } + } +#endif + + /* + * open the cert data base + */ + if (certdb) { + /* initialize Certificate database */ + error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate, + newInit, flags, certdb); + if (error != CKR_OK) { + goto loser; + } + } + + /* + * open the key data base: + * NOTE:is we want to implement a single database, we open + * the same database file as the certificate here. + * + * cert an key db's have different tables, so they will not + * conflict. + */ + if (keydb) { + /* initialize the Key database */ + error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate, + newInit, flags, keydb); + if (error != CKR_OK) { + goto loser; + } + } + + +loser: + if (cert) { + sqlite3_free(cert); + } + if (key) { + sqlite3_free(key); + } + + if (error != CKR_OK) { + /* currently redundant, but could be necessary if more code is added + * just before loser */ + if (keydb && *keydb) { + sdb_Close(*keydb); + } + if (certdb && *certdb) { + sdb_Close(*certdb); + } + } + + return error; +} + +CK_RV +s_shutdown() +{ +#ifdef SQLITE_UNSAFE_THREADS + if (sqlite_lock) { + PR_DestroyLock(sqlite_lock); + sqlite_lock = NULL; + } +#endif + return CKR_OK; +} diff --git a/security/nss/lib/softoken/sdb.h b/security/nss/lib/softoken/sdb.h new file mode 100644 index 000000000..818bc4bf1 --- /dev/null +++ b/security/nss/lib/softoken/sdb.h @@ -0,0 +1,115 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Red Hat, Inc. + * + * The Initial Developer of the Original Code is + * Red Hat, Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert Relyea (rrelyea@redhat.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This file implements PKCS 11 on top of our existing security modules + * + * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. + * This implementation has two slots: + * slot 1 is our generic crypto support. It does not require login. + * It supports Public Key ops, and all they bulk ciphers and hashes. + * It can also support Private Key ops for imported Private keys. It does + * not have any token storage. + * slot 2 is our private key support. It requires a login before use. It + * can store Private Keys and Certs as token objects. Currently only private + * keys and their associated Certificates are saved on the token. + * + * In this implementation, session objects are only visible to the session + * that created or generated them. + */ + +/* + * the following data structures should be moved to a 'rdb.h'. + */ + +#ifndef _SDB_H +#define _SDB_H 1 +#include "pkcs11t.h" +#include "secitem.h" +#include "sftkdbt.h" +#include <sqlite3.h> + +#define STATIC_CMD_SIZE 2048 + +typedef struct SDBFindStr SDBFind; +typedef struct SDBStr SDB; +typedef struct SDBPasswordEntryStr SDBPasswordEntry; + +struct SDBStr { + void *private; + int version; + SDBType sdb_type; + int sdb_flags; + void *app_private; + CK_RV (*sdb_FindObjectsInit)(SDB *sdb, const CK_ATTRIBUTE *template, + CK_ULONG count, SDBFind **find); + CK_RV (*sdb_FindObjects)(SDB *sdb, SDBFind *find, CK_OBJECT_HANDLE *ids, + CK_ULONG arraySize, CK_ULONG *count); + CK_RV (*sdb_FindObjectsFinal)(SDB *sdb, SDBFind *find); + CK_RV (*sdb_GetAttributeValue)(SDB *sdb, CK_OBJECT_HANDLE object, + CK_ATTRIBUTE *template, CK_ULONG count); + CK_RV (*sdb_SetAttributeValue)(SDB *sdb, CK_OBJECT_HANDLE object, + const CK_ATTRIBUTE *template, CK_ULONG count); + CK_RV (*sdb_CreateObject)(SDB *sdb, CK_OBJECT_HANDLE *object, + const CK_ATTRIBUTE *template, CK_ULONG count); + CK_RV (*sdb_DestroyObject)(SDB *sdb, CK_OBJECT_HANDLE object); + CK_RV (*sdb_GetPWEntry)(SDB *sdb, SDBPasswordEntry *entry); + CK_RV (*sdb_PutPWEntry)(SDB *sdb, SDBPasswordEntry *entry); + CK_RV (*sdb_Begin)(SDB *sdb); + CK_RV (*sdb_Commit)(SDB *sdb); + CK_RV (*sdb_Abort)(SDB *sdb); + CK_RV (*sdb_Reset)(SDB *sdb); + CK_RV (*sdb_Close)(SDB *sdb); +}; + +struct SDBPasswordEntryStr { + SECItem salt; + SECItem value; + unsigned char data[128]; +}; + +CK_RV s_open(const char *directory, const char *certPrefix, + const char *keyPrefix, + int cert_version, int key_version, + int flags, SDB **certdb, SDB **keydb, int *newInit); +CK_RV s_shutdown(); + +/* flags */ +#define SDB_RDONLY 1 +#define SDB_RDWR 2 +#define SDB_CREATE 4 + +#endif diff --git a/security/nss/lib/softoken/sftkdb.c b/security/nss/lib/softoken/sftkdb.c new file mode 100644 index 000000000..6f126f9f5 --- /dev/null +++ b/security/nss/lib/softoken/sftkdb.c @@ -0,0 +1,2738 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * The following code handles the storage of PKCS 11 modules used by the + * NSS. For the rest of NSS, only one kind of database handle exists: + * + * SFTKDBHandle + * + * There is one SFTKDBHandle for the each key database and one for each cert + * database. These databases are opened as associated pairs, one pair per + * slot. SFTKDBHandles are reference counted objects. + * + * Each SFTKDBHandle points to a low level database handle (SDB). This handle + * represents the underlying physical database. These objects are not + * reference counted, an are 'owned' by their respective SFTKDBHandles. + * + * + */ +#include "sftkdb.h" +#include "pkcs11t.h" +#include "pkcs11i.h" +#include "sdb.h" +#include "prprf.h" +#include "secmodt.h" +#include "sftkpars.h" +#include "pratom.h" +#include "blapi.h" +#include "secoid.h" +#include "sechash.h" +#include "lowpbe.h" +#include "secdert.h" +#include "prsystem.h" +#include "lgglue.h" + +/* + * private defines + */ +struct SFTKDBHandleStr { + SDB *db; + PRInt32 ref; + CK_OBJECT_HANDLE type; + SECItem passwordKey; + SECItem *newKey; + PZLock *passwordLock; + SFTKDBHandle *peerDB; + SDB *update; +}; + +#define SFTK_KEYDB_TYPE 0x40000000 +#define SFTK_CERTDB_TYPE 0x00000000 +#define SFTK_OBJ_TYPE_MASK 0xc0000000 +#define SFTK_OBJ_ID_MASK (~SFTK_OBJ_TYPE_MASK) +#define SFTK_TOKEN_TYPE 0x80000000 + +static SECStatus sftkdb_decrypt(SECItem *passKey, SECItem *cipherText, + SECItem **plainText); +static SECStatus sftkdb_encrypt(PLArenaPool *arena, SECItem *passKey, + SECItem *plainText, SECItem **cipherText); + + +/* + * We want all databases to have the same binary representation independent of + * endianness or length of the host architecture. In general PKCS #11 attributes + * are endian/length independent except those attributes that pass CK_ULONG. + * + * The following functions fixes up the CK_ULONG type attributes so that the data + * base sees a machine independent view. CK_ULONGs are stored as 4 byte network + * byte order values (big endian). + */ +#define DB_ULONG_SIZE 4 +#define BBP 8 + +static PRBool +sftkdb_isULONG(CK_ATTRIBUTE_TYPE type) +{ + switch(type) { + case CKA_CLASS: + case CKA_CERTIFICATE_TYPE: + case CKA_CERTIFICATE_CATEGORY: + case CKA_KEY_TYPE: + case CKA_JAVA_MIDP_SECURITY_DOMAIN: + + case CKA_TRUST_DIGITAL_SIGNATURE: + case CKA_TRUST_NON_REPUDIATION: + case CKA_TRUST_KEY_ENCIPHERMENT: + case CKA_TRUST_DATA_ENCIPHERMENT: + case CKA_TRUST_KEY_AGREEMENT: + case CKA_TRUST_KEY_CERT_SIGN: + case CKA_TRUST_CRL_SIGN: + + case CKA_TRUST_SERVER_AUTH: + case CKA_TRUST_CLIENT_AUTH: + case CKA_TRUST_CODE_SIGNING: + case CKA_TRUST_EMAIL_PROTECTION: + case CKA_TRUST_IPSEC_END_SYSTEM: + case CKA_TRUST_IPSEC_TUNNEL: + case CKA_TRUST_IPSEC_USER: + case CKA_TRUST_TIME_STAMPING: + case CKA_TRUST_STEP_UP_APPROVED: + return PR_TRUE; + default: + break; + } + return PR_FALSE; + +} + +/* are the attributes private? */ +static PRBool +sftkdb_isPrivate(CK_ATTRIBUTE_TYPE type) +{ + switch(type) { + case CKA_VALUE: + case CKA_PRIVATE_EXPONENT: + case CKA_PRIME_1: + case CKA_PRIME_2: + case CKA_EXPONENT_1: + case CKA_EXPONENT_2: + case CKA_COEFFICIENT: + return PR_TRUE; + default: + break; + } + return PR_FALSE; +} + +/* + * fix up the input templates. Our fixed up ints are stored in data and must + * be freed by the caller. The new template must also be freed. If there are no + * CK_ULONG attributes, the orignal template is passed in as is. + */ +static CK_ATTRIBUTE * +sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, + unsigned char **dataOut) +{ + int i,j; + int ulongCount = 0; + unsigned char *data; + CK_ATTRIBUTE *ntemplate; + + *dataOut = NULL; + + /* first count the number of CK_ULONG attributes */ + for (i=0; i < count; i++) { + /* Don't 'fixup' NULL values */ + if (!template[i].pValue) { + continue; + } + if (template[i].ulValueLen == sizeof (CK_ULONG)) { + if ( sftkdb_isULONG(template[i].type)) { + ulongCount++; + } + } + } + /* no attributes to fixup, just call on through */ + if (ulongCount == 0) { + return (CK_ATTRIBUTE *)template; + } + + /* allocate space for new ULONGS */ + data = (unsigned char *)PORT_Alloc(DB_ULONG_SIZE*ulongCount); + if (!data) { + return NULL; + } + + /* allocate new template */ + ntemplate = PORT_NewArray(CK_ATTRIBUTE,count); + if (!ntemplate) { + PORT_Free(data); + return NULL; + } + *dataOut = data; + /* copy the old template, fixup the actual ulongs */ + for (i=0; i < count; i++) { + ntemplate[i] = template[i]; + /* Don't 'fixup' NULL values */ + if (!template[i].pValue) { + continue; + } + if (template[i].ulValueLen == sizeof (CK_ULONG)) { + if ( sftkdb_isULONG(template[i].type) ) { + CK_ULONG value = *(CK_ULONG *) template[i].pValue; + for (j=0; j < DB_ULONG_SIZE; j++) { + data[j] = (value >> (DB_ULONG_SIZE-1-j)*BBP) & 0xff; + } + ntemplate[i].pValue = data; + ntemplate[i].ulValueLen = DB_ULONG_SIZE; + data += DB_ULONG_SIZE; + } + } + } + return ntemplate; +} + + + +/* + * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated + * separate data sections for the database ULONG values. + */ +static CK_RV +sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_ATTRIBUTE *ntemplate, + int count, SFTKDBHandle *handle) +{ + int i,j; + CK_RV crv = CKR_OK; + + for (i=0; i < count; i++) { + CK_ULONG length = template[i].ulValueLen; + template[i].ulValueLen = ntemplate[i].ulValueLen; + /* fixup ulongs */ + if (ntemplate[i].ulValueLen == DB_ULONG_SIZE) { + if (sftkdb_isULONG(template[i].type)) { + if (template[i].pValue) { + CK_ULONG value = 0; + unsigned char *data; + + data = (unsigned char *)ntemplate[i].pValue; + for (j=0; j < DB_ULONG_SIZE; j++) { + value |= (((CK_ULONG)data[j]) << (DB_ULONG_SIZE-1-j)*BBP); + } + if (length < sizeof(CK_ULONG)) { + template[i].ulValueLen = -1; + crv = CKR_BUFFER_TOO_SMALL; + continue; + } + PORT_Memcpy(template[i].pValue,&value,sizeof(CK_ULONG)); + } + template[i].ulValueLen = sizeof(CK_ULONG); + } + } + /* fixup private attributes */ + if ((handle != NULL) && (handle->type == SFTK_KEYDB_TYPE) && + (template[i].pValue != NULL) && (template[i].ulValueLen != -1) + && sftkdb_isPrivate(ntemplate[i].type)) { + /* we have a private attribute */ + /* This code depends on the fact that the cipherText is bigger + * than the plain text */ + SECItem cipherText; + SECItem *plainText; + SECStatus rv; + + cipherText.data = ntemplate[i].pValue; + cipherText.len = ntemplate[i].ulValueLen; + PZ_Lock(handle->passwordLock); + if (handle->passwordKey.data == NULL) { + PZ_Unlock(handle->passwordLock); + template[i].ulValueLen = -1; + crv = CKR_USER_NOT_LOGGED_IN; + continue; + } + rv = sftkdb_decrypt(&handle->passwordKey, &cipherText, &plainText); + PZ_Unlock(handle->passwordLock); + if (rv != SECSuccess) { + PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); + template[i].ulValueLen = -1; + crv = CKR_GENERAL_ERROR; + continue; + } + PORT_Assert(template[i].ulValueLen >= plainText->len); + if (template[i].ulValueLen < plainText->len) { + SECITEM_FreeItem(plainText,PR_TRUE); + PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); + template[i].ulValueLen = -1; + crv = CKR_GENERAL_ERROR; + continue; + } + + /* copy the plain text back into the template */ + PORT_Memcpy(template[i].pValue, plainText->data, plainText->len); + template[i].ulValueLen = plainText->len; + SECITEM_FreeItem(plainText,PR_TRUE); + } + } + return crv; +} + +static CK_RV +sftkdb_CreateObject(SFTKDBHandle *handle, SDB *db, CK_OBJECT_HANDLE *objectID, + CK_ATTRIBUTE *template, CK_ULONG count) +{ + PRBool inTransaction = PR_FALSE; + CK_RV crv; + + crv = (*db->sdb_Begin)(db); + if (crv != CKR_OK) { + goto loser; + } + inTransaction = PR_TRUE; + crv = (*db->sdb_CreateObject)(db, objectID, template, count); + if (crv != CKR_OK) { + goto loser; + } + crv = (*db->sdb_Commit)(db); + inTransaction = PR_FALSE; + +loser: + if (inTransaction) { + (*handle->db->sdb_Abort)(handle->db); + /* It is trivial to show the following code cannot + * happen unless something is horribly wrong with our compilier or + * hardware */ + PORT_Assert(crv != CKR_OK); + if (crv == CKR_OK) crv = CKR_GENERAL_ERROR; + } + return crv; +} + +CK_ATTRIBUTE * +sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, + SFTKDBHandle *handle,CK_ULONG *pcount, + CK_RV *crv) +{ + int count; + CK_ATTRIBUTE *template; + int i, templateIndex; + SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); + + *crv = CKR_OK; + + if (sessObject == NULL) { + *crv = CKR_GENERAL_ERROR; /* internal programming error */ + return NULL; + } + + PZ_Lock(sessObject->attributeLock); + count = 0; + for (i=0; i < sessObject->hashSize; i++) { + SFTKAttribute *attr; + for (attr=sessObject->head[i]; attr; attr=attr->next) { + count++; + } + } + template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count); + if (template == NULL) { + PZ_Unlock(sessObject->attributeLock); + *crv = CKR_HOST_MEMORY; + return NULL; + } + templateIndex = 0; + for (i=0; i < sessObject->hashSize; i++) { + SFTKAttribute *attr; + for (attr=sessObject->head[i]; attr; attr=attr->next) { + CK_ATTRIBUTE *tp = &template[templateIndex++]; + /* copy the attribute */ + *tp = attr->attrib; + + /* fixup ULONG s */ + if ((tp->ulValueLen == sizeof (CK_ULONG)) && + (sftkdb_isULONG(tp->type)) ) { + CK_ULONG value = *(CK_ULONG *) tp->pValue; + unsigned char *data; + int j; + + tp->pValue = PORT_ArenaAlloc(arena, DB_ULONG_SIZE); + data = (unsigned char *)tp->pValue; + if (data == NULL) { + *crv = CKR_HOST_MEMORY; + break; + } + for (j=0; j < DB_ULONG_SIZE; j++) { + data[j] = (value >> (DB_ULONG_SIZE-1-j)*BBP) & 0xff; + } + tp->ulValueLen = DB_ULONG_SIZE; + } + + /* encrypt private attributes */ + if ((handle != NULL) && (handle->type == SFTK_KEYDB_TYPE) && + sftkdb_isPrivate(tp->type)) { + + /* we have a private attribute */ + SECItem *cipherText; + SECItem plainText; + SECStatus rv; + + plainText.data = tp->pValue; + plainText.len = tp->ulValueLen; + PZ_Lock(handle->passwordLock); + if (handle->passwordKey.data == NULL) { + PZ_Unlock(handle->passwordLock); + *crv = CKR_USER_NOT_LOGGED_IN; + break; + } + rv = sftkdb_encrypt(arena, &handle->passwordKey, &plainText, + &cipherText); + PZ_Unlock(handle->passwordLock); + if (rv == SECSuccess) { + tp->pValue = cipherText->data; + tp->ulValueLen = cipherText->len; + } else { + *crv = CKR_GENERAL_ERROR; /* better error code here? */ + break; + } + PORT_Memset(plainText.data, 0, plainText.len); + } + } + } + PORT_Assert(templateIndex <= count); + PZ_Unlock(sessObject->attributeLock); + + if (*crv != CKR_OK) { + return NULL; + } + if (pcount) { + *pcount = count; + } + return template; + +} + +#define GET_SDB(handle) ((handle)->update ? (handle)->update : (handle)->db) + +CK_RV +sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, + CK_OBJECT_HANDLE *objectID) +{ + CK_ATTRIBUTE *template; + PLArenaPool *arena; + CK_ULONG count; + CK_RV crv; + SDB *db; + + *objectID = CK_INVALID_HANDLE; + + if (handle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + db = GET_SDB(handle); + + arena = PORT_NewArena(256); + if (arena == NULL) { + return CKR_HOST_MEMORY; + } + + template = sftk_ExtractTemplate(arena, object, handle, &count, &crv); + if (!template) { + goto loser; + } + + crv = sftkdb_CreateObject(handle, db, objectID, template, count); + +loser: + if (arena) { + PORT_FreeArena(arena,PR_FALSE); + } + if (crv == CKR_OK) { + *objectID |= (handle->type | SFTK_TOKEN_TYPE); + } + return crv; +} + + + + +CK_RV +sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template, + CK_ULONG count, SDBFind **find) +{ + unsigned char *data = NULL; + CK_ATTRIBUTE *ntemplate = NULL; + CK_RV crv; + SDB *db; + + if (handle == NULL) { + return CKR_OK; + } + db = GET_SDB(handle); + + if (count != 0) { + ntemplate = sftkdb_fixupTemplateIn(template, count, &data); + if (ntemplate == NULL) { + return CKR_HOST_MEMORY; + } + } + + crv = (*db->sdb_FindObjectsInit)(db, ntemplate, + count, find); + if (data) { + PORT_Free(ntemplate); + PORT_Free(data); + } + return crv; +} + +CK_RV +sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, + CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count) +{ + CK_RV crv; + SDB *db; + + if (handle == NULL) { + *count = 0; + return CKR_OK; + } + db = GET_SDB(handle); + + crv = (*db->sdb_FindObjects)(db, find, ids, + arraySize, count); + if (crv == CKR_OK) { + int i; + for (i=0; i < *count; i++) { + ids[i] |= (handle->type | SFTK_TOKEN_TYPE); + } + } + return crv; +} + +CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find) +{ + SDB *db; + if (handle == NULL) { + return CKR_OK; + } + db = GET_SDB(handle); + return (*db->sdb_FindObjectsFinal)(db, find); +} + +CK_RV +sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id, + CK_ATTRIBUTE *template, CK_ULONG count) +{ + CK_RV crv,crv2; + CK_ATTRIBUTE *ntemplate; + unsigned char *data = NULL; + SDB *db; + int i; + + if (handle == NULL) { + return CKR_GENERAL_ERROR; + } + + /* short circuit common attributes */ + if (count == 1 && + (template[0].type == CKA_TOKEN || + template[0].type == CKA_PRIVATE || + template[0].type == CKA_SENSITIVE)) { + CK_BBOOL boolVal = CK_TRUE; + + if (template[0].pValue == NULL) { + template[0].ulValueLen = sizeof(CK_BBOOL); + return CKR_OK; + } + if (template[0].ulValueLen < sizeof(CK_BBOOL)) { + template[0].ulValueLen = -1; + return CKR_BUFFER_TOO_SMALL; + } + + if ((template[0].type == CKA_PRIVATE) && + (handle->type != SFTK_KEYDB_TYPE)) { + boolVal = CK_FALSE; + } + if ((template[0].type == CKA_SENSITIVE) && + (handle->type != SFTK_KEYDB_TYPE)) { + boolVal = CK_FALSE; + } + *(CK_BBOOL *)template[0].pValue = boolVal; + template[0].ulValueLen = sizeof(CK_BBOOL); + return CKR_OK; + } + + db = GET_SDB(handle); + /* nothing to do */ + if (count == 0) { + return CKR_OK; + } + ntemplate = sftkdb_fixupTemplateIn(template, count, &data); + if (ntemplate == NULL) { + return CKR_HOST_MEMORY; + } + object_id &= SFTK_OBJ_ID_MASK; + crv = (*db->sdb_GetAttributeValue)(db, object_id, + ntemplate, count); + crv2 = sftkdb_fixupTemplateOut(template, ntemplate, count, handle); + if (crv == CKR_OK) crv = crv2; + if (data) { + PORT_Free(ntemplate); + PORT_Free(data); + } + return crv; + +} + +CK_RV +sftkdb_SetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id, + const CK_ATTRIBUTE *template, CK_ULONG count) +{ + CK_RV crv = CKR_OK; + CK_ATTRIBUTE *ntemplate; + unsigned char *data = NULL; + SDB *db; + + if (handle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + + db = GET_SDB(handle); + /* nothing to do */ + if (count == 0) { + return CKR_OK; + } + ntemplate = sftkdb_fixupTemplateIn(template, count, &data); + if (ntemplate == NULL) { + return CKR_HOST_MEMORY; + } + object_id &= SFTK_OBJ_ID_MASK; + crv = (*db->sdb_Begin)(db); + if (crv != CKR_OK) { + goto loser; + } + crv = (*db->sdb_SetAttributeValue)(db, object_id, + ntemplate, count); + if (crv != CKR_OK) { + goto loser; + } + crv = (*db->sdb_Commit)(db); +loser: + if (crv != CKR_OK) { + (*db->sdb_Abort)(db); + } + if (data) { + PORT_Free(ntemplate); + PORT_Free(data); + } + return crv; +} + +CK_RV +sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id) +{ + CK_RV crv = CKR_OK; + SDB *db; + + if (handle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + db = GET_SDB(handle); + object_id &= SFTK_OBJ_ID_MASK; + crv = (*db->sdb_Begin)(db); + if (crv != CKR_OK) { + goto loser; + } + crv = (*db->sdb_DestroyObject)(db, object_id); + if (crv != CKR_OK) { + goto loser; + } + crv = (*db->sdb_Commit)(db); +loser: + if (crv != CKR_OK) { + (*db->sdb_Abort)(db); + } + return crv; +} + +CK_RV +sftkdb_CloseDB(SFTKDBHandle *handle) +{ + if (handle == NULL) { + return CKR_OK; + } + if (handle->update) { + (*handle->update->sdb_Close)(handle->update); + } + if (handle->db) { + (*handle->db->sdb_Close)(handle->db); + } + PORT_Free(handle); + return CKR_OK; +} + +/* + * reset a database to it's uninitialized state. + */ +static CK_RV +sftkdb_ResetDB(SFTKDBHandle *handle) +{ + CK_RV crv = CKR_OK; + SDB *db; + if (handle == NULL) { + return CKR_TOKEN_WRITE_PROTECTED; + } + db = GET_SDB(handle); + crv = (*db->sdb_Begin)(db); + if (crv != CKR_OK) { + goto loser; + } + crv = (*db->sdb_Reset)(db); + if (crv != CKR_OK) { + goto loser; + } + crv = (*db->sdb_Commit)(db); +loser: + if (crv != CKR_OK) { + (*db->sdb_Abort)(db); + } + return crv; +} + + +CK_RV +sftkdb_Begin(SFTKDBHandle *handle) +{ + CK_RV crv = CKR_OK; + SDB *db; + + if (handle == NULL) { + return CKR_OK; + } + db = GET_SDB(handle); + if (db) { + crv = (*db->sdb_Begin)(db); + } + return crv; +} + +CK_RV +sftkdb_Commit(SFTKDBHandle *handle) +{ + CK_RV crv = CKR_OK; + SDB *db; + + if (handle == NULL) { + return CKR_OK; + } + db = GET_SDB(handle); + if (db) { + (*db->sdb_Commit)(db); + } + return crv; +} + +CK_RV +sftkdb_Abort(SFTKDBHandle *handle) +{ + CK_RV crv = CKR_OK; + SDB *db; + + if (handle == NULL) { + return CKR_OK; + } + db = GET_SDB(handle); + if (db) { + crv = (db->sdb_Abort)(db); + } + return crv; +} + + +/**************************************************************** + * + * Secmod database. + * + * The new secmod database is simply a text file with each of the module + * entries. in the following form: + * + * # + * # This is a comment The next line is the library to load + * library=libmypkcs11.so + * name="My PKCS#11 module" + * params="my library's param string" + * nss="NSS parameters" + * other="parameters for other libraries and applications" + * + * library=libmynextpk11.so + * name="My other PKCS#11 module" + */ + +static char * +sftkdb_quote(const char *string, char quote) +{ + char *newString = 0; + int escapes = 0, size = 0; + const char *src; + char *dest; + + size=2; + for (src=string; *src ; src++) { + if ((*src == quote) || (*src == '\\')) escapes++; + size++; + } + + dest = newString = PORT_ZAlloc(escapes+size+1); + if (newString == NULL) { + return NULL; + } + + *dest++=quote; + for (src=string; *src; src++,dest++) { + if ((*src == '\\') || (*src == quote)) { + *dest++ = '\\'; + } + *dest = *src; + } + *dest=quote; + + return newString; +} + +/* + * Smart string cat functions. Automatically manage the memory. + * The first parameter is the source string. If it's null, we + * allocate memory for it. If it's not, we reallocate memory + * so the the concanenated string fits. + */ +static char * +sftkdb_DupnCat(char *baseString, const char *str, int str_len) +{ + int len = (baseString ? PORT_Strlen(baseString) : 0) + 1; + char *newString; + + len += str_len; + newString = (char *) PORT_Realloc(baseString,len); + if (newString == NULL) { + PORT_Free(baseString); + return NULL; + } + if (baseString == NULL) *newString = 0; + return PORT_Strncat(newString,str, str_len); +} + +/* Same as sftkdb_DupnCat except it concatenates the full string, not a + * partial one */ +static char * +sftkdb_DupCat(char *baseString, const char *str) +{ + return sftkdb_DupnCat(baseString, str, PORT_Strlen(str)); +} + +/* function to free up all the memory associated with a null terminated + * array of module specs */ +static SECStatus +sftkdb_releaseSpecList(char **moduleSpecList) +{ + if (moduleSpecList) { + char **index; + for(index = moduleSpecList; *index; index++) { + PORT_Free(*index); + } + PORT_Free(moduleSpecList); + } + return SECSuccess; +} + +#define SECMOD_STEP 10 +static SECStatus +sftkdb_growList(char ***pModuleList, int *useCount, int last) +{ + char **newModuleList; + + *useCount += SECMOD_STEP; + newModuleList = (char **)PORT_Realloc(*pModuleList, + *useCount*sizeof(char *)); + if (newModuleList == NULL) { + return SECFailure; + } + PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP); + *pModuleList = newModuleList; + return SECSuccess; +} + +static +char *sftk_getOldSecmodName(const char *dbname,const char *filename) +{ + char *file = NULL; + char *dirPath = PORT_Strdup(dbname); + char *sep; + + sep = PORT_Strrchr(dirPath,*PATH_SEPARATOR); +#ifdef WINDOWS + if (!sep) { + sep = PORT_Strrchr(dirPath,'/'); + } +#endif + if (sep) { + *(sep)=0; + } + file= PR_smprintf("%s"PATH_SEPARATOR"%s", dirPath, filename); + PORT_Free(dirPath); + return file; +} + +#define MAX_LINE_LENGTH 2048 +#define SFTK_DEFAULT_INTERNAL_INIT1 "library= name=\"NSS Internal PKCS #11 Module\" parameters=" +#define SFTK_DEFAULT_INTERNAL_INIT2 " NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={" +#define SFTK_DEFAULT_INTERNAL_INIT3 " askpw=any timeout=30})\"" + +#ifdef XP_UNIX +#include <unistd.h> +#endif +/* + * Read all the existing modules in out of the file. + */ +char ** +sftkdb_ReadSecmodDB(SDBType dbType, const char *appName, + const char *filename, const char *dbname, + char *params, PRBool rw) +{ + FILE *fd = NULL; + char **moduleList = NULL; + int moduleCount = 1; + int useCount = SECMOD_STEP; + char line[MAX_LINE_LENGTH]; + PRBool internal = PR_FALSE; + PRBool skipParams = PR_FALSE; + char *moduleString = NULL; + char *paramsValue=NULL; + PRBool failed = PR_TRUE; + + if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) { + return sftkdbCall_ReadSecmodDB(appName, filename, dbname, params, rw); + } + + moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **)); + if (moduleList == NULL) return NULL; + + /* do we really want to use streams here */ + fd = fopen(dbname, "r"); + if (fd == NULL) goto done; + + /* + * the following loop takes line separated config lines and colapses + * the lines to a single string, escaping and quoting as necessary. + */ + /* loop state variables */ + moduleString = NULL; /* current concatenated string */ + internal = PR_FALSE; /* is this an internal module */ + skipParams = PR_FALSE; /* did we find an override parameter block*/ + paramsValue = NULL; /* the current parameter block value */ + while (fgets(line, sizeof(line), fd) != NULL) { + int len = PORT_Strlen(line); + + /* remove the ending newline */ + if (len && line[len-1] == '\n') { + len--; + line[len] = 0; + } + if (*line == '#') { + continue; + } + if (*line != 0) { + /* + * The PKCS #11 group standard assumes blocks of strings + * separated by new lines, clumped by new lines. Internally + * we take strings separated by spaces, so we may need to escape + * certain spaces. + */ + char *value = PORT_Strchr(line,'='); + + /* there is no value, write out the stanza as is */ + if (value == NULL || value[1] == 0) { + if (moduleString) { + moduleString = sftkdb_DupnCat(moduleString," ", 1); + if (moduleString == NULL) goto loser; + } + moduleString = sftkdb_DupCat(moduleString, line); + if (moduleString == NULL) goto loser; + /* value is already quoted, just write it out */ + } else if (value[1] == '"') { + if (moduleString) { + moduleString = sftkdb_DupnCat(moduleString," ", 1); + if (moduleString == NULL) goto loser; + } + moduleString = sftkdb_DupCat(moduleString, line); + if (moduleString == NULL) goto loser; + /* we have an override parameter section, remember that + * we found this (see following comment about why this + * is necessary). */ + if (PORT_Strncasecmp(line, "parameters", 10) == 0) { + skipParams = PR_TRUE; + } + /* + * The internal token always overrides it's parameter block + * from the passed in parameters, so wait until then end + * before we include the parameter block in case we need to + * override it. NOTE: if the parameter block is quoted with ("), + * this override does not happen. This allows you to override + * the application's parameter configuration. + * + * parameter block state is controlled by the following variables: + * skipParams - Bool : set to true of we have an override param + * block (all other blocks, either implicit or explicit are + * ignored). + * paramsValue - char * : pointer to the current param block. In + * the absence of overrides, paramsValue is set to the first + * parameter block we find. All subsequent blocks are ignored. + * When we find an internal token, the application passed + * parameters take precident. + */ + } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) { + /* already have parameters */ + if (paramsValue) { + continue; + } + paramsValue = sftkdb_quote(&value[1], '"'); + if (paramsValue == NULL) goto loser; + continue; + } else { + /* may need to quote */ + char *newLine; + if (moduleString) { + moduleString = sftkdb_DupnCat(moduleString," ", 1); + if (moduleString == NULL) goto loser; + } + moduleString = sftkdb_DupnCat(moduleString,line,value-line+1); + if (moduleString == NULL) goto loser; + newLine = sftkdb_quote(&value[1],'"'); + if (newLine == NULL) goto loser; + moduleString = sftkdb_DupCat(moduleString,newLine); + PORT_Free(newLine); + if (moduleString == NULL) goto loser; + } + + /* check to see if it's internal? */ + if (PORT_Strncasecmp(line, "NSS=", 4) == 0) { + /* This should be case insensitive! reviewers make + * me fix it if it's not */ + if (PORT_Strstr(line,"internal")) { + internal = PR_TRUE; + /* override the parameters */ + if (paramsValue) { + PORT_Free(paramsValue); + } + paramsValue = sftkdb_quote(params, '"'); + } + } + continue; + } + if ((moduleString == NULL) || (*moduleString == 0)) { + continue; + } + + /* + * if we are here, we have found a complete stanza. Now write out + * any param section we may have found. + */ + if (paramsValue) { + /* we had an override */ + if (!skipParams) { + moduleString = sftkdb_DupnCat(moduleString," parameters=", 12); + if (moduleString == NULL) goto loser; + moduleString = sftkdb_DupCat(moduleString, paramsValue); + if (moduleString == NULL) goto loser; + } + PORT_Free(paramsValue); + paramsValue = NULL; + } + + if ((moduleCount+1) >= useCount) { + SECStatus rv; + rv = sftkdb_growList(&moduleList, &useCount, moduleCount+1); + if (rv != SECSuccess) { + goto loser; + } + } + + if (internal) { + moduleList[0] = moduleString; + } else { + moduleList[moduleCount] = moduleString; + moduleCount++; + } + moduleString = NULL; + internal = PR_FALSE; + skipParams = PR_FALSE; + } + + if (moduleString) { + PORT_Free(moduleString); + moduleString = NULL; + } +done: + /* if we couldn't open a pkcs11 database, look for the old one */ + if (fd == NULL) { + char *olddbname = sftk_getOldSecmodName(dbname,filename); + PRStatus status; + char **oldModuleList; + int i; + + /* couldn't get the old name */ + if (!olddbname) { + goto bail; + } + + /* old one doesn't exist */ + status = PR_Access(olddbname, PR_ACCESS_EXISTS); + if (status != PR_SUCCESS) { + goto bail; + } + + oldModuleList = sftkdbCall_ReadSecmodDB(appName, filename, + olddbname, params, rw); + /* old one had no modules */ + if (!oldModuleList) { + goto bail; + } + + /* count the modules */ + for (i=0; oldModuleList[i]; i++) { } + + /* grow the moduleList if necessary */ + if (i >= useCount) { + SECStatus rv; + rv = sftkdb_growList(&moduleList,&useCount,moduleCount+1); + if (rv != SECSuccess) { + goto loser; + } + } + + /* write each module out, and copy it */ + for (i=0; oldModuleList[i]; i++) { + if (rw) { + sftkdb_AddSecmodDB(dbType,appName,filename,dbname, + oldModuleList[i],rw); + } + if (moduleList[i]) { + PORT_Free(moduleList[i]); + } + moduleList[i] = PORT_Strdup(oldModuleList[i]); + } + + /* done with the old module list */ + sftkdbCall_ReleaseSecmodDBData(appName, filename, olddbname, + oldModuleList, rw); + } +bail: + + if (!moduleList[0]) { + char * newParams; + moduleString = PORT_Strdup(SFTK_DEFAULT_INTERNAL_INIT1); + newParams = sftkdb_quote(params,'"'); + if (newParams == NULL) goto loser; + moduleString = sftkdb_DupCat(moduleString, newParams); + PORT_Free(newParams); + if (moduleString == NULL) goto loser; + moduleString = sftkdb_DupCat(moduleString, SFTK_DEFAULT_INTERNAL_INIT2); + if (moduleString == NULL) goto loser; + moduleString = sftkdb_DupCat(moduleString, SECMOD_SLOT_FLAGS); + if (moduleString == NULL) goto loser; + moduleString = sftkdb_DupCat(moduleString, SFTK_DEFAULT_INTERNAL_INIT3); + if (moduleString == NULL) goto loser; + moduleList[0] = moduleString; + moduleString = NULL; + } + failed = PR_FALSE; + +loser: + /* + * cleanup + */ + /* deal with trust cert db here */ + if (moduleString) { + PORT_Free(moduleString); + moduleString = NULL; + } + if (paramsValue) { + PORT_Free(paramsValue); + paramsValue = NULL; + } + if (failed || (moduleList[0] == NULL)) { + /* This is wrong! FIXME */ + sftkdb_releaseSpecList(moduleList); + moduleList = NULL; + failed = PR_TRUE; + } + if (fd != NULL) { + fclose(fd); + } else if (!failed && rw) { + /* update our internal module */ + sftkdb_AddSecmodDB(dbType,appName,filename,dbname,moduleList[0],rw); + } + return moduleList; +} + +SECStatus +sftkdb_ReleaseSecmodDBData(SDBType dbType, const char *appName, + const char *filename, const char *dbname, + char **moduleSpecList, PRBool rw) +{ + if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) { + return sftkdbCall_ReleaseSecmodDBData(appName, filename, dbname, + moduleSpecList, rw); + } + if (moduleSpecList) { + sftkdb_releaseSpecList(moduleSpecList); + } + return SECSuccess; +} + + +/* + * Delete a module from the Data Base + */ +SECStatus +sftkdb_DeleteSecmodDB(SDBType dbType, const char *appName, + const char *filename, const char *dbname, + char *args, PRBool rw) +{ + /* SHDB_FIXME implement */ + FILE *fd = NULL; + FILE *fd2 = NULL; + char line[MAX_LINE_LENGTH]; + char *dbname2 = NULL; + char *block = NULL; + char *name = NULL; + char *lib = NULL; + int name_len, lib_len; + PRBool skip = PR_FALSE; + PRBool found = PR_FALSE; + + if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) { + return sftkdbCall_DeleteSecmodDB(appName, filename, dbname, args, rw); + } + + if (!rw) { + return SECFailure; + } + + dbname2 = strdup(dbname); + if (dbname2 == NULL) goto loser; + dbname2[strlen(dbname)-1]++; + + /* do we really want to use streams here */ + fd = fopen(dbname, "r"); + if (fd == NULL) goto loser; + fd2 = fopen(dbname2, "w+"); + if (fd2 == NULL) goto loser; + + name = sftk_argGetParamValue("name",args); + if (name) { + name_len = PORT_Strlen(name); + } + lib = sftk_argGetParamValue("library",args); + if (lib) { + lib_len = PORT_Strlen(lib); + } + + + /* + * the following loop takes line separated config files and colapses + * the lines to a single string, escaping and quoting as necessary. + */ + /* loop state variables */ + block = NULL; + skip = PR_FALSE; + while (fgets(line, sizeof(line), fd) != NULL) { + /* If we are processing a block (we haven't hit a blank line yet */ + if (*line != '\n') { + /* skip means we are in the middle of a block we are deleting */ + if (skip) { + continue; + } + /* if we haven't found the block yet, check to see if this block + * matches our requirements */ + if (!found && ((name && (PORT_Strncasecmp(line,"name=",5) == 0) && + (PORT_Strncmp(line+5,name,name_len) == 0)) || + (lib && (PORT_Strncasecmp(line,"library=",8) == 0) && + (PORT_Strncmp(line+8,lib,lib_len) == 0)))) { + + /* yup, we don't need to save any more data, */ + PORT_Free(block); + block=NULL; + /* we don't need to collect more of this block */ + skip = PR_TRUE; + /* we don't need to continue searching for the block */ + found =PR_TRUE; + continue; + } + /* not our match, continue to collect data in this block */ + block = sftkdb_DupCat(block,line); + continue; + } + /* we've collected a block of data that wasn't the module we were + * looking for, write it out */ + if (block) { + fwrite(block, PORT_Strlen(block), 1, fd2); + PORT_Free(block); + block = NULL; + } + /* If we didn't just delete the this block, keep the blank line */ + if (!skip) { + fputs(line,fd2); + } + /* we are definately not in a deleted block anymore */ + skip = PR_FALSE; + } + fclose(fd); + fclose(fd2); + /* rename dbname2 to dbname */ + if (found) { + PR_Delete(dbname); + PR_Rename(dbname2,dbname); + } + PORT_Free(dbname2); + return SECSuccess; + +loser: + if (fd != NULL) { + fclose(fd); + } + if (fd2 != NULL) { + fclose(fd2); + } + if (dbname2) { + PR_Delete(dbname2); + PORT_Free(dbname2); + } + return SECFailure; +} + +/* + * Add a module to the Data base + */ +SECStatus +sftkdb_AddSecmodDB(SDBType dbType, const char *appName, + const char *filename, const char *dbname, + char *module, PRBool rw) +{ + FILE *fd = NULL; + char *block = NULL; + PRBool libFound = PR_FALSE; + + if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) { + return sftkdbCall_AddSecmodDB(appName, filename, dbname, module, rw); + } + + /* can't write to a read only module */ + if (!rw) { + return SECFailure; + } + + /* remove the previous version if it exists */ + (void) sftkdb_DeleteSecmodDB(dbType, appName, filename, dbname, module, rw); + + /* do we really want to use streams here */ + fd = fopen(dbname, "a+"); + if (fd == NULL) { + return SECFailure; + } + module = sftk_argStrip(module); + while (*module) { + int count; + char *keyEnd = PORT_Strchr(module,'='); + char *value; + + if (PORT_Strncmp(module, "library=", 8) == 0) { + libFound=PR_TRUE; + } + if (keyEnd == NULL) { + block = sftkdb_DupCat(block, module); + break; + } + value = sftk_argFetchValue(&keyEnd[1], &count); + block = sftkdb_DupnCat(block, module, keyEnd-module+1); + if (block == NULL) { goto loser; } + if (value) { + block = sftkdb_DupCat(block, sftk_argStrip(value)); + PORT_Free(value); + } + if (block == NULL) { goto loser; } + block = sftkdb_DupnCat(block, "\n", 1); + module = keyEnd + 1 + count; + module = sftk_argStrip(module); + } + if (block) { + if (!libFound) { + fprintf(fd,"library=\n"); + } + fwrite(block, PORT_Strlen(block), 1, fd); + fprintf(fd,"\n"); + PORT_Free(block); + block = NULL; + } + fclose(fd); + return SECSuccess; + +loser: + PORT_Free(block); + fclose(fd); + return SECFailure; +} + +/****************************************************************** + * + * Key DB password handling functions + * + * These functions manage the key db password (set, reset, initialize, use). + * + * The key is managed on 'this side' of the database. All private data is + * encrypted before it is sent to the database itself. Besides PBE's, the + * database management code can also mix in various fixed keys so the data + * in the database is no longer considered 'plain text'. + */ + + +/* take string password and turn it into a key. The key is dependent + * on a global salt entry acquired from the database. This salted + * value will be based to a pkcs5 pbe function before it is used + * in an actual encryption */ +static SECStatus +sftkdb_passwordToKey(SFTKDBHandle *keydb, SDBPasswordEntry *entry, + const char *pw, SECItem *key) +{ + SHA1Context *cx = NULL; + SECStatus rv = SECFailure; + + key->data = PORT_Alloc(SHA1_LENGTH); + if (key->data == NULL) { + goto loser; + } + key->len = SHA1_LENGTH; + + cx = SHA1_NewContext(); + if ( cx == NULL) { + goto loser; + } + SHA1_Begin(cx); + if (entry && entry->salt.data ) { + SHA1_Update(cx, entry->salt.data, entry->salt.len); + } + SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw)); + SHA1_End(cx, key->data, &key->len, key->len); + rv = SECSuccess; + +loser: + if (cx) { + SHA1_DestroyContext(cx, PR_TRUE); + } + if (rv != SECSuccess) { + if (key->data != NULL) { + PORT_ZFree(key->data,key->len); + } + key->data = NULL; + } + return rv; +} + +/* + * Cipher text stored in the database contains 3 elements: + * 1) an identifier describing the encryption algorithm. + * 2) an entry specific salt value. + * 3) the encrypted value. + * + * The following data structure represents the encrypted data in a decoded + * (but still encrypted) form. + */ +typedef struct sftkCipherValueStr sftkCipherValue; +struct sftkCipherValueStr { + PLArenaPool *arena; + SECOidTag alg; + NSSPKCS5PBEParameter *param; + SECItem salt; + SECItem value; +}; + +#define SFTK_CIPHERTEXT_VERSION 3 + +struct SFTKDBEncryptedDataInfoStr { + SECAlgorithmID algorithm; + SECItem encryptedData; +}; +typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo; + +const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(SFTKDBEncryptedDataInfo) }, + { SEC_ASN1_INLINE, + offsetof(SFTKDBEncryptedDataInfo,algorithm), + SECOID_AlgorithmIDTemplate }, + { SEC_ASN1_OCTET_STRING, + offsetof(SFTKDBEncryptedDataInfo,encryptedData) }, + { 0 } +}; + +/* + * This parses the cipherText into cipher value. NOTE: cipherValue will point + * to data in cipherText, if cipherText is freed, cipherValue will be invalid. + * + * Use existing NSS data record: (sizes and offsets in bytes) + * + * offset size label Description + * 0 1 version Data base version number must be 3 + * 1 1 slen Length of Salt + * 2 1 nlen Length of optional nickname + * 3 slen sdata Salt data + * 3+slen nlen ndata Optional nickname data + * 3+nlen+slen 1 olen Length of algorithm OID + * 4+nlen+slen olen odata Algorithm OID data. + * 4+nlen+slen+ + * olen rest vdata Encrypted data. + * + * rest is the rest of the block passed into us. + */ +static SECStatus +sftkdb_decodeCipherText(SECItem *cipherText, sftkCipherValue *cipherValue) +{ + PLArenaPool *arena = NULL; + SFTKDBEncryptedDataInfo edi; + SECStatus rv; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + return SECFailure; + } + cipherValue->arena = NULL; + cipherValue->param = NULL; + + rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate, + cipherText); + if (rv != SECSuccess) { + goto loser; + } + cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm); + cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm); + if (cipherValue->param == NULL) { + goto loser; + } + cipherValue->value = edi.encryptedData; + cipherValue->arena = arena; + + return SECSuccess; +loser: + if (cipherValue->param) { + nsspkcs5_DestroyPBEParameter(cipherValue->param); + cipherValue->param = NULL; + } + if (arena) { + PORT_FreeArena(arena,PR_FALSE); + } + return SECFailure; +} + + + +/* + * unlike decode, Encode actually allocates a SECItem the caller must free + * The caller can pass an optional arena to to indicate where to place + * the resultant cipherText. + */ +static SECStatus +sftkdb_encodeCipherText(PLArenaPool *arena, sftkCipherValue *cipherValue, + SECItem **cipherText) +{ + SFTKDBEncryptedDataInfo edi; + SECAlgorithmID *algid; + SECStatus rv; + PLArenaPool *localArena = NULL; + + + localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (localArena == NULL) { + return SECFailure; + } + + algid = nsspkcs5_CreateAlgorithmID(localArena, cipherValue->alg, + cipherValue->param); + if (algid == NULL) { + rv = SECFailure; + goto loser; + } + rv = SECOID_CopyAlgorithmID(localArena, &edi.algorithm, algid); + SECOID_DestroyAlgorithmID(algid, PR_TRUE); + if (rv != SECSuccess) { + goto loser; + } + edi.encryptedData = cipherValue->value; + + *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi, + sftkdb_EncryptedDataInfoTemplate); + if (*cipherText == NULL) { + rv = SECFailure; + } + +loser: + if (localArena) { + PORT_FreeArena(localArena,PR_FALSE); + } + + return rv; +} + + +/* + * Use our key to decode a cipherText block from the database. + * + * plain text is allocated by nsspkcs5_CipherData and must be freed + * with SECITEM_FreeItem by the caller. + */ +static SECStatus +sftkdb_decrypt(SECItem *passKey, SECItem *cipherText, SECItem **plain) +{ + SECStatus rv; + sftkCipherValue cipherValue; + + /* First get the cipher type */ + rv = sftkdb_decodeCipherText(cipherText, &cipherValue); + if (rv != SECSuccess) { + goto loser; + } + + *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value, + PR_FALSE, NULL); + if (*plain == NULL) { + rv = SECFailure; + goto loser; + } + +loser: + if (cipherValue.param) { + nsspkcs5_DestroyPBEParameter(cipherValue.param); + } + if (cipherValue.arena) { + PORT_FreeArena(cipherValue.arena,PR_FALSE); + } + return rv; +} + +#define SALT_LENGTH 20 + +/* + * encrypt a block. This function returned the encrypted ciphertext which + * the caller must free. If the caller provides an arena, cipherText will + * be allocated out of that arena. This also generated the per entry + * salt automatically. + */ +static SECStatus +sftkdb_encrypt(PLArenaPool *arena, SECItem *passKey, SECItem *plainText, + SECItem **cipherText) +{ + SECStatus rv; + sftkCipherValue cipherValue; + SECItem *cipher = NULL; + NSSPKCS5PBEParameter *param = NULL; + unsigned char saltData[SALT_LENGTH]; + + cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC; + cipherValue.salt.len = SALT_LENGTH; + cipherValue.salt.data = saltData; + RNG_GenerateGlobalRandomBytes(saltData,SALT_LENGTH); + + param = nsspkcs5_NewParam(cipherValue.alg, &cipherValue.salt, 1); + if (param == NULL) { + rv = SECFailure; + goto loser; + } + cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL); + if (cipher == NULL) { + rv = SECFailure; + goto loser; + } + cipherValue.value = *cipher; + cipherValue.param = param; + + rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText); + if (rv != SECSuccess) { + goto loser; + } + +loser: + if (cipher) { + SECITEM_FreeItem(cipher, PR_FALSE); + } + if (param) { + nsspkcs5_DestroyPBEParameter(param); + } + return rv; +} + + +/* + * stub files for legacy db's to be able to encrypt and decrypt + * various keys and attributes. + */ +SECStatus +sftkdb_encrypt_stub(PRArenaPool *arena, SDB *sdb, SECItem *plainText, + SECItem **cipherText) +{ + SFTKDBHandle *handle = sdb->app_private; + SECStatus rv; + + if (handle == NULL) { + return SECFailure; + } + + /* if we aren't th handle, try the other handle */ + if (handle->type != SFTK_KEYDB_TYPE) { + handle = handle->peerDB; + } + + /* not a key handle */ + if (handle == NULL || handle->passwordLock == NULL) { + return SECFailure; + } + + PZ_Lock(handle->passwordLock); + if (handle->passwordKey.data == NULL) { + PZ_Unlock(handle->passwordLock); + /* PORT_SetError */ + return SECFailure; + } + + rv = sftkdb_encrypt(arena, + handle->newKey?handle->newKey:&handle->passwordKey, + plainText, cipherText); + PZ_Unlock(handle->passwordLock); + + return rv; +} + +/* + * stub files for legacy db's to be able to encrypt and decrypt + * various keys and attributes. + */ +SECStatus +sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) +{ + SFTKDBHandle *handle = sdb->app_private; + SECStatus rv; + + if (handle == NULL) { + return SECFailure; + } + + /* if we aren't th handle, try the other handle */ + if (handle->type != SFTK_KEYDB_TYPE) { + handle = handle->peerDB; + } + + /* not a key handle */ + if (handle == NULL || handle->passwordLock == NULL) { + return SECFailure; + } + + PZ_Lock(handle->passwordLock); + if (handle->passwordKey.data == NULL) { + PZ_Unlock(handle->passwordLock); + /* PORT_SetError */ + return SECFailure; + } + rv = sftkdb_decrypt(&handle->passwordKey, cipherText, plainText); + PZ_Unlock(handle->passwordLock); + + return rv; +} + +/* + * safely swith the passed in key for the one caches in the keydb handle + * + * A key attached to the handle tells us the the token is logged in. + * We can used the key attached to the handle in sftkdb_encrypt + * and sftkdb_decrypt calls. + */ +static void +sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey) +{ + unsigned char *data; + int len; + + if (keydb->passwordLock == NULL) { + PORT_Assert(keydb->type != SFTK_KEYDB_TYPE); + return; + } + + /* an atomic pointer set would be nice */ + PZ_Lock(keydb->passwordLock); + data = keydb->passwordKey.data; + len = keydb->passwordKey.len; + keydb->passwordKey.data = passKey->data; + keydb->passwordKey.len = passKey->len; + passKey->data = data; + passKey->len = len; + PZ_Unlock(keydb->passwordLock); +} + +/* + * known attributes + */ +static const CK_ATTRIBUTE_TYPE known_attributes[] = { + CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, + CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, + CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, + CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, + CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, + CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, + CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, + CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, + CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, + CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, + CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, + CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, + CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, + CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, + CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, + CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, + CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, + CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, + CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, + CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, + CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, + CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NETSCAPE_URL, CKA_NETSCAPE_EMAIL, + CKA_NETSCAPE_SMIME_INFO, CKA_NETSCAPE_SMIME_TIMESTAMP, + CKA_NETSCAPE_PKCS8_SALT, CKA_NETSCAPE_PASSWORD_CHECK, CKA_NETSCAPE_EXPIRES, + CKA_NETSCAPE_KRL, CKA_NETSCAPE_PQG_COUNTER, CKA_NETSCAPE_PQG_SEED, + CKA_NETSCAPE_PQG_H, CKA_NETSCAPE_PQG_SEED_BITS, CKA_NETSCAPE_MODULE_SPEC, + CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, + CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, + CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, + CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, + CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, + CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, + CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, + CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS +}; + +static int known_attributes_size= sizeof(known_attributes)/ + sizeof(known_attributes[0]); + +static CK_RV +sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id, + CK_ATTRIBUTE *ptemplate, CK_ULONG *max) +{ + int i,j; + CK_RV crv; + + if (*max < known_attributes_size) { + *max = known_attributes_size; + return CKR_BUFFER_TOO_SMALL; + } + for (i=0; i < known_attributes_size; i++) { + ptemplate[i].type = known_attributes[i]; + ptemplate[i].pValue = NULL; + ptemplate[i].ulValueLen = 0; + } + + crv = (*source->sdb_GetAttributeValue)(source, id, + ptemplate, known_attributes_size); + + if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { + return crv; + } + + for (i=0, j=0; i < known_attributes_size; i++, j++) { + while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) { + i++; + } + if (i >= known_attributes_size) { + break; + } + /* cheap optimization */ + if (i == j) { + continue; + } + ptemplate[j] = ptemplate[i]; + } + *max = j; + return CKR_OK; +} + +#ifdef notdef +static void +dump_attribute(CK_ATTRIBUTE *attr) +{ + unsigned char *buf = attr->pValue; + int count,i; + + printf("%08x: (%d) ",attr->type, attr->ulValueLen); + count = attr->ulValueLen; + if (count > 10) count = 10; + for (i=0; i < count; i++) { + printf("%02x",buf[i]); + } + printf("\n"); +} +#endif + + +#define MAX_ATTRIBUTES 500 +static CK_RV +sftkdb_copyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, SECItem *key) +{ + CK_ATTRIBUTE template[MAX_ATTRIBUTES]; + CK_ATTRIBUTE *ptemplate; + CK_ULONG max_attributes = MAX_ATTRIBUTES; + SDB *source = handle->update; + SDB *target = handle->db; + int i; + CK_RV crv; + + ptemplate = &template[0]; + id &= SFTK_OBJ_ID_MASK; + crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes); + if (crv == CKR_BUFFER_TOO_SMALL) { + ptemplate = PORT_NewArray(CK_ATTRIBUTE, max_attributes); + if (ptemplate == NULL) { + crv = CKR_HOST_MEMORY; + } else { + crv = sftkdb_GetObjectTemplate(source, id, + ptemplate, &max_attributes); + } + } + if (crv != CKR_OK) { + goto loser; + } + + for (i=0; i < max_attributes; i++) { + ptemplate[i].pValue = PORT_Alloc(ptemplate[i].ulValueLen); + if (ptemplate[i].pValue == NULL) { + crv = CKR_HOST_MEMORY; + goto loser; + } + } + crv = (*source->sdb_GetAttributeValue)(source, id, + ptemplate, max_attributes); + if (crv != CKR_OK) { + goto loser; + } + + crv = sftkdb_CreateObject(handle, target, &id, ptemplate, max_attributes); + if (ptemplate && ptemplate != template) { + PORT_Free(ptemplate); + } + +loser: + if (ptemplate) { + for (i=0; i < max_attributes; i++) { + if (ptemplate[i].pValue) { + PORT_Memset(ptemplate[i].pValue, 0, ptemplate[i].ulValueLen); + PORT_Free(ptemplate[i].pValue); + } + } + if (ptemplate != template) { + PORT_Free(ptemplate); + } + } + return crv; +} + + +#define MAX_IDS 10 +/* + * update a new database from an old one, now that we have the key + */ +static CK_RV +sftkdb_update(SFTKDBHandle *handle, SECItem *key) +{ + SDBFind *find = NULL; + CK_ULONG idCount = MAX_IDS; + CK_OBJECT_HANDLE ids[MAX_IDS]; + CK_RV crv, crv2; + PRBool inTransaction = PR_FALSE; + int i; + + if (handle == NULL) { + return CKR_OK; + } + if (handle->update == NULL) { + return CKR_OK; + } + + /* find all the objects */ + crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find); + + if (crv != CKR_OK) { + goto loser; + } + while ((crv == CKR_OK) && (idCount == MAX_IDS)) { + crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount); + for (i=0; (crv == CKR_OK) && (i < idCount); i++) { + crv = sftkdb_copyObject(handle, ids[i], key); + } + } + crv2 = sftkdb_FindObjectsFinal(handle, find); + if (crv == CKR_OK) crv = crv2; + +loser: + /* update Meta data - even if we didn't update objects */ + if (handle->type == SFTK_KEYDB_TYPE) { + SDBPasswordEntry entry; + crv = (*handle->db->sdb_Begin)(handle->db); + if (crv != CKR_OK) { + goto loser2; + } + inTransaction = PR_TRUE; + crv = (*handle->update->sdb_GetPWEntry)(handle->update, & entry); + if (crv != CKR_OK) { + goto loser2; + } + crv = (*handle->db->sdb_PutPWEntry)(handle->db, &entry); + if (crv != CKR_OK) { + goto loser2; + } + crv = (*handle->db->sdb_Commit)(handle->db); + inTransaction = PR_FALSE; + } +loser2: + if (inTransaction) { + (*handle->db->sdb_Abort)(handle->db); + } + if (handle->update) { + (*handle->update->sdb_Close)(handle->update); + handle->update = NULL; + } + return crv; +} + +/* + * return success if we have a valid password entry. + * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT + * in the token flags. + */ +SECStatus +sftkdb_HasPasswordSet(SFTKDBHandle *keydb) +{ + SDBPasswordEntry entry; + CK_RV crv; + SDB *db; + + if (keydb == NULL) { + return SECFailure; + } + + db = GET_SDB(keydb); + if (db == NULL) { + return SECFailure; + } + + crv = (*db->sdb_GetPWEntry)(db, &entry); + return (crv == CKR_OK) ? SECSuccess : SECFailure; +} + +#define SFTK_PW_CHECK_STRING "password-check" +#define SFTK_PW_CHECK_LEN 14 + +/* + * check if the supplied password is valid + */ +SECStatus +sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw) +{ + SECStatus rv; + SDBPasswordEntry entry; + SECItem key; + SECItem *result = NULL; + SDB *db; + CK_RV crv; + + if (keydb == NULL) { + return SECFailure; + } + + db = GET_SDB(keydb); + if (db == NULL) { + return SECFailure; + } + + key.data = NULL; + key.len = 0; + + if (pw == NULL) pw=""; + + /* get the entry from the database */ + crv = (*db->sdb_GetPWEntry)(db, &entry); + if (crv != CKR_OK) { + rv = SECFailure; + goto loser; + } + + /* get our intermediate key based on the entry salt value */ + rv = sftkdb_passwordToKey(keydb, &entry, pw, &key); + if (rv != SECSuccess) { + goto loser; + } + + /* decrypt the entry value */ + rv = sftkdb_decrypt(&key, &entry.value, &result); + if (rv != SECSuccess) { + goto loser; + } + + /* if it's what we expect, update our key in the database handle and + * return Success */ + if ((result->len == SFTK_PW_CHECK_LEN) && + PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0){ + /* load the keys, so the keydb can parse it's key set */ + sftkdb_switchKeys(keydb, &key); + if (keydb->update) { + /* update the peer certdb if it exists */ + if (keydb->peerDB) { + sftkdb_update(keydb->peerDB, &key); + } + sftkdb_update(keydb, &key); + } + } else { + rv = SECFailure; + /*PORT_SetError( bad password); */ + } + +loser: + if (key.data) { + PORT_ZFree(key.data,key.len); + } + if (result) { + SECITEM_FreeItem(result,PR_TRUE); + } + return rv; +} + +/* + * return Success if the there is a cached password key. + */ +SECStatus +sftkdb_PWCached(SFTKDBHandle *keydb) +{ + return keydb->passwordKey.data ? SECSuccess : SECFailure; +} + +static SECStatus +sftk_convertPrivateAttributes(SFTKDBHandle *keydb, CK_OBJECT_HANDLE id, + SECItem *newKey) +{ + CK_RV crv = CKR_OK; + CK_RV crv2; + CK_ATTRIBUTE *first, *last; + CK_ATTRIBUTE privAttrs[] = { + {CKA_VALUE, NULL, 0}, + {CKA_PRIVATE_EXPONENT, NULL, 0}, + {CKA_PRIME_1, NULL, 0}, + {CKA_PRIME_2, NULL, 0}, + {CKA_EXPONENT_1, NULL, 0}, + {CKA_EXPONENT_2, NULL, 0}, + {CKA_COEFFICIENT, NULL, 0} }; + CK_ULONG privAttrCount = sizeof(privAttrs)/sizeof(CK_ATTRIBUTE); + PLArenaPool *arena = NULL; + int i, count; + + + /* get a new arena to simplify cleanup */ + arena = PORT_NewArena(1024); + if (!arena) { + return SECFailure; + } + + /* + * STEP 1. Read the old attributes in the clear. + */ + + /* Get the attribute sizes. + * ignore the error code, we will have unknown attributes here */ + crv2 = sftkdb_GetAttributeValue(keydb, id, privAttrs, privAttrCount); + + /* + * find the valid block of attributes and fill allocate space for + * their data */ + first = last = NULL; + for (i=0; i < privAttrCount; i++) { + /* find the block of attributes that are appropriate for this + * objects. There should only be once contiguous block, if not + * there's an error. + * + * find the first and last good entry. + */ + if ((privAttrs[i].ulValueLen == -1) || (privAttrs[i].ulValueLen == 0)){ + if (!first) continue; + if (!last) { + /* previous entry was last good entry */ + last= &privAttrs[i-1]; + } + continue; + } + if (!first) { + first = &privAttrs[i]; + } + if (last) { + /* OOPS, we've found another good entry beyond the end of the + * last good entry, we need to fail here. */ + crv = CKR_GENERAL_ERROR; + break; + } + privAttrs[i].pValue = PORT_ArenaAlloc(arena,privAttrs[i].ulValueLen); + if (privAttrs[i].pValue == NULL) { + crv = CKR_HOST_MEMORY; + break; + } + } + if (first == NULL) { + /* no valid entries found, return error based on crv2 */ + /* set error */ + goto loser; + } + if (last == NULL) { + last = &privAttrs[privAttrCount-1]; + } + if (crv != CKR_OK) { + /* set error */ + goto loser; + } + /* read the attributes */ + count = (last-first)+1; + crv = sftkdb_GetAttributeValue(keydb, id, first, count); + if (crv != CKR_OK) { + /* set error */ + goto loser; + } + + + /* + * STEP 2: read the encrypt the attributes with the new key. + */ + for (i=0; i < count; i++) { + SECItem plainText; + SECItem *result; + SECStatus rv; + + plainText.data = first[i].pValue; + plainText.len = first[i].ulValueLen; + rv = sftkdb_encrypt(arena, newKey, &plainText, &result); + if (rv != SECSuccess) { + goto loser; + } + first[i].pValue = result->data; + first[i].ulValueLen = result->len; + /* clear our sensitive data out */ + PORT_Memset(plainText.data, 0, plainText.len); + } + + + /* + * STEP 3: write the newly encrypted attributes out directly + */ + id &= SFTK_OBJ_ID_MASK; + keydb->newKey = newKey; + crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, id, first, count); + keydb->newKey = NULL; + if (crv != CKR_OK) { + /* set error */ + goto loser; + } + + /* free up our mess */ + /* NOTE: at this point we know we've cleared out any unencrypted data */ + PORT_FreeArena(arena, PR_FALSE); + return SECSuccess; + +loser: + /* there may be unencrypted data, clear it out down */ + PORT_FreeArena(arena, PR_TRUE); + return SECFailure; +} + + +/* + * must be called with the old key active. + */ +SECStatus +sftkdb_convertPrivateObjects(SFTKDBHandle *keydb, SECItem *newKey) +{ + SDBFind *find = NULL; + CK_ULONG idCount = MAX_IDS; + CK_OBJECT_HANDLE ids[MAX_IDS]; + CK_RV crv, crv2; + int i; + + /* find all the private objects */ + crv = sftkdb_FindObjectsInit(keydb, NULL, 0, &find); + + if (crv != CKR_OK) { + /* set error */ + return SECFailure; + } + while ((crv == CKR_OK) && (idCount == MAX_IDS)) { + crv = sftkdb_FindObjects(keydb, find, ids, MAX_IDS, &idCount); + for (i=0; (crv == CKR_OK) && (i < idCount); i++) { + SECStatus rv; + rv = sftk_convertPrivateAttributes(keydb, ids[i], newKey); + if (rv != SECSuccess) { + crv = CKR_GENERAL_ERROR; + /* error should be already set here */ + } + } + } + crv2 = sftkdb_FindObjectsFinal(keydb, find); + if (crv == CKR_OK) crv = crv2; + if (crv != CKR_OK) { + /* set error */ + return SECFailure; + } + return SECSuccess; +} + + +/* + * change the database password. + */ +SECStatus +sftkdb_ChangePassword(SFTKDBHandle *keydb, char *oldPin, char *newPin) +{ + SECStatus rv = SECSuccess; + SECItem plainText; + SECItem newKey; + SECItem *result = NULL; + SDBPasswordEntry entry; + CK_RV crv; + SDB *db; + + if (keydb == NULL) { + return SECFailure; + } + + db = GET_SDB(keydb); + if (db == NULL) { + return SECFailure; + } + + newKey.data = NULL; + + /* make sure we have a valid old pin */ + crv = (*keydb->db->sdb_Begin)(keydb->db); + if (crv != CKR_OK) { + rv = SECFailure; + goto loser; + } + crv = (*db->sdb_GetPWEntry)(db, &entry); + if (crv == CKR_OK) { + rv = sftkdb_CheckPassword(keydb, oldPin); + if (rv == SECFailure) { + goto loser; + } + } else { + entry.salt.data = entry.data; + entry.salt.len = SALT_LENGTH; + RNG_GenerateGlobalRandomBytes(entry.data,entry.salt.len); + } + + rv = sftkdb_passwordToKey(keydb, &entry, newPin, &newKey); + if (rv != SECSuccess) { + goto loser; + } + + + /* + * convert encrypted entries here. + */ + rv = sftkdb_convertPrivateObjects(keydb, &newKey); + if (rv != SECSuccess) { + goto loser; + } + + + plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING; + plainText.len = SFTK_PW_CHECK_LEN; + + rv = sftkdb_encrypt(NULL, &newKey, &plainText, &result); + if (rv != SECSuccess) { + goto loser; + } + entry.value.data = result->data; + entry.value.len = result->len; + crv = (*keydb->db->sdb_PutPWEntry)(keydb->db, &entry); + if (crv != CKR_OK) { + rv = SECFailure; + goto loser; + } + crv = (*keydb->db->sdb_Commit)(keydb->db); + if (crv != CKR_OK) { + rv = SECFailure; + goto loser; + } + + keydb->newKey = NULL; + + sftkdb_switchKeys(keydb, &newKey); + +loser: + if (newKey.data) { + PORT_ZFree(newKey.data,newKey.len); + } + if (result) { + SECITEM_FreeItem(result, PR_FALSE); + } + if (rv != SECSuccess) { + (*keydb->db->sdb_Abort)(keydb->db); + } + + return rv; +} + +/* + * loose our cached password + */ +SECStatus +sftkdb_ClearPassword(SFTKDBHandle *keydb) +{ + SECItem oldKey; + oldKey.data = NULL; + oldKey.len = 0; + sftkdb_switchKeys(keydb, &oldKey); + if (oldKey.data) { + PORT_ZFree(oldKey.data, oldKey.len); + } + return SECSuccess; +} + +/****************************************************************** + * DB handle managing functions. + * + * These functions are called by softoken to initialize, acquire, + * and release database handles. + */ + +/* release a database handle */ +void +sftk_freeDB(SFTKDBHandle *handle) +{ + PRInt32 ref; + + if (!handle) return; + ref = PR_AtomicDecrement(&handle->ref); + if (ref == 0) { + sftkdb_CloseDB(handle); + } + return; +} + + +/* + * acquire a database handle for a certificate db + * (database for public objects) + */ +SFTKDBHandle * +sftk_getCertDB(SFTKSlot *slot) +{ + SFTKDBHandle *dbHandle; + + PZ_Lock(slot->slotLock); + dbHandle = slot->certDB; + if (dbHandle) { + PR_AtomicIncrement(&dbHandle->ref); + } + PZ_Unlock(slot->slotLock); + return dbHandle; +} + +/* + * acquire a database handle for a key database + * (database for private objects) + */ +SFTKDBHandle * +sftk_getKeyDB(SFTKSlot *slot) +{ + SFTKDBHandle *dbHandle; + + PZ_Lock(slot->slotLock); + dbHandle = slot->keyDB; + if (dbHandle) { + PR_AtomicIncrement(&dbHandle->ref); + } + PZ_Unlock(slot->slotLock); + return dbHandle; +} + +/* + * acquire the database for a specific object. NOTE: objectID must point + * to a Token object! + */ +SFTKDBHandle * +sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID) +{ + SFTKDBHandle *dbHandle; + + PZ_Lock(slot->slotLock); + dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB; + if (dbHandle) { + PR_AtomicIncrement(&dbHandle->ref); + } + PZ_Unlock(slot->slotLock); + return dbHandle; +} + +/* + * initialize a new database handle + */ +static SFTKDBHandle * +sftk_NewDBHandle(SDB *sdb, int type) +{ + SFTKDBHandle *handle = PORT_New(SFTKDBHandle); + handle->ref = 1; + handle->db = sdb; + handle->update = NULL; + handle->peerDB = NULL; + handle->newKey = NULL; + handle->type = type; + handle->passwordKey.data = NULL; + handle->passwordKey.len = 0; + handle->passwordLock = NULL; + if (type == SFTK_KEYDB_TYPE) { + handle->passwordLock = PZ_NewLock(); + } + sdb->app_private = handle; + return handle; +} + +/* + * reset the key database to it's uninitialized state. This call + * will clear all the key entried. + */ +SECStatus +sftkdb_ResetKeyDB(SFTKDBHandle *handle) +{ + CK_RV crv; + + /* only rest the key db */ + if (handle->type != SFTK_KEYDB_TYPE) { + return SECFailure; + } + crv = sftkdb_ResetDB(handle); + if (crv != CKR_OK) { + /* set error */ + return SECFailure; + } + return SECSuccess; +} + +static PRBool +sftk_oldVersionExists(const char *dir, int version) +{ + int i; + PRStatus exists = PR_FAILURE; + char *file = NULL; + + for (i=version; i > 1 ; i--) { + file = PR_smprintf("%s%d.db",dir,i); + if (file == NULL) { + continue; + } + exists = PR_Access(file, PR_ACCESS_EXISTS); + PR_smprintf_free(file); + if (exists == PR_SUCCESS) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +static PRBool +sftk_hasLegacyDB(const char *confdir, const char *certPrefix, + const char *keyPrefix, int certVersion, int keyVersion) +{ + char *dir; + PRBool exists; + + dir= PR_smprintf("%s/%scert", confdir, certPrefix); + if (dir == NULL) { + return PR_FALSE; + } + + exists = sftk_oldVersionExists(dir, certVersion); + PR_smprintf_free(dir); + if (exists) { + return PR_TRUE; + } + + dir= PR_smprintf("%s/%skey", confdir, keyPrefix); + if (dir == NULL) { + return PR_FALSE; + } + + exists = sftk_oldVersionExists(dir, keyVersion); + PR_smprintf_free(dir); + return exists; +} + +/* + * initialize certificate and key database handles as a pair. + * + * This function figures out what type of database we are opening and + * calls the appropriate low level function to open the database. + * It also figures out whether or not to setup up automatic update. + */ +CK_RV +sftk_DBInit(const char *configdir, const char *certPrefix, + const char *keyPrefix, PRBool readOnly, PRBool noCertDB, + PRBool noKeyDB, PRBool forceOpen, + SFTKDBHandle **certDB, SFTKDBHandle **keyDB) +{ + const char *confdir; + SDBType dbType; + char *appName = NULL; + SDB *keySDB, *certSDB; + CK_RV crv = CKR_OK; + int flags = SDB_RDONLY; + PRBool newInit = PR_FALSE; + PRBool needUpdate = PR_FALSE; + + if (!readOnly) { + flags = SDB_CREATE; + } + + *certDB = NULL; + *keyDB = NULL; + + if (noKeyDB && noCertDB) { + return CKR_OK; + } + confdir = sftk_EvaluateConfigDir(configdir, &dbType, &appName); + + /* + * now initialize the appropriate database + */ + switch (dbType) { + case SDB_LEGACY: + crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, + noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB); + break; + case SDB_MULTIACCESS: + crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags, + noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB); + break; + case SDB_SQL: + case SDB_EXTERN: /* SHOULD open a loadable db */ + crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags, + noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit); + + /* + * if we failed to open the DB's read only, use the old ones if + * the exists. + */ + if (crv != CKR_OK && (flags == SDB_RDONLY)) { + if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) { + /* we have legacy databases, if we failed to open the new format + * DB's read only, just use the legacy ones */ + crv = sftkdbCall_open(confdir, certPrefix, + keyPrefix, 8, 3, flags, noCertDB? NULL : &certSDB, + noKeyDB ? NULL : &keySDB); + } + } else if (newInit && crv == CKR_OK) { + /* if the new format DB was also a newly created DB, and we + * succeeded, then need to update that new database with data + * from the existing legacy DB */ + if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) { + needUpdate = 1; + } + } + break; + default: + crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST + * return one of the types we already + * specified. */ + } + if (crv != CKR_OK) { + goto loser; + } + if (!noCertDB) { + *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE); + } else { + *certDB = NULL; + } + if (!noKeyDB) { + *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE); + } else { + *keyDB = NULL; + } + + /* link them together */ + if (*certDB) { + (*certDB)->peerDB = *keyDB; + } + if (*keyDB) { + (*keyDB)->peerDB = *certDB; + } + + if (needUpdate) { + SDB *updateCert = NULL; + SDB *updateKey = NULL; + CK_RV crv2; + + crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, + noCertDB ? NULL : &updateCert, noKeyDB ? NULL : &updateKey); + if (crv2 == CKR_OK) { + if (*certDB) { + (*certDB)->update = updateCert; + updateCert->app_private = (*certDB); + } + if (*keyDB) { + (*keyDB)->update = updateKey; + updateKey->app_private = (*keyDB); + } else { + /* we don't have a key DB, update the certificate DB now */ + sftkdb_update(*certDB, NULL); + } + } + } +loser: + if (appName) { + PORT_Free(appName); + } + return forceOpen ? CKR_OK : crv; +} + +CK_RV +sftkdb_Shutdown(void) +{ + s_shutdown(); + sftkdbCall_Shutdown(); + return CKR_OK; +} + diff --git a/security/nss/lib/softoken/sftkdb.h b/security/nss/lib/softoken/sftkdb.h new file mode 100644 index 000000000..0491c3e68 --- /dev/null +++ b/security/nss/lib/softoken/sftkdb.h @@ -0,0 +1,90 @@ +/* + * license + */ + +#include "sftkdbt.h" +#include "sdb.h" +#include "pkcs11i.h" +#include "pkcs11t.h" + +/* raw database stuff */ +CK_RV sftkdb_write(SFTKDBHandle *handle, SFTKObject *,CK_OBJECT_HANDLE *); +CK_RV sftkdb_FindObjectsInit(SFTKDBHandle *sdb, const CK_ATTRIBUTE *template, + CK_ULONG count, SDBFind **find); +CK_RV sftkdb_FindObjects(SFTKDBHandle *sdb, SDBFind *find, + CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count); +CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *sdb, SDBFind *find); +CK_RV sftkdb_GetAttributeValue(SFTKDBHandle *handle, + CK_OBJECT_HANDLE object_id, CK_ATTRIBUTE *template, CK_ULONG count); +CK_RV sftkdb_SetAttributeValue(SFTKDBHandle *handle, + CK_OBJECT_HANDLE object_id, const CK_ATTRIBUTE *template, + CK_ULONG count); +CK_RV sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id); +CK_RV sftkdb_closeDB(SFTKDBHandle *handle); + + +/* secmod.db functions */ +char ** sftkdb_ReadSecmodDB(SDBType dbType, const char *appName, + const char *filename, const char *dbname, + char *params, PRBool rw); +SECStatus sftkdb_ReleaseSecmodDBData(SDBType dbType, const char *appName, + const char *filename, const char *dbname, + char **moduleSpecList, PRBool rw); +SECStatus sftkdb_DeleteSecmodDB(SDBType dbType, const char *appName, + const char *filename, const char *dbname, + char *args, PRBool rw); +SECStatus sftkdb_AddSecmodDB(SDBType dbType, const char *appName, + const char *filename, const char *dbname, + char *module, PRBool rw); + +/* keydb functions */ + +SECStatus sftkdb_PWIsInitialized(SFTKDBHandle *keydb); +SECStatus sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw); +SECStatus sftkdb_PWCached(SFTKDBHandle *keydb); +SECStatus sftkdb_HasPasswordSet(SFTKDBHandle *keydb); +SECStatus sftkdb_ResetKeyDB(SFTKDBHandle *keydb); +SECStatus sftkdb_ChangePassword(SFTKDBHandle *keydb, char *oldPin, char *newPin); +SECStatus sftkdb_ClearPassword(SFTKDBHandle *keydb); + +/* Utility functions */ +/* + * OK there are now lots of options here, lets go through them all: + * + * configdir - base directory where all the cert, key, and module datbases live. + * certPrefix - prefix added to the beginning of the cert database example: " + * "https-server1-" + * keyPrefix - prefix added to the beginning of the key database example: " + * "https-server1-" + * secmodName - name of the security module database (usually "secmod.db"). + * readOnly - Boolean: true if the databases are to be openned read only. + * nocertdb - Don't open the cert DB and key DB's, just initialize the + * Volatile certdb. + * nomoddb - Don't open the security module DB, just initialize the + * PKCS #11 module. + * forceOpen - Continue to force initializations even if the databases cannot + * be opened. + */ +CK_RV sftk_DBInit(const char *configdir, const char *certPrefix, + const char *keyPrefix, PRBool readOnly, PRBool noCertDB, + PRBool noKeyDB, PRBool forceOpen, + SFTKDBHandle **certDB, SFTKDBHandle **keyDB); +CK_RV sftkdb_Shutdown(void); + +SFTKDBHandle *sftk_getCertDB(SFTKSlot *slot); +SFTKDBHandle *sftk_getKeyDB(SFTKSlot *slot); +SFTKDBHandle *sftk_getDBForTokenObject(SFTKSlot *slot, + CK_OBJECT_HANDLE objectID); +void sftk_freeDB(SFTKDBHandle *certHandle); + +/* + * for lgglue, stubs to encrypt and decrypt password entries + */ +SECStatus sftkdb_encrypt_stub(PRArenaPool *arena, SDB *sdb, SECItem *plainText, + SECItem **cipherText); +SECStatus sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, + SECItem **plainText); + + + + diff --git a/security/nss/lib/softoken/sftkdbt.h b/security/nss/lib/softoken/sftkdbt.h new file mode 100644 index 000000000..f9d7c9eaa --- /dev/null +++ b/security/nss/lib/softoken/sftkdbt.h @@ -0,0 +1,17 @@ +/* + * license + */ + + +#ifndef SFTKDBT_H +#define SFTKDBT_H 1 +typedef struct SFTKDBHandleStr SFTKDBHandle; + +typedef enum { + SDB_SQL, + SDB_EXTERN, + SDB_LEGACY, + SDB_MULTIACCESS +} SDBType; + +#endif diff --git a/security/nss/lib/softoken/sftkpars.c b/security/nss/lib/softoken/sftkpars.c new file mode 100644 index 000000000..96189937e --- /dev/null +++ b/security/nss/lib/softoken/sftkpars.c @@ -0,0 +1,616 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * The following code handles the storage of PKCS 11 modules used by the + * NSS. This file is written to abstract away how the modules are + * stored so we can deside that later. + */ +#include "sftkpars.h" +#include "pkcs11i.h" +#include "sdb.h" +#include "prprf.h" +#include "prenv.h" + +/* + * this file contains routines for parsing PKCS #11 module spec + * strings. + */ + +#define SFTK_HANDLE_STRING_ARG(param,target,value,command) \ + if (PORT_Strncasecmp(param,value,sizeof(value)-1) == 0) { \ + param += sizeof(value)-1; \ + target = sftk_argFetchValue(param,&next); \ + param += next; \ + command ;\ + } else + +#define SFTK_HANDLE_FINAL_ARG(param) \ + { param = sftk_argSkipParameter(param); } param = sftk_argStrip(param); + +static PRBool sftk_argGetPair(char c) { + switch (c) { + case '\'': return c; + case '\"': return c; + case '<': return '>'; + case '{': return '}'; + case '[': return ']'; + case '(': return ')'; + default: break; + } + return ' '; +} + +static PRBool sftk_argIsBlank(char c) { + return isspace(c); +} + +static PRBool sftk_argIsEscape(char c) { + return c == '\\'; +} + +static PRBool sftk_argIsQuote(char c) { + switch (c) { + case '\'': + case '\"': + case '<': + case '{': /* } end curly to keep vi bracket matching working */ + case '(': /* ) */ + case '[': /* ] */ return PR_TRUE; + default: break; + } + return PR_FALSE; +} + +char *sftk_argStrip(char *c) { + while (*c && sftk_argIsBlank(*c)) c++; + return c; +} + +static char * +sftk_argFindEnd(char *string) { + char endChar = ' '; + PRBool lastEscape = PR_FALSE; + + if (sftk_argIsQuote(*string)) { + endChar = sftk_argGetPair(*string); + string++; + } + + for (;*string; string++) { + if (lastEscape) { + lastEscape = PR_FALSE; + continue; + } + if (sftk_argIsEscape(*string) && !lastEscape) { + lastEscape = PR_TRUE; + continue; + } + if ((endChar == ' ') && sftk_argIsBlank(*string)) break; + if (*string == endChar) { + break; + } + } + + return string; +} + +char * +sftk_argFetchValue(char *string, int *pcount) +{ + char *end = sftk_argFindEnd(string); + char *retString, *copyString; + PRBool lastEscape = PR_FALSE; + int len; + + len = end - string; + if (len == 0) { + *pcount = 0; + return NULL; + } + + copyString = retString = (char *)PORT_Alloc(len+1); + + if (*end) len++; + *pcount = len; + if (retString == NULL) return NULL; + + + if (sftk_argIsQuote(*string)) string++; + for (; string < end; string++) { + if (sftk_argIsEscape(*string) && !lastEscape) { + lastEscape = PR_TRUE; + continue; + } + lastEscape = PR_FALSE; + *copyString++ = *string; + } + *copyString = 0; + return retString; +} + +static char * +sftk_argSkipParameter(char *string) +{ + char *end; + /* look for the end of the <name>= */ + for (;*string; string++) { + if (*string == '=') { string++; break; } + if (sftk_argIsBlank(*string)) return(string); + } + + end = sftk_argFindEnd(string); + if (*end) end++; + return end; +} + +char * +sftk_argGetParamValue(char *paramName,char *parameters) +{ + char searchValue[256]; + int paramLen = strlen(paramName); + char *returnValue = NULL; + int next; + + if ((parameters == NULL) || (*parameters == 0)) return NULL; + + PORT_Assert(paramLen+2 < sizeof(searchValue)); + + PORT_Strcpy(searchValue,paramName); + PORT_Strcat(searchValue,"="); + while (*parameters) { + if (PORT_Strncasecmp(parameters,searchValue,paramLen+1) == 0) { + parameters += paramLen+1; + returnValue = sftk_argFetchValue(parameters,&next); + break; + } else { + parameters = sftk_argSkipParameter(parameters); + } + parameters = sftk_argStrip(parameters); + } + return returnValue; +} + +static char * +sftk_argNextFlag(char *flags) +{ + for (; *flags ; flags++) { + if (*flags == ',') { + flags++; + break; + } + } + return flags; +} + +static PRBool +sftk_argHasFlag(char *label, char *flag, char *parameters) +{ + char *flags,*index; + int len = strlen(flag); + PRBool found = PR_FALSE; + + flags = sftk_argGetParamValue(label,parameters); + if (flags == NULL) return PR_FALSE; + + for (index=flags; *index; index=sftk_argNextFlag(index)) { + if (PORT_Strncasecmp(index,flag,len) == 0) { + found=PR_TRUE; + break; + } + } + PORT_Free(flags); + return found; +} + +/* + * decode a number. handle octal (leading '0'), hex (leading '0x') or decimal + */ +static long +sftk_argDecodeNumber(char *num) +{ + int radix = 10; + unsigned long value = 0; + long retValue = 0; + int sign = 1; + int digit; + + if (num == NULL) return retValue; + + num = sftk_argStrip(num); + + if (*num == '-') { + sign = -1; + num++; + } + + if (*num == '0') { + radix = 8; + num++; + if ((*num == 'x') || (*num == 'X')) { + radix = 16; + num++; + } + } + + + for ( ;*num; num++ ) { + if (isdigit(*num)) { + digit = *num - '0'; + } else if ((*num >= 'a') && (*num <= 'f')) { + digit = *num - 'a' + 10; + } else if ((*num >= 'A') && (*num <= 'F')) { + digit = *num - 'A' + 10; + } else { + break; + } + if (digit >= radix) break; + value = value*radix + digit; + } + + retValue = ((int) value) * sign; + return retValue; +} + +static char * +sftk_argGetName(char *inString, int *next) +{ + char *name=NULL; + char *string; + int len; + + /* look for the end of the <name>= */ + for (string = inString;*string; string++) { + if (*string == '=') { break; } + if (sftk_argIsBlank(*string)) break; + } + + len = string - inString; + + *next = len; + if (*string == '=') (*next) += 1; + if (len > 0) { + name = PORT_Alloc(len+1); + PORT_Strncpy(name,inString,len); + name[len] = 0; + } + return name; +} + +#define FREE_CLEAR(p) if (p) { PORT_Free(p); p = NULL; } + +static void +sftk_parseTokenFlags(char *tmp, sftk_token_parameters *parsed) { + parsed->readOnly = sftk_argHasFlag("flags","readOnly",tmp); + parsed->noCertDB = sftk_argHasFlag("flags","noCertDB",tmp); + parsed->noKeyDB = sftk_argHasFlag("flags","noKeyDB",tmp); + parsed->forceOpen = sftk_argHasFlag("flags","forceOpen",tmp); + parsed->pwRequired = sftk_argHasFlag("flags","passwordRequired",tmp); + parsed->optimizeSpace = sftk_argHasFlag("flags","optimizeSpace",tmp); + return; +} + +static void +sftk_parseFlags(char *tmp, sftk_parameters *parsed) { + parsed->noModDB = sftk_argHasFlag("flags","noModDB",tmp); + parsed->readOnly = sftk_argHasFlag("flags","readOnly",tmp); + /* keep legacy interface working */ + parsed->noCertDB = sftk_argHasFlag("flags","noCertDB",tmp); + parsed->forceOpen = sftk_argHasFlag("flags","forceOpen",tmp); + parsed->pwRequired = sftk_argHasFlag("flags","passwordRequired",tmp); + parsed->optimizeSpace = sftk_argHasFlag("flags","optimizeSpace",tmp); + return; +} + +static CK_RV +sftk_parseTokenParameters(char *param, sftk_token_parameters *parsed) +{ + int next; + char *tmp; + char *index; + index = sftk_argStrip(param); + + while (*index) { + SFTK_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;) + SFTK_HANDLE_STRING_ARG(index,parsed->certPrefix,"certPrefix=",;) + SFTK_HANDLE_STRING_ARG(index,parsed->keyPrefix,"keyPrefix=",;) + SFTK_HANDLE_STRING_ARG(index,parsed->tokdes,"tokenDescription=",;) + SFTK_HANDLE_STRING_ARG(index,parsed->slotdes,"slotDescription=",;) + SFTK_HANDLE_STRING_ARG(index,tmp,"minPWLen=", + if(tmp) { parsed->minPW=atoi(tmp); PORT_Free(tmp); }) + SFTK_HANDLE_STRING_ARG(index,tmp,"flags=", + if(tmp) { sftk_parseTokenFlags(param,parsed); PORT_Free(tmp); }) + SFTK_HANDLE_FINAL_ARG(index) + } + return CKR_OK; +} + +static void +sftk_parseTokens(char *tokenParams, sftk_parameters *parsed) +{ + char *tokenIndex; + sftk_token_parameters *tokens = NULL; + int i=0,count = 0,next; + + if ((tokenParams == NULL) || (*tokenParams == 0)) return; + + /* first count the number of slots */ + for (tokenIndex = sftk_argStrip(tokenParams); *tokenIndex; + tokenIndex = sftk_argStrip(sftk_argSkipParameter(tokenIndex))) { + count++; + } + + /* get the data structures */ + tokens = (sftk_token_parameters *) + PORT_ZAlloc(count*sizeof(sftk_token_parameters)); + if (tokens == NULL) return; + + for (tokenIndex = sftk_argStrip(tokenParams), i = 0; + *tokenIndex && i < count ; i++ ) { + char *name; + name = sftk_argGetName(tokenIndex,&next); + tokenIndex += next; + + tokens[i].slotID = sftk_argDecodeNumber(name); + tokens[i].readOnly = PR_FALSE; + tokens[i].noCertDB = PR_FALSE; + tokens[i].noKeyDB = PR_FALSE; + if (!sftk_argIsBlank(*tokenIndex)) { + char *args = sftk_argFetchValue(tokenIndex,&next); + tokenIndex += next; + if (args) { + sftk_parseTokenParameters(args,&tokens[i]); + PORT_Free(args); + } + } + if (name) PORT_Free(name); + tokenIndex = sftk_argStrip(tokenIndex); + } + parsed->token_count = i; + parsed->tokens = tokens; + return; +} + +CK_RV +sftk_parseParameters(char *param, sftk_parameters *parsed, PRBool isFIPS) +{ + int next; + char *tmp; + char *index; + char *certPrefix = NULL, *keyPrefix = NULL; + char *tokdes = NULL, *ptokdes = NULL; + char *slotdes = NULL, *pslotdes = NULL; + char *fslotdes = NULL, *fpslotdes = NULL; + char *minPW = NULL; + index = sftk_argStrip(param); + + PORT_Memset(parsed, 0, sizeof(sftk_parameters)); + + while (*index) { + SFTK_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;) + SFTK_HANDLE_STRING_ARG(index,parsed->secmodName,"secmod=",;) + SFTK_HANDLE_STRING_ARG(index,parsed->man,"manufacturerID=",;) + SFTK_HANDLE_STRING_ARG(index,parsed->libdes,"libraryDescription=",;) + /* constructed values, used so legacy interfaces still work */ + SFTK_HANDLE_STRING_ARG(index,certPrefix,"certPrefix=",;) + SFTK_HANDLE_STRING_ARG(index,keyPrefix,"keyPrefix=",;) + SFTK_HANDLE_STRING_ARG(index,tokdes,"cryptoTokenDescription=",;) + SFTK_HANDLE_STRING_ARG(index,ptokdes,"dbTokenDescription=",;) + SFTK_HANDLE_STRING_ARG(index,slotdes,"cryptoSlotDescription=",;) + SFTK_HANDLE_STRING_ARG(index,pslotdes,"dbSlotDescription=",;) + SFTK_HANDLE_STRING_ARG(index,fslotdes,"FIPSSlotDescription=",;) + SFTK_HANDLE_STRING_ARG(index,fpslotdes,"FIPSTokenDescription=",;) + SFTK_HANDLE_STRING_ARG(index,minPW,"minPWLen=",;) + + SFTK_HANDLE_STRING_ARG(index,tmp,"flags=", + if(tmp) { sftk_parseFlags(param,parsed); PORT_Free(tmp); }) + SFTK_HANDLE_STRING_ARG(index,tmp,"tokens=", + if(tmp) { sftk_parseTokens(tmp,parsed); PORT_Free(tmp); }) + SFTK_HANDLE_FINAL_ARG(index) + } + if (parsed->tokens == NULL) { + int count = isFIPS ? 1 : 2; + int index = count-1; + sftk_token_parameters *tokens = NULL; + + tokens = (sftk_token_parameters *) + PORT_ZAlloc(count*sizeof(sftk_token_parameters)); + if (tokens == NULL) { + goto loser; + } + parsed->tokens = tokens; + parsed->token_count = count; + tokens[index].slotID = isFIPS ? FIPS_SLOT_ID : PRIVATE_KEY_SLOT_ID; + tokens[index].certPrefix = certPrefix; + tokens[index].keyPrefix = keyPrefix; + tokens[index].minPW = minPW ? atoi(minPW) : 0; + tokens[index].readOnly = parsed->readOnly; + tokens[index].noCertDB = parsed->noCertDB; + tokens[index].noKeyDB = parsed->noCertDB; + tokens[index].forceOpen = parsed->forceOpen; + tokens[index].pwRequired = parsed->pwRequired; + tokens[index].optimizeSpace = parsed->optimizeSpace; + tokens[0].optimizeSpace = parsed->optimizeSpace; + certPrefix = NULL; + keyPrefix = NULL; + if (isFIPS) { + tokens[index].tokdes = fslotdes; + tokens[index].slotdes = fpslotdes; + fslotdes = NULL; + fpslotdes = NULL; + } else { + tokens[index].tokdes = ptokdes; + tokens[index].slotdes = pslotdes; + tokens[0].slotID = NETSCAPE_SLOT_ID; + tokens[0].tokdes = tokdes; + tokens[0].slotdes = slotdes; + tokens[0].noCertDB = PR_TRUE; + tokens[0].noKeyDB = PR_TRUE; + ptokdes = NULL; + pslotdes = NULL; + tokdes = NULL; + slotdes = NULL; + } + } + +loser: + FREE_CLEAR(certPrefix); + FREE_CLEAR(keyPrefix); + FREE_CLEAR(tokdes); + FREE_CLEAR(ptokdes); + FREE_CLEAR(slotdes); + FREE_CLEAR(pslotdes); + FREE_CLEAR(fslotdes); + FREE_CLEAR(fpslotdes); + FREE_CLEAR(minPW); + return CKR_OK; +} + +void +sftk_freeParams(sftk_parameters *params) +{ + int i; + + for (i=0; i < params->token_count; i++) { + FREE_CLEAR(params->tokens[i].configdir); + FREE_CLEAR(params->tokens[i].certPrefix); + FREE_CLEAR(params->tokens[i].keyPrefix); + FREE_CLEAR(params->tokens[i].tokdes); + FREE_CLEAR(params->tokens[i].slotdes); + } + + FREE_CLEAR(params->configdir); + FREE_CLEAR(params->secmodName); + FREE_CLEAR(params->man); + FREE_CLEAR(params->libdes); + FREE_CLEAR(params->tokens); +} + +#define SQLDB "sql:" +#define EXTERNDB "extern:" +#define LEGACY "dbm:" +const char * +sftk_EvaluateConfigDir(const char *configdir, SDBType *dbType, char **appName) +{ + *appName = NULL; + *dbType = SDB_LEGACY; + if (PORT_Strncmp(configdir, MULTIACCESS, sizeof(MULTIACCESS)-1) == 0) { + char *cdir; + *dbType = SDB_MULTIACCESS; + + *appName = PORT_Strdup(configdir+sizeof(MULTIACCESS)-1); + if (*appName == NULL) { + return configdir; + } + cdir = *appName; + while (*cdir && *cdir != ':') { + cdir++; + } + if (*cdir == ':') { + *cdir = 0; + cdir++; + } + configdir = cdir; + } else if (PORT_Strncmp(configdir, SQLDB, sizeof(SQLDB)-1) == 0) { + *dbType = SDB_SQL; + configdir = configdir + sizeof(SQLDB) -1; + } else if (PORT_Strncmp(configdir, EXTERNDB, sizeof(EXTERNDB)-1) == 0) { + *dbType = SDB_EXTERN; + configdir = configdir + sizeof(EXTERNDB) -1; + } else if (PORT_Strncmp(configdir, LEGACY, sizeof(LEGACY)-1) == 0) { + *dbType = SDB_LEGACY; + configdir = configdir + sizeof(LEGACY) -1; + } else { + /* look up the default from the environment */ + char *defaultType = PR_GetEnv("NSS_DEFAULT_DB_TYPE"); + if (defaultType == NULL) { + /* none specified, go with the legacy */ + return configdir; + } + if (PORT_Strncmp(defaultType, SQLDB, sizeof(SQLDB)-2) == 0) { + *dbType = SDB_SQL; + } else if (PORT_Strncmp(defaultType,EXTERNDB,sizeof(EXTERNDB)-2)==0) { + *dbType = SDB_EXTERN; + } else if (PORT_Strncmp(defaultType, LEGACY, sizeof(LEGACY)-2) == 0) { + *dbType = SDB_LEGACY; + } + } + return configdir; +} + +char * +sftk_getSecmodName(char *param, SDBType *dbType, char **appName, + char **filename, PRBool *rw) +{ + int next; + char *configdir = NULL; + char *secmodName = NULL; + char *value = NULL; + char *save_params = param; + const char *lconfigdir; + param = sftk_argStrip(param); + + + while (*param) { + SFTK_HANDLE_STRING_ARG(param,configdir,"configDir=",;) + SFTK_HANDLE_STRING_ARG(param,secmodName,"secmod=",;) + SFTK_HANDLE_FINAL_ARG(param) + } + + *rw = PR_TRUE; + if (sftk_argHasFlag("flags","readOnly",save_params) || + sftk_argHasFlag("flags","noModDB",save_params)) *rw = PR_FALSE; + + if (!secmodName || *secmodName == '\0') { + if (secmodName) PORT_Free(secmodName); + secmodName = PORT_Strdup(SECMOD_DB); + } + + *filename = secmodName; + lconfigdir = sftk_EvaluateConfigDir(configdir, dbType, appName); + + /* only use the renamed secmod for legacy databases */ + if ((*dbType != SDB_LEGACY) && (*dbType != SDB_MULTIACCESS)) { + secmodName="pkcs11.txt"; + } + + if (lconfigdir) { + value = PR_smprintf("%s" PATH_SEPARATOR "%s",lconfigdir,secmodName); + } else { + value = PR_smprintf("%s",secmodName); + } + if (configdir) PORT_Free(configdir); + return value; +} diff --git a/security/nss/lib/softoken/sftkpars.h b/security/nss/lib/softoken/sftkpars.h new file mode 100644 index 000000000..beb9edf97 --- /dev/null +++ b/security/nss/lib/softoken/sftkpars.h @@ -0,0 +1,17 @@ +/* + * license + */ +#include "pkcs11i.h" +#include "sftkdbt.h" + +/* parsing functions */ +char * sftk_argFetchValue(char *string, int *pcount); +char * sftk_getSecmodName(char *param, SDBType *dbType, char **appName, char **filename,PRBool *rw); +char *sftk_argStrip(char *c); +CK_RV sftk_parseParameters(char *param, sftk_parameters *parsed, PRBool isFIPS); +void sftk_freeParams(sftk_parameters *params); +const char *sftk_EvaluateConfigDir(const char *configdir, SDBType *dbType, char **app); +char * sftk_argGetParamValue(char *paramName,char *parameters); + + + diff --git a/security/nss/lib/softoken/softoken.h b/security/nss/lib/softoken/softoken.h index ed9108dcc..6078c40b2 100644 --- a/security/nss/lib/softoken/softoken.h +++ b/security/nss/lib/softoken/softoken.h @@ -147,6 +147,10 @@ SECStatus RSA_DecryptRaw(NSSLOWKEYPrivateKey *key, unsigned char *output, */ extern SECStatus EC_FillParams(PRArenaPool *arena, const SECItem *encodedParams, ECParams *params); +extern SECStatus EC_DecodeParams(const SECItem *encodedParams, + ECParams **ecparams); +extern SECStatus EC_CopyParams(PRArenaPool *arena, ECParams *dstParams, + const ECParams *srcParams); #endif |