tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

keydb.c (61987B)


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