security/nss/lib/softoken/legacydb/keydb.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "lowkeyi.h"
     6 #include "secasn1.h"
     7 #include "secder.h"
     8 #include "secoid.h"
     9 #include "blapi.h"
    10 #include "secitem.h"
    11 #include "pcert.h"
    12 #include "mcom_db.h"
    13 #include "secerr.h"
    15 #include "keydbi.h"
    16 #include "lgdb.h"
    18 /*
    19  * Record keys for keydb
    20  */
    21 #define SALT_STRING "global-salt"
    22 #define VERSION_STRING "Version"
    23 #define KEYDB_PW_CHECK_STRING	"password-check"
    24 #define KEYDB_PW_CHECK_LEN	14
    25 #define KEYDB_FAKE_PW_CHECK_STRING	"fake-password-check"
    26 #define KEYDB_FAKE_PW_CHECK_LEN	19
    28 /* Size of the global salt for key database */
    29 #define SALT_LENGTH     16
    31 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    33 const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = {
    34     { SEC_ASN1_SEQUENCE,
    35 	0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) },
    36     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    37 	offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,algorithm),
    38 	SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
    39     { SEC_ASN1_OCTET_STRING,
    40 	offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,encryptedData) },
    41     { 0 }
    42 };
    44 const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = {
    45 	{ SEC_ASN1_POINTER, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate }
    46 };
    49 /* ====== Default key databse encryption algorithm ====== */
    50 static void
    51 sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey)
    52 {
    53     if ( dbkey && dbkey->arena ) {
    54 	PORT_FreeArena(dbkey->arena, PR_FALSE);
    55     }
    56 }
    58 static void
    59 free_dbt(DBT *dbt)
    60 {
    61     if ( dbt ) {
    62 	PORT_Free(dbt->data);
    63 	PORT_Free(dbt);
    64     }
    66     return;
    67 }
    69 static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 
    70 		     unsigned int flags);
    71 static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 
    72 		     unsigned int flags);
    73 static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags);
    74 static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags);
    75 static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 
    76 		     unsigned int flags);
    77 static void keydb_Close(NSSLOWKEYDBHandle *db);
    79 /*
    80  * format of key database entries for version 3 of database:
    81  *	byte offset	field
    82  *	-----------	-----
    83  *	0		version
    84  *	1		salt-len
    85  *	2		nn-len
    86  *	3..		salt-data
    87  *	...		nickname
    88  *	...		encrypted-key-data
    89  */
    90 static DBT *
    91 encode_dbkey(NSSLOWKEYDBKey *dbkey,unsigned char version)
    92 {
    93     DBT *bufitem = NULL;
    94     unsigned char *buf;
    95     int nnlen;
    96     char *nn;
    98     bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT));
    99     if ( bufitem == NULL ) {
   100 	goto loser;
   101     }
   103     if ( dbkey->nickname ) {
   104 	nn = dbkey->nickname;
   105 	nnlen = PORT_Strlen(nn) + 1;
   106     } else {
   107 	nn = "";
   108 	nnlen = 1;
   109     }
   111     /* compute the length of the record */
   112     /* 1 + 1 + 1 == version number header + salt length + nn len */
   113     bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1;
   115     bufitem->data = (void *)PORT_ZAlloc(bufitem->size);
   116     if ( bufitem->data == NULL ) {
   117 	goto loser;
   118     }
   120     buf = (unsigned char *)bufitem->data;
   122     /* set version number */
   123     buf[0] = version;
   125     /* set length of salt */
   126     PORT_Assert(dbkey->salt.len < 256);
   127     buf[1] = dbkey->salt.len;
   129     /* set length of nickname */
   130     PORT_Assert(nnlen < 256);
   131     buf[2] = nnlen;
   133     /* copy salt */
   134     PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len);
   136     /* copy nickname */
   137     PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen);
   139     /* copy encrypted key */
   140     PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data,
   141 	      dbkey->derPK.len);
   143     return(bufitem);
   145 loser:
   146     if ( bufitem ) {
   147 	free_dbt(bufitem);
   148     }
   150     return(NULL);
   151 }
   153 static NSSLOWKEYDBKey *
   154 decode_dbkey(DBT *bufitem, int expectedVersion)
   155 {
   156     NSSLOWKEYDBKey *dbkey;
   157     PLArenaPool *arena = NULL;
   158     unsigned char *buf;
   159     int version;
   160     int keyoff;
   161     int nnlen;
   162     int saltoff;
   164     buf = (unsigned char *)bufitem->data;
   166     version = buf[0];
   168     if ( version != expectedVersion ) {
   169 	goto loser;
   170     }
   172     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   173     if ( arena == NULL ) {
   174 	goto loser;
   175     }
   177     dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
   178     if ( dbkey == NULL ) {
   179 	goto loser;
   180     }
   182     dbkey->arena = arena;
   183     dbkey->salt.data = NULL;
   184     dbkey->derPK.data = NULL;
   186     dbkey->salt.len = buf[1];
   187     dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len);
   188     if ( dbkey->salt.data == NULL ) {
   189 	goto loser;
   190     }
   192     saltoff = 2;
   193     keyoff = 2 + dbkey->salt.len;
   195     if ( expectedVersion >= 3 ) {
   196 	nnlen = buf[2];
   197 	if ( nnlen ) {
   198 	    dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1);
   199 	    if ( dbkey->nickname ) {
   200 		PORT_Memcpy(dbkey->nickname, &buf[keyoff+1], nnlen);
   201 	    }
   202 	}
   203 	keyoff += ( nnlen + 1 );
   204 	saltoff = 3;
   205     }
   207     PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len);
   209     dbkey->derPK.len = bufitem->size - keyoff;
   210     dbkey->derPK.data = (unsigned char *)PORT_ArenaZAlloc(arena,dbkey->derPK.len);
   211     if ( dbkey->derPK.data == NULL ) {
   212 	goto loser;
   213     }
   215     PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len);
   217     return(dbkey);
   219 loser:
   221     if ( arena ) {
   222 	PORT_FreeArena(arena, PR_FALSE);
   223     }
   225     return(NULL);
   226 }
   228 static NSSLOWKEYDBKey *
   229 get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index)
   230 {
   231     NSSLOWKEYDBKey *dbkey;
   232     DBT entry;
   233     int ret;
   235     /* get it from the database */
   236     ret = keydb_Get(handle, index, &entry, 0);
   237     if ( ret ) {
   238 	PORT_SetError(SEC_ERROR_BAD_DATABASE);
   239 	return NULL;
   240     }
   242     /* set up dbkey struct */
   244     dbkey = decode_dbkey(&entry, handle->version);
   246     return(dbkey);
   247 }
   249 static SECStatus
   250 put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update)
   251 {
   252     DBT *keydata = NULL;
   253     int status;
   255     keydata = encode_dbkey(dbkey, handle->version);
   256     if ( keydata == NULL ) {
   257 	goto loser;
   258     }
   260     /* put it in the database */
   261     if ( update ) {
   262 	status = keydb_Put(handle, index, keydata, 0);
   263     } else {
   264 	status = keydb_Put(handle, index, keydata, R_NOOVERWRITE);
   265     }
   267     if ( status ) {
   268 	goto loser;
   269     }
   271     /* sync the database */
   272     status = keydb_Sync(handle, 0);
   273     if ( status ) {
   274 	goto loser;
   275     }
   277     free_dbt(keydata);
   278     return(SECSuccess);
   280 loser:
   281     if ( keydata ) {
   282 	free_dbt(keydata);
   283     }
   285     return(SECFailure);
   286 }
   288 SECStatus
   289 nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle, 
   290 		 SECStatus (* keyfunc)(DBT *k, DBT *d, void *pdata),
   291 		 void *udata )
   292 {
   293     DBT data;
   294     DBT key;
   295     SECStatus status;
   296     int ret;
   298     if (handle == NULL) {
   299 	return(SECFailure);
   300     }
   302     ret = keydb_Seq(handle, &key, &data, R_FIRST);
   303     if ( ret ) {
   304 	return(SECFailure);
   305     }
   307     do {
   308 	/* skip version record */
   309 	if ( data.size > 1 ) {
   310 	    if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
   311 		if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
   312 		    continue;
   313 		}
   314 	    }
   316 	    /* skip password check */
   317 	    if ( key.size == KEYDB_PW_CHECK_LEN ) {
   318 		if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,
   319 				 KEYDB_PW_CHECK_LEN) == 0 ) {
   320 		    continue;
   321 		}
   322 	    }
   324 	    status = (* keyfunc)(&key, &data, udata);
   325 	    if (status != SECSuccess) {
   326 		return(status);
   327 	    }
   328 	}
   329     } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
   331     return(SECSuccess);
   332 }
   334 #ifdef notdef
   335 typedef struct keyNode {
   336     struct keyNode *next;
   337     DBT key;
   338 } keyNode;
   340 typedef struct {
   341     PLArenaPool *arena;
   342     keyNode *head;
   343 } keyList;
   345 static SECStatus
   346 sec_add_key_to_list(DBT *key, DBT *data, void *arg)
   347 {
   348     keyList *keylist;
   349     keyNode *node;
   350     void *keydata;
   352     keylist = (keyList *)arg;
   354     /* allocate the node struct */
   355     node = (keyNode*)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode));
   356     if ( node == NULL ) {
   357 	return(SECFailure);
   358     }
   360     /* allocate room for key data */
   361     keydata = PORT_ArenaZAlloc(keylist->arena, key->size);
   362     if ( keydata == NULL ) {
   363 	return(SECFailure);
   364     }
   366     /* link node into list */
   367     node->next = keylist->head;
   368     keylist->head = node;
   370     /* copy key into node */
   371     PORT_Memcpy(keydata, key->data, key->size);
   372     node->key.size = key->size;
   373     node->key.data = keydata;
   375     return(SECSuccess);
   376 }
   377 #endif
   379 static SECItem *
   380 decodeKeyDBGlobalSalt(DBT *saltData)
   381 {
   382     SECItem *saltitem;
   384     saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
   385     if ( saltitem == NULL ) {
   386 	return(NULL);
   387     }
   389     saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size);
   390     if ( saltitem->data == NULL ) {
   391 	PORT_Free(saltitem);
   392 	return(NULL);
   393     }
   395     saltitem->len = saltData->size;
   396     PORT_Memcpy(saltitem->data, saltData->data, saltitem->len);
   398     return(saltitem);
   399 }
   401 static SECItem *
   402 GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
   403 {
   404     DBT saltKey;
   405     DBT saltData;
   406     int ret;
   408     saltKey.data = SALT_STRING;
   409     saltKey.size = sizeof(SALT_STRING) - 1;
   411     ret = keydb_Get(handle, &saltKey, &saltData, 0);
   412     if ( ret ) {
   413 	return(NULL);
   414     }
   416     return(decodeKeyDBGlobalSalt(&saltData));
   417 }
   419 static SECStatus
   420 StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle, SECItem *salt)
   421 {
   422     DBT saltKey;
   423     DBT saltData;
   424     int status;
   426     saltKey.data = SALT_STRING;
   427     saltKey.size = sizeof(SALT_STRING) - 1;
   429     saltData.data = (void *)salt->data;
   430     saltData.size = salt->len;
   432     /* put global salt into the database now */
   433     status = keydb_Put(handle, &saltKey, &saltData, 0);
   434     if ( status ) {
   435 	return(SECFailure);
   436     }
   438     return(SECSuccess);
   439 }
   441 static SECStatus
   442 makeGlobalVersion(NSSLOWKEYDBHandle *handle)
   443 {
   444     unsigned char version;
   445     DBT versionData;
   446     DBT versionKey;
   447     int status;
   449     version = NSSLOWKEY_DB_FILE_VERSION;
   450     versionData.data = &version;
   451     versionData.size = 1;
   452     versionKey.data = VERSION_STRING;
   453     versionKey.size = sizeof(VERSION_STRING)-1;
   455     /* put version string into the database now */
   456     status = keydb_Put(handle, &versionKey, &versionData, 0);
   457     if ( status ) {
   458 	return(SECFailure);
   459     }
   460     handle->version = version;
   462     return(SECSuccess);
   463 }
   466 static SECStatus
   467 makeGlobalSalt(NSSLOWKEYDBHandle *handle)
   468 {
   469     DBT saltKey;
   470     DBT saltData;
   471     unsigned char saltbuf[16];
   472     int status;
   474     saltKey.data = SALT_STRING;
   475     saltKey.size = sizeof(SALT_STRING) - 1;
   477     saltData.data = (void *)saltbuf;
   478     saltData.size = sizeof(saltbuf);
   479     RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf));
   481     /* put global salt into the database now */
   482     status = keydb_Put(handle, &saltKey, &saltData, 0);
   483     if ( status ) {
   484 	return(SECFailure);
   485     }
   487     return(SECSuccess);
   488 }
   490 static SECStatus
   491 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
   492 		   SECItem *encCheck);
   494 static unsigned char
   495 nsslowkey_version(NSSLOWKEYDBHandle *handle)
   496 {
   497     DBT versionKey;
   498     DBT versionData;
   499     int ret;
   500     versionKey.data = VERSION_STRING;
   501     versionKey.size = sizeof(VERSION_STRING)-1;
   503     if (handle->db == NULL) {
   504 	return 255;
   505     }
   507     /* lookup version string in database */
   508     ret = keydb_Get( handle, &versionKey, &versionData, 0 );
   510     /* error accessing the database */
   511     if ( ret < 0 ) {
   512 	return 255;
   513     }
   515     if ( ret >= 1 ) {
   516 	return 0;
   517     }
   518     return *( (unsigned char *)versionData.data);
   519 }
   521 static PRBool
   522 seckey_HasAServerKey(NSSLOWKEYDBHandle *handle)
   523 {
   524     DBT key;
   525     DBT data;
   526     int ret;
   527     PRBool found = PR_FALSE;
   529     ret = keydb_Seq(handle, &key, &data, R_FIRST);
   530     if ( ret ) {
   531 	return PR_FALSE;
   532     }
   534     do {
   535 	/* skip version record */
   536 	if ( data.size > 1 ) {
   537 	    /* skip salt */
   538 	    if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
   539 		if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
   540 		    continue;
   541 		}
   542 	    }
   543 	    /* skip pw check entry */
   544 	    if ( key.size == KEYDB_PW_CHECK_LEN ) {
   545 		if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING, 
   546 						KEYDB_PW_CHECK_LEN) == 0 ) {
   547 		    continue;
   548 		}
   549 	    }
   551 	    /* keys stored by nickname will have 0 as the last byte of the
   552 	     * db key.  Other keys must be stored by modulus.  We will not
   553 	     * update those because they are left over from a keygen that
   554 	     * never resulted in a cert.
   555 	     */
   556 	    if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
   557 		continue;
   558 	    }
   560 	    if (PORT_Strcmp(key.data,"Server-Key") == 0) {
   561 		found = PR_TRUE;
   562 	        break;
   563 	    }
   565 	}
   566     } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
   568     return found;
   569 }
   571 /* forward declare local create function */
   572 static NSSLOWKEYDBHandle * nsslowkey_NewHandle(DB *dbHandle);
   574 /*
   575  * currently updates key database from v2 to v3
   576  */
   577 static SECStatus
   578 nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle)
   579 {
   580     SECStatus rv;
   581     DBT checkKey;
   582     DBT checkData;
   583     DBT saltKey;
   584     DBT saltData;
   585     DBT key;
   586     DBT data;
   587     unsigned char version;
   588     NSSLOWKEYDBKey *dbkey = NULL;
   589     NSSLOWKEYDBHandle *update = NULL;
   590     SECItem *oldSalt = NULL;
   591     int ret;
   592     SECItem checkitem;
   594     if ( handle->updatedb == NULL ) {
   595 	return SECSuccess;
   596     }
   598     /* create a full DB Handle for our update so we 
   599      * can use the correct locks for the db primatives */
   600     update = nsslowkey_NewHandle(handle->updatedb);
   601     if ( update == NULL) {
   602 	return SECSuccess;
   603     }
   605     /* update has now inherited the database handle */
   606     handle->updatedb = NULL;
   608     /*
   609      * check the version record
   610      */
   611     version = nsslowkey_version(update);
   612     if (version != 2) {
   613 	goto done;
   614     }
   616     saltKey.data = SALT_STRING;
   617     saltKey.size = sizeof(SALT_STRING) - 1;
   619     ret = keydb_Get(update, &saltKey, &saltData, 0);
   620     if ( ret ) {
   621 	/* no salt in old db, so it is corrupted */
   622 	goto done;
   623     }
   625     oldSalt = decodeKeyDBGlobalSalt(&saltData);
   626     if ( oldSalt == NULL ) {
   627 	/* bad salt in old db, so it is corrupted */
   628 	goto done;
   629     }
   631     /*
   632      * look for a pw check entry
   633      */
   634     checkKey.data = KEYDB_PW_CHECK_STRING;
   635     checkKey.size = KEYDB_PW_CHECK_LEN;
   637     ret = keydb_Get(update, &checkKey, &checkData, 0 );
   638     if (ret) {
   639 	/*
   640 	 * if we have a key, but no KEYDB_PW_CHECK_STRING, then this must
   641 	 * be an old server database, and it does have a password associated
   642 	 * with it. Put a fake entry in so we can identify this db when we do
   643 	 * get the password for it.
   644 	 */
   645 	if (seckey_HasAServerKey(update)) {
   646 	    DBT fcheckKey;
   647 	    DBT fcheckData;
   649 	    /*
   650 	     * include a fake string
   651 	     */
   652 	    fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING;
   653 	    fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN;
   654 	    fcheckData.data = "1";
   655 	    fcheckData.size = 1;
   656 	    /* put global salt into the new database now */
   657 	    ret = keydb_Put( handle, &saltKey, &saltData, 0);
   658 	    if ( ret ) {
   659 		goto done;
   660 	    }
   661 	    ret = keydb_Put( handle, &fcheckKey, &fcheckData, 0);
   662 	    if ( ret ) {
   663 		goto done;
   664 	    }
   665 	} else {
   666 	    goto done;
   667 	}
   668     } else {
   669 	/* put global salt into the new database now */
   670 	ret = keydb_Put( handle, &saltKey, &saltData, 0);
   671 	if ( ret ) {
   672 	    goto done;
   673 	}
   675 	dbkey = decode_dbkey(&checkData, 2);
   676 	if ( dbkey == NULL ) {
   677 	    goto done;
   678 	}
   679 	checkitem = dbkey->derPK;
   680 	dbkey->derPK.data = NULL;
   682 	/* format the new pw check entry */
   683 	rv = encodePWCheckEntry(NULL, &dbkey->derPK, SEC_OID_RC4, &checkitem);
   684 	if ( rv != SECSuccess ) {
   685 	    goto done;
   686 	}
   688 	rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE);
   689 	if ( rv != SECSuccess ) {
   690 	    goto done;
   691 	}
   693 	/* free the dbkey */
   694 	sec_destroy_dbkey(dbkey);
   695 	dbkey = NULL;
   696     }
   699     /* now traverse the database */
   700     ret = keydb_Seq(update, &key, &data, R_FIRST);
   701     if ( ret ) {
   702 	goto done;
   703     }
   705     do {
   706 	/* skip version record */
   707 	if ( data.size > 1 ) {
   708 	    /* skip salt */
   709 	    if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
   710 		if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
   711 		    continue;
   712 		}
   713 	    }
   714 	    /* skip pw check entry */
   715 	    if ( key.size == checkKey.size ) {
   716 		if ( PORT_Memcmp(key.data, checkKey.data, key.size) == 0 ) {
   717 		    continue;
   718 		}
   719 	    }
   721 	    /* keys stored by nickname will have 0 as the last byte of the
   722 	     * db key.  Other keys must be stored by modulus.  We will not
   723 	     * update those because they are left over from a keygen that
   724 	     * never resulted in a cert.
   725 	     */
   726 	    if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
   727 		continue;
   728 	    }
   730 	    dbkey = decode_dbkey(&data, 2);
   731 	    if ( dbkey == NULL ) {
   732 		continue;
   733 	    }
   735 	    /* This puts the key into the new database with the same
   736 	     * index (nickname) that it had before.  The second pass
   737 	     * of the update will have the password.  It will decrypt
   738 	     * and re-encrypt the entries using a new algorithm.
   739 	     */
   740 	    dbkey->nickname = (char *)key.data;
   741 	    rv = put_dbkey(handle, &key, dbkey, PR_FALSE);
   742 	    dbkey->nickname = NULL;
   744 	    sec_destroy_dbkey(dbkey);
   745 	}
   746     } while ( keydb_Seq(update, &key, &data, R_NEXT) == 0 );
   748     dbkey = NULL;
   750 done:
   751     /* sync the database */
   752     ret = keydb_Sync(handle, 0);
   754     nsslowkey_CloseKeyDB(update);
   756     if ( oldSalt ) {
   757 	SECITEM_FreeItem(oldSalt, PR_TRUE);
   758     }
   760     if ( dbkey ) {
   761 	sec_destroy_dbkey(dbkey);
   762     }
   764     return(SECSuccess);
   765 }
   767 static SECStatus
   768 openNewDB(const char *appName, const char *prefix, const char *dbname, 
   769 	NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg)
   770 {
   771     SECStatus rv = SECFailure;
   772     int status = RDB_FAIL;
   773     char *updname = NULL;
   774     DB *updatedb = NULL;
   775     PRBool updated = PR_FALSE;
   776     int ret;
   778     if (appName) {
   779 	handle->db = rdbopen( appName, prefix, "key", NO_CREATE, &status);
   780     } else {
   781 	handle->db = dbopen( dbname, NO_CREATE, 0600, DB_HASH, 0 );
   782     }
   783     /* if create fails then we lose */
   784     if ( handle->db == NULL ) {
   785 	return (status == RDB_RETRY) ? SECWouldBlock: SECFailure;
   786     }
   788     /* force a transactional read, which will verify that one and only one
   789      * process attempts the update. */
   790     if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION) {
   791 	/* someone else has already updated the database for us */
   792 	db_InitComplete(handle->db);
   793 	return SECSuccess;
   794     }
   796     /*
   797      * if we are creating a multiaccess database, see if there is a
   798      * local database we can update from.
   799      */
   800     if (appName) {
   801         NSSLOWKEYDBHandle *updateHandle;
   802 	updatedb = dbopen( dbname, NO_RDONLY, 0600, DB_HASH, 0 );
   803 	if (!updatedb) {
   804 	    goto noupdate;
   805 	}
   807 	/* nsslowkey_version needs a full handle because it calls
   808          * the kdb_Get() function, which needs to lock.
   809          */
   810         updateHandle = nsslowkey_NewHandle(updatedb);
   811 	if (!updateHandle) {
   812 	    updatedb->close(updatedb);
   813 	    goto noupdate;
   814 	}
   816 	handle->version = nsslowkey_version(updateHandle);
   817 	if (handle->version != NSSLOWKEY_DB_FILE_VERSION) {
   818 	    nsslowkey_CloseKeyDB(updateHandle);
   819 	    goto noupdate;
   820 	}
   822 	/* copy the new DB from the old one */
   823 	db_Copy(handle->db, updatedb);
   824 	nsslowkey_CloseKeyDB(updateHandle);
   825 	db_InitComplete(handle->db);
   826 	return SECSuccess;
   827     }
   828 noupdate:
   830     /* update the version number */
   831     rv = makeGlobalVersion(handle);
   832     if ( rv != SECSuccess ) {
   833 	goto loser;
   834     }
   836     /*
   837      * try to update from v2 db
   838      */
   839     updname = (*namecb)(cbarg, 2);
   840     if ( updname != NULL ) {
   841 	handle->updatedb = dbopen( updname, NO_RDONLY, 0600, DB_HASH, 0 );
   842         PORT_Free( updname );
   844 	if ( handle->updatedb ) {
   845 	    /*
   846 	     * Try to update the db using a null password.  If the db
   847 	     * doesn't have a password, then this will work.  If it does
   848 	     * have a password, then this will fail and we will do the
   849 	     * update later
   850 	     */
   851 	    rv = nsslowkey_UpdateKeyDBPass1(handle);
   852 	    if ( rv == SECSuccess ) {
   853 		updated = PR_TRUE;
   854 	    }
   855 	}
   857     }
   859     /* we are using the old salt if we updated from an old db */
   860     if ( ! updated ) {
   861 	rv = makeGlobalSalt(handle);
   862 	if ( rv != SECSuccess ) {
   863 	   goto loser;
   864 	}
   865     }
   867     /* sync the database */
   868     ret = keydb_Sync(handle, 0);
   869     if ( ret ) {
   870 	rv = SECFailure;
   871 	goto loser;
   872     }
   873     rv = SECSuccess;
   875 loser:
   876     db_InitComplete(handle->db);
   877     return rv;
   878 }
   881 static DB *
   882 openOldDB(const char *appName, const char *prefix, const char *dbname, 
   883 					PRBool openflags) {
   884     DB *db = NULL;
   886     if (appName) {
   887 	db = rdbopen( appName, prefix, "key", openflags, NULL);
   888     } else {
   889 	db = dbopen( dbname, openflags, 0600, DB_HASH, 0 );
   890     }
   892     return db;
   893 }
   895 /* check for correct version number */
   896 static PRBool
   897 verifyVersion(NSSLOWKEYDBHandle *handle)
   898 {
   899     int version = nsslowkey_version(handle);
   901     handle->version = version;
   902     if (version != NSSLOWKEY_DB_FILE_VERSION ) {
   903 	if (handle->db) {
   904 	    keydb_Close(handle);
   905 	    handle->db = NULL;
   906 	}
   907     }
   908     return handle->db != NULL;
   909 }
   911 static NSSLOWKEYDBHandle *
   912 nsslowkey_NewHandle(DB *dbHandle)
   913 {
   914     NSSLOWKEYDBHandle *handle;
   915     handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc (sizeof(NSSLOWKEYDBHandle));
   916     if (handle == NULL) {
   917 	PORT_SetError (SEC_ERROR_NO_MEMORY);
   918 	return NULL;
   919     }
   921     handle->appname = NULL;
   922     handle->dbname = NULL;
   923     handle->global_salt = NULL;
   924     handle->updatedb = NULL;
   925     handle->db = dbHandle;
   926     handle->ref = 1;
   927     handle->lock = PZ_NewLock(nssILockKeyDB);
   929     return handle;
   930 }
   932 NSSLOWKEYDBHandle *
   933 nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix,
   934 				NSSLOWKEYDBNameFunc namecb, void *cbarg)
   935 {
   936     NSSLOWKEYDBHandle *handle = NULL;
   937     SECStatus rv;
   938     int openflags;
   939     char *dbname = NULL;
   942     handle = nsslowkey_NewHandle(NULL);
   944     openflags = readOnly ? NO_RDONLY : NO_RDWR;
   947     dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION);
   948     if ( dbname == NULL ) {
   949 	goto loser;
   950     }
   951     handle->appname = appName ? PORT_Strdup(appName) : NULL ;
   952     handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) : 
   953 			(prefix ? PORT_Strdup(prefix) : NULL);
   954     handle->readOnly = readOnly;
   958     handle->db = openOldDB(appName, prefix, dbname, openflags);
   959     if (handle->db) {
   960 	verifyVersion(handle);
   961 	if (handle->version == 255) {
   962 	    goto loser;
   963 	}
   964     }
   966     /* if first open fails, try to create a new DB */
   967     if ( handle->db == NULL ) {
   968 	if ( readOnly ) {
   969 	    goto loser;
   970 	}
   972 	rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg);
   973 	/* two processes started to initialize the database at the same time.
   974 	 * The multiprocess code blocked the second one, then had it retry to
   975 	 * see if it can just open the database normally */
   976 	if (rv == SECWouldBlock) {
   977 	    handle->db = openOldDB(appName,prefix,dbname, openflags);
   978 	    verifyVersion(handle);
   979 	    if (handle->db == NULL) {
   980 		goto loser;
   981 	    }
   982 	} else if (rv != SECSuccess) {
   983 	    goto loser;
   984 	}
   985     }
   987     handle->global_salt = GetKeyDBGlobalSalt(handle);
   988     if ( dbname )
   989         PORT_Free( dbname );
   990     return handle;
   992 loser:
   994     if ( dbname )
   995         PORT_Free( dbname );
   996     PORT_SetError(SEC_ERROR_BAD_DATABASE);
   997     nsslowkey_CloseKeyDB(handle);
   998     return NULL;
   999 }
  1001 /*
  1002  * Close the database
  1003  */
  1004 void
  1005 nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle)
  1007     if (handle != NULL) {
  1008 	if (handle->db != NULL) {
  1009 	    keydb_Close(handle);
  1011 	if (handle->updatedb) {
  1012 	    handle->updatedb->close(handle->updatedb);
  1014 	if (handle->dbname) PORT_Free(handle->dbname);
  1015 	if (handle->appname) PORT_Free(handle->appname);
  1016 	if (handle->global_salt) {
  1017 	    SECITEM_FreeItem(handle->global_salt,PR_TRUE);
  1019 	if (handle->lock != NULL) {
  1020 	    SKIP_AFTER_FORK(PZ_DestroyLock(handle->lock));
  1023 	PORT_Free(handle);
  1027 /* Get the key database version */
  1028 int
  1029 nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle)
  1031     PORT_Assert(handle != NULL);
  1033     return handle->version;
  1036 /*
  1037  * Delete a private key that was stored in the database
  1038  */
  1039 SECStatus
  1040 nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, const SECItem *pubkey)
  1042     DBT namekey;
  1043     int ret;
  1045     if (handle == NULL) {
  1046 	PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1047 	return(SECFailure);
  1050     /* set up db key and data */
  1051     namekey.data = pubkey->data;
  1052     namekey.size = pubkey->len;
  1054     /* delete it from the database */
  1055     ret = keydb_Del(handle, &namekey, 0);
  1056     if ( ret ) {
  1057 	PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1058 	return(SECFailure);
  1061     /* sync the database */
  1062     ret = keydb_Sync(handle, 0);
  1063     if ( ret ) {
  1064 	PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1065 	return(SECFailure);
  1068     return(SECSuccess);
  1071 /*
  1072  * Store a key in the database, indexed by its public key modulus.(value!)
  1073  */
  1074 SECStatus
  1075 nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle, 
  1076 			   NSSLOWKEYPrivateKey *privkey,
  1077 			   SECItem *pubKeyData,
  1078 			   char *nickname,
  1079 			   SDB *sdb)
  1081     return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 
  1082 	     nickname, sdb, PR_FALSE);
  1085 SECStatus
  1086 nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle, 
  1087 			   NSSLOWKEYPrivateKey *privkey,
  1088 			   SECItem *pubKeyData,
  1089 			   char *nickname,
  1090 			   SDB *sdb)
  1092     return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 
  1093 	     nickname, sdb, PR_TRUE);
  1096 /* see if the symetric CKA_ID already Exists.
  1097  */
  1098 PRBool
  1099 nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id)
  1101     DBT namekey;
  1102     DBT dummy;
  1103     int status;
  1105     namekey.data = (char *)id->data;
  1106     namekey.size = id->len;
  1107     status = keydb_Get(handle, &namekey, &dummy, 0);
  1108     if ( status ) {
  1109 	return PR_FALSE;
  1112     return PR_TRUE;
  1115 /* see if the public key for this cert is in the database filed
  1116  * by modulus
  1117  */
  1118 PRBool
  1119 nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert)
  1121     NSSLOWKEYPublicKey *pubkey = NULL;
  1122     DBT namekey;
  1123     DBT dummy;
  1124     int status;
  1126     /* get cert's public key */
  1127     pubkey = nsslowcert_ExtractPublicKey(cert);
  1128     if ( pubkey == NULL ) {
  1129 	return PR_FALSE;
  1132     /* TNH - make key from NSSLOWKEYPublicKey */
  1133     switch (pubkey->keyType) {
  1134       case NSSLOWKEYRSAKey:
  1135 	namekey.data = pubkey->u.rsa.modulus.data;
  1136 	namekey.size = pubkey->u.rsa.modulus.len;
  1137 	break;
  1138       case NSSLOWKEYDSAKey:
  1139 	namekey.data = pubkey->u.dsa.publicValue.data;
  1140 	namekey.size = pubkey->u.dsa.publicValue.len;
  1141 	break;
  1142       case NSSLOWKEYDHKey:
  1143 	namekey.data = pubkey->u.dh.publicValue.data;
  1144 	namekey.size = pubkey->u.dh.publicValue.len;
  1145 	break;
  1146 #ifndef NSS_DISABLE_ECC
  1147       case NSSLOWKEYECKey:
  1148 	namekey.data = pubkey->u.ec.publicValue.data;
  1149 	namekey.size = pubkey->u.ec.publicValue.len;
  1150 	break;
  1151 #endif /* NSS_DISABLE_ECC */
  1152       default:
  1153 	/* XXX We don't do Fortezza or DH yet. */
  1154 	return PR_FALSE;
  1157     if (handle->version != 3) {
  1158 	unsigned char buf[SHA1_LENGTH];
  1159 	SHA1_HashBuf(buf,namekey.data,namekey.size);
  1160 	/* NOTE: don't use pubkey after this! it's now thrashed */
  1161 	PORT_Memcpy(namekey.data,buf,sizeof(buf));
  1162 	namekey.size = sizeof(buf);
  1165     status = keydb_Get(handle, &namekey, &dummy, 0);
  1166     /* some databases have the key stored as a signed value */
  1167     if (status) {
  1168 	unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size+1);
  1169 	if (buf) {
  1170 	    PORT_Memcpy(&buf[1], namekey.data, namekey.size);
  1171 	    buf[0] = 0;
  1172 	    namekey.data = buf;
  1173 	    namekey.size ++;
  1174     	    status = keydb_Get(handle, &namekey, &dummy, 0);
  1175 	    PORT_Free(buf);
  1178     lg_nsslowkey_DestroyPublicKey(pubkey);
  1179     if ( status ) {
  1180 	return PR_FALSE;
  1183     return PR_TRUE;
  1186 typedef struct NSSLowPasswordDataParamStr {
  1187     SECItem salt;
  1188     SECItem iter;
  1189 } NSSLowPasswordDataParam;
  1191 static const SEC_ASN1Template NSSLOWPasswordParamTemplate[] =
  1193     {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLowPasswordDataParam) },
  1194     {SEC_ASN1_OCTET_STRING, offsetof(NSSLowPasswordDataParam, salt) },
  1195     {SEC_ASN1_INTEGER, offsetof(NSSLowPasswordDataParam, iter) },
  1196     {0}
  1197 };
  1198 struct LGEncryptedDataInfoStr {
  1199     SECAlgorithmID algorithm;
  1200     SECItem encryptedData;
  1201 };
  1202 typedef struct LGEncryptedDataInfoStr LGEncryptedDataInfo;
  1204 const SEC_ASN1Template lg_EncryptedDataInfoTemplate[] = {
  1205     { SEC_ASN1_SEQUENCE,
  1206         0, NULL, sizeof(LGEncryptedDataInfo) },
  1207     { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
  1208         offsetof(LGEncryptedDataInfo,algorithm),
  1209         SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
  1210     { SEC_ASN1_OCTET_STRING,
  1211         offsetof(LGEncryptedDataInfo,encryptedData) },
  1212     { 0 }
  1213 };
  1215 static SECItem *
  1216 nsslowkey_EncodePW(SECOidTag alg, const SECItem *salt, SECItem *data)
  1218     NSSLowPasswordDataParam param;
  1219     LGEncryptedDataInfo edi;
  1220     PLArenaPool *arena;
  1221     unsigned char one = 1;
  1222     SECItem *epw = NULL;
  1223     SECItem *encParam;
  1224     SECStatus rv;
  1226     param.salt = *salt;
  1227     param.iter.type = siBuffer;  /* encode as signed integer */
  1228     param.iter.data = &one;
  1229     param.iter.len = 1;
  1230     edi.encryptedData = *data;
  1232     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1233     if (arena == NULL) {
  1234 	return NULL;
  1237     encParam = SEC_ASN1EncodeItem(arena, NULL, &param,
  1238 				  NSSLOWPasswordParamTemplate);
  1239     if (encParam == NULL) {
  1240 	goto loser;
  1242     rv = SECOID_SetAlgorithmID(arena, &edi.algorithm, alg, encParam);
  1243     if (rv != SECSuccess) {
  1244 	goto loser;
  1246     epw = SEC_ASN1EncodeItem(NULL, NULL, &edi, lg_EncryptedDataInfoTemplate);
  1248 loser:
  1249     PORT_FreeArena(arena, PR_FALSE);
  1250     return epw;
  1253 static SECItem *
  1254 nsslowkey_DecodePW(const SECItem *derData, SECOidTag *alg, SECItem *salt)
  1256     NSSLowPasswordDataParam param;
  1257     LGEncryptedDataInfo edi;
  1258     PLArenaPool *arena;
  1259     SECItem *pwe = NULL;
  1260     SECStatus rv;
  1262     salt->data = NULL;
  1263     param.iter.type = siBuffer;  /* decode as signed integer */
  1265     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1266     if (arena == NULL) {
  1267 	return NULL;
  1270     rv = SEC_QuickDERDecodeItem(arena, &edi, lg_EncryptedDataInfoTemplate, 
  1271 						derData);
  1272     if (rv != SECSuccess) {
  1273 	goto loser;
  1275     *alg = SECOID_GetAlgorithmTag(&edi.algorithm);
  1276     rv = SEC_QuickDERDecodeItem(arena, &param, NSSLOWPasswordParamTemplate,
  1277 						&edi.algorithm.parameters);
  1278     if (rv != SECSuccess) {
  1279 	goto loser;
  1281     rv = SECITEM_CopyItem(NULL, salt, &param.salt);
  1282     if (rv != SECSuccess) {
  1283 	goto loser;
  1285     pwe = SECITEM_DupItem(&edi.encryptedData);
  1287 loser:
  1288     if (!pwe && salt->data) {
  1289 	PORT_Free(salt->data);
  1290 	salt->data = NULL;
  1292     PORT_FreeArena(arena, PR_FALSE);
  1293     return pwe;
  1297 /*
  1298  * check to see if the user has a password
  1299  */
  1300 static SECStatus
  1301 nsslowkey_GetPWCheckEntry(NSSLOWKEYDBHandle *handle,NSSLOWKEYPasswordEntry *entry)
  1303     DBT checkkey; /*, checkdata; */
  1304     NSSLOWKEYDBKey *dbkey = NULL;
  1305     SECItem   *global_salt = NULL; 
  1306     SECItem   *item = NULL; 
  1307     SECItem   entryData, oid;
  1308     SECItem   none = { siBuffer, NULL, 0 };
  1309     SECStatus rv = SECFailure;
  1310     SECOidTag algorithm;
  1312     if (handle == NULL) {
  1313 	/* PORT_SetError */
  1314 	return(SECFailure);
  1317     global_salt = GetKeyDBGlobalSalt(handle);
  1318     if (!global_salt) {
  1319 	global_salt = &none;
  1321     if (global_salt->len > sizeof(entry->data)) {
  1322 	/* PORT_SetError */
  1323 	goto loser;
  1326     PORT_Memcpy(entry->data, global_salt->data, global_salt->len);
  1327     entry->salt.data = entry->data;
  1328     entry->salt.len = global_salt->len;
  1329     entry->value.data = &entry->data[entry->salt.len];
  1331     checkkey.data = KEYDB_PW_CHECK_STRING;
  1332     checkkey.size = KEYDB_PW_CHECK_LEN;
  1333     dbkey = get_dbkey(handle, &checkkey);
  1334     if (dbkey == NULL) {
  1335 	/* handle 'FAKE' check here */
  1336 	goto loser;
  1339     oid.len = dbkey->derPK.data[0];
  1340     oid.data = &dbkey->derPK.data[1];
  1342     if (dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 +oid.len)) {
  1343 	goto loser;
  1345     algorithm = SECOID_FindOIDTag(&oid);
  1346     entryData.type = siBuffer;
  1347     entryData.len = dbkey->derPK.len - (oid.len+1);
  1348     entryData.data = &dbkey->derPK.data[oid.len+1];
  1350     item = nsslowkey_EncodePW(algorithm, &dbkey->salt, &entryData);
  1351     if (!item || (item->len + entry->salt.len) > sizeof(entry->data)) {
  1352 	goto loser;
  1354     PORT_Memcpy(entry->value.data, item->data, item->len);
  1355     entry->value.len = item->len;
  1356     rv = SECSuccess;
  1358 loser:
  1359     if (item) {
  1360 	SECITEM_FreeItem(item, PR_TRUE);
  1362     if (dbkey) {
  1363  	sec_destroy_dbkey(dbkey);
  1365     if (global_salt != &none) {
  1366 	SECITEM_FreeItem(global_salt,PR_TRUE);
  1368     return rv;
  1371 /*
  1372  * check to see if the user has a password
  1373  */
  1374 static SECStatus
  1375 nsslowkey_PutPWCheckEntry(NSSLOWKEYDBHandle *handle,NSSLOWKEYPasswordEntry *entry)
  1377     DBT checkkey;
  1378     NSSLOWKEYDBKey *dbkey = NULL;
  1379     SECItem   *item = NULL; 
  1380     SECItem   salt; 
  1381     SECOidTag algid;
  1382     SECStatus rv = SECFailure;
  1383     PLArenaPool *arena;
  1384     int ret;
  1386     if (handle == NULL) {
  1387 	/* PORT_SetError */
  1388 	return(SECFailure);
  1391     checkkey.data = KEYDB_PW_CHECK_STRING;
  1392     checkkey.size = KEYDB_PW_CHECK_LEN;
  1394     salt.data = NULL;
  1395     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1396     if (arena == NULL) {
  1397 	return SECFailure;
  1400     item = nsslowkey_DecodePW(&entry->value, &algid, &salt);
  1401     if (item == NULL) {
  1402 	goto loser;
  1405     dbkey = PORT_ArenaZNew(arena, NSSLOWKEYDBKey);
  1406     if (dbkey == NULL) {
  1407 	goto loser;
  1410     dbkey->arena = arena;
  1412     rv = SECITEM_CopyItem(arena, &dbkey->salt, &salt);
  1413     if (rv != SECSuccess) {
  1414 	goto loser;
  1417     rv = encodePWCheckEntry(arena, &dbkey->derPK, algid, item);
  1418     if (rv != SECSuccess) {
  1419 	goto loser;
  1422     rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE);
  1423     if (rv != SECSuccess) {
  1424 	goto loser;
  1427     if (handle->global_salt) {
  1428 	SECITEM_FreeItem(handle->global_salt, PR_TRUE);
  1429 	handle->global_salt = NULL;
  1431     rv = StoreKeyDBGlobalSalt(handle, &entry->salt);
  1432     if (rv != SECSuccess) {
  1433 	goto loser;
  1435     ret = keydb_Sync(handle, 0);
  1436     if ( ret ) {
  1437 	rv = SECFailure;
  1438 	goto loser;
  1440     handle->global_salt = GetKeyDBGlobalSalt(handle);
  1442 loser:
  1443     if (item) {
  1444 	SECITEM_FreeItem(item, PR_TRUE);
  1446     if (arena) {
  1447 	PORT_FreeArena(arena, PR_TRUE);
  1449     if (salt.data) {
  1450 	PORT_Free(salt.data);
  1452     return rv;
  1455 #ifdef EC_DEBUG
  1456 #define SEC_PRINT(str1, str2, num, sitem) \
  1457     printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
  1458             str1, str2, num, sitem->len); \
  1459     for (i = 0; i < sitem->len; i++) { \
  1460 	    printf("%02x:", sitem->data[i]); \
  1461     } \
  1462     printf("\n") 
  1463 #else
  1464 #define SEC_PRINT(a, b, c, d) 
  1465 #endif /* EC_DEBUG */
  1468 SECStatus 
  1469 seckey_encrypt_private_key( PLArenaPool *permarena, NSSLOWKEYPrivateKey *pk, 
  1470 			    SDB *sdbpw, SECItem *result)
  1472     NSSLOWKEYPrivateKeyInfo *pki = NULL;
  1473     SECStatus rv = SECFailure;
  1474     PLArenaPool *temparena = NULL;
  1475     SECItem *der_item = NULL;
  1476     SECItem *cipherText = NULL;
  1477     SECItem *dummy = NULL;
  1478 #ifndef NSS_DISABLE_ECC
  1479     SECItem *fordebug = NULL;
  1480     int savelen;
  1481 #endif
  1483     temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
  1484     if(temparena == NULL)
  1485 	goto loser;
  1487     /* allocate structures */
  1488     pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 
  1489 	sizeof(NSSLOWKEYPrivateKeyInfo));
  1490     der_item = (SECItem *)PORT_ArenaZAlloc(temparena, sizeof(SECItem));
  1491     if((pki == NULL) || (der_item == NULL))
  1492 	goto loser;
  1495     /* setup private key info */
  1496     dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version), 
  1497 	NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
  1498     if(dummy == NULL)
  1499 	goto loser;
  1501     /* Encode the key, and set the algorithm (with params) */
  1502     switch (pk->keyType) {
  1503       case NSSLOWKEYRSAKey:
  1504         lg_prepare_low_rsa_priv_key_for_asn1(pk);
  1505 	dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 
  1506 				   lg_nsslowkey_RSAPrivateKeyTemplate);
  1507 	if (dummy == NULL) {
  1508 	    rv = SECFailure;
  1509 	    goto loser;
  1512 	rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 
  1513 				   SEC_OID_PKCS1_RSA_ENCRYPTION, 0);
  1514 	if (rv == SECFailure) {
  1515 	    goto loser;
  1518 	break;
  1519       case NSSLOWKEYDSAKey:
  1520         lg_prepare_low_dsa_priv_key_for_asn1(pk);
  1521 	dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
  1522 				   lg_nsslowkey_DSAPrivateKeyTemplate);
  1523 	if (dummy == NULL) {
  1524 	    rv = SECFailure;
  1525 	    goto loser;
  1528         lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
  1529 	dummy = SEC_ASN1EncodeItem(temparena, NULL, &pk->u.dsa.params,
  1530 				   lg_nsslowkey_PQGParamsTemplate);
  1531 	if (dummy == NULL) {
  1532 	    rv = SECFailure;
  1533 	    goto loser;
  1536 	rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
  1537 				   SEC_OID_ANSIX9_DSA_SIGNATURE, dummy);
  1538 	if (rv == SECFailure) {
  1539 	    goto loser;
  1542 	break;
  1543       case NSSLOWKEYDHKey:
  1544         lg_prepare_low_dh_priv_key_for_asn1(pk);
  1545 	dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
  1546 				   lg_nsslowkey_DHPrivateKeyTemplate);
  1547 	if (dummy == NULL) {
  1548 	    rv = SECFailure;
  1549 	    goto loser;
  1552 	rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
  1553 				   SEC_OID_X942_DIFFIE_HELMAN_KEY, dummy);
  1554 	if (rv == SECFailure) {
  1555 	    goto loser;
  1557 	break;
  1558 #ifndef NSS_DISABLE_ECC
  1559       case NSSLOWKEYECKey:
  1560 	lg_prepare_low_ec_priv_key_for_asn1(pk);
  1561 	/* Public value is encoded as a bit string so adjust length
  1562 	 * to be in bits before ASN encoding and readjust 
  1563 	 * immediately after.
  1565 	 * Since the SECG specification recommends not including the
  1566 	 * parameters as part of ECPrivateKey, we zero out the curveOID
  1567 	 * length before encoding and restore it later.
  1568 	 */
  1569 	pk->u.ec.publicValue.len <<= 3;
  1570 	savelen = pk->u.ec.ecParams.curveOID.len;
  1571 	pk->u.ec.ecParams.curveOID.len = 0;
  1572 	dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
  1573 				   lg_nsslowkey_ECPrivateKeyTemplate);
  1574 	pk->u.ec.ecParams.curveOID.len = savelen;
  1575 	pk->u.ec.publicValue.len >>= 3;
  1577 	if (dummy == NULL) {
  1578 	    rv = SECFailure;
  1579 	    goto loser;
  1582 	dummy = &pk->u.ec.ecParams.DEREncoding;
  1584 	/* At this point dummy should contain the encoded params */
  1585 	rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
  1586 				   SEC_OID_ANSIX962_EC_PUBLIC_KEY, dummy);
  1588 	if (rv == SECFailure) {
  1589 	    goto loser;
  1592 	fordebug = &(pki->privateKey);
  1593 	SEC_PRINT("seckey_encrypt_private_key()", "PrivateKey", 
  1594 		  pk->keyType, fordebug);
  1596 	break;
  1597 #endif /* NSS_DISABLE_ECC */
  1598       default:
  1599 	/* We don't support DH or Fortezza private keys yet */
  1600 	PORT_Assert(PR_FALSE);
  1601 	break;
  1604     /* setup encrypted private key info */
  1605     dummy = SEC_ASN1EncodeItem(temparena, der_item, pki, 
  1606 	lg_nsslowkey_PrivateKeyInfoTemplate);
  1608     SEC_PRINT("seckey_encrypt_private_key()", "PrivateKeyInfo", 
  1609 	      pk->keyType, der_item);
  1611     if(dummy == NULL) {
  1612 	rv = SECFailure;
  1613 	goto loser;
  1616     rv = lg_util_encrypt(temparena, sdbpw, dummy, &cipherText);
  1617     if (rv != SECSuccess) {
  1618 	goto loser;
  1621     rv = SECITEM_CopyItem ( permarena, result, cipherText);
  1623 loser:
  1625     if(temparena != NULL)
  1626 	PORT_FreeArena(temparena, PR_TRUE);
  1628     return rv;
  1631 static SECStatus 
  1632 seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SDB *sdbpw,
  1633 		       NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update)
  1635     NSSLOWKEYDBKey *dbkey = NULL;
  1636     PLArenaPool *arena = NULL;
  1637     SECStatus rv = SECFailure;
  1639     if((keydb == NULL) || (index == NULL) || (sdbpw == NULL) ||
  1640 	(pk == NULL))
  1641 	return SECFailure;
  1643     arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
  1644     if(arena == NULL)
  1645 	return SECFailure;
  1647     dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
  1648     if(dbkey == NULL)
  1649 	goto loser;
  1650     dbkey->arena = arena;
  1651     dbkey->nickname = nickname;
  1653     rv = seckey_encrypt_private_key(arena, pk, sdbpw, &dbkey->derPK);
  1654     if(rv != SECSuccess)
  1655 	goto loser;
  1657     rv = put_dbkey(keydb, index, dbkey, update);
  1659     /* let success fall through */
  1660 loser:
  1661     if(arena != NULL)
  1662 	PORT_FreeArena(arena, PR_TRUE);
  1664     return rv;
  1667 /*
  1668  * Store a key in the database, indexed by its public key modulus.
  1669  * Note that the nickname is optional.  It was only used by keyutil.
  1670  */
  1671 SECStatus
  1672 nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, 
  1673 			      NSSLOWKEYPrivateKey *privkey,
  1674 			      SECItem *pubKeyData,
  1675 			      char *nickname,
  1676 			      SDB *sdbpw,
  1677                               PRBool update)
  1679     DBT namekey;
  1680     SECStatus rv;
  1682     if (handle == NULL) {
  1683 	PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1684 	return(SECFailure);
  1687     /* set up db key and data */
  1688     namekey.data = pubKeyData->data;
  1689     namekey.size = pubKeyData->len;
  1691     /* encrypt the private key */
  1692     rv = seckey_put_private_key(handle, &namekey, sdbpw, privkey, nickname,
  1693 				update);
  1695     return(rv);
  1698 static NSSLOWKEYPrivateKey *
  1699 seckey_decrypt_private_key(SECItem*epki,
  1700 			   SDB *sdbpw)
  1702     NSSLOWKEYPrivateKey *pk = NULL;
  1703     NSSLOWKEYPrivateKeyInfo *pki = NULL;
  1704     SECStatus rv = SECFailure;
  1705     PLArenaPool *temparena = NULL, *permarena = NULL;
  1706     SECItem *dest = NULL;
  1707 #ifndef NSS_DISABLE_ECC
  1708     SECItem *fordebug = NULL;
  1709 #endif
  1711     if((epki == NULL) || (sdbpw == NULL))
  1712 	goto loser;
  1714     temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
  1715     permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
  1716     if((temparena == NULL) || (permarena == NULL))
  1717 	goto loser;
  1719     /* allocate temporary items */
  1720     pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 
  1721 	sizeof(NSSLOWKEYPrivateKeyInfo));
  1723     /* allocate permanent arena items */
  1724     pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(permarena,
  1725 	sizeof(NSSLOWKEYPrivateKey));
  1727     if((pk == NULL) || (pki == NULL))
  1728 	goto loser;
  1730     pk->arena = permarena;
  1732     rv = lg_util_decrypt(sdbpw, epki, &dest);
  1733     if (rv != SECSuccess) {
  1734 	goto loser;
  1737     if(dest != NULL)
  1739         SECItem newPrivateKey;
  1740         SECItem newAlgParms;
  1742         SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1,
  1743 		  dest);
  1745 	rv = SEC_QuickDERDecodeItem(temparena, pki, 
  1746 	    lg_nsslowkey_PrivateKeyInfoTemplate, dest);
  1747 	if(rv == SECSuccess)
  1749 	    switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
  1750 	      case SEC_OID_X500_RSA_ENCRYPTION:
  1751 	      case SEC_OID_PKCS1_RSA_ENCRYPTION:
  1752 		pk->keyType = NSSLOWKEYRSAKey;
  1753 		lg_prepare_low_rsa_priv_key_for_asn1(pk);
  1754                 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
  1755                     &pki->privateKey) ) break;
  1756 		rv = SEC_QuickDERDecodeItem(permarena, pk,
  1757 					lg_nsslowkey_RSAPrivateKeyTemplate,
  1758 					&newPrivateKey);
  1759 		if (rv == SECSuccess) {
  1760 		    break;
  1762 		/* Try decoding with the alternative template, but only allow
  1763 		 * a zero-length modulus for a secret key object.
  1764 		 * See bug 715073.
  1765 		 */
  1766 		rv = SEC_QuickDERDecodeItem(permarena, pk,
  1767 					lg_nsslowkey_RSAPrivateKeyTemplate2,
  1768 					&newPrivateKey);
  1769 		/* A publicExponent of 0 is the defining property of a secret
  1770 		 * key disguised as an RSA key. When decoding with the
  1771 		 * alternative template, only accept a secret key with an
  1772 		 * improperly encoded modulus and a publicExponent of 0.
  1773 		 */
  1774 		if (rv == SECSuccess) {
  1775 		    if (pk->u.rsa.modulus.len == 2 &&
  1776 			pk->u.rsa.modulus.data[0] == SEC_ASN1_INTEGER &&
  1777 			pk->u.rsa.modulus.data[1] == 0 &&
  1778 			pk->u.rsa.publicExponent.len == 1 &&
  1779 			pk->u.rsa.publicExponent.data[0] == 0) {
  1780 			/* Fix the zero-length integer by setting it to 0. */
  1781 			pk->u.rsa.modulus.data = pk->u.rsa.publicExponent.data;
  1782 			pk->u.rsa.modulus.len = pk->u.rsa.publicExponent.len;
  1783 		    } else {
  1784 			PORT_SetError(SEC_ERROR_BAD_DER);
  1785 			rv = SECFailure;
  1788 		break;
  1789 	      case SEC_OID_ANSIX9_DSA_SIGNATURE:
  1790 		pk->keyType = NSSLOWKEYDSAKey;
  1791 		lg_prepare_low_dsa_priv_key_for_asn1(pk);
  1792                 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
  1793                     &pki->privateKey) ) break;
  1794 		rv = SEC_QuickDERDecodeItem(permarena, pk,
  1795 					lg_nsslowkey_DSAPrivateKeyTemplate,
  1796 					&newPrivateKey);
  1797 		if (rv != SECSuccess)
  1798 		    goto loser;
  1799 		lg_prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
  1800                 if (SECSuccess != SECITEM_CopyItem(permarena, &newAlgParms,
  1801                     &pki->algorithm.parameters) ) break;
  1802 		rv = SEC_QuickDERDecodeItem(permarena, &pk->u.dsa.params,
  1803 					lg_nsslowkey_PQGParamsTemplate,
  1804 					&newAlgParms);
  1805 		break;
  1806 	      case SEC_OID_X942_DIFFIE_HELMAN_KEY:
  1807 		pk->keyType = NSSLOWKEYDHKey;
  1808 		lg_prepare_low_dh_priv_key_for_asn1(pk);
  1809                 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
  1810                     &pki->privateKey) ) break;
  1811 		rv = SEC_QuickDERDecodeItem(permarena, pk,
  1812 					lg_nsslowkey_DHPrivateKeyTemplate,
  1813 					&newPrivateKey);
  1814 		break;
  1815 #ifndef NSS_DISABLE_ECC
  1816 	      case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
  1817 		pk->keyType = NSSLOWKEYECKey;
  1818 		lg_prepare_low_ec_priv_key_for_asn1(pk);
  1820 		fordebug = &pki->privateKey;
  1821 		SEC_PRINT("seckey_decrypt_private_key()", "PrivateKey", 
  1822 			  pk->keyType, fordebug);
  1823                 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
  1824                     &pki->privateKey) ) break;
  1825 		rv = SEC_QuickDERDecodeItem(permarena, pk,
  1826 					lg_nsslowkey_ECPrivateKeyTemplate,
  1827 					&newPrivateKey);
  1828 		if (rv != SECSuccess)
  1829 		    goto loser;
  1831 		lg_prepare_low_ecparams_for_asn1(&pk->u.ec.ecParams);
  1833 		rv = SECITEM_CopyItem(permarena, 
  1834 		    &pk->u.ec.ecParams.DEREncoding, 
  1835 		    &pki->algorithm.parameters);
  1837 		if (rv != SECSuccess)
  1838 		    goto loser;
  1840 		/* Fill out the rest of EC params */
  1841 		rv = LGEC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding,
  1842 				   &pk->u.ec.ecParams);
  1844 		if (rv != SECSuccess)
  1845 		    goto loser;
  1847 		if (pk->u.ec.publicValue.len != 0) {
  1848 		    pk->u.ec.publicValue.len >>= 3;
  1851 		break;
  1852 #endif /* NSS_DISABLE_ECC */
  1853 	      default:
  1854 		rv = SECFailure;
  1855 		break;
  1858 	else if(PORT_GetError() == SEC_ERROR_BAD_DER)
  1860 	    PORT_SetError(SEC_ERROR_BAD_PASSWORD);
  1861 	    goto loser;
  1865     /* let success fall through */
  1866 loser:
  1867     if(temparena != NULL)
  1868 	PORT_FreeArena(temparena, PR_TRUE);
  1869     if(dest != NULL)
  1870 	SECITEM_ZfreeItem(dest, PR_TRUE);
  1872     if(rv != SECSuccess)
  1874 	if(permarena != NULL)
  1875 	    PORT_FreeArena(permarena, PR_TRUE);
  1876 	pk = NULL;
  1879     return pk;
  1882 static NSSLOWKEYPrivateKey *
  1883 seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SDB *sdbpw)
  1885     if( ( dbkey == NULL ) || ( sdbpw == NULL ) ) {
  1886 	return NULL;
  1889     return seckey_decrypt_private_key(&(dbkey->derPK), sdbpw);
  1892 static NSSLOWKEYPrivateKey *
  1893 seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname,
  1894 		       SDB *sdbpw)
  1896     NSSLOWKEYDBKey *dbkey = NULL;
  1897     NSSLOWKEYPrivateKey *pk = NULL;
  1899     if( ( keydb == NULL ) || ( index == NULL ) || ( sdbpw == NULL ) ) {
  1900 	return NULL;
  1903     dbkey = get_dbkey(keydb, index);
  1904     if(dbkey == NULL) {
  1905 	goto loser;
  1908     if ( nickname ) {
  1909 	if ( dbkey->nickname && ( dbkey->nickname[0] != 0 ) ) {
  1910 	    *nickname = PORT_Strdup(dbkey->nickname);
  1911 	} else {
  1912 	    *nickname = NULL;
  1916     pk = seckey_decode_encrypted_private_key(dbkey, sdbpw);
  1918     /* let success fall through */
  1919 loser:
  1921     if ( dbkey != NULL ) {
  1922 	sec_destroy_dbkey(dbkey);
  1925     return pk;
  1928 /*
  1929  * Find a key in the database, indexed by its public key modulus
  1930  * This is used to find keys that have been stored before their
  1931  * certificate arrives.  Once the certificate arrives the key
  1932  * is looked up by the public modulus in the certificate, and the
  1933  * re-stored by its nickname.
  1934  */
  1935 NSSLOWKEYPrivateKey *
  1936 nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus,
  1937 			  				 SDB *sdbpw)
  1939     DBT namekey;
  1940     NSSLOWKEYPrivateKey *pk = NULL;
  1942     if (handle == NULL) {
  1943 	PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1944 	return NULL;
  1947     /* set up db key */
  1948     namekey.data = modulus->data;
  1949     namekey.size = modulus->len;
  1951     pk = seckey_get_private_key(handle, &namekey, NULL, sdbpw);
  1953     /* no need to free dbkey, since its on the stack, and the data it
  1954      * points to is owned by the database
  1955      */
  1956     return(pk);
  1959 char *
  1960 nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, 
  1961 					SECItem *modulus, SDB *sdbpw)
  1963     DBT namekey;
  1964     NSSLOWKEYPrivateKey *pk = NULL;
  1965     char *nickname = NULL;
  1967     if (handle == NULL) {
  1968 	PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1969 	return NULL;
  1972     /* set up db key */
  1973     namekey.data = modulus->data;
  1974     namekey.size = modulus->len;
  1976     pk = seckey_get_private_key(handle, &namekey, &nickname, sdbpw);
  1977     if (pk) {
  1978 	lg_nsslowkey_DestroyPrivateKey(pk);
  1981     /* no need to free dbkey, since its on the stack, and the data it
  1982      * points to is owned by the database
  1983      */
  1984     return(nickname);
  1986 /* ===== ENCODING ROUTINES ===== */
  1988 static SECStatus
  1989 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
  1990 		   SECItem *encCheck)
  1992     SECOidData *oidData;
  1993     SECStatus rv;
  1995     oidData = SECOID_FindOIDByTag(alg);
  1996     if ( oidData == NULL ) {
  1997 	rv = SECFailure;
  1998 	goto loser;
  2001     entry->len = 1 + oidData->oid.len + encCheck->len;
  2002     if ( arena ) {
  2003 	entry->data = (unsigned char *)PORT_ArenaAlloc(arena, entry->len);
  2004     } else {
  2005 	entry->data = (unsigned char *)PORT_Alloc(entry->len);
  2008     if ( entry->data == NULL ) {
  2009 	goto loser;
  2012     /* first length of oid */
  2013     entry->data[0] = (unsigned char)oidData->oid.len;
  2014     /* next oid itself */
  2015     PORT_Memcpy(&entry->data[1], oidData->oid.data, oidData->oid.len);
  2016     /* finally the encrypted check string */
  2017     PORT_Memcpy(&entry->data[1+oidData->oid.len], encCheck->data,
  2018 		encCheck->len);
  2020     return(SECSuccess);
  2022 loser:
  2023     return(SECFailure);
  2027 #define MAX_DB_SIZE 0xffff 
  2028 /*
  2029  * Clear out all the keys in the existing database
  2030  */
  2031 static SECStatus
  2032 nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle)
  2034     SECStatus rv;
  2035     int ret;
  2036     int errors = 0;
  2038     if ( handle->db == NULL ) {
  2039 	return(SECSuccess);
  2042     if (handle->readOnly) {
  2043 	/* set an error code */
  2044 	return SECFailure;
  2047     if (handle->appname == NULL && handle->dbname == NULL) {
  2048 	return SECFailure;
  2051     keydb_Close(handle);
  2052     if (handle->appname) {
  2053 	handle->db= 
  2054 	    rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL);
  2055     } else {
  2056 	handle->db = dbopen( handle->dbname, NO_CREATE, 0600, DB_HASH, 0 );
  2058     if (handle->db == NULL) {
  2059 	/* set an error code */
  2060 	return SECFailure;
  2063     rv = makeGlobalVersion(handle);
  2064     if ( rv != SECSuccess ) {
  2065 	errors++;
  2066 	goto done;
  2069     if (handle->global_salt) {
  2070 	rv = StoreKeyDBGlobalSalt(handle, handle->global_salt);
  2071     } else {
  2072 	rv = makeGlobalSalt(handle);
  2073 	if ( rv == SECSuccess ) {
  2074 	    handle->global_salt = GetKeyDBGlobalSalt(handle);
  2077     if ( rv != SECSuccess ) {
  2078 	errors++;
  2081 done:
  2082     /* sync the database */
  2083     ret = keydb_Sync(handle, 0);
  2084     db_InitComplete(handle->db);
  2086     return (errors == 0 ? SECSuccess : SECFailure);
  2089 static int
  2090 keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
  2092     PRStatus prstat;
  2093     int ret;
  2094     PRLock *kdbLock = kdb->lock;
  2095     DB *db = kdb->db;
  2097     PORT_Assert(kdbLock != NULL);
  2098     PZ_Lock(kdbLock);
  2100     ret = (* db->get)(db, key, data, flags);
  2102     prstat = PZ_Unlock(kdbLock);
  2104     return(ret);
  2107 static int
  2108 keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
  2110     PRStatus prstat;
  2111     int ret = 0;
  2112     PRLock *kdbLock = kdb->lock;
  2113     DB *db = kdb->db;
  2115     PORT_Assert(kdbLock != NULL);
  2116     PZ_Lock(kdbLock);
  2118     ret = (* db->put)(db, key, data, flags);
  2120     prstat = PZ_Unlock(kdbLock);
  2122     return(ret);
  2125 static int
  2126 keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags)
  2128     PRStatus prstat;
  2129     int ret;
  2130     PRLock *kdbLock = kdb->lock;
  2131     DB *db = kdb->db;
  2133     PORT_Assert(kdbLock != NULL);
  2134     PZ_Lock(kdbLock);
  2136     ret = (* db->sync)(db, flags);
  2138     prstat = PZ_Unlock(kdbLock);
  2140     return(ret);
  2143 static int
  2144 keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags)
  2146     PRStatus prstat;
  2147     int ret;
  2148     PRLock *kdbLock = kdb->lock;
  2149     DB *db = kdb->db;
  2151     PORT_Assert(kdbLock != NULL);
  2152     PZ_Lock(kdbLock);
  2154     ret = (* db->del)(db, key, flags);
  2156     prstat = PZ_Unlock(kdbLock);
  2158     return(ret);
  2161 static int
  2162 keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
  2164     PRStatus prstat;
  2165     int ret;
  2166     PRLock *kdbLock = kdb->lock;
  2167     DB *db = kdb->db;
  2169     PORT_Assert(kdbLock != NULL);
  2170     PZ_Lock(kdbLock);
  2172     ret = (* db->seq)(db, key, data, flags);
  2174     prstat = PZ_Unlock(kdbLock);
  2176     return(ret);
  2179 static void
  2180 keydb_Close(NSSLOWKEYDBHandle *kdb)
  2182     PRStatus prstat;
  2183     PRLock *kdbLock = kdb->lock;
  2184     DB *db = kdb->db;
  2186     PORT_Assert(kdbLock != NULL);
  2187     SKIP_AFTER_FORK(PZ_Lock(kdbLock));
  2189     (* db->close)(db);
  2191     SKIP_AFTER_FORK(prstat = PZ_Unlock(kdbLock));
  2193     return;
  2196 /*
  2197  * SDB Entry Points for the Key DB 
  2198  */
  2200 CK_RV
  2201 lg_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2)
  2203     NSSLOWKEYDBHandle *keydb;
  2204     NSSLOWKEYPasswordEntry entry;
  2205     SECStatus rv;
  2207     keydb = lg_getKeyDB(sdb);
  2208     if (keydb == NULL) {
  2209         return CKR_TOKEN_WRITE_PROTECTED;
  2211     if (PORT_Strcmp(id,"password") != 0) {
  2212 	/* shouldn't happen */
  2213 	return CKR_GENERAL_ERROR; /* no extra data stored */
  2215     rv = nsslowkey_GetPWCheckEntry(keydb, &entry);
  2216     if (rv != SECSuccess) {
  2217         return CKR_GENERAL_ERROR;
  2219     item1->len = entry.salt.len;
  2220     PORT_Memcpy(item1->data, entry.salt.data, item1->len);
  2221     item2->len = entry.value.len;
  2222     PORT_Memcpy(item2->data, entry.value.data, item2->len);
  2223     return CKR_OK;
  2226 CK_RV
  2227 lg_PutMetaData(SDB *sdb, const char *id, 
  2228 	       const SECItem *item1, const SECItem *item2)
  2230     NSSLOWKEYDBHandle *keydb;
  2231     NSSLOWKEYPasswordEntry entry;
  2232     SECStatus rv;
  2234     keydb = lg_getKeyDB(sdb);
  2235     if (keydb == NULL) {
  2236         return CKR_TOKEN_WRITE_PROTECTED;
  2238     if (PORT_Strcmp(id,"password") != 0) {
  2239 	/* shouldn't happen */
  2240 	return CKR_GENERAL_ERROR; /* no extra data stored */
  2242     entry.salt = *item1;
  2243     entry.value = *item2;
  2244     rv = nsslowkey_PutPWCheckEntry(keydb, &entry);
  2245     if (rv != SECSuccess) {
  2246         return CKR_GENERAL_ERROR;
  2248     return CKR_OK;
  2251 CK_RV
  2252 lg_Reset(SDB *sdb)
  2254     NSSLOWKEYDBHandle *keydb;
  2255     SECStatus rv;
  2257     keydb = lg_getKeyDB(sdb);
  2258     if (keydb == NULL) {
  2259         return CKR_TOKEN_WRITE_PROTECTED;
  2261     rv = nsslowkey_ResetKeyDB(keydb);
  2262     if (rv != SECSuccess) {
  2263         return CKR_GENERAL_ERROR;
  2265     return CKR_OK;

mercurial