Back to index

lightning-sunbird  0.9+nobinonly
keydb.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /* $Id: keydb.c,v 1.40.2.7 2007/11/16 02:05:58 julien.pierre.boogz%sun.com Exp $ */
00038 
00039 #include "lowkeyi.h"
00040 #include "seccomon.h"
00041 #include "sechash.h"
00042 #include "secder.h"
00043 #include "secasn1.h"
00044 #include "secoid.h"
00045 #include "blapi.h"
00046 #include "secitem.h"
00047 #include "pcert.h"
00048 #include "mcom_db.h"
00049 #include "lowpbe.h"
00050 #include "secerr.h"
00051 #include "cdbhdl.h"
00052 
00053 #include "keydbi.h"
00054 #include "softoken.h"
00055 
00056 
00057 /*
00058  * Record keys for keydb
00059  */
00060 #define SALT_STRING "global-salt"
00061 #define VERSION_STRING "Version"
00062 #define KEYDB_PW_CHECK_STRING      "password-check"
00063 #define KEYDB_PW_CHECK_LEN  14
00064 #define KEYDB_FAKE_PW_CHECK_STRING "fake-password-check"
00065 #define KEYDB_FAKE_PW_CHECK_LEN    19
00066 
00067 /* Size of the global salt for key database */
00068 #define SALT_LENGTH     16
00069 
00070 const SEC_ASN1Template nsslowkey_AttributeTemplate[] = {
00071     { SEC_ASN1_SEQUENCE, 
00072        0, NULL, sizeof(NSSLOWKEYAttribute) },
00073     { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) },
00074     { SEC_ASN1_SET_OF, offsetof(NSSLOWKEYAttribute, attrValue), 
00075        SEC_AnyTemplate },
00076     { 0 }
00077 };
00078 
00079 const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = {
00080     { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate },
00081 };
00082 /* ASN1 Templates for new decoder/encoder */
00083 const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = {
00084     { SEC_ASN1_SEQUENCE,
00085        0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) },
00086     { SEC_ASN1_INTEGER,
00087        offsetof(NSSLOWKEYPrivateKeyInfo,version) },
00088     { SEC_ASN1_INLINE,
00089        offsetof(NSSLOWKEYPrivateKeyInfo,algorithm),
00090        SECOID_AlgorithmIDTemplate },
00091     { SEC_ASN1_OCTET_STRING,
00092        offsetof(NSSLOWKEYPrivateKeyInfo,privateKey) },
00093     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
00094        offsetof(NSSLOWKEYPrivateKeyInfo, attributes),
00095        nsslowkey_SetOfAttributeTemplate },
00096     { 0 }
00097 };
00098 
00099 const SEC_ASN1Template nsslowkey_PointerToPrivateKeyInfoTemplate[] = {
00100     { SEC_ASN1_POINTER, 0, nsslowkey_PrivateKeyInfoTemplate }
00101 };
00102 
00103 const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[] = {
00104     { SEC_ASN1_SEQUENCE,
00105        0, NULL, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo) },
00106     { SEC_ASN1_INLINE,
00107        offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,algorithm),
00108        SECOID_AlgorithmIDTemplate },
00109     { SEC_ASN1_OCTET_STRING,
00110        offsetof(NSSLOWKEYEncryptedPrivateKeyInfo,encryptedData) },
00111     { 0 }
00112 };
00113 
00114 const SEC_ASN1Template nsslowkey_PointerToEncryptedPrivateKeyInfoTemplate[] = {
00115        { SEC_ASN1_POINTER, 0, nsslowkey_EncryptedPrivateKeyInfoTemplate }
00116 };
00117 
00118 
00119 /* ====== Default key databse encryption algorithm ====== */
00120 
00121 static SECOidTag defaultKeyDBAlg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
00122 
00123 /*
00124  * Default algorithm for encrypting data in the key database
00125  */
00126 SECOidTag
00127 nsslowkey_GetDefaultKeyDBAlg(void)
00128 {
00129     return(defaultKeyDBAlg);
00130 }
00131 
00132 void
00133 nsslowkey_SetDefaultKeyDBAlg(SECOidTag alg)
00134 {
00135     defaultKeyDBAlg = alg;
00136 
00137     return;
00138 }
00139 
00140 static void
00141 sec_destroy_dbkey(NSSLOWKEYDBKey *dbkey)
00142 {
00143     if ( dbkey && dbkey->arena ) {
00144        PORT_FreeArena(dbkey->arena, PR_FALSE);
00145     }
00146 }
00147 
00148 static void
00149 free_dbt(DBT *dbt)
00150 {
00151     if ( dbt ) {
00152        PORT_Free(dbt->data);
00153        PORT_Free(dbt);
00154     }
00155     
00156     return;
00157 }
00158 
00159 static int keydb_Get(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 
00160                    unsigned int flags);
00161 static int keydb_Put(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 
00162                    unsigned int flags);
00163 static int keydb_Sync(NSSLOWKEYDBHandle *db, unsigned int flags);
00164 static int keydb_Del(NSSLOWKEYDBHandle *db, DBT *key, unsigned int flags);
00165 static int keydb_Seq(NSSLOWKEYDBHandle *db, DBT *key, DBT *data, 
00166                    unsigned int flags);
00167 static void keydb_Close(NSSLOWKEYDBHandle *db);
00168 
00169 static void
00170 keydb_InitLocks(NSSLOWKEYDBHandle *handle) 
00171 {
00172     if (handle->lock == NULL) {
00173        handle->lock = PZ_NewLock(nssILockKeyDB);
00174     }
00175 
00176     return;
00177 }
00178 
00179 static void
00180 keydb_DestroyLocks(NSSLOWKEYDBHandle *handle)
00181 {
00182     if (handle->lock != NULL) {
00183        PZ_DestroyLock(handle->lock);
00184        handle->lock = NULL;
00185     }
00186 
00187     return;
00188 }
00189 
00190 /*
00191  * format of key database entries for version 3 of database:
00192  *     byte offset   field
00193  *     -----------   -----
00194  *     0             version
00195  *     1             salt-len
00196  *     2             nn-len
00197  *     3..           salt-data
00198  *     ...           nickname
00199  *     ...           encrypted-key-data
00200  */
00201 static DBT *
00202 encode_dbkey(NSSLOWKEYDBKey *dbkey,unsigned char version)
00203 {
00204     DBT *bufitem = NULL;
00205     unsigned char *buf;
00206     int nnlen;
00207     char *nn;
00208     
00209     bufitem = (DBT *)PORT_ZAlloc(sizeof(DBT));
00210     if ( bufitem == NULL ) {
00211        goto loser;
00212     }
00213     
00214     if ( dbkey->nickname ) {
00215        nn = dbkey->nickname;
00216        nnlen = PORT_Strlen(nn) + 1;
00217     } else {
00218        nn = "";
00219        nnlen = 1;
00220     }
00221     
00222     /* compute the length of the record */
00223     /* 1 + 1 + 1 == version number header + salt length + nn len */
00224     bufitem->size = dbkey->salt.len + nnlen + dbkey->derPK.len + 1 + 1 + 1;
00225     
00226     bufitem->data = (void *)PORT_ZAlloc(bufitem->size);
00227     if ( bufitem->data == NULL ) {
00228        goto loser;
00229     }
00230 
00231     buf = (unsigned char *)bufitem->data;
00232     
00233     /* set version number */
00234     buf[0] = version;
00235 
00236     /* set length of salt */
00237     PORT_Assert(dbkey->salt.len < 256);
00238     buf[1] = dbkey->salt.len;
00239 
00240     /* set length of nickname */
00241     PORT_Assert(nnlen < 256);
00242     buf[2] = nnlen;
00243 
00244     /* copy salt */
00245     PORT_Memcpy(&buf[3], dbkey->salt.data, dbkey->salt.len);
00246 
00247     /* copy nickname */
00248     PORT_Memcpy(&buf[3 + dbkey->salt.len], nn, nnlen);
00249 
00250     /* copy encrypted key */
00251     PORT_Memcpy(&buf[3 + dbkey->salt.len + nnlen], dbkey->derPK.data,
00252              dbkey->derPK.len);
00253     
00254     return(bufitem);
00255     
00256 loser:
00257     if ( bufitem ) {
00258        free_dbt(bufitem);
00259     }
00260     
00261     return(NULL);
00262 }
00263 
00264 static NSSLOWKEYDBKey *
00265 decode_dbkey(DBT *bufitem, int expectedVersion)
00266 {
00267     NSSLOWKEYDBKey *dbkey;
00268     PLArenaPool *arena = NULL;
00269     unsigned char *buf;
00270     int version;
00271     int keyoff;
00272     int nnlen;
00273     int saltoff;
00274     
00275     buf = (unsigned char *)bufitem->data;
00276 
00277     version = buf[0];
00278     
00279     if ( version != expectedVersion ) {
00280        goto loser;
00281     }
00282     
00283     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00284     if ( arena == NULL ) {
00285        goto loser;
00286     }
00287     
00288     dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
00289     if ( dbkey == NULL ) {
00290        goto loser;
00291     }
00292 
00293     dbkey->arena = arena;
00294     dbkey->salt.data = NULL;
00295     dbkey->derPK.data = NULL;
00296     
00297     dbkey->salt.len = buf[1];
00298     dbkey->salt.data = (unsigned char *)PORT_ArenaZAlloc(arena, dbkey->salt.len);
00299     if ( dbkey->salt.data == NULL ) {
00300        goto loser;
00301     }
00302 
00303     saltoff = 2;
00304     keyoff = 2 + dbkey->salt.len;
00305     
00306     if ( expectedVersion >= 3 ) {
00307        nnlen = buf[2];
00308        if ( nnlen ) {
00309            dbkey->nickname = (char *)PORT_ArenaZAlloc(arena, nnlen + 1);
00310            if ( dbkey->nickname ) {
00311               PORT_Memcpy(dbkey->nickname, &buf[keyoff+1], nnlen);
00312            }
00313        }
00314        keyoff += ( nnlen + 1 );
00315        saltoff = 3;
00316     }
00317 
00318     PORT_Memcpy(dbkey->salt.data, &buf[saltoff], dbkey->salt.len);
00319     
00320     dbkey->derPK.len = bufitem->size - keyoff;
00321     dbkey->derPK.data = (unsigned char *)PORT_ArenaZAlloc(arena,dbkey->derPK.len);
00322     if ( dbkey->derPK.data == NULL ) {
00323        goto loser;
00324     }
00325     
00326     PORT_Memcpy(dbkey->derPK.data, &buf[keyoff], dbkey->derPK.len);
00327     
00328     return(dbkey);
00329     
00330 loser:
00331 
00332     if ( arena ) {
00333        PORT_FreeArena(arena, PR_FALSE);
00334     }
00335     
00336     return(NULL);
00337 }
00338 
00339 static NSSLOWKEYDBKey *
00340 get_dbkey(NSSLOWKEYDBHandle *handle, DBT *index)
00341 {
00342     NSSLOWKEYDBKey *dbkey;
00343     DBT entry;
00344     int ret;
00345     
00346     /* get it from the database */
00347     ret = keydb_Get(handle, index, &entry, 0);
00348     if ( ret ) {
00349        PORT_SetError(SEC_ERROR_BAD_DATABASE);
00350        return NULL;
00351     }
00352 
00353     /* set up dbkey struct */
00354 
00355     dbkey = decode_dbkey(&entry, handle->version);
00356 
00357     return(dbkey);
00358 }
00359 
00360 static SECStatus
00361 put_dbkey(NSSLOWKEYDBHandle *handle, DBT *index, NSSLOWKEYDBKey *dbkey, PRBool update)
00362 {
00363     DBT *keydata = NULL;
00364     int status;
00365     
00366     keydata = encode_dbkey(dbkey, handle->version);
00367     if ( keydata == NULL ) {
00368        goto loser;
00369     }
00370     
00371     /* put it in the database */
00372     if ( update ) {
00373        status = keydb_Put(handle, index, keydata, 0);
00374     } else {
00375        status = keydb_Put(handle, index, keydata, R_NOOVERWRITE);
00376     }
00377     
00378     if ( status ) {
00379        goto loser;
00380     }
00381 
00382     /* sync the database */
00383     status = keydb_Sync(handle, 0);
00384     if ( status ) {
00385        goto loser;
00386     }
00387 
00388     free_dbt(keydata);
00389     return(SECSuccess);
00390 
00391 loser:
00392     if ( keydata ) {
00393        free_dbt(keydata);
00394     }
00395     
00396     return(SECFailure);
00397 }
00398 
00399 SECStatus
00400 nsslowkey_TraverseKeys(NSSLOWKEYDBHandle *handle, 
00401                SECStatus (* keyfunc)(DBT *k, DBT *d, void *pdata),
00402                void *udata )
00403 {
00404     DBT data;
00405     DBT key;
00406     SECStatus status;
00407     int ret;
00408 
00409     if (handle == NULL) {
00410        return(SECFailure);
00411     }
00412 
00413     ret = keydb_Seq(handle, &key, &data, R_FIRST);
00414     if ( ret ) {
00415        return(SECFailure);
00416     }
00417     
00418     do {
00419        /* skip version record */
00420        if ( data.size > 1 ) {
00421            if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
00422               if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
00423                   continue;
00424               }
00425            }
00426 
00427            /* skip password check */
00428            if ( key.size == KEYDB_PW_CHECK_LEN ) {
00429               if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING,
00430                              KEYDB_PW_CHECK_LEN) == 0 ) {
00431                   continue;
00432               }
00433            }
00434            
00435            status = (* keyfunc)(&key, &data, udata);
00436            if (status != SECSuccess) {
00437               return(status);
00438            }
00439        }
00440     } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
00441 
00442     return(SECSuccess);
00443 }
00444 
00445 typedef struct keyNode {
00446     struct keyNode *next;
00447     DBT key;
00448 } keyNode;
00449 
00450 typedef struct {
00451     PLArenaPool *arena;
00452     keyNode *head;
00453 } keyList;
00454 
00455 static SECStatus
00456 sec_add_key_to_list(DBT *key, DBT *data, void *arg)
00457 {
00458     keyList *keylist;
00459     keyNode *node;
00460     void *keydata;
00461     
00462     keylist = (keyList *)arg;
00463 
00464     /* allocate the node struct */
00465     node = (keyNode*)PORT_ArenaZAlloc(keylist->arena, sizeof(keyNode));
00466     if ( node == NULL ) {
00467        return(SECFailure);
00468     }
00469     
00470     /* allocate room for key data */
00471     keydata = PORT_ArenaZAlloc(keylist->arena, key->size);
00472     if ( keydata == NULL ) {
00473        return(SECFailure);
00474     }
00475 
00476     /* link node into list */
00477     node->next = keylist->head;
00478     keylist->head = node;
00479 
00480     /* copy key into node */
00481     PORT_Memcpy(keydata, key->data, key->size);
00482     node->key.size = key->size;
00483     node->key.data = keydata;
00484     
00485     return(SECSuccess);
00486 }
00487 
00488 static SECItem *
00489 decodeKeyDBGlobalSalt(DBT *saltData)
00490 {
00491     SECItem *saltitem;
00492     
00493     saltitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
00494     if ( saltitem == NULL ) {
00495        return(NULL);
00496     }
00497     
00498     saltitem->data = (unsigned char *)PORT_ZAlloc(saltData->size);
00499     if ( saltitem->data == NULL ) {
00500        PORT_Free(saltitem);
00501        return(NULL);
00502     }
00503     
00504     saltitem->len = saltData->size;
00505     PORT_Memcpy(saltitem->data, saltData->data, saltitem->len);
00506     
00507     return(saltitem);
00508 }
00509 
00510 static SECItem *
00511 GetKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
00512 {
00513     DBT saltKey;
00514     DBT saltData;
00515     int ret;
00516     
00517     saltKey.data = SALT_STRING;
00518     saltKey.size = sizeof(SALT_STRING) - 1;
00519 
00520     ret = keydb_Get(handle, &saltKey, &saltData, 0);
00521     if ( ret ) {
00522        return(NULL);
00523     }
00524 
00525     return(decodeKeyDBGlobalSalt(&saltData));
00526 }
00527 
00528 static SECStatus
00529 StoreKeyDBGlobalSalt(NSSLOWKEYDBHandle *handle)
00530 {
00531     DBT saltKey;
00532     DBT saltData;
00533     int status;
00534     
00535     saltKey.data = SALT_STRING;
00536     saltKey.size = sizeof(SALT_STRING) - 1;
00537 
00538     saltData.data = (void *)handle->global_salt->data;
00539     saltData.size = handle->global_salt->len;
00540 
00541     /* put global salt into the database now */
00542     status = keydb_Put(handle, &saltKey, &saltData, 0);
00543     if ( status ) {
00544        return(SECFailure);
00545     }
00546 
00547     return(SECSuccess);
00548 }
00549 
00550 static SECStatus
00551 makeGlobalVersion(NSSLOWKEYDBHandle *handle)
00552 {
00553     unsigned char version;
00554     DBT versionData;
00555     DBT versionKey;
00556     int status;
00557     
00558     version = NSSLOWKEY_DB_FILE_VERSION;
00559     versionData.data = &version;
00560     versionData.size = 1;
00561     versionKey.data = VERSION_STRING;
00562     versionKey.size = sizeof(VERSION_STRING)-1;
00563               
00564     /* put version string into the database now */
00565     status = keydb_Put(handle, &versionKey, &versionData, 0);
00566     if ( status ) {
00567        return(SECFailure);
00568     }
00569     handle->version = version;
00570 
00571     return(SECSuccess);
00572 }
00573 
00574 
00575 static SECStatus
00576 makeGlobalSalt(NSSLOWKEYDBHandle *handle)
00577 {
00578     DBT saltKey;
00579     DBT saltData;
00580     unsigned char saltbuf[16];
00581     int status;
00582     SECStatus rv;
00583     
00584     saltKey.data = SALT_STRING;
00585     saltKey.size = sizeof(SALT_STRING) - 1;
00586 
00587     saltData.data = (void *)saltbuf;
00588     saltData.size = sizeof(saltbuf);
00589     rv = RNG_GenerateGlobalRandomBytes(saltbuf, sizeof(saltbuf));
00590     if ( rv != SECSuccess ) {
00591        sftk_fatalError = PR_TRUE;
00592        return(rv);
00593     }
00594 
00595     /* put global salt into the database now */
00596     status = keydb_Put(handle, &saltKey, &saltData, 0);
00597     if ( status ) {
00598        return(SECFailure);
00599     }
00600 
00601     return(SECSuccess);
00602 }
00603 
00604 static SECStatus
00605 ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle,
00606                      SECItem *oldpwitem, SECItem *newpwitem,
00607                      SECOidTag new_algorithm);
00608 /*
00609  * Second pass of updating the key db.  This time we have a password.
00610  */
00611 static SECStatus
00612 nsslowkey_UpdateKeyDBPass2(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
00613 {
00614     SECStatus rv;
00615     
00616     rv = ChangeKeyDBPasswordAlg(handle, pwitem, pwitem,
00617                           nsslowkey_GetDefaultKeyDBAlg());
00618     
00619     return(rv);
00620 }
00621 
00622 static SECStatus
00623 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
00624                  SECItem *encCheck);
00625 
00626 static unsigned char
00627 nsslowkey_version(NSSLOWKEYDBHandle *handle)
00628 {
00629     DBT versionKey;
00630     DBT versionData;
00631     int ret;
00632     versionKey.data = VERSION_STRING;
00633     versionKey.size = sizeof(VERSION_STRING)-1;
00634 
00635     if (handle->db == NULL) {
00636        return 255;
00637     }
00638 
00639     /* lookup version string in database */
00640     ret = keydb_Get( handle, &versionKey, &versionData, 0 );
00641 
00642     /* error accessing the database */
00643     if ( ret < 0 ) {
00644        return 255;
00645     }
00646 
00647     if ( ret >= 1 ) {
00648        return 0;
00649     }
00650     return *( (unsigned char *)versionData.data);
00651 }
00652 
00653 static PRBool
00654 seckey_HasAServerKey(NSSLOWKEYDBHandle *handle)
00655 {
00656     DBT key;
00657     DBT data;
00658     int ret;
00659     PRBool found = PR_FALSE;
00660 
00661     ret = keydb_Seq(handle, &key, &data, R_FIRST);
00662     if ( ret ) {
00663        return PR_FALSE;
00664     }
00665     
00666     do {
00667        /* skip version record */
00668        if ( data.size > 1 ) {
00669            /* skip salt */
00670            if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
00671               if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
00672                   continue;
00673               }
00674            }
00675            /* skip pw check entry */
00676            if ( key.size == KEYDB_PW_CHECK_LEN ) {
00677               if ( PORT_Memcmp(key.data, KEYDB_PW_CHECK_STRING, 
00678                                           KEYDB_PW_CHECK_LEN) == 0 ) {
00679                   continue;
00680               }
00681            }
00682 
00683            /* keys stored by nickname will have 0 as the last byte of the
00684             * db key.  Other keys must be stored by modulus.  We will not
00685             * update those because they are left over from a keygen that
00686             * never resulted in a cert.
00687             */
00688            if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
00689               continue;
00690            }
00691 
00692            if (PORT_Strcmp(key.data,"Server-Key") == 0) {
00693               found = PR_TRUE;
00694                break;
00695            }
00696            
00697        }
00698     } while ( keydb_Seq(handle, &key, &data, R_NEXT) == 0 );
00699 
00700     return found;
00701 }
00702 
00703 /* forward declare local create function */
00704 static NSSLOWKEYDBHandle * nsslowkey_NewHandle(DB *dbHandle);
00705 
00706 /*
00707  * currently updates key database from v2 to v3
00708  */
00709 static SECStatus
00710 nsslowkey_UpdateKeyDBPass1(NSSLOWKEYDBHandle *handle)
00711 {
00712     SECStatus rv;
00713     DBT checkKey;
00714     DBT checkData;
00715     DBT saltKey;
00716     DBT saltData;
00717     DBT key;
00718     DBT data;
00719     unsigned char version;
00720     NSSLOWKEYDBKey *dbkey = NULL;
00721     NSSLOWKEYDBHandle *update = NULL;
00722     SECItem *oldSalt = NULL;
00723     int ret;
00724     SECItem checkitem;
00725 
00726     if ( handle->updatedb == NULL ) {
00727        return SECSuccess;
00728     }
00729 
00730     /* create a full DB Handle for our update so we 
00731      * can use the correct locks for the db primatives */
00732     update = nsslowkey_NewHandle(handle->updatedb);
00733     if ( update == NULL) {
00734        return SECSuccess;
00735     }
00736 
00737     /* update has now inherited the database handle */
00738     handle->updatedb = NULL;
00739 
00740     /*
00741      * check the version record
00742      */
00743     version = nsslowkey_version(update);
00744     if (version != 2) {
00745        goto done;
00746     }
00747 
00748     saltKey.data = SALT_STRING;
00749     saltKey.size = sizeof(SALT_STRING) - 1;
00750 
00751     ret = keydb_Get(update, &saltKey, &saltData, 0);
00752     if ( ret ) {
00753        /* no salt in old db, so it is corrupted */
00754        goto done;
00755     }
00756 
00757     oldSalt = decodeKeyDBGlobalSalt(&saltData);
00758     if ( oldSalt == NULL ) {
00759        /* bad salt in old db, so it is corrupted */
00760        goto done;
00761     }
00762 
00763     /*
00764      * look for a pw check entry
00765      */
00766     checkKey.data = KEYDB_PW_CHECK_STRING;
00767     checkKey.size = KEYDB_PW_CHECK_LEN;
00768     
00769     ret = keydb_Get(update, &checkKey, &checkData, 0 );
00770     if (ret) {
00771        /*
00772         * if we have a key, but no KEYDB_PW_CHECK_STRING, then this must
00773         * be an old server database, and it does have a password associated
00774         * with it. Put a fake entry in so we can identify this db when we do
00775         * get the password for it.
00776         */
00777        if (seckey_HasAServerKey(update)) {
00778            DBT fcheckKey;
00779            DBT fcheckData;
00780 
00781            /*
00782             * include a fake string
00783             */
00784            fcheckKey.data = KEYDB_FAKE_PW_CHECK_STRING;
00785            fcheckKey.size = KEYDB_FAKE_PW_CHECK_LEN;
00786            fcheckData.data = "1";
00787            fcheckData.size = 1;
00788            /* put global salt into the new database now */
00789            ret = keydb_Put( handle, &saltKey, &saltData, 0);
00790            if ( ret ) {
00791               goto done;
00792            }
00793            ret = keydb_Put( handle, &fcheckKey, &fcheckData, 0);
00794            if ( ret ) {
00795               goto done;
00796            }
00797        } else {
00798            goto done;
00799        }
00800     } else {
00801        /* put global salt into the new database now */
00802        ret = keydb_Put( handle, &saltKey, &saltData, 0);
00803        if ( ret ) {
00804            goto done;
00805        }
00806 
00807        dbkey = decode_dbkey(&checkData, 2);
00808        if ( dbkey == NULL ) {
00809            goto done;
00810        }
00811        checkitem = dbkey->derPK;
00812        dbkey->derPK.data = NULL;
00813     
00814        /* format the new pw check entry */
00815        rv = encodePWCheckEntry(NULL, &dbkey->derPK, SEC_OID_RC4, &checkitem);
00816        if ( rv != SECSuccess ) {
00817            goto done;
00818        }
00819 
00820        rv = put_dbkey(handle, &checkKey, dbkey, PR_TRUE);
00821        if ( rv != SECSuccess ) {
00822            goto done;
00823        }
00824 
00825        /* free the dbkey */
00826        sec_destroy_dbkey(dbkey);
00827        dbkey = NULL;
00828     }
00829     
00830     
00831     /* now traverse the database */
00832     ret = keydb_Seq(update, &key, &data, R_FIRST);
00833     if ( ret ) {
00834        goto done;
00835     }
00836     
00837     do {
00838        /* skip version record */
00839        if ( data.size > 1 ) {
00840            /* skip salt */
00841            if ( key.size == ( sizeof(SALT_STRING) - 1 ) ) {
00842               if ( PORT_Memcmp(key.data, SALT_STRING, key.size) == 0 ) {
00843                   continue;
00844               }
00845            }
00846            /* skip pw check entry */
00847            if ( key.size == checkKey.size ) {
00848               if ( PORT_Memcmp(key.data, checkKey.data, key.size) == 0 ) {
00849                   continue;
00850               }
00851            }
00852 
00853            /* keys stored by nickname will have 0 as the last byte of the
00854             * db key.  Other keys must be stored by modulus.  We will not
00855             * update those because they are left over from a keygen that
00856             * never resulted in a cert.
00857             */
00858            if ( ((unsigned char *)key.data)[key.size-1] != 0 ) {
00859               continue;
00860            }
00861            
00862            dbkey = decode_dbkey(&data, 2);
00863            if ( dbkey == NULL ) {
00864               continue;
00865            }
00866 
00867            /* This puts the key into the new database with the same
00868             * index (nickname) that it had before.  The second pass
00869             * of the update will have the password.  It will decrypt
00870             * and re-encrypt the entries using a new algorithm.
00871             */
00872            dbkey->nickname = (char *)key.data;
00873            rv = put_dbkey(handle, &key, dbkey, PR_FALSE);
00874            dbkey->nickname = NULL;
00875 
00876            sec_destroy_dbkey(dbkey);
00877        }
00878     } while ( keydb_Seq(update, &key, &data, R_NEXT) == 0 );
00879 
00880     dbkey = NULL;
00881 
00882 done:
00883     /* sync the database */
00884     ret = keydb_Sync(handle, 0);
00885 
00886     nsslowkey_CloseKeyDB(update);
00887     
00888     if ( oldSalt ) {
00889        SECITEM_FreeItem(oldSalt, PR_TRUE);
00890     }
00891     
00892     if ( dbkey ) {
00893        sec_destroy_dbkey(dbkey);
00894     }
00895 
00896     return(SECSuccess);
00897 }
00898 
00899 static SECStatus
00900 openNewDB(const char *appName, const char *prefix, const char *dbname, 
00901        NSSLOWKEYDBHandle *handle, NSSLOWKEYDBNameFunc namecb, void *cbarg)
00902 {
00903     SECStatus rv = SECFailure;
00904     int status = RDB_FAIL;
00905     char *updname = NULL;
00906     DB *updatedb = NULL;
00907     PRBool updated = PR_FALSE;
00908     int ret;
00909 
00910     if (appName) {
00911        handle->db = rdbopen( appName, prefix, "key", NO_CREATE, &status);
00912     } else {
00913        handle->db = dbopen( dbname, NO_CREATE, 0600, DB_HASH, 0 );
00914     }
00915     /* if create fails then we lose */
00916     if ( handle->db == NULL ) {
00917        return (status == RDB_RETRY) ? SECWouldBlock: SECFailure;
00918     }
00919 
00920     rv = db_BeginTransaction(handle->db);
00921     if (rv != SECSuccess) {
00922        db_InitComplete(handle->db);
00923        return rv;
00924     }
00925 
00926     /* force a transactional read, which will verify that one and only one
00927      * process attempts the update. */
00928     if (nsslowkey_version(handle) == NSSLOWKEY_DB_FILE_VERSION) {
00929        /* someone else has already updated the database for us */
00930        db_FinishTransaction(handle->db, PR_FALSE);
00931        db_InitComplete(handle->db);
00932        return SECSuccess;
00933     }
00934 
00935     /*
00936      * if we are creating a multiaccess database, see if there is a
00937      * local database we can update from.
00938      */
00939     if (appName) {
00940         NSSLOWKEYDBHandle *updateHandle;
00941        updatedb = dbopen( dbname, NO_RDONLY, 0600, DB_HASH, 0 );
00942        if (!updatedb) {
00943            goto noupdate;
00944        }
00945 
00946        /* nsslowkey_version needs a full handle because it calls
00947          * the kdb_Get() function, which needs to lock.
00948          */
00949         updateHandle = nsslowkey_NewHandle(updatedb);
00950        if (!updateHandle) {
00951            updatedb->close(updatedb);
00952            goto noupdate;
00953        }
00954 
00955        handle->version = nsslowkey_version(updateHandle);
00956        if (handle->version != NSSLOWKEY_DB_FILE_VERSION) {
00957            nsslowkey_CloseKeyDB(updateHandle);
00958            goto noupdate;
00959        }
00960 
00961        /* copy the new DB from the old one */
00962        db_Copy(handle->db, updatedb);
00963        nsslowkey_CloseKeyDB(updateHandle);
00964        db_FinishTransaction(handle->db,PR_FALSE);
00965        db_InitComplete(handle->db);
00966        return SECSuccess;
00967     }
00968 noupdate:
00969 
00970     /* update the version number */
00971     rv = makeGlobalVersion(handle);
00972     if ( rv != SECSuccess ) {
00973        goto loser;
00974     }
00975 
00976     /*
00977      * try to update from v2 db
00978      */
00979     updname = (*namecb)(cbarg, 2);
00980     if ( updname != NULL ) {
00981        handle->updatedb = dbopen( updname, NO_RDONLY, 0600, DB_HASH, 0 );
00982         PORT_Free( updname );
00983 
00984        if ( handle->updatedb ) {
00985            /*
00986             * Try to update the db using a null password.  If the db
00987             * doesn't have a password, then this will work.  If it does
00988             * have a password, then this will fail and we will do the
00989             * update later
00990             */
00991            rv = nsslowkey_UpdateKeyDBPass1(handle);
00992            if ( rv == SECSuccess ) {
00993               updated = PR_TRUE;
00994            }
00995        }
00996            
00997     }
00998 
00999     /* we are using the old salt if we updated from an old db */
01000     if ( ! updated ) {
01001        rv = makeGlobalSalt(handle);
01002        if ( rv != SECSuccess ) {
01003           goto loser;
01004        }
01005     }
01006        
01007     /* sync the database */
01008     ret = keydb_Sync(handle, 0);
01009     if ( ret ) {
01010        rv = SECFailure;
01011        goto loser;
01012     }
01013     rv = SECSuccess;
01014 
01015 loser:
01016     db_FinishTransaction(handle->db, rv != SECSuccess);
01017     db_InitComplete(handle->db);
01018     return rv;
01019 }
01020 
01021 
01022 static DB *
01023 openOldDB(const char *appName, const char *prefix, const char *dbname, 
01024                                    PRBool openflags) {
01025     DB *db = NULL;
01026 
01027     if (appName) {
01028        db = rdbopen( appName, prefix, "key", openflags, NULL);
01029     } else {
01030        db = dbopen( dbname, openflags, 0600, DB_HASH, 0 );
01031     }
01032 
01033     return db;
01034 }
01035 
01036 /* check for correct version number */
01037 static PRBool
01038 verifyVersion(NSSLOWKEYDBHandle *handle)
01039 {
01040     int version = nsslowkey_version(handle);
01041 
01042     handle->version = version;
01043     if (version != NSSLOWKEY_DB_FILE_VERSION ) {
01044        if (handle->db) {
01045            keydb_Close(handle);
01046            handle->db = NULL;
01047        }
01048     }
01049     return handle->db != NULL;
01050 }
01051 
01052 static NSSLOWKEYDBHandle *
01053 nsslowkey_NewHandle(DB *dbHandle)
01054 {
01055     NSSLOWKEYDBHandle *handle;
01056     handle = (NSSLOWKEYDBHandle *)PORT_ZAlloc (sizeof(NSSLOWKEYDBHandle));
01057     if (handle == NULL) {
01058        PORT_SetError (SEC_ERROR_NO_MEMORY);
01059        return NULL;
01060     }
01061 
01062     handle->appname = NULL;
01063     handle->dbname = NULL;
01064     handle->global_salt = NULL;
01065     handle->updatedb = NULL;
01066     handle->db = dbHandle;
01067     handle->ref = 1;
01068 
01069     keydb_InitLocks(handle);
01070     return handle;
01071 }
01072 
01073 NSSLOWKEYDBHandle *
01074 nsslowkey_OpenKeyDB(PRBool readOnly, const char *appName, const char *prefix,
01075                             NSSLOWKEYDBNameFunc namecb, void *cbarg)
01076 {
01077     NSSLOWKEYDBHandle *handle = NULL;
01078     SECStatus rv;
01079     int openflags;
01080     char *dbname = NULL;
01081 
01082 
01083     handle = nsslowkey_NewHandle(NULL);
01084 
01085     openflags = readOnly ? NO_RDONLY : NO_RDWR;
01086 
01087 
01088     dbname = (*namecb)(cbarg, NSSLOWKEY_DB_FILE_VERSION);
01089     if ( dbname == NULL ) {
01090        goto loser;
01091     }
01092     handle->appname = appName ? PORT_Strdup(appName) : NULL ;
01093     handle->dbname = (appName == NULL) ? PORT_Strdup(dbname) : 
01094                      (prefix ? PORT_Strdup(prefix) : NULL);
01095     handle->readOnly = readOnly;
01096 
01097 
01098 
01099     handle->db = openOldDB(appName, prefix, dbname, openflags);
01100     if (handle->db) {
01101        verifyVersion(handle);
01102        if (handle->version == 255) {
01103            goto loser;
01104        }
01105     }
01106 
01107     /* if first open fails, try to create a new DB */
01108     if ( handle->db == NULL ) {
01109        if ( readOnly ) {
01110            goto loser;
01111        }
01112 
01113        rv = openNewDB(appName, prefix, dbname, handle, namecb, cbarg);
01114        /* two processes started to initialize the database at the same time.
01115         * The multiprocess code blocked the second one, then had it retry to
01116         * see if it can just open the database normally */
01117        if (rv == SECWouldBlock) {
01118            handle->db = openOldDB(appName,prefix,dbname, openflags);
01119            verifyVersion(handle);
01120            if (handle->db == NULL) {
01121               goto loser;
01122            }
01123        } else if (rv != SECSuccess) {
01124            goto loser;
01125        }
01126     }
01127 
01128     handle->global_salt = GetKeyDBGlobalSalt(handle);
01129     if ( dbname )
01130         PORT_Free( dbname );
01131     return handle;
01132 
01133 loser:
01134 
01135     if ( dbname )
01136         PORT_Free( dbname );
01137     PORT_SetError(SEC_ERROR_BAD_DATABASE);
01138     nsslowkey_CloseKeyDB(handle);
01139     return NULL;
01140 }
01141 
01142 /*
01143  * Close the database
01144  */
01145 void
01146 nsslowkey_CloseKeyDB(NSSLOWKEYDBHandle *handle)
01147 {
01148     if (handle != NULL) {
01149        if (handle->db != NULL) {
01150            keydb_Close(handle);
01151        }
01152        if (handle->updatedb) {
01153            handle->updatedb->close(handle->updatedb);
01154         }
01155        if (handle->dbname) PORT_Free(handle->dbname);
01156        if (handle->appname) PORT_Free(handle->appname);
01157        if (handle->global_salt) {
01158            SECITEM_FreeItem(handle->global_salt,PR_TRUE);
01159        }
01160        keydb_DestroyLocks(handle);
01161            
01162        PORT_Free(handle);
01163     }
01164 }
01165 
01166 /* Get the key database version */
01167 int
01168 nsslowkey_GetKeyDBVersion(NSSLOWKEYDBHandle *handle)
01169 {
01170     PORT_Assert(handle != NULL);
01171 
01172     return handle->version;
01173 }
01174 
01175 /*
01176  * Delete a private key that was stored in the database
01177  */
01178 SECStatus
01179 nsslowkey_DeleteKey(NSSLOWKEYDBHandle *handle, SECItem *pubkey)
01180 {
01181     DBT namekey;
01182     int ret;
01183 
01184     if (handle == NULL) {
01185        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01186        return(SECFailure);
01187     }
01188 
01189     /* set up db key and data */
01190     namekey.data = pubkey->data;
01191     namekey.size = pubkey->len;
01192 
01193     /* delete it from the database */
01194     ret = keydb_Del(handle, &namekey, 0);
01195     if ( ret ) {
01196        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01197        return(SECFailure);
01198     }
01199 
01200     /* sync the database */
01201     ret = keydb_Sync(handle, 0);
01202     if ( ret ) {
01203        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01204        return(SECFailure);
01205     }
01206 
01207     return(SECSuccess);
01208 }
01209 
01210 /*
01211  * Store a key in the database, indexed by its public key modulus.(value!)
01212  */
01213 SECStatus
01214 nsslowkey_StoreKeyByPublicKey(NSSLOWKEYDBHandle *handle, 
01215                         NSSLOWKEYPrivateKey *privkey,
01216                         SECItem *pubKeyData,
01217                         char *nickname,
01218                         SECItem *arg)
01219 {
01220     return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 
01221             nickname, arg, nsslowkey_GetDefaultKeyDBAlg(),PR_FALSE);
01222 }
01223 
01224 SECStatus
01225 nsslowkey_UpdateNickname(NSSLOWKEYDBHandle *handle, 
01226                         NSSLOWKEYPrivateKey *privkey,
01227                         SECItem *pubKeyData,
01228                         char *nickname,
01229                         SECItem *arg)
01230 {
01231     return nsslowkey_StoreKeyByPublicKeyAlg(handle, privkey, pubKeyData, 
01232             nickname, arg, nsslowkey_GetDefaultKeyDBAlg(),PR_TRUE);
01233 }
01234 
01235 /* see if the symetric CKA_ID already Exists.
01236  */
01237 PRBool
01238 nsslowkey_KeyForIDExists(NSSLOWKEYDBHandle *handle, SECItem *id)
01239 {
01240     DBT namekey;
01241     DBT dummy;
01242     int status;
01243 
01244     namekey.data = (char *)id->data;
01245     namekey.size = id->len;
01246     status = keydb_Get(handle, &namekey, &dummy, 0);
01247     if ( status ) {
01248        return PR_FALSE;
01249     }
01250     
01251     return PR_TRUE;
01252 }
01253 
01254 /* see if the public key for this cert is in the database filed
01255  * by modulus
01256  */
01257 PRBool
01258 nsslowkey_KeyForCertExists(NSSLOWKEYDBHandle *handle, NSSLOWCERTCertificate *cert)
01259 {
01260     NSSLOWKEYPublicKey *pubkey = NULL;
01261     DBT namekey;
01262     DBT dummy;
01263     int status;
01264     
01265     /* get cert's public key */
01266     pubkey = nsslowcert_ExtractPublicKey(cert);
01267     if ( pubkey == NULL ) {
01268        return PR_FALSE;
01269     }
01270 
01271     /* TNH - make key from NSSLOWKEYPublicKey */
01272     switch (pubkey->keyType) {
01273       case NSSLOWKEYRSAKey:
01274        namekey.data = pubkey->u.rsa.modulus.data;
01275        namekey.size = pubkey->u.rsa.modulus.len;
01276        break;
01277       case NSSLOWKEYDSAKey:
01278        namekey.data = pubkey->u.dsa.publicValue.data;
01279        namekey.size = pubkey->u.dsa.publicValue.len;
01280        break;
01281       case NSSLOWKEYDHKey:
01282        namekey.data = pubkey->u.dh.publicValue.data;
01283        namekey.size = pubkey->u.dh.publicValue.len;
01284        break;
01285 #ifdef NSS_ENABLE_ECC
01286       case NSSLOWKEYECKey:
01287        namekey.data = pubkey->u.ec.publicValue.data;
01288        namekey.size = pubkey->u.ec.publicValue.len;
01289        break;
01290 #endif /* NSS_ENABLE_ECC */
01291       default:
01292        /* XXX We don't do Fortezza or DH yet. */
01293        return PR_FALSE;
01294     }
01295 
01296     if (handle->version != 3) {
01297        unsigned char buf[SHA1_LENGTH];
01298        SHA1_HashBuf(buf,namekey.data,namekey.size);
01299        /* NOTE: don't use pubkey after this! it's now thrashed */
01300        PORT_Memcpy(namekey.data,buf,sizeof(buf));
01301        namekey.size = sizeof(buf);
01302     }
01303 
01304     status = keydb_Get(handle, &namekey, &dummy, 0);
01305     /* some databases have the key stored as a signed value */
01306     if (status) {
01307        unsigned char *buf = (unsigned char *)PORT_Alloc(namekey.size+1);
01308        if (buf) {
01309            PORT_Memcpy(&buf[1], namekey.data, namekey.size);
01310            buf[0] = 0;
01311            namekey.data = buf;
01312            namekey.size ++;
01313            status = keydb_Get(handle, &namekey, &dummy, 0);
01314            PORT_Free(buf);
01315        }
01316     }
01317     nsslowkey_DestroyPublicKey(pubkey);
01318     if ( status ) {
01319        return PR_FALSE;
01320     }
01321     
01322     return PR_TRUE;
01323 }
01324 
01325 /*
01326  * check to see if the user has a password
01327  */
01328 SECStatus
01329 nsslowkey_HasKeyDBPassword(NSSLOWKEYDBHandle *handle)
01330 {
01331     DBT checkkey, checkdata;
01332     int ret;
01333 
01334     if (handle == NULL) {
01335        return(SECFailure);
01336     }
01337 
01338     checkkey.data = KEYDB_PW_CHECK_STRING;
01339     checkkey.size = KEYDB_PW_CHECK_LEN;
01340     
01341     ret = keydb_Get(handle, &checkkey, &checkdata, 0 );
01342     if ( ret ) {
01343        /* see if this was an updated DB first */
01344        checkkey.data = KEYDB_FAKE_PW_CHECK_STRING;
01345        checkkey.size = KEYDB_FAKE_PW_CHECK_LEN;
01346        ret = keydb_Get(handle, &checkkey, &checkdata, 0 );
01347        if ( ret ) {
01348            return(SECFailure);
01349        }
01350     }
01351 
01352     return(SECSuccess);
01353 }
01354 
01355 /*
01356  * Set up the password checker in the key database.
01357  * This is done by encrypting a known plaintext with the user's key.
01358  */
01359 SECStatus
01360 nsslowkey_SetKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
01361 {
01362     return nsslowkey_SetKeyDBPasswordAlg(handle, pwitem,
01363                                   nsslowkey_GetDefaultKeyDBAlg());
01364 }
01365 
01366 static SECStatus
01367 HashPassword(unsigned char *hashresult, char *pw, SECItem *salt)
01368 {
01369     SHA1Context *cx;
01370     unsigned int outlen;
01371     cx = SHA1_NewContext();
01372     if ( cx == NULL ) {
01373        return(SECFailure);
01374     }
01375     
01376     SHA1_Begin(cx);
01377     if ( ( salt != NULL ) && ( salt->data != NULL ) ) {
01378        SHA1_Update(cx, salt->data, salt->len);
01379     }
01380     
01381     SHA1_Update(cx, (unsigned char *)pw, PORT_Strlen(pw));
01382     SHA1_End(cx, hashresult, &outlen, SHA1_LENGTH);
01383     
01384     SHA1_DestroyContext(cx, PR_TRUE);
01385     
01386     return(SECSuccess);
01387 }
01388 
01389 SECItem *
01390 nsslowkey_HashPassword(char *pw, SECItem *salt)
01391 {
01392     SECItem *pwitem;
01393     SECStatus rv;
01394     
01395     pwitem = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
01396     if ( pwitem == NULL ) {
01397        return(NULL);
01398     }
01399     pwitem->len = SHA1_LENGTH;
01400     pwitem->data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);
01401     if ( pwitem->data == NULL ) {
01402        PORT_Free(pwitem);
01403        return(NULL);
01404     }
01405     if ( pw ) {
01406        rv = HashPassword(pwitem->data, pw, salt);
01407        if ( rv != SECSuccess ) {
01408            SECITEM_ZfreeItem(pwitem, PR_TRUE);
01409            return(NULL);
01410        }
01411     }
01412     
01413     return(pwitem);
01414 }
01415 
01416 /* Derive the actual password value for the database from a pw string */
01417 SECItem *
01418 nsslowkey_DeriveKeyDBPassword(NSSLOWKEYDBHandle *keydb, char *pw)
01419 {
01420     PORT_Assert(keydb != NULL);
01421     PORT_Assert(pw != NULL);
01422     if (keydb == NULL || pw == NULL) return(NULL);
01423 
01424     return nsslowkey_HashPassword(pw, keydb->global_salt);
01425 }
01426 
01427 /*
01428  * Derive an RC4 key from a password key and a salt.  This
01429  * was the method to used to encrypt keys in the version 2?
01430  * database
01431  */
01432 SECItem *
01433 seckey_create_rc4_key(SECItem *pwitem, SECItem *salt)
01434 {
01435     MD5Context *md5 = NULL;
01436     unsigned int part;
01437     SECStatus rv = SECFailure;
01438     SECItem *key = NULL;
01439 
01440     key = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
01441     if(key != NULL)
01442     {
01443        key->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
01444               MD5_LENGTH);
01445        key->len = MD5_LENGTH;
01446        if(key->data != NULL)
01447        {
01448            md5 = MD5_NewContext();
01449            if ( md5 != NULL ) 
01450            {
01451               MD5_Begin(md5);
01452               MD5_Update(md5, salt->data, salt->len);
01453               MD5_Update(md5, pwitem->data, pwitem->len);
01454               MD5_End(md5, key->data, &part, MD5_LENGTH);
01455               MD5_DestroyContext(md5, PR_TRUE);
01456               rv = SECSuccess;
01457            }
01458        }
01459        
01460        if(rv != SECSuccess)
01461        {
01462            SECITEM_FreeItem(key, PR_TRUE);
01463            key = NULL;
01464        }
01465     }
01466 
01467     return key;
01468 }
01469 
01470 SECItem *
01471 seckey_create_rc4_salt(void)
01472 {
01473     SECItem *salt = NULL;
01474     SECStatus rv = SECFailure;
01475 
01476     salt = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
01477     if(salt == NULL)
01478        return NULL;
01479 
01480     salt->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
01481        SALT_LENGTH);
01482     if(salt->data != NULL)
01483     {
01484        salt->len = SALT_LENGTH;
01485        rv = RNG_GenerateGlobalRandomBytes(salt->data, salt->len);
01486        if(rv != SECSuccess)
01487            sftk_fatalError = PR_TRUE;
01488     }
01489        
01490     if(rv != SECSuccess)
01491     {
01492        SECITEM_FreeItem(salt, PR_TRUE);
01493        salt = NULL;
01494     }
01495 
01496     return salt;
01497 }
01498 
01499 SECItem *
01500 seckey_rc4_decode(SECItem *key, SECItem *src)
01501 {
01502     SECItem *dest = NULL;
01503     RC4Context *ctxt = NULL;
01504     SECStatus rv = SECFailure;
01505 
01506     if((key == NULL) || (src == NULL))
01507        return NULL;
01508 
01509     dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
01510     if(dest == NULL)
01511        return NULL;
01512 
01513     dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) *
01514        (src->len + 64));  /* TNH - padding? */
01515     if(dest->data != NULL)
01516     {
01517        ctxt = RC4_CreateContext(key->data, key->len);
01518        if(ctxt != NULL)
01519        {
01520            rv = RC4_Decrypt(ctxt, dest->data, &dest->len,
01521                   src->len + 64, src->data, src->len);
01522            RC4_DestroyContext(ctxt, PR_TRUE);
01523        }
01524     }
01525 
01526     if(rv == SECFailure)
01527        if(dest != NULL)
01528        {
01529            SECITEM_FreeItem(dest, PR_TRUE);
01530            dest = NULL;
01531        }
01532 
01533     return dest;
01534 }
01535 
01536 
01537 #ifdef EC_DEBUG
01538 #define SEC_PRINT(str1, str2, num, sitem) \
01539     printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
01540             str1, str2, num, sitem->len); \
01541     for (i = 0; i < sitem->len; i++) { \
01542            printf("%02x:", sitem->data[i]); \
01543     } \
01544     printf("\n") 
01545 #else
01546 #define SEC_PRINT(a, b, c, d) 
01547 #endif /* EC_DEBUG */
01548 
01549 /* TNH - keydb is unused */
01550 /* TNH - the pwitem should be the derived key for RC4 */
01551 NSSLOWKEYEncryptedPrivateKeyInfo *
01552 seckey_encrypt_private_key(
01553         NSSLOWKEYPrivateKey *pk, SECItem *pwitem, NSSLOWKEYDBHandle *keydb,
01554        SECOidTag algorithm, SECItem **salt)
01555 {
01556     NSSLOWKEYEncryptedPrivateKeyInfo *epki = NULL;
01557     NSSLOWKEYPrivateKeyInfo *pki = NULL;
01558     SECStatus rv = SECFailure;
01559     PLArenaPool *temparena = NULL, *permarena = NULL;
01560     SECItem *der_item = NULL;
01561     NSSPKCS5PBEParameter *param = NULL;
01562     SECItem *dummy = NULL, *dest = NULL;
01563     SECAlgorithmID *algid;
01564 #ifdef NSS_ENABLE_ECC
01565     SECItem *fordebug = NULL;
01566     int savelen;
01567     int i;
01568 #endif
01569 
01570     *salt = NULL;
01571     permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
01572     if(permarena == NULL)
01573        return NULL;
01574 
01575     temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
01576     if(temparena == NULL)
01577        goto loser;
01578 
01579     /* allocate structures */
01580     epki = (NSSLOWKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(permarena,
01581        sizeof(NSSLOWKEYEncryptedPrivateKeyInfo));
01582     pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 
01583        sizeof(NSSLOWKEYPrivateKeyInfo));
01584     der_item = (SECItem *)PORT_ArenaZAlloc(temparena, sizeof(SECItem));
01585     if((epki == NULL) || (pki == NULL) || (der_item == NULL))
01586        goto loser;
01587 
01588     epki->arena = permarena;
01589 
01590     /* setup private key info */
01591     dummy = SEC_ASN1EncodeInteger(temparena, &(pki->version), 
01592        NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
01593     if(dummy == NULL)
01594        goto loser;
01595 
01596     /* Encode the key, and set the algorithm (with params) */
01597     switch (pk->keyType) {
01598       case NSSLOWKEYRSAKey:
01599         prepare_low_rsa_priv_key_for_asn1(pk);
01600        dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk, 
01601                                nsslowkey_RSAPrivateKeyTemplate);
01602        if (dummy == NULL) {
01603            rv = SECFailure;
01604            goto loser;
01605        }
01606        
01607        rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm), 
01608                                SEC_OID_PKCS1_RSA_ENCRYPTION, 0);
01609        if (rv == SECFailure) {
01610            goto loser;
01611        }
01612        
01613        break;
01614       case NSSLOWKEYDSAKey:
01615         prepare_low_dsa_priv_key_for_asn1(pk);
01616        dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
01617                                nsslowkey_DSAPrivateKeyTemplate);
01618        if (dummy == NULL) {
01619            rv = SECFailure;
01620            goto loser;
01621        }
01622        
01623         prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
01624        dummy = SEC_ASN1EncodeItem(temparena, NULL, &pk->u.dsa.params,
01625                                nsslowkey_PQGParamsTemplate);
01626        if (dummy == NULL) {
01627            rv = SECFailure;
01628            goto loser;
01629        }
01630        
01631        rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
01632                                SEC_OID_ANSIX9_DSA_SIGNATURE, dummy);
01633        if (rv == SECFailure) {
01634            goto loser;
01635        }
01636        
01637        break;
01638       case NSSLOWKEYDHKey:
01639         prepare_low_dh_priv_key_for_asn1(pk);
01640        dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
01641                                nsslowkey_DHPrivateKeyTemplate);
01642        if (dummy == NULL) {
01643            rv = SECFailure;
01644            goto loser;
01645        }
01646 
01647        rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
01648                                SEC_OID_X942_DIFFIE_HELMAN_KEY, dummy);
01649        if (rv == SECFailure) {
01650            goto loser;
01651        }
01652        break;
01653 #ifdef NSS_ENABLE_ECC
01654       case NSSLOWKEYECKey:
01655        prepare_low_ec_priv_key_for_asn1(pk);
01656        /* Public value is encoded as a bit string so adjust length
01657         * to be in bits before ASN encoding and readjust 
01658         * immediately after.
01659         *
01660         * Since the SECG specification recommends not including the
01661         * parameters as part of ECPrivateKey, we zero out the curveOID
01662         * length before encoding and restore it later.
01663         */
01664        pk->u.ec.publicValue.len <<= 3;
01665        savelen = pk->u.ec.ecParams.curveOID.len;
01666        pk->u.ec.ecParams.curveOID.len = 0;
01667        dummy = SEC_ASN1EncodeItem(temparena, &(pki->privateKey), pk,
01668                                nsslowkey_ECPrivateKeyTemplate);
01669        pk->u.ec.ecParams.curveOID.len = savelen;
01670        pk->u.ec.publicValue.len >>= 3;
01671 
01672        if (dummy == NULL) {
01673            rv = SECFailure;
01674            goto loser;
01675        }
01676 
01677        dummy = &pk->u.ec.ecParams.DEREncoding;
01678 
01679        /* At this point dummy should contain the encoded params */
01680        rv = SECOID_SetAlgorithmID(temparena, &(pki->algorithm),
01681                                SEC_OID_ANSIX962_EC_PUBLIC_KEY, dummy);
01682 
01683        if (rv == SECFailure) {
01684            goto loser;
01685        }
01686        
01687        fordebug = &(pki->privateKey);
01688        SEC_PRINT("seckey_encrypt_private_key()", "PrivateKey", 
01689                 pk->keyType, fordebug);
01690 
01691        break;
01692 #endif /* NSS_ENABLE_ECC */
01693       default:
01694        /* We don't support DH or Fortezza private keys yet */
01695        PORT_Assert(PR_FALSE);
01696        break;
01697     }
01698 
01699     /* setup encrypted private key info */
01700     dummy = SEC_ASN1EncodeItem(temparena, der_item, pki, 
01701        nsslowkey_PrivateKeyInfoTemplate);
01702 
01703     SEC_PRINT("seckey_encrypt_private_key()", "PrivateKeyInfo", 
01704              pk->keyType, der_item);
01705 
01706     if(dummy == NULL) {
01707        rv = SECFailure;
01708        goto loser;
01709     }
01710 
01711     rv = SECFailure; /* assume failure */
01712     *salt = seckey_create_rc4_salt();
01713     if (*salt == NULL) {
01714        goto loser;
01715     }
01716 
01717     param = nsspkcs5_NewParam(algorithm,*salt,1);
01718     if (param == NULL) {
01719        goto loser;
01720     }
01721 
01722     dest = nsspkcs5_CipherData(param, pwitem, der_item, PR_TRUE, NULL);
01723     if (dest == NULL) {
01724        goto loser;
01725     }
01726 
01727     rv = SECITEM_CopyItem(permarena, &epki->encryptedData, dest);
01728     if (rv != SECSuccess) {
01729        goto loser;
01730     }
01731 
01732     algid = nsspkcs5_CreateAlgorithmID(permarena, algorithm, param);
01733     if (algid == NULL) {
01734        rv = SECFailure;
01735        goto loser;
01736     }
01737 
01738     rv = SECOID_CopyAlgorithmID(permarena, &epki->algorithm, algid);
01739     SECOID_DestroyAlgorithmID(algid, PR_TRUE);
01740 
01741 loser:
01742     if(dest != NULL)
01743        SECITEM_FreeItem(dest, PR_TRUE);
01744 
01745     if(param != NULL)
01746        nsspkcs5_DestroyPBEParameter(param);
01747 
01748     /* let success fall through */
01749 
01750     if(rv == SECFailure)
01751     {
01752        PORT_FreeArena(permarena, PR_TRUE);
01753        epki = NULL;
01754        if(*salt != NULL)
01755            SECITEM_FreeItem(*salt, PR_TRUE);
01756     }
01757 
01758     if(temparena != NULL)
01759        PORT_FreeArena(temparena, PR_TRUE);
01760 
01761     return epki;
01762 }
01763 
01764 static SECStatus 
01765 seckey_put_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, SECItem *pwitem,
01766                      NSSLOWKEYPrivateKey *pk, char *nickname, PRBool update,
01767                      SECOidTag algorithm)
01768 {
01769     NSSLOWKEYDBKey *dbkey = NULL;
01770     NSSLOWKEYEncryptedPrivateKeyInfo *epki = NULL;
01771     PLArenaPool  *arena = NULL;
01772     SECItem *dummy = NULL;
01773     SECItem *salt = NULL;
01774     SECStatus rv = SECFailure;
01775 
01776     if((keydb == NULL) || (index == NULL) || (pwitem == NULL) ||
01777        (pk == NULL))
01778        return SECFailure;
01779        
01780     arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
01781     if(arena == NULL)
01782        return SECFailure;
01783 
01784     dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
01785     if(dbkey == NULL)
01786        goto loser;
01787     dbkey->arena = arena;
01788     dbkey->nickname = nickname;
01789 
01790     /* TNH - for RC4, the salt should be created here */
01791        
01792     epki = seckey_encrypt_private_key(pk, pwitem, keydb, algorithm, &salt);
01793     if(epki == NULL)
01794        goto loser;
01795 
01796     if(salt != NULL)
01797     {
01798        rv = SECITEM_CopyItem(arena, &(dbkey->salt), salt);
01799        SECITEM_ZfreeItem(salt, PR_TRUE);
01800     }
01801 
01802     dummy = SEC_ASN1EncodeItem(arena, &(dbkey->derPK), epki, 
01803        nsslowkey_EncryptedPrivateKeyInfoTemplate);
01804     if(dummy == NULL)
01805        rv = SECFailure;
01806     else
01807        rv = put_dbkey(keydb, index, dbkey, update);
01808 
01809     /* let success fall through */
01810 loser:
01811     if(arena != NULL)
01812         PORT_FreeArena(arena, PR_TRUE);
01813     if(epki != NULL)
01814         PORT_FreeArena(epki->arena, PR_TRUE);
01815 
01816     return rv;
01817 }
01818 
01819 /*
01820  * Store a key in the database, indexed by its public key modulus.
01821  * Note that the nickname is optional.  It was only used by keyutil.
01822  */
01823 SECStatus
01824 nsslowkey_StoreKeyByPublicKeyAlg(NSSLOWKEYDBHandle *handle, 
01825                            NSSLOWKEYPrivateKey *privkey,
01826                            SECItem *pubKeyData,
01827                            char *nickname,
01828                            SECItem *pwitem,
01829                            SECOidTag algorithm,
01830                               PRBool update)
01831 {
01832     DBT namekey;
01833     SECStatus rv;
01834 
01835     if (handle == NULL) {
01836        PORT_SetError(SEC_ERROR_BAD_DATABASE);
01837        return(SECFailure);
01838     }
01839 
01840     /* set up db key and data */
01841     namekey.data = pubKeyData->data;
01842     namekey.size = pubKeyData->len;
01843 
01844     /* encrypt the private key */
01845     rv = seckey_put_private_key(handle, &namekey, pwitem, privkey, nickname,
01846                             update, algorithm);
01847     
01848     return(rv);
01849 }
01850 
01851 NSSLOWKEYPrivateKey *
01852 seckey_decrypt_private_key(NSSLOWKEYEncryptedPrivateKeyInfo *epki,
01853                         SECItem *pwitem)
01854 {
01855     NSSLOWKEYPrivateKey *pk = NULL;
01856     NSSLOWKEYPrivateKeyInfo *pki = NULL;
01857     SECStatus rv = SECFailure;
01858     SECOidTag algorithm;
01859     PLArenaPool *temparena = NULL, *permarena = NULL;
01860     SECItem *salt = NULL, *dest = NULL, *key = NULL;
01861     NSSPKCS5PBEParameter *param;
01862 #ifdef NSS_ENABLE_ECC
01863     ECPrivateKey *ecpriv;
01864     SECItem *fordebug = NULL;
01865     int i;
01866 #endif
01867 
01868     if((epki == NULL) || (pwitem == NULL))
01869        goto loser;
01870 
01871     temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
01872     permarena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
01873     if((temparena == NULL) || (permarena == NULL))
01874        goto loser;
01875 
01876     /* allocate temporary items */
01877     pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(temparena, 
01878        sizeof(NSSLOWKEYPrivateKeyInfo));
01879 
01880     /* allocate permanent arena items */
01881     pk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(permarena,
01882        sizeof(NSSLOWKEYPrivateKey));
01883 
01884     if((pk == NULL) || (pki == NULL))
01885        goto loser;
01886 
01887     pk->arena = permarena;
01888        
01889     algorithm = SECOID_GetAlgorithmTag(&(epki->algorithm));
01890     switch(algorithm)
01891     {
01892        case SEC_OID_RC4:
01893            salt = SECITEM_DupItem(&epki->algorithm.parameters);
01894            if(salt != NULL)
01895            {
01896               key = seckey_create_rc4_key(pwitem, salt);
01897               if(key != NULL)
01898               {
01899                   dest = seckey_rc4_decode(key, &epki->encryptedData);
01900               }
01901            }  
01902            if(salt != NULL)
01903               SECITEM_ZfreeItem(salt, PR_TRUE);
01904            if(key != NULL)
01905               SECITEM_ZfreeItem(key, PR_TRUE);
01906            break;
01907        default:
01908            /* we depend on the fact that if this key was encoded with
01909             * DES, that the pw was also encoded with DES, so we don't have
01910             * to do the update here, the password code will handle it. */
01911            param = nsspkcs5_AlgidToParam(&epki->algorithm);
01912            if (param == NULL) {
01913               break;
01914            }
01915            dest = nsspkcs5_CipherData(param, pwitem, &epki->encryptedData, 
01916                                                  PR_FALSE, NULL);
01917            nsspkcs5_DestroyPBEParameter(param);
01918            break;
01919     }
01920 
01921     if(dest != NULL)
01922     {
01923         SECItem newPrivateKey;
01924         SECItem newAlgParms;
01925 
01926         SEC_PRINT("seckey_decrypt_private_key()", "PrivateKeyInfo", -1,
01927                 dest);
01928 
01929        rv = SEC_QuickDERDecodeItem(temparena, pki, 
01930            nsslowkey_PrivateKeyInfoTemplate, dest);
01931        if(rv == SECSuccess)
01932        {
01933            switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
01934              case SEC_OID_X500_RSA_ENCRYPTION:
01935              case SEC_OID_PKCS1_RSA_ENCRYPTION:
01936               pk->keyType = NSSLOWKEYRSAKey;
01937               prepare_low_rsa_priv_key_for_asn1(pk);
01938                 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
01939                     &pki->privateKey) ) break;
01940               rv = SEC_QuickDERDecodeItem(permarena, pk,
01941                                    nsslowkey_RSAPrivateKeyTemplate,
01942                                    &newPrivateKey);
01943               break;
01944              case SEC_OID_ANSIX9_DSA_SIGNATURE:
01945               pk->keyType = NSSLOWKEYDSAKey;
01946               prepare_low_dsa_priv_key_for_asn1(pk);
01947                 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
01948                     &pki->privateKey) ) break;
01949               rv = SEC_QuickDERDecodeItem(permarena, pk,
01950                                    nsslowkey_DSAPrivateKeyTemplate,
01951                                    &newPrivateKey);
01952               if (rv != SECSuccess)
01953                   goto loser;
01954               prepare_low_pqg_params_for_asn1(&pk->u.dsa.params);
01955                 if (SECSuccess != SECITEM_CopyItem(permarena, &newAlgParms,
01956                     &pki->algorithm.parameters) ) break;
01957               rv = SEC_QuickDERDecodeItem(permarena, &pk->u.dsa.params,
01958                                    nsslowkey_PQGParamsTemplate,
01959                                    &newAlgParms);
01960               break;
01961              case SEC_OID_X942_DIFFIE_HELMAN_KEY:
01962               pk->keyType = NSSLOWKEYDHKey;
01963               prepare_low_dh_priv_key_for_asn1(pk);
01964                 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
01965                     &pki->privateKey) ) break;
01966               rv = SEC_QuickDERDecodeItem(permarena, pk,
01967                                    nsslowkey_DHPrivateKeyTemplate,
01968                                    &newPrivateKey);
01969               break;
01970 #ifdef NSS_ENABLE_ECC
01971              case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
01972               pk->keyType = NSSLOWKEYECKey;
01973               prepare_low_ec_priv_key_for_asn1(pk);
01974 
01975               fordebug = &pki->privateKey;
01976               SEC_PRINT("seckey_decrypt_private_key()", "PrivateKey", 
01977                        pk->keyType, fordebug);
01978                 if (SECSuccess != SECITEM_CopyItem(permarena, &newPrivateKey,
01979                     &pki->privateKey) ) break;
01980               rv = SEC_QuickDERDecodeItem(permarena, pk,
01981                                    nsslowkey_ECPrivateKeyTemplate,
01982                                    &newPrivateKey);
01983               if (rv != SECSuccess)
01984                   goto loser;
01985 
01986               prepare_low_ecparams_for_asn1(&pk->u.ec.ecParams);
01987 
01988               rv = SECITEM_CopyItem(permarena, 
01989                   &pk->u.ec.ecParams.DEREncoding, 
01990                   &pki->algorithm.parameters);
01991 
01992               if (rv != SECSuccess)
01993                   goto loser;
01994 
01995               /* Fill out the rest of EC params */
01996               rv = EC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding,
01997                                &pk->u.ec.ecParams);
01998 
01999               if (rv != SECSuccess)
02000                   goto loser;
02001 
02002               /* 
02003                * NOTE: Encoding of the publicValue is optional
02004                * so we need to be able to regenerate the publicValue
02005                * from the base point and the private key.
02006                *
02007                * XXX This part of the code needs more testing.
02008                */
02009               if (pk->u.ec.publicValue.len == 0) {
02010                   rv = EC_NewKeyFromSeed(&pk->u.ec.ecParams, 
02011                                   &ecpriv, pk->u.ec.privateValue.data,
02012                                   pk->u.ec.privateValue.len);
02013                   if (rv == SECSuccess) {
02014                      SECITEM_CopyItem(permarena, &pk->u.ec.publicValue,
02015                                     &(ecpriv->publicValue));
02016                      PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
02017                   }
02018               } else {
02019                   /* If publicValue was filled as part of DER decoding,
02020                    * change length in bits to length in bytes.
02021                    */
02022                   pk->u.ec.publicValue.len >>= 3;
02023               }
02024 
02025               break;
02026 #endif /* NSS_ENABLE_ECC */
02027              default:
02028               rv = SECFailure;
02029               break;
02030            }
02031        }
02032        else if(PORT_GetError() == SEC_ERROR_BAD_DER)
02033        {
02034            PORT_SetError(SEC_ERROR_BAD_PASSWORD);
02035            goto loser;
02036        }
02037     }
02038 
02039     /* let success fall through */
02040 loser:
02041     if(temparena != NULL)
02042        PORT_FreeArena(temparena, PR_TRUE);
02043     if(dest != NULL)
02044        SECITEM_ZfreeItem(dest, PR_TRUE);
02045 
02046     if(rv != SECSuccess)
02047     {
02048        if(permarena != NULL)
02049            PORT_FreeArena(permarena, PR_TRUE);
02050        pk = NULL;
02051     }
02052 
02053     return pk;
02054 }
02055 
02056 static NSSLOWKEYPrivateKey *
02057 seckey_decode_encrypted_private_key(NSSLOWKEYDBKey *dbkey, SECItem *pwitem)
02058 {
02059     NSSLOWKEYPrivateKey *pk = NULL;
02060     NSSLOWKEYEncryptedPrivateKeyInfo *epki;
02061     PLArenaPool *temparena = NULL;
02062     SECStatus rv;
02063     SECOidTag algorithm;
02064 
02065     if( ( dbkey == NULL ) || ( pwitem == NULL ) ) {
02066        return NULL;
02067     }
02068 
02069     temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02070     if(temparena == NULL) {
02071        return NULL;
02072     }
02073 
02074     epki = (NSSLOWKEYEncryptedPrivateKeyInfo *)
02075        PORT_ArenaZAlloc(temparena, sizeof(NSSLOWKEYEncryptedPrivateKeyInfo));
02076 
02077     if(epki == NULL) {
02078        goto loser;
02079     }
02080 
02081     rv = SEC_QuickDERDecodeItem(temparena, epki,
02082                          nsslowkey_EncryptedPrivateKeyInfoTemplate,
02083                          &(dbkey->derPK)); 
02084     if(rv != SECSuccess) {
02085        goto loser;
02086     }
02087 
02088     algorithm = SECOID_GetAlgorithmTag(&(epki->algorithm));
02089     switch(algorithm)
02090     {
02091       case SEC_OID_RC4:
02092        /* TNH - this code should derive the actual RC4 key from salt and
02093            pwitem */
02094        rv = SECITEM_CopyItem(temparena, &(epki->algorithm.parameters),
02095                            &(dbkey->salt));
02096        break;
02097       default:
02098        break;
02099     }
02100 
02101     pk = seckey_decrypt_private_key(epki, pwitem);
02102 
02103     /* let success fall through */
02104 loser:
02105 
02106     PORT_FreeArena(temparena, PR_TRUE);
02107     return pk;
02108 }
02109 
02110 NSSLOWKEYPrivateKey *
02111 seckey_get_private_key(NSSLOWKEYDBHandle *keydb, DBT *index, char **nickname,
02112                      SECItem *pwitem)
02113 {
02114     NSSLOWKEYDBKey *dbkey = NULL;
02115     NSSLOWKEYPrivateKey *pk = NULL;
02116 
02117     if( ( keydb == NULL ) || ( index == NULL ) || ( pwitem == NULL ) ) {
02118        return NULL;
02119     }
02120 
02121     dbkey = get_dbkey(keydb, index);
02122     if(dbkey == NULL) {
02123        goto loser;
02124     }
02125     
02126     if ( nickname ) {
02127        if ( dbkey->nickname && ( dbkey->nickname[0] != 0 ) ) {
02128            *nickname = PORT_Strdup(dbkey->nickname);
02129        } else {
02130            *nickname = NULL;
02131        }
02132     }
02133     
02134     pk = seckey_decode_encrypted_private_key(dbkey, pwitem);
02135     
02136     /* let success fall through */
02137 loser:
02138 
02139     if ( dbkey != NULL ) {
02140        sec_destroy_dbkey(dbkey);
02141     }
02142 
02143     return pk;
02144 }
02145 
02146 /*
02147  * used by pkcs11 to import keys into it's object format... In the future
02148  * we really need a better way to tie in...
02149  */
02150 NSSLOWKEYPrivateKey *
02151 nsslowkey_DecryptKey(DBT *key, SECItem *pwitem,
02152                                     NSSLOWKEYDBHandle *handle) {
02153     return seckey_get_private_key(handle,key,NULL,pwitem);
02154 }
02155 
02156 /*
02157  * Find a key in the database, indexed by its public key modulus
02158  * This is used to find keys that have been stored before their
02159  * certificate arrives.  Once the certificate arrives the key
02160  * is looked up by the public modulus in the certificate, and the
02161  * re-stored by its nickname.
02162  */
02163 NSSLOWKEYPrivateKey *
02164 nsslowkey_FindKeyByPublicKey(NSSLOWKEYDBHandle *handle, SECItem *modulus,
02165                                                   SECItem *pwitem)
02166 {
02167     DBT namekey;
02168     NSSLOWKEYPrivateKey *pk = NULL;
02169 
02170     if (handle == NULL) {
02171        PORT_SetError(SEC_ERROR_BAD_DATABASE);
02172        return NULL;
02173     }
02174 
02175     /* set up db key */
02176     namekey.data = modulus->data;
02177     namekey.size = modulus->len;
02178 
02179     pk = seckey_get_private_key(handle, &namekey, NULL, pwitem);
02180     
02181     /* no need to free dbkey, since its on the stack, and the data it
02182      * points to is owned by the database
02183      */
02184     return(pk);
02185 }
02186 
02187 char *
02188 nsslowkey_FindKeyNicknameByPublicKey(NSSLOWKEYDBHandle *handle, 
02189                                    SECItem *modulus, SECItem *pwitem)
02190 {
02191     DBT namekey;
02192     NSSLOWKEYPrivateKey *pk = NULL;
02193     char *nickname = NULL;
02194 
02195     if (handle == NULL) {
02196        PORT_SetError(SEC_ERROR_BAD_DATABASE);
02197        return NULL;
02198     }
02199 
02200     /* set up db key */
02201     namekey.data = modulus->data;
02202     namekey.size = modulus->len;
02203 
02204     pk = seckey_get_private_key(handle, &namekey, &nickname, pwitem);
02205     if (pk) {
02206        nsslowkey_DestroyPrivateKey(pk);
02207     }
02208     
02209     /* no need to free dbkey, since its on the stack, and the data it
02210      * points to is owned by the database
02211      */
02212     return(nickname);
02213 }
02214 /* ===== ENCODING ROUTINES ===== */
02215 
02216 static SECStatus
02217 encodePWCheckEntry(PLArenaPool *arena, SECItem *entry, SECOidTag alg,
02218                  SECItem *encCheck)
02219 {
02220     SECOidData *oidData;
02221     SECStatus rv;
02222     
02223     oidData = SECOID_FindOIDByTag(alg);
02224     if ( oidData == NULL ) {
02225        rv = SECFailure;
02226        goto loser;
02227     }
02228 
02229     entry->len = 1 + oidData->oid.len + encCheck->len;
02230     if ( arena ) {
02231        entry->data = (unsigned char *)PORT_ArenaAlloc(arena, entry->len);
02232     } else {
02233        entry->data = (unsigned char *)PORT_Alloc(entry->len);
02234     }
02235     
02236     if ( entry->data == NULL ) {
02237        goto loser;
02238     }
02239        
02240     /* first length of oid */
02241     entry->data[0] = (unsigned char)oidData->oid.len;
02242     /* next oid itself */
02243     PORT_Memcpy(&entry->data[1], oidData->oid.data, oidData->oid.len);
02244     /* finally the encrypted check string */
02245     PORT_Memcpy(&entry->data[1+oidData->oid.len], encCheck->data,
02246               encCheck->len);
02247 
02248     return(SECSuccess);
02249 
02250 loser:
02251     return(SECFailure);
02252 }
02253 
02254 /*
02255  * Set up the password checker in the key database.
02256  * This is done by encrypting a known plaintext with the user's key.
02257  */
02258 SECStatus
02259 nsslowkey_SetKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle, 
02260                         SECItem *pwitem, SECOidTag algorithm)
02261 {
02262     DBT checkkey;
02263     NSSPKCS5PBEParameter *param = NULL;
02264     SECStatus rv = SECFailure;
02265     NSSLOWKEYDBKey *dbkey = NULL;
02266     PLArenaPool *arena;
02267     SECItem *salt = NULL;
02268     SECItem *dest = NULL, test_key;
02269     
02270     if (handle == NULL) {
02271        return(SECFailure);
02272     }
02273 
02274     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02275     if ( arena == NULL ) {
02276        rv = SECFailure;
02277        goto loser;
02278     }
02279     
02280     dbkey = (NSSLOWKEYDBKey *)PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYDBKey));
02281     if ( dbkey == NULL ) {
02282        rv = SECFailure;
02283        goto loser;
02284     }
02285     
02286     dbkey->arena = arena;
02287 
02288     /* encrypt key */
02289     checkkey.data = test_key.data = (unsigned char *)KEYDB_PW_CHECK_STRING;
02290     checkkey.size = test_key.len = KEYDB_PW_CHECK_LEN;
02291 
02292     salt = seckey_create_rc4_salt();
02293     if(salt == NULL) {
02294        rv = SECFailure;
02295        goto loser;
02296     }
02297 
02298     param = nsspkcs5_NewParam(algorithm, salt, 1);
02299     if (param == NULL) {
02300        rv = SECFailure;
02301        goto loser;
02302     }
02303 
02304     dest = nsspkcs5_CipherData(param, pwitem, &test_key, PR_TRUE, NULL);
02305     if (dest == NULL)
02306     {
02307        rv = SECFailure;
02308        goto loser;
02309     }
02310 
02311     rv = SECITEM_CopyItem(arena, &dbkey->salt, salt);
02312     if (rv == SECFailure) {
02313        goto loser;
02314     }
02315    
02316     rv = encodePWCheckEntry(arena, &dbkey->derPK, algorithm, dest);
02317        
02318     if ( rv != SECSuccess ) {
02319        goto loser;
02320     }
02321        
02322     rv = put_dbkey(handle, &checkkey, dbkey, PR_TRUE);
02323     
02324     /* let success fall through */
02325 loser: 
02326     if ( arena != NULL ) {
02327        PORT_FreeArena(arena, PR_TRUE);
02328     }
02329     
02330     if ( dest != NULL ) {
02331        SECITEM_ZfreeItem(dest, PR_TRUE);
02332     }
02333     
02334     if ( salt != NULL ) {
02335        SECITEM_ZfreeItem(salt, PR_TRUE);
02336     }
02337 
02338     if (param != NULL) {
02339        nsspkcs5_DestroyPBEParameter(param);
02340     }
02341        
02342     return(rv);
02343 }
02344 
02345 static SECStatus
02346 seckey_CheckKeyDB1Password(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
02347 {
02348     SECStatus rv = SECFailure;
02349     keyList keylist;
02350     keyNode *node = NULL;
02351     NSSLOWKEYPrivateKey *privkey = NULL;
02352 
02353 
02354     /*
02355      * first find a key
02356      */
02357 
02358     /* traverse the database, collecting the keys of all records */
02359     keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02360     if ( keylist.arena == NULL ) 
02361     {
02362        PORT_SetError(SEC_ERROR_NO_MEMORY);
02363        return(SECFailure);
02364     }
02365     keylist.head = NULL;
02366     
02367     /* TNH - TraverseKeys should not be public, since it exposes
02368        the underlying DBT data type. */
02369     rv = nsslowkey_TraverseKeys(handle, sec_add_key_to_list, (void *)&keylist);
02370     if ( rv != SECSuccess ) 
02371        goto done;
02372 
02373     /* just get the first key from the list */
02374     node = keylist.head;
02375 
02376     /* no private keys, accept any password */
02377     if (node == NULL) {
02378        rv = SECSuccess;
02379        goto done;
02380     }
02381     privkey = seckey_get_private_key(handle, &node->key, NULL, pwitem);
02382     if (privkey == NULL) {
02383         rv = SECFailure;
02384         goto done;
02385     }
02386 
02387     /* if we can decrypt the private key, then we had the correct password */
02388     rv = SECSuccess;
02389     nsslowkey_DestroyPrivateKey(privkey);
02390 
02391 done:
02392 
02393     /* free the arena */
02394     if ( keylist.arena ) {
02395        PORT_FreeArena(keylist.arena, PR_FALSE);
02396     }
02397     
02398     return(rv);
02399 }
02400 
02401 /*
02402  * check to see if the user has typed the right password
02403  */
02404 SECStatus
02405 nsslowkey_CheckKeyDBPassword(NSSLOWKEYDBHandle *handle, SECItem *pwitem)
02406 {
02407     DBT checkkey;
02408     DBT checkdata;
02409     NSSPKCS5PBEParameter *param = NULL;
02410     SECStatus rv = SECFailure;
02411     NSSLOWKEYDBKey *dbkey = NULL;
02412     SECItem *key = NULL;
02413     SECItem *dest = NULL;
02414     SECOidTag algorithm;
02415     SECItem oid;
02416     SECItem encstring;
02417     PRBool update = PR_FALSE;
02418     int ret;
02419     
02420     if (handle == NULL) {
02421        goto loser;
02422     }
02423 
02424     checkkey.data = KEYDB_PW_CHECK_STRING;
02425     checkkey.size = KEYDB_PW_CHECK_LEN;
02426     
02427     dbkey = get_dbkey(handle, &checkkey);
02428     
02429     if ( dbkey == NULL ) {
02430        checkkey.data = KEYDB_FAKE_PW_CHECK_STRING;
02431        checkkey.size = KEYDB_FAKE_PW_CHECK_LEN;
02432        ret = keydb_Get(handle, &checkkey, &checkdata, 0 );
02433        if (ret) {
02434            goto loser;
02435        }
02436        /* if we have the fake PW_CHECK, then try to decode the key
02437         * rather than the pwcheck item.
02438         */
02439        rv = seckey_CheckKeyDB1Password(handle,pwitem);
02440        if (rv == SECSuccess) {
02441            /* OK we have enough to complete our conversion */
02442            nsslowkey_UpdateKeyDBPass2(handle,pwitem);
02443        }
02444        return rv;
02445     }
02446 
02447     /* build the oid item */
02448     oid.len = dbkey->derPK.data[0];
02449     oid.data = &dbkey->derPK.data[1];
02450     
02451     /* make sure entry is the correct length
02452      * since we are probably using a block cipher, the block will be
02453      * padded, so we may get a bit more than the exact size we need.
02454      */
02455     if ( dbkey->derPK.len < (KEYDB_PW_CHECK_LEN + 1 + oid.len ) ) {
02456        goto loser;
02457     }
02458 
02459     /* find the algorithm tag */
02460     algorithm = SECOID_FindOIDTag(&oid);
02461 
02462     /* make a secitem of the encrypted check string */
02463     encstring.len = dbkey->derPK.len - ( oid.len + 1 );
02464     encstring.data = &dbkey->derPK.data[oid.len+1];
02465     encstring.type = 0;
02466     
02467     switch(algorithm)
02468     {
02469        case SEC_OID_RC4:
02470            key = seckey_create_rc4_key(pwitem, &dbkey->salt);
02471            if(key != NULL) {
02472               dest = seckey_rc4_decode(key, &encstring);
02473               SECITEM_FreeItem(key, PR_TRUE);
02474            }
02475            break;
02476        default:
02477            param = nsspkcs5_NewParam(algorithm, &dbkey->salt, 1);
02478            if (param != NULL) {
02479                 /* Decrypt - this function implements a workaround for
02480                  * a previous coding error.  It will decrypt values using
02481                  * DES rather than 3DES, if the initial try at 3DES
02482                  * decryption fails.  In this case, the update flag is
02483                  * set to TRUE.  This indication is used later to force
02484                  * an update of the database to "real" 3DES encryption.
02485                  */
02486               dest = nsspkcs5_CipherData(param, pwitem, 
02487                                       &encstring, PR_FALSE, &update);
02488               nsspkcs5_DestroyPBEParameter(param);
02489            }  
02490            break;
02491     }
02492 
02493     if(dest == NULL) {
02494        goto loser;
02495     }
02496 
02497     if ((dest->len == KEYDB_PW_CHECK_LEN) &&
02498        (PORT_Memcmp(dest->data, 
02499                    KEYDB_PW_CHECK_STRING, KEYDB_PW_CHECK_LEN) == 0)) {
02500        rv = SECSuccess;
02501        /* we succeeded */
02502        if ( algorithm == SEC_OID_RC4 ) {
02503            /* partially updated database */
02504            nsslowkey_UpdateKeyDBPass2(handle, pwitem);
02505        }
02506         /* Force an update of the password to remove the incorrect DES
02507          * encryption (see the note above)
02508          */
02509        if (update && 
02510             (algorithm == SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC)) {
02511            /* data base was encoded with DES not triple des, fix it */
02512            nsslowkey_UpdateKeyDBPass2(handle,pwitem);
02513        }
02514     }
02515                      
02516 loser:
02517     sec_destroy_dbkey(dbkey);
02518     if(dest != NULL) {
02519        SECITEM_ZfreeItem(dest, PR_TRUE);
02520     }
02521 
02522     return(rv);
02523 }
02524 
02525 /*
02526  *  Change the database password and/or algorithm.  This internal
02527  *  routine does not check the old password.  That must be done by 
02528  *  the caller.
02529  */
02530 static SECStatus
02531 ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle *handle,
02532                      SECItem *oldpwitem, SECItem *newpwitem,
02533                      SECOidTag new_algorithm)
02534 {
02535     SECStatus rv;
02536     keyList keylist;
02537     keyNode *node = NULL;
02538     NSSLOWKEYPrivateKey *privkey = NULL;
02539     char *nickname;
02540     DBT newkey;
02541     int ret;
02542 
02543     /* traverse the database, collecting the keys of all records */
02544     keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02545     if ( keylist.arena == NULL ) 
02546     {
02547        PORT_SetError(SEC_ERROR_NO_MEMORY);
02548        return(SECFailure);
02549     }
02550     keylist.head = NULL;
02551 
02552     rv = db_BeginTransaction(handle->db);
02553     if (rv != SECSuccess) {
02554        goto loser;
02555     }
02556     
02557     /* TNH - TraverseKeys should not be public, since it exposes
02558        the underlying DBT data type. */
02559     rv = nsslowkey_TraverseKeys(handle, sec_add_key_to_list, (void *)&keylist);
02560     if ( rv != SECSuccess ) 
02561        goto loser;
02562 
02563     /* walk the list, re-encrypting each entry */
02564     node = keylist.head;
02565     while ( node != NULL ) 
02566     {
02567        privkey = seckey_get_private_key(handle, &node->key, &nickname,
02568                                     oldpwitem);
02569        
02570        if (privkey == NULL) {
02571            PORT_SetError(SEC_ERROR_BAD_DATABASE);
02572            rv = SECFailure;
02573            goto loser;
02574        }
02575 
02576        /* delete the old record */
02577        ret = keydb_Del(handle, &node->key, 0);
02578        if ( ret ) {
02579            PORT_SetError(SEC_ERROR_BAD_DATABASE);
02580            rv = SECFailure;
02581            goto loser;
02582        }
02583        
02584        /* get the public key, which we use as the database index */
02585 
02586        switch (privkey->keyType) {
02587          case NSSLOWKEYRSAKey:
02588            newkey.data = privkey->u.rsa.modulus.data;
02589            newkey.size = privkey->u.rsa.modulus.len;
02590            break;
02591          case NSSLOWKEYDSAKey:
02592            newkey.data = privkey->u.dsa.publicValue.data;
02593            newkey.size = privkey->u.dsa.publicValue.len;
02594            break;
02595          case NSSLOWKEYDHKey:
02596            newkey.data = privkey->u.dh.publicValue.data;
02597            newkey.size = privkey->u.dh.publicValue.len;
02598            break;
02599 #ifdef NSS_ENABLE_ECC
02600          case NSSLOWKEYECKey:
02601            newkey.data = privkey->u.ec.publicValue.data;
02602            newkey.size = privkey->u.ec.publicValue.len;
02603            break;
02604 #endif /* NSS_ENABLE_ECC */
02605          default:
02606            /* should we continue here and loose the key? */
02607            PORT_SetError(SEC_ERROR_BAD_DATABASE);
02608            rv = SECFailure;
02609            goto loser;
02610        }
02611 
02612        rv = seckey_put_private_key(handle, &newkey, newpwitem, privkey,
02613                                 nickname, PR_TRUE, new_algorithm);
02614        
02615        if ( rv != SECSuccess ) 
02616        {
02617            PORT_SetError(SEC_ERROR_BAD_DATABASE);
02618            rv = SECFailure;
02619            goto loser;
02620        }
02621 
02622        /* next node */
02623        node = node->next;
02624     }
02625 
02626     rv = nsslowkey_SetKeyDBPasswordAlg(handle, newpwitem, new_algorithm);
02627 
02628 loser:
02629 
02630     db_FinishTransaction(handle->db,rv != SECSuccess);
02631 
02632     /* free the arena */
02633     if ( keylist.arena ) {
02634        PORT_FreeArena(keylist.arena, PR_FALSE);
02635     }
02636     
02637     return(rv);
02638 }
02639 
02640 /*
02641  * Re-encrypt the entire key database with a new password.
02642  * NOTE: The really  should create a new database rather than doing it
02643  * in place in the original
02644  */
02645 SECStatus
02646 nsslowkey_ChangeKeyDBPassword(NSSLOWKEYDBHandle *handle,
02647                            SECItem *oldpwitem, SECItem *newpwitem)
02648 {
02649     SECStatus rv;
02650     
02651     if (handle == NULL) {
02652        PORT_SetError(SEC_ERROR_BAD_DATABASE);
02653        rv = SECFailure;
02654        goto loser;
02655     }
02656 
02657     rv = nsslowkey_CheckKeyDBPassword(handle, oldpwitem);
02658     if ( rv != SECSuccess ) {
02659        return(SECFailure);  /* return rv? */
02660     }
02661 
02662     rv = ChangeKeyDBPasswordAlg(handle, oldpwitem, newpwitem, 
02663                             nsslowkey_GetDefaultKeyDBAlg());
02664 
02665 loser:
02666     return(rv);
02667 }
02668     
02669 
02670 #define MAX_DB_SIZE 0xffff 
02671 /*
02672  * Clear out all the keys in the existing database
02673  */
02674 SECStatus
02675 nsslowkey_ResetKeyDB(NSSLOWKEYDBHandle *handle)
02676 {
02677     SECStatus rv;
02678     int ret;
02679     int errors = 0;
02680 
02681     if ( handle->db == NULL ) {
02682        return(SECSuccess);
02683     }
02684 
02685     if (handle->readOnly) {
02686        /* set an error code */
02687        return SECFailure;
02688      }
02689 
02690     if (handle->appname == NULL && handle->dbname == NULL) {
02691        return SECFailure;
02692     }
02693 
02694     keydb_Close(handle);
02695     if (handle->appname) {
02696        handle->db= 
02697            rdbopen(handle->appname, handle->dbname, "key", NO_CREATE, NULL);
02698     } else {
02699        handle->db = dbopen( handle->dbname, NO_CREATE, 0600, DB_HASH, 0 );
02700     }
02701     if (handle->db == NULL) {
02702        /* set an error code */
02703        return SECFailure;
02704     }
02705     
02706     rv = makeGlobalVersion(handle);
02707     if ( rv != SECSuccess ) {
02708        errors++;
02709        goto done;
02710     }
02711 
02712     if (handle->global_salt) {
02713        rv = StoreKeyDBGlobalSalt(handle);
02714     } else {
02715        rv = makeGlobalSalt(handle);
02716        if ( rv == SECSuccess ) {
02717            handle->global_salt = GetKeyDBGlobalSalt(handle);
02718        }
02719     }
02720     if ( rv != SECSuccess ) {
02721        errors++;
02722     }
02723 
02724 done:
02725     /* sync the database */
02726     ret = keydb_Sync(handle, 0);
02727     db_InitComplete(handle->db);
02728 
02729     return (errors == 0 ? SECSuccess : SECFailure);
02730 }
02731 
02732 static int
02733 keydb_Get(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
02734 {
02735     PRStatus prstat;
02736     int ret;
02737     PRLock *kdbLock = kdb->lock;
02738     DB *db = kdb->db;
02739     
02740     PORT_Assert(kdbLock != NULL);
02741     PZ_Lock(kdbLock);
02742 
02743     ret = (* db->get)(db, key, data, flags);
02744 
02745     prstat = PZ_Unlock(kdbLock);
02746 
02747     return(ret);
02748 }
02749 
02750 static int
02751 keydb_Put(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
02752 {
02753     PRStatus prstat;
02754     int ret = 0;
02755     PRLock *kdbLock = kdb->lock;
02756     DB *db = kdb->db;
02757 
02758     PORT_Assert(kdbLock != NULL);
02759     PZ_Lock(kdbLock);
02760 
02761     ret = (* db->put)(db, key, data, flags);
02762     
02763     prstat = PZ_Unlock(kdbLock);
02764 
02765     return(ret);
02766 }
02767 
02768 static int
02769 keydb_Sync(NSSLOWKEYDBHandle *kdb, unsigned int flags)
02770 {
02771     PRStatus prstat;
02772     int ret;
02773     PRLock *kdbLock = kdb->lock;
02774     DB *db = kdb->db;
02775 
02776     PORT_Assert(kdbLock != NULL);
02777     PZ_Lock(kdbLock);
02778 
02779     ret = (* db->sync)(db, flags);
02780     
02781     prstat = PZ_Unlock(kdbLock);
02782 
02783     return(ret);
02784 }
02785 
02786 static int
02787 keydb_Del(NSSLOWKEYDBHandle *kdb, DBT *key, unsigned int flags)
02788 {
02789     PRStatus prstat;
02790     int ret;
02791     PRLock *kdbLock = kdb->lock;
02792     DB *db = kdb->db;
02793 
02794     PORT_Assert(kdbLock != NULL);
02795     PZ_Lock(kdbLock);
02796 
02797     ret = (* db->del)(db, key, flags);
02798     
02799     prstat = PZ_Unlock(kdbLock);
02800 
02801     return(ret);
02802 }
02803 
02804 static int
02805 keydb_Seq(NSSLOWKEYDBHandle *kdb, DBT *key, DBT *data, unsigned int flags)
02806 {
02807     PRStatus prstat;
02808     int ret;
02809     PRLock *kdbLock = kdb->lock;
02810     DB *db = kdb->db;
02811     
02812     PORT_Assert(kdbLock != NULL);
02813     PZ_Lock(kdbLock);
02814     
02815     ret = (* db->seq)(db, key, data, flags);
02816 
02817     prstat = PZ_Unlock(kdbLock);
02818 
02819     return(ret);
02820 }
02821 
02822 static void
02823 keydb_Close(NSSLOWKEYDBHandle *kdb)
02824 {
02825     PRStatus prstat;
02826     PRLock *kdbLock = kdb->lock;
02827     DB *db = kdb->db;
02828 
02829     PORT_Assert(kdbLock != NULL);
02830     PZ_Lock(kdbLock);
02831 
02832     (* db->close)(db);
02833     
02834     prstat = PZ_Unlock(kdbLock);
02835 
02836     return;
02837 }
02838