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