tor-browser

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

sftkpwd.c (46623B)


      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 *  The following code handles the storage of PKCS 11 modules used by the
      6 * NSS. For the rest of NSS, only one kind of database handle exists:
      7 *
      8 *     SFTKDBHandle
      9 *
     10 * There is one SFTKDBHandle for the each key database and one for each cert
     11 * database. These databases are opened as associated pairs, one pair per
     12 * slot. SFTKDBHandles are reference counted objects.
     13 *
     14 * Each SFTKDBHandle points to a low level database handle (SDB). This handle
     15 * represents the underlying physical database. These objects are not
     16 * reference counted, an are 'owned' by their respective SFTKDBHandles.
     17 *
     18 *
     19 */
     20 #include "sftkdb.h"
     21 #include "sftkdbti.h"
     22 #include "pkcs11t.h"
     23 #include "pkcs11i.h"
     24 #include "sdb.h"
     25 #include "prprf.h"
     26 #include "secasn1.h"
     27 #include "pratom.h"
     28 #include "blapi.h"
     29 #include "secoid.h"
     30 #include "lowpbe.h"
     31 #include "secdert.h"
     32 #include "prsystem.h"
     33 #include "lgglue.h"
     34 #include "secerr.h"
     35 #include "softoken.h"
     36 
     37 static const int NSS_MP_PBE_ITERATION_COUNT = 10000;
     38 
     39 static int
     40 getPBEIterationCount(void)
     41 {
     42    int c = NSS_MP_PBE_ITERATION_COUNT;
     43 
     44    char *val = getenv("NSS_MIN_MP_PBE_ITERATION_COUNT");
     45    if (val && *val) {
     46        int minimum = atoi(val);
     47        if (c < minimum) {
     48            c = minimum;
     49        }
     50    }
     51 
     52    val = getenv("NSS_MAX_MP_PBE_ITERATION_COUNT");
     53    if (val && *val) {
     54        int maximum = atoi(val);
     55        if (c > maximum) {
     56            c = maximum;
     57        }
     58    }
     59    /* never let c be less than one, no matter what the environment
     60     * variable is set to */
     61    if (c < 1) {
     62        c = 1;
     63    }
     64    return c;
     65 }
     66 
     67 PRBool
     68 sftk_isLegacyIterationCountAllowed(void)
     69 {
     70    static const char *legacyCountEnvVar =
     71        "NSS_ALLOW_LEGACY_DBM_ITERATION_COUNT";
     72    char *iterEnv = getenv(legacyCountEnvVar);
     73    return (iterEnv && strcmp("0", iterEnv) != 0);
     74 }
     75 
     76 /******************************************************************
     77 *
     78 * Key DB password handling functions
     79 *
     80 * These functions manage the key db password (set, reset, initialize, use).
     81 *
     82 * The key is managed on 'this side' of the database. All private data is
     83 * encrypted before it is sent to the database itself. Besides PBE's, the
     84 * database management code can also mix in various fixed keys so the data
     85 * in the database is no longer considered 'plain text'.
     86 */
     87 
     88 /* take string password and turn it into a key. The key is dependent
     89 * on a global salt entry acquired from the database. This salted
     90 * value will be based to a pkcs5 pbe function before it is used
     91 * in an actual encryption */
     92 static SECStatus
     93 sftkdb_passwordToKey(SFTKDBHandle *keydb, SECItem *salt,
     94                     const char *pw, SECItem *key)
     95 {
     96    HASH_HashType hType;
     97    const SECHashObject *hashObj;
     98    void *ctx = NULL;
     99    SECStatus rv = SECFailure;
    100 
    101    hType = salt->len == SHA384_LENGTH ? HASH_AlgSHA384 : HASH_AlgSHA1;
    102    hashObj = HASH_GetRawHashObject(hType);
    103 
    104    if (!pw) {
    105        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    106        return SECFailure;
    107    }
    108 
    109    key->data = PORT_Alloc(hashObj->length);
    110    if (key->data == NULL) {
    111        goto loser;
    112    }
    113    key->len = hashObj->length;
    114 
    115    ctx = hashObj->create();
    116    if (ctx == NULL) {
    117        goto loser;
    118    }
    119    hashObj->begin(ctx);
    120    if (salt && salt->data) {
    121        hashObj->update(ctx, salt->data, salt->len);
    122    }
    123    hashObj->update(ctx, (unsigned char *)pw, PORT_Strlen(pw));
    124    hashObj->end(ctx, key->data, &key->len, key->len);
    125    rv = SECSuccess;
    126 
    127 loser:
    128    if (ctx) {
    129        hashObj->destroy(ctx, PR_TRUE);
    130    }
    131    if (rv != SECSuccess) {
    132        if (key->data != NULL) {
    133            PORT_ZFree(key->data, key->len);
    134        }
    135        key->data = NULL;
    136    }
    137    return rv;
    138 }
    139 
    140 /*
    141 * Cipher text stored in the database contains 3 elements:
    142 * 1) an identifier describing the encryption algorithm.
    143 * 2) an entry specific salt value.
    144 * 3) the encrypted value.
    145 *
    146 * The following data structure represents the encrypted data in a decoded
    147 * (but still encrypted) form.
    148 */
    149 typedef struct sftkCipherValueStr sftkCipherValue;
    150 struct sftkCipherValueStr {
    151    PLArenaPool *arena;
    152    SECOidTag alg;
    153    NSSPKCS5PBEParameter *param;
    154    SECItem salt;
    155    SECItem value;
    156 };
    157 
    158 #define SFTK_CIPHERTEXT_VERSION 3
    159 
    160 struct SFTKDBEncryptedDataInfoStr {
    161    SECAlgorithmID algorithm;
    162    SECItem encryptedData;
    163 };
    164 typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo;
    165 
    166 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    167 
    168 const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate[] = {
    169    { SEC_ASN1_SEQUENCE,
    170      0, NULL, sizeof(SFTKDBEncryptedDataInfo) },
    171    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    172      offsetof(SFTKDBEncryptedDataInfo, algorithm),
    173      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
    174    { SEC_ASN1_OCTET_STRING,
    175      offsetof(SFTKDBEncryptedDataInfo, encryptedData) },
    176    { 0 }
    177 };
    178 
    179 /*
    180 * This parses the cipherText into cipher value. NOTE: cipherValue will point
    181 * to data in cipherText, if cipherText is freed, cipherValue will be invalid.
    182 */
    183 static SECStatus
    184 sftkdb_decodeCipherText(const SECItem *cipherText, sftkCipherValue *cipherValue)
    185 {
    186    PLArenaPool *arena = NULL;
    187    SFTKDBEncryptedDataInfo edi;
    188    SECStatus rv;
    189 
    190    PORT_Assert(cipherValue);
    191    cipherValue->arena = NULL;
    192    cipherValue->param = NULL;
    193 
    194    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    195    if (arena == NULL) {
    196        return SECFailure;
    197    }
    198 
    199    rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate,
    200                                cipherText);
    201    if (rv != SECSuccess) {
    202        goto loser;
    203    }
    204    cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm);
    205    cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm);
    206    if (cipherValue->param == NULL) {
    207        goto loser;
    208    }
    209    cipherValue->value = edi.encryptedData;
    210    cipherValue->arena = arena;
    211 
    212    return SECSuccess;
    213 loser:
    214    if (cipherValue->param) {
    215        nsspkcs5_DestroyPBEParameter(cipherValue->param);
    216        cipherValue->param = NULL;
    217    }
    218    if (arena) {
    219        PORT_FreeArena(arena, PR_FALSE);
    220    }
    221    return SECFailure;
    222 }
    223 
    224 /*
    225 * unlike decode, Encode actually allocates a SECItem the caller must free
    226 * The caller can pass an optional arena to to indicate where to place
    227 * the resultant cipherText.
    228 */
    229 static SECStatus
    230 sftkdb_encodeCipherText(PLArenaPool *arena, sftkCipherValue *cipherValue,
    231                        SECItem **cipherText)
    232 {
    233    SFTKDBEncryptedDataInfo edi;
    234    SECAlgorithmID *algid;
    235    SECStatus rv;
    236    PLArenaPool *localArena = NULL;
    237 
    238    localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    239    if (localArena == NULL) {
    240        return SECFailure;
    241    }
    242 
    243    algid = nsspkcs5_CreateAlgorithmID(localArena, cipherValue->alg,
    244                                       cipherValue->param);
    245    if (algid == NULL) {
    246        rv = SECFailure;
    247        goto loser;
    248    }
    249    rv = SECOID_CopyAlgorithmID(localArena, &edi.algorithm, algid);
    250    SECOID_DestroyAlgorithmID(algid, PR_TRUE);
    251    if (rv != SECSuccess) {
    252        goto loser;
    253    }
    254    edi.encryptedData = cipherValue->value;
    255 
    256    *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi,
    257                                     sftkdb_EncryptedDataInfoTemplate);
    258    if (*cipherText == NULL) {
    259        rv = SECFailure;
    260    }
    261 
    262 loser:
    263    if (localArena) {
    264        PORT_FreeArena(localArena, PR_TRUE);
    265    }
    266 
    267    return rv;
    268 }
    269 
    270 /*
    271 * Use our key to decode a cipherText block from the database.
    272 *
    273 * plain text is allocated by nsspkcs5_CipherData and must be freed
    274 * with SECITEM_FreeItem by the caller.
    275 */
    276 SECStatus
    277 sftkdb_DecryptAttribute(SFTKDBHandle *handle, SECItem *passKey,
    278                        CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type,
    279                        SECItem *cipherText, SECItem **plain)
    280 {
    281    SECStatus rv;
    282    sftkCipherValue cipherValue;
    283 
    284    /* First get the cipher type */
    285    *plain = NULL;
    286    rv = sftkdb_decodeCipherText(cipherText, &cipherValue);
    287    if (rv != SECSuccess) {
    288        goto loser;
    289    }
    290 
    291    *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value,
    292                                 PR_FALSE, NULL);
    293    if (*plain == NULL) {
    294        rv = SECFailure;
    295        goto loser;
    296    }
    297 
    298    /* If we are using aes 256, we need to check authentication as well.*/
    299    if ((type != CKT_INVALID_TYPE) &&
    300        (cipherValue.alg == SEC_OID_PKCS5_PBES2) &&
    301        (cipherValue.param->encAlg == SEC_OID_AES_256_CBC)) {
    302        SECItem signature;
    303        unsigned char signData[SDB_MAX_META_DATA_LEN];
    304        CK_RV crv;
    305 
    306        /* if we get here from the old legacy db, there is clearly an
    307         * error, don't return the plaintext */
    308        if (handle == NULL) {
    309            rv = SECFailure;
    310            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    311            goto loser;
    312        }
    313 
    314        signature.data = signData;
    315        signature.len = sizeof(signData);
    316        rv = SECFailure;
    317        /* sign sftkdb_GetAttriibuteSignature returns a crv, not an rv */
    318        crv = sftkdb_GetAttributeSignature(handle, handle, id, type,
    319                                           &signature);
    320        if (crv == CKR_OK) {
    321            rv = sftkdb_VerifyAttribute(handle, passKey, CK_INVALID_HANDLE,
    322                                        type, *plain, &signature);
    323        }
    324        if (rv != SECSuccess) {
    325            /*  handle bug 1720226 where old versions of NSS misfiled the signature
    326             *  attribute on password update */
    327            id |= SFTK_KEYDB_TYPE | SFTK_TOKEN_TYPE;
    328            signature.len = sizeof(signData);
    329            crv = sftkdb_GetAttributeSignature(handle, handle, id, type,
    330                                               &signature);
    331            if (crv != CKR_OK) {
    332                rv = SECFailure;
    333                PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    334                goto loser;
    335            }
    336            rv = sftkdb_VerifyAttribute(handle, passKey, CK_INVALID_HANDLE,
    337                                        type, *plain, &signature);
    338        }
    339    }
    340 
    341 loser:
    342    if (cipherValue.param) {
    343        nsspkcs5_DestroyPBEParameter(cipherValue.param);
    344    }
    345    if (cipherValue.arena) {
    346        PORT_FreeArena(cipherValue.arena, PR_FALSE);
    347    }
    348    /* Item decrypted, but failed integrity, clear it out */
    349    if (*plain && rv != SECSuccess) {
    350        SECITEM_ZfreeItem(*plain, PR_TRUE);
    351        *plain = NULL;
    352    }
    353    return rv;
    354 }
    355 
    356 /* If the database can't store the integrity check, it's a non-FIPS database
    357 * and we use the old encryption scheme for it */
    358 static PRBool
    359 sftkdb_useLegacyEncryption(SFTKDBHandle *handle, SDB *db)
    360 {
    361    if ((handle == NULL) || (db == NULL)) {
    362        /* this is the case where the legacy db is calling back to us to
    363         * encrypt or decrypt attributes inside the lower level db code.
    364         * This is because the legacy db stored keys as pkcs #8 encrypted
    365         * blobs rather than individual encrypted attributes */
    366        return PR_TRUE;
    367    }
    368    /* currently, only the legacy db can't store meta data, but if we
    369     * add a new db that also can't store meta data, then it to wouldn't
    370     * be able to do the integrity checks. In both cases use the old encryption
    371     * algorithms. */
    372    if ((db->sdb_flags & SDB_HAS_META) == 0) {
    373        return PR_TRUE;
    374    }
    375    return PR_FALSE;
    376 }
    377 
    378 /*
    379 * encrypt a block. This function returned the encrypted ciphertext which
    380 * the caller must free. If the caller provides an arena, cipherText will
    381 * be allocated out of that arena. This also generated the per entry
    382 * salt automatically.
    383 */
    384 SECStatus
    385 sftkdb_EncryptAttribute(PLArenaPool *arena, SFTKDBHandle *handle, SDB *db,
    386                        SECItem *passKey, int iterationCount,
    387                        CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type,
    388                        SECItem *plainText, SECItem **cipherText)
    389 {
    390    SECStatus rv;
    391    sftkCipherValue cipherValue;
    392    SECItem *cipher = NULL;
    393    NSSPKCS5PBEParameter *param = NULL;
    394    unsigned char saltData[HASH_LENGTH_MAX];
    395    SECItem *signature = NULL;
    396    HASH_HashType hashType = HASH_AlgNULL;
    397 
    398    if (sftkdb_useLegacyEncryption(handle, db)) {
    399        cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
    400        cipherValue.salt.len = SHA1_LENGTH;
    401        hashType = HASH_AlgSHA1;
    402    } else {
    403        cipherValue.alg = SEC_OID_AES_256_CBC;
    404        cipherValue.salt.len = SHA256_LENGTH;
    405        hashType = HASH_AlgSHA256;
    406    }
    407    cipherValue.salt.data = saltData;
    408    RNG_GenerateGlobalRandomBytes(saltData, cipherValue.salt.len);
    409 
    410    param = nsspkcs5_NewParam(cipherValue.alg, hashType, &cipherValue.salt,
    411                              iterationCount);
    412    if (param == NULL) {
    413        rv = SECFailure;
    414        goto loser;
    415    }
    416    cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL);
    417    if (cipher == NULL) {
    418        rv = SECFailure;
    419        goto loser;
    420    }
    421    cipherValue.value = *cipher;
    422    cipherValue.param = param;
    423 
    424    rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText);
    425    if (rv != SECSuccess) {
    426        goto loser;
    427    }
    428 
    429    /* If we are using aes 256, we need to add authentication as well */
    430    if ((type != CKT_INVALID_TYPE) &&
    431        (cipherValue.param->encAlg == SEC_OID_AES_256_CBC)) {
    432        rv = sftkdb_SignAttribute(arena, handle, db, passKey, iterationCount,
    433                                  CK_INVALID_HANDLE, type, plainText,
    434                                  &signature);
    435        if (rv != SECSuccess) {
    436            goto loser;
    437        }
    438        rv = sftkdb_PutAttributeSignature(handle, db, id, type,
    439                                          signature);
    440        if (rv != SECSuccess) {
    441            goto loser;
    442        }
    443    }
    444 
    445 loser:
    446    if ((arena == NULL) && signature) {
    447        SECITEM_ZfreeItem(signature, PR_TRUE);
    448    }
    449    if (cipher) {
    450        SECITEM_FreeItem(cipher, PR_TRUE);
    451    }
    452    if (param) {
    453        nsspkcs5_DestroyPBEParameter(param);
    454    }
    455    return rv;
    456 }
    457 
    458 /*
    459 * use the password and the pbe parameters to generate an HMAC for the
    460 * given plain text data. This is used by sftkdb_VerifyAttribute and
    461 * sftkdb_SignAttribute. Signature is returned in signData. The caller
    462 * must preallocate the space in the secitem.
    463 */
    464 static SECStatus
    465 sftkdb_pbehash(SECOidTag sigOid, SECItem *passKey,
    466               NSSPKCS5PBEParameter *param,
    467               CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE attrType,
    468               SECItem *plainText, SECItem *signData)
    469 {
    470    SECStatus rv = SECFailure;
    471    SECItem *key = NULL;
    472    HMACContext *hashCx = NULL;
    473    HASH_HashType hashType = HASH_AlgNULL;
    474    const SECHashObject *hashObj;
    475    unsigned char addressData[SDB_ULONG_SIZE];
    476    hashType = HASH_FromHMACOid(param->encAlg);
    477    if (hashType == HASH_AlgNULL) {
    478        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
    479        return SECFailure;
    480    }
    481 
    482    hashObj = HASH_GetRawHashObject(hashType);
    483    if (hashObj == NULL) {
    484        goto loser;
    485    }
    486 
    487    key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE);
    488    if (!key) {
    489        goto loser;
    490    }
    491 
    492    hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE);
    493    if (!hashCx) {
    494        goto loser;
    495    }
    496    HMAC_Begin(hashCx);
    497    /* Tie this value to a particular object. This is most important for
    498     * the trust attributes, where and attacker could copy a value for
    499     * 'validCA' from another cert in the database */
    500    sftk_ULong2SDBULong(addressData, objectID);
    501    HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
    502    sftk_ULong2SDBULong(addressData, attrType);
    503    HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
    504 
    505    HMAC_Update(hashCx, plainText->data, plainText->len);
    506    rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len);
    507 
    508 loser:
    509    if (hashCx) {
    510        HMAC_Destroy(hashCx, PR_TRUE);
    511    }
    512    if (key) {
    513        SECITEM_ZfreeItem(key, PR_TRUE);
    514    }
    515    return rv;
    516 }
    517 
    518 /*
    519 * Use our key to verify a signText block from the database matches
    520 * the plainText from the database. The signText is a PKCS 5 v2 pbe.
    521 * plainText is the plainText of the attribute.
    522 */
    523 SECStatus
    524 sftkdb_VerifyAttribute(SFTKDBHandle *handle,
    525                       SECItem *passKey, CK_OBJECT_HANDLE objectID,
    526                       CK_ATTRIBUTE_TYPE attrType,
    527                       SECItem *plainText, SECItem *signText)
    528 {
    529    SECStatus rv;
    530    sftkCipherValue signValue;
    531    SECItem signature;
    532    unsigned char signData[HASH_LENGTH_MAX];
    533 
    534    /* First get the cipher type */
    535    rv = sftkdb_decodeCipherText(signText, &signValue);
    536    if (rv != SECSuccess) {
    537        goto loser;
    538    }
    539    signature.data = signData;
    540    signature.len = sizeof(signData);
    541 
    542    rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param,
    543                        objectID, attrType, plainText, &signature);
    544    if (rv != SECSuccess) {
    545        goto loser;
    546    }
    547    if (SECITEM_CompareItem(&signValue.value, &signature) != 0) {
    548        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
    549        rv = SECFailure;
    550    }
    551 
    552 loser:
    553    PORT_Memset(signData, 0, sizeof signData);
    554    if (signValue.param) {
    555        nsspkcs5_DestroyPBEParameter(signValue.param);
    556    }
    557    if (signValue.arena) {
    558        PORT_FreeArena(signValue.arena, PR_TRUE);
    559    }
    560    return rv;
    561 }
    562 
    563 /*
    564 * Use our key to create a signText block the plain text of an
    565 * attribute. The signText is a PKCS 5 v2 pbe.
    566 */
    567 SECStatus
    568 sftkdb_SignAttribute(PLArenaPool *arena, SFTKDBHandle *keyDB, SDB *db,
    569                     SECItem *passKey, int iterationCount,
    570                     CK_OBJECT_HANDLE objectID,
    571                     CK_ATTRIBUTE_TYPE attrType,
    572                     SECItem *plainText, SECItem **signature)
    573 {
    574    SECStatus rv;
    575    sftkCipherValue signValue;
    576    NSSPKCS5PBEParameter *param = NULL;
    577    unsigned char saltData[HASH_LENGTH_MAX];
    578    unsigned char signData[HASH_LENGTH_MAX];
    579    SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */
    580    SECOidTag prfAlg = SEC_OID_HMAC_SHA256;  /* hash for pb key generation */
    581    HASH_HashType prfType;
    582    unsigned int hmacLength;
    583    unsigned int prfLength;
    584 
    585    /* this code allows us to fetch the lengths and hashes on the fly
    586     * by simply changing the OID above */
    587    prfType = HASH_FromHMACOid(prfAlg);
    588    PORT_Assert(prfType != HASH_AlgNULL);
    589    prfLength = HASH_GetRawHashObject(prfType)->length;
    590    PORT_Assert(prfLength <= HASH_LENGTH_MAX);
    591 
    592    hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length;
    593    PORT_Assert(hmacLength <= HASH_LENGTH_MAX);
    594 
    595    /* initialize our CipherValue structure */
    596    signValue.alg = SEC_OID_PKCS5_PBMAC1;
    597    signValue.salt.len = prfLength;
    598    signValue.salt.data = saltData;
    599    signValue.value.data = signData;
    600    signValue.value.len = hmacLength;
    601    RNG_GenerateGlobalRandomBytes(saltData, prfLength);
    602 
    603    /* initialize our pkcs5 parameter */
    604    param = nsspkcs5_NewParam(signValue.alg, HASH_AlgSHA1, &signValue.salt,
    605                              iterationCount);
    606    if (param == NULL) {
    607        rv = SECFailure;
    608        goto loser;
    609    }
    610    param->keyID = pbeBitGenIntegrityKey;
    611    /* set the PKCS 5 v2 parameters, not extractable from the
    612     * data passed into nsspkcs5_NewParam */
    613    param->encAlg = hmacAlg;
    614    param->hashType = prfType;
    615    param->keyLen = hmacLength;
    616    rv = SECOID_SetAlgorithmID(param->poolp, &param->prfAlg, prfAlg, NULL);
    617    if (rv != SECSuccess) {
    618        goto loser;
    619    }
    620 
    621    /* calculate the mac */
    622    rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType,
    623                        plainText, &signValue.value);
    624    if (rv != SECSuccess) {
    625        goto loser;
    626    }
    627    signValue.param = param;
    628 
    629    /* write it out */
    630    rv = sftkdb_encodeCipherText(arena, &signValue, signature);
    631    if (rv != SECSuccess) {
    632        goto loser;
    633    }
    634 
    635 loser:
    636    PORT_Memset(signData, 0, sizeof signData);
    637    if (param) {
    638        nsspkcs5_DestroyPBEParameter(param);
    639    }
    640    return rv;
    641 }
    642 
    643 /*
    644 * safely swith the passed in key for the one caches in the keydb handle
    645 *
    646 * A key attached to the handle tells us the the token is logged in.
    647 * We can used the key attached to the handle in sftkdb_EncryptAttribute
    648 *  and sftkdb_DecryptAttribute calls.
    649 */
    650 static void
    651 sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey, int iterationCount)
    652 {
    653    unsigned char *data;
    654    int len;
    655 
    656    if (keydb->passwordLock == NULL) {
    657        PORT_Assert(keydb->type != SFTK_KEYDB_TYPE);
    658        return;
    659    }
    660 
    661    /* an atomic pointer set would be nice */
    662    SKIP_AFTER_FORK(PZ_Lock(keydb->passwordLock));
    663    data = keydb->passwordKey.data;
    664    len = keydb->passwordKey.len;
    665    keydb->passwordKey.data = passKey->data;
    666    keydb->passwordKey.len = passKey->len;
    667    keydb->defaultIterationCount = iterationCount;
    668    passKey->data = data;
    669    passKey->len = len;
    670    SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock));
    671 }
    672 
    673 /*
    674 * returns true if we are in a middle of a merge style update.
    675 */
    676 PRBool
    677 sftkdb_InUpdateMerge(SFTKDBHandle *keydb)
    678 {
    679    return keydb->updateID ? PR_TRUE : PR_FALSE;
    680 }
    681 
    682 /*
    683 * returns true if we are looking for the password for the user's old source
    684 * database as part of a merge style update.
    685 */
    686 PRBool
    687 sftkdb_NeedUpdateDBPassword(SFTKDBHandle *keydb)
    688 {
    689    if (!sftkdb_InUpdateMerge(keydb)) {
    690        return PR_FALSE;
    691    }
    692    if (keydb->updateDBIsInit && !keydb->updatePasswordKey) {
    693        return PR_TRUE;
    694    }
    695    return PR_FALSE;
    696 }
    697 
    698 /*
    699 * fetch an update password key from a handle.
    700 */
    701 SECItem *
    702 sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle)
    703 {
    704    SECItem *key = NULL;
    705 
    706    /* if we're a cert db, fetch it from our peer key db */
    707    if (handle->type == SFTK_CERTDB_TYPE) {
    708        handle = handle->peerDB;
    709    }
    710 
    711    /* don't have one */
    712    if (!handle) {
    713        return NULL;
    714    }
    715 
    716    PZ_Lock(handle->passwordLock);
    717    if (handle->updatePasswordKey) {
    718        key = SECITEM_DupItem(handle->updatePasswordKey);
    719    }
    720    PZ_Unlock(handle->passwordLock);
    721 
    722    return key;
    723 }
    724 
    725 /*
    726 * free the update password key from a handle.
    727 */
    728 void
    729 sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle)
    730 {
    731    SECItem *key = NULL;
    732 
    733    /* don't have one */
    734    if (!handle) {
    735        return;
    736    }
    737 
    738    /* if we're a cert db, we don't have one */
    739    if (handle->type == SFTK_CERTDB_TYPE) {
    740        return;
    741    }
    742 
    743    PZ_Lock(handle->passwordLock);
    744    if (handle->updatePasswordKey) {
    745        key = handle->updatePasswordKey;
    746        handle->updatePasswordKey = NULL;
    747    }
    748    PZ_Unlock(handle->passwordLock);
    749 
    750    if (key) {
    751        SECITEM_ZfreeItem(key, PR_TRUE);
    752    }
    753 
    754    return;
    755 }
    756 
    757 /*
    758 * what password db we use depends heavily on the update state machine
    759 *
    760 *  1) no update db, return the normal database.
    761 *  2) update db and no merge return the update db.
    762 *  3) update db and in merge:
    763 *      return the update db if we need the update db's password,
    764 *      otherwise return our normal datbase.
    765 */
    766 static SDB *
    767 sftk_getPWSDB(SFTKDBHandle *keydb)
    768 {
    769    if (!keydb->update) {
    770        return keydb->db;
    771    }
    772    if (!sftkdb_InUpdateMerge(keydb)) {
    773        return keydb->update;
    774    }
    775    if (sftkdb_NeedUpdateDBPassword(keydb)) {
    776        return keydb->update;
    777    }
    778    return keydb->db;
    779 }
    780 
    781 /*
    782 * return success if we have a valid password entry.
    783 * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT
    784 * in the token flags.
    785 */
    786 SECStatus
    787 sftkdb_HasPasswordSet(SFTKDBHandle *keydb)
    788 {
    789    SECItem salt, value;
    790    unsigned char saltData[SDB_MAX_META_DATA_LEN];
    791    unsigned char valueData[SDB_MAX_META_DATA_LEN];
    792    CK_RV crv;
    793    SDB *db;
    794 
    795    if (keydb == NULL) {
    796        return SECFailure;
    797    }
    798 
    799    db = sftk_getPWSDB(keydb);
    800    if (db == NULL) {
    801        return SECFailure;
    802    }
    803 
    804    salt.data = saltData;
    805    salt.len = sizeof(saltData);
    806    value.data = valueData;
    807    value.len = sizeof(valueData);
    808    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
    809 
    810    /* If no password is set, we can update right away */
    811    if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update && crv != CKR_OK) {
    812        /* update the peer certdb if it exists */
    813        if (keydb->peerDB) {
    814            sftkdb_Update(keydb->peerDB, NULL);
    815        }
    816        sftkdb_Update(keydb, NULL);
    817    }
    818    return (crv == CKR_OK) ? SECSuccess : SECFailure;
    819 }
    820 
    821 /* pull out the common final part of checking a password */
    822 SECStatus
    823 sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key,
    824                           const char *pw, SECItem *value,
    825                           PRBool *tokenRemoved);
    826 
    827 /*
    828 * check to see if we have the NULL password set.
    829 * We special case the NULL password so that if you have no password set, you
    830 * don't do thousands of hash rounds. This allows us to startup and get
    831 * webpages without slowdown in normal mode.
    832 */
    833 SECStatus
    834 sftkdb_CheckPasswordNull(SFTKDBHandle *keydb, PRBool *tokenRemoved)
    835 {
    836    /* just like sftkdb_CheckPassowd, we get the salt and value, and
    837     * create a dbkey */
    838    SECStatus rv;
    839    SECItem salt, value;
    840    unsigned char saltData[SDB_MAX_META_DATA_LEN];
    841    unsigned char valueData[SDB_MAX_META_DATA_LEN];
    842    SECItem key;
    843    SDB *db;
    844    CK_RV crv;
    845    sftkCipherValue cipherValue;
    846 
    847    cipherValue.param = NULL;
    848    cipherValue.arena = NULL;
    849 
    850    if (keydb == NULL) {
    851        return SECFailure;
    852    }
    853 
    854    db = sftk_getPWSDB(keydb);
    855    if (db == NULL) {
    856        return SECFailure;
    857    }
    858 
    859    key.data = NULL;
    860    key.len = 0;
    861 
    862    /* get the entry from the database */
    863    salt.data = saltData;
    864    salt.len = sizeof(saltData);
    865    value.data = valueData;
    866    value.len = sizeof(valueData);
    867    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
    868    if (crv != CKR_OK) {
    869        rv = SECFailure;
    870        goto done;
    871    }
    872 
    873    /* get our intermediate key based on the entry salt value */
    874    rv = sftkdb_passwordToKey(keydb, &salt, "", &key);
    875    if (rv != SECSuccess) {
    876        goto done;
    877    }
    878 
    879    /* First get the cipher type */
    880    rv = sftkdb_decodeCipherText(&value, &cipherValue);
    881    if (rv != SECSuccess) {
    882        goto done;
    883    }
    884 
    885    if (cipherValue.param->iter != 1) {
    886        rv = SECFailure;
    887        goto done;
    888    }
    889 
    890    rv = sftkdb_finishPasswordCheck(keydb, &key, "", &value, tokenRemoved);
    891 
    892 done:
    893    if (key.data) {
    894        PORT_ZFree(key.data, key.len);
    895    }
    896    if (cipherValue.param) {
    897        nsspkcs5_DestroyPBEParameter(cipherValue.param);
    898    }
    899    if (cipherValue.arena) {
    900        PORT_FreeArena(cipherValue.arena, PR_FALSE);
    901    }
    902    return rv;
    903 }
    904 
    905 #define SFTK_PW_CHECK_STRING "password-check"
    906 #define SFTK_PW_CHECK_LEN 14
    907 
    908 /*
    909 * check if the supplied password is valid
    910 */
    911 SECStatus
    912 sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw, PRBool *tokenRemoved)
    913 {
    914    SECStatus rv;
    915    SECItem salt, value;
    916    unsigned char saltData[SDB_MAX_META_DATA_LEN];
    917    unsigned char valueData[SDB_MAX_META_DATA_LEN];
    918    SECItem key;
    919    SDB *db;
    920    CK_RV crv;
    921 
    922    if (keydb == NULL) {
    923        return SECFailure;
    924    }
    925 
    926    db = sftk_getPWSDB(keydb);
    927    if (db == NULL) {
    928        return SECFailure;
    929    }
    930 
    931    key.data = NULL;
    932    key.len = 0;
    933 
    934    if (pw == NULL)
    935        pw = "";
    936 
    937    /* get the entry from the database */
    938    salt.data = saltData;
    939    salt.len = sizeof(saltData);
    940    value.data = valueData;
    941    value.len = sizeof(valueData);
    942    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
    943    if (crv != CKR_OK) {
    944        rv = SECFailure;
    945        goto done;
    946    }
    947 
    948    /* get our intermediate key based on the entry salt value */
    949    rv = sftkdb_passwordToKey(keydb, &salt, pw, &key);
    950    if (rv != SECSuccess) {
    951        goto done;
    952    }
    953 
    954    rv = sftkdb_finishPasswordCheck(keydb, &key, pw, &value, tokenRemoved);
    955 
    956 done:
    957    if (key.data) {
    958        PORT_ZFree(key.data, key.len);
    959    }
    960    return rv;
    961 }
    962 
    963 /* we need to pass iterationCount in case we are updating a new database
    964 * and from an old one. */
    965 SECStatus
    966 sftkdb_finishPasswordCheck(SFTKDBHandle *keydb, SECItem *key, const char *pw,
    967                           SECItem *value, PRBool *tokenRemoved)
    968 {
    969    SECItem *result = NULL;
    970    SECStatus rv;
    971    int iterationCount = getPBEIterationCount();
    972 
    973    if (*pw == 0) {
    974        iterationCount = 1;
    975    } else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) {
    976        iterationCount = 1;
    977    }
    978 
    979    /* decrypt the entry value */
    980    rv = sftkdb_DecryptAttribute(keydb, key, CK_INVALID_HANDLE,
    981                                 CKT_INVALID_TYPE, value, &result);
    982    if (rv != SECSuccess) {
    983        goto done;
    984    }
    985 
    986    /* if it's what we expect, update our key in the database handle and
    987     * return Success */
    988    if ((result->len == SFTK_PW_CHECK_LEN) &&
    989        PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0) {
    990        /*
    991         * We have a password, now lets handle any potential update cases..
    992         *
    993         * First, the normal case: no update. In this case we only need the
    994         *  the password for our only DB, which we now have, we switch
    995         *  the keys and fall through.
    996         * Second regular (non-merge) update: The target DB does not yet have
    997         *  a password initialized, we now have the password for the source DB,
    998         *  so we can switch the keys and simply update the target database.
    999         * Merge update case: This one is trickier.
   1000         *   1) If we need the source DB password, then we just got it here.
   1001         *       We need to save that password,
   1002         *       then we need to check to see if we need or have the target
   1003         *         database password.
   1004         *       If we have it (it's the same as the source), or don't need
   1005         *         it (it's not set or is ""), we can start the update now.
   1006         *       If we don't have it, we need the application to get it from
   1007         *         the user. Clear our sessions out to simulate a token
   1008         *         removal. C_GetTokenInfo will change the token description
   1009         *         and the token will still appear to be logged out.
   1010         *   2) If we already have the source DB  password, this password is
   1011         *         for the target database. We can now move forward with the
   1012         *         update, as we now have both required passwords.
   1013         *
   1014         */
   1015        PZ_Lock(keydb->passwordLock);
   1016        if (sftkdb_NeedUpdateDBPassword(keydb)) {
   1017            /* Squirrel this special key away.
   1018             * This has the side effect of turning sftkdb_NeedLegacyPW off,
   1019             * as well as changing which database is returned from
   1020             * SFTK_GET_PW_DB (thus effecting both sftkdb_CheckPassword()
   1021             * and sftkdb_HasPasswordSet()) */
   1022            keydb->updatePasswordKey = SECITEM_DupItem(key);
   1023            PZ_Unlock(keydb->passwordLock);
   1024            if (keydb->updatePasswordKey == NULL) {
   1025                /* PORT_Error set by SECITEM_DupItem */
   1026                rv = SECFailure;
   1027                goto done;
   1028            }
   1029 
   1030            /* Simulate a token removal -- we need to do this any
   1031             * any case at this point so the token name is correct. */
   1032            *tokenRemoved = PR_TRUE;
   1033 
   1034            /*
   1035             * OK, we got the update DB password, see if we need a password
   1036             * for the target...
   1037             */
   1038            if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
   1039                /* We have a password, do we know what the password is?
   1040                 *  check 1) for the password the user supplied for the
   1041                 *           update DB,
   1042                 *    and 2) for the null password.
   1043                 *
   1044                 * RECURSION NOTE: we are calling ourselves here. This means
   1045                 *  any updates, switchKeys, etc will have been completed
   1046                 *  if these functions return successfully, in those cases
   1047                 *  just exit returning Success. We don't recurse infinitely
   1048                 *  because we are making this call from a NeedUpdateDBPassword
   1049                 *  block and we've already set that update password at this
   1050                 *  point.  */
   1051                rv = sftkdb_CheckPassword(keydb, pw, tokenRemoved);
   1052                if (rv == SECSuccess) {
   1053                    /* source and target databases have the same password, we
   1054                     * are good to go */
   1055                    goto done;
   1056                }
   1057                sftkdb_CheckPasswordNull(keydb, tokenRemoved);
   1058 
   1059                /*
   1060                 * Important 'NULL' code here. At this point either we
   1061                 * succeeded in logging in with "" or we didn't.
   1062                 *
   1063                 *  If we did succeed at login, our machine state will be set
   1064                 * to logged in appropriately. The application will find that
   1065                 * it's logged in as soon as it opens a new session. We have
   1066                 * also completed the update. Life is good.
   1067                 *
   1068                 *  If we did not succeed, well the user still successfully
   1069                 * logged into the update database, since we faked the token
   1070                 * removal it's just like the user logged into his smart card
   1071                 * then removed it. the actual login work, so we report that
   1072                 * success back to the user, but we won't actually be
   1073                 * logged in. The application will find this out when it
   1074                 * checks it's login state, thus triggering another password
   1075                 * prompt so we can get the real target DB password.
   1076                 *
   1077                 * summary, we exit from here with SECSuccess no matter what.
   1078                 */
   1079                rv = SECSuccess;
   1080                goto done;
   1081            } else {
   1082                /* there is no password, just fall through to update.
   1083                 * update will write the source DB's password record
   1084                 * into the target DB just like it would in a non-merge
   1085                 * update case. */
   1086            }
   1087        } else {
   1088            PZ_Unlock(keydb->passwordLock);
   1089        }
   1090        /* load the keys, so the keydb can parse it's key set */
   1091        sftkdb_switchKeys(keydb, key, iterationCount);
   1092 
   1093        /* we need to update, do it now */
   1094        if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) {
   1095            /* update the peer certdb if it exists */
   1096            if (keydb->peerDB) {
   1097                sftkdb_Update(keydb->peerDB, key);
   1098            }
   1099            sftkdb_Update(keydb, key);
   1100        }
   1101    } else {
   1102        rv = SECFailure;
   1103        /*PORT_SetError( bad password); */
   1104    }
   1105 
   1106 done:
   1107    if (result) {
   1108        SECITEM_ZfreeItem(result, PR_TRUE);
   1109    }
   1110    return rv;
   1111 }
   1112 
   1113 /*
   1114 * return Success if the there is a cached password key.
   1115 */
   1116 SECStatus
   1117 sftkdb_PWCached(SFTKDBHandle *keydb)
   1118 {
   1119    SECStatus rv;
   1120    PZ_Lock(keydb->passwordLock);
   1121    rv = keydb->passwordKey.data ? SECSuccess : SECFailure;
   1122    PZ_Unlock(keydb->passwordLock);
   1123    return rv;
   1124 }
   1125 
   1126 static CK_RV
   1127 sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
   1128                CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount)
   1129 {
   1130    SFTKDBHandle *keyHandle = handle;
   1131    SDB *keyTarget = NULL;
   1132    if (handle->type != SFTK_KEYDB_TYPE) {
   1133        keyHandle = handle->peerDB;
   1134    }
   1135    if (keyHandle == NULL) {
   1136        return CKR_OK;
   1137    }
   1138    // Old DBs don't have metadata, so we can return early here.
   1139    keyTarget = SFTK_GET_SDB(keyHandle);
   1140    if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
   1141        return CKR_OK;
   1142    }
   1143 
   1144    id &= SFTK_OBJ_ID_MASK;
   1145 
   1146    CK_ATTRIBUTE_TYPE authAttrTypes[] = {
   1147        CKA_MODULUS,
   1148        CKA_PUBLIC_EXPONENT,
   1149        CKA_NSS_CERT_SHA1_HASH,
   1150        CKA_NSS_CERT_MD5_HASH,
   1151        CKA_NAME_HASH_ALGORITHM,
   1152        CKA_HASH_OF_CERTIFICATE,
   1153        CKA_PKCS_TRUST_SERVER_AUTH,
   1154        CKA_PKCS_TRUST_CLIENT_AUTH,
   1155        CKA_PKCS_TRUST_EMAIL_PROTECTION,
   1156        CKA_PKCS_TRUST_CODE_SIGNING,
   1157        CKA_NSS_TRUST_SERVER_AUTH,
   1158        CKA_NSS_TRUST_CLIENT_AUTH,
   1159        CKA_NSS_TRUST_EMAIL_PROTECTION,
   1160        CKA_NSS_TRUST_CODE_SIGNING,
   1161        CKA_NSS_TRUST_STEP_UP_APPROVED,
   1162        CKA_NSS_OVERRIDE_EXTENSIONS,
   1163    };
   1164    const CK_ULONG authAttrTypeCount = sizeof(authAttrTypes) / sizeof(authAttrTypes[0]);
   1165 
   1166    // We don't know what attributes this object has, so we update them one at a
   1167    // time.
   1168    unsigned int i;
   1169    for (i = 0; i < authAttrTypeCount; i++) {
   1170        CK_ATTRIBUTE authAttr = { authAttrTypes[i], NULL, 0 };
   1171        CK_RV rv = sftkdb_GetAttributeValue(handle, id, &authAttr, 1);
   1172        if (rv != CKR_OK) {
   1173            continue;
   1174        }
   1175        if ((authAttr.ulValueLen == -1) || (authAttr.ulValueLen == 0)) {
   1176            continue;
   1177        }
   1178        authAttr.pValue = PORT_ArenaAlloc(arena, authAttr.ulValueLen);
   1179        if (authAttr.pValue == NULL) {
   1180            return CKR_HOST_MEMORY;
   1181        }
   1182        rv = sftkdb_GetAttributeValue(handle, id, &authAttr, 1);
   1183        if (rv != CKR_OK) {
   1184            return rv;
   1185        }
   1186        if ((authAttr.ulValueLen == -1) || (authAttr.ulValueLen == 0)) {
   1187            return CKR_GENERAL_ERROR;
   1188        }
   1189        // GetAttributeValue just verified the old macs, so it is safe to write
   1190        // them out now.
   1191        if (authAttr.ulValueLen == sizeof(CK_ULONG) &&
   1192            sftkdb_isULONGAttribute(authAttr.type)) {
   1193            CK_ULONG value = *(CK_ULONG *)authAttr.pValue;
   1194            sftk_ULong2SDBULong(authAttr.pValue, value);
   1195            authAttr.ulValueLen = SDB_ULONG_SIZE;
   1196        }
   1197        SECItem *signText;
   1198        SECItem plainText;
   1199        plainText.data = authAttr.pValue;
   1200        plainText.len = authAttr.ulValueLen;
   1201        if (sftkdb_SignAttribute(arena, handle, keyTarget, newKey,
   1202                                 iterationCount, id, authAttr.type,
   1203                                 &plainText, &signText) != SECSuccess) {
   1204            return CKR_GENERAL_ERROR;
   1205        }
   1206        if (sftkdb_PutAttributeSignature(handle, keyTarget, id, authAttr.type,
   1207                                         signText) != SECSuccess) {
   1208            return CKR_GENERAL_ERROR;
   1209        }
   1210    }
   1211 
   1212    return CKR_OK;
   1213 }
   1214 
   1215 static CK_RV
   1216 sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
   1217                     CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount)
   1218 {
   1219    CK_ATTRIBUTE_TYPE privAttrTypes[] = {
   1220        CKA_VALUE,
   1221        CKA_SEED,
   1222        CKA_PRIVATE_EXPONENT,
   1223        CKA_PRIME_1,
   1224        CKA_PRIME_2,
   1225        CKA_EXPONENT_1,
   1226        CKA_EXPONENT_2,
   1227        CKA_COEFFICIENT,
   1228    };
   1229    const CK_ULONG privAttrCount = sizeof(privAttrTypes) / sizeof(privAttrTypes[0]);
   1230 
   1231    // We don't know what attributes this object has, so we update them one at a
   1232    // time.
   1233    unsigned int i;
   1234    for (i = 0; i < privAttrCount; i++) {
   1235        // Read the old attribute in the clear.
   1236        CK_OBJECT_HANDLE sdbId = id & SFTK_OBJ_ID_MASK;
   1237        CK_ATTRIBUTE privAttr = { privAttrTypes[i], NULL, 0 };
   1238        CK_RV crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1);
   1239        if (crv != CKR_OK) {
   1240            continue;
   1241        }
   1242        if ((privAttr.ulValueLen == -1) || (privAttr.ulValueLen == 0)) {
   1243            continue;
   1244        }
   1245        privAttr.pValue = PORT_ArenaAlloc(arena, privAttr.ulValueLen);
   1246        if (privAttr.pValue == NULL) {
   1247            return CKR_HOST_MEMORY;
   1248        }
   1249        crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1);
   1250        if (crv != CKR_OK) {
   1251            return crv;
   1252        }
   1253        if ((privAttr.ulValueLen == -1) || (privAttr.ulValueLen == 0)) {
   1254            return CKR_GENERAL_ERROR;
   1255        }
   1256        SECItem plainText;
   1257        SECItem *result;
   1258        plainText.data = privAttr.pValue;
   1259        plainText.len = privAttr.ulValueLen;
   1260        if (sftkdb_EncryptAttribute(arena, keydb, keydb->db, newKey,
   1261                                    iterationCount, sdbId, privAttr.type,
   1262                                    &plainText, &result) != SECSuccess) {
   1263            return CKR_GENERAL_ERROR;
   1264        }
   1265        privAttr.pValue = result->data;
   1266        privAttr.ulValueLen = result->len;
   1267        // Clear sensitive data.
   1268        PORT_Memset(plainText.data, 0, plainText.len);
   1269 
   1270        // Write the newly encrypted attributes out directly.
   1271        keydb->newKey = newKey;
   1272        keydb->newDefaultIterationCount = iterationCount;
   1273        crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, sdbId, &privAttr, 1);
   1274        keydb->newKey = NULL;
   1275        if (crv != CKR_OK) {
   1276            return crv;
   1277        }
   1278    }
   1279 
   1280    return CKR_OK;
   1281 }
   1282 
   1283 static CK_RV
   1284 sftk_convertAttributes(SFTKDBHandle *handle, CK_OBJECT_HANDLE id,
   1285                       SECItem *newKey, int iterationCount)
   1286 {
   1287    CK_RV crv = CKR_OK;
   1288    PLArenaPool *arena = NULL;
   1289 
   1290    /* get a new arena to simplify cleanup */
   1291    arena = PORT_NewArena(1024);
   1292    if (!arena) {
   1293        return CKR_HOST_MEMORY;
   1294    }
   1295 
   1296    /*
   1297     * first handle the MACS
   1298     */
   1299    crv = sftk_updateMacs(arena, handle, id, newKey, iterationCount);
   1300    if (crv != CKR_OK) {
   1301        goto loser;
   1302    }
   1303 
   1304    if (handle->type == SFTK_KEYDB_TYPE) {
   1305        crv = sftk_updateEncrypted(arena, handle, id, newKey,
   1306                                   iterationCount);
   1307        if (crv != CKR_OK) {
   1308            goto loser;
   1309        }
   1310    }
   1311 
   1312    /* free up our mess */
   1313    PORT_FreeArena(arena, PR_TRUE);
   1314    return CKR_OK;
   1315 
   1316 loser:
   1317    /* there may be unencrypted data, clear it out down */
   1318    PORT_FreeArena(arena, PR_TRUE);
   1319    return crv;
   1320 }
   1321 
   1322 /*
   1323 * must be called with the old key active.
   1324 */
   1325 CK_RV
   1326 sftkdb_convertObjects(SFTKDBHandle *handle, CK_ATTRIBUTE *template,
   1327                      CK_ULONG count, SECItem *newKey, int iterationCount)
   1328 {
   1329    SDBFind *find = NULL;
   1330    CK_ULONG idCount = SFTK_MAX_IDS;
   1331    CK_OBJECT_HANDLE ids[SFTK_MAX_IDS];
   1332    CK_RV crv, crv2;
   1333    unsigned int i;
   1334 
   1335    crv = sftkdb_FindObjectsInit(handle, template, count, &find);
   1336 
   1337    if (crv != CKR_OK) {
   1338        return crv;
   1339    }
   1340    while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) {
   1341        crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount);
   1342        for (i = 0; (crv == CKR_OK) && (i < idCount); i++) {
   1343            crv = sftk_convertAttributes(handle, ids[i], newKey,
   1344                                         iterationCount);
   1345        }
   1346    }
   1347    crv2 = sftkdb_FindObjectsFinal(handle, find);
   1348    if (crv == CKR_OK)
   1349        crv = crv2;
   1350 
   1351    return crv;
   1352 }
   1353 
   1354 /*
   1355 * change the database password.
   1356 */
   1357 SECStatus
   1358 sftkdb_ChangePassword(SFTKDBHandle *keydb,
   1359                      char *oldPin, char *newPin, PRBool *tokenRemoved)
   1360 {
   1361    SECStatus rv = SECSuccess;
   1362    SECItem plainText;
   1363    SECItem newKey;
   1364    SECItem *result = NULL;
   1365    SECItem salt, value;
   1366    SFTKDBHandle *certdb;
   1367    unsigned char saltData[SDB_MAX_META_DATA_LEN];
   1368    unsigned char valueData[SDB_MAX_META_DATA_LEN];
   1369    int iterationCount = getPBEIterationCount();
   1370    int preferred_salt_length;
   1371    CK_RV crv;
   1372    SDB *db;
   1373 
   1374    if (keydb == NULL) {
   1375        return SECFailure;
   1376    }
   1377 
   1378    db = SFTK_GET_SDB(keydb);
   1379    if (db == NULL) {
   1380        return SECFailure;
   1381    }
   1382 
   1383    newKey.data = NULL;
   1384 
   1385    /* make sure we have a valid old pin */
   1386    crv = (*keydb->db->sdb_Begin)(keydb->db);
   1387    if (crv != CKR_OK) {
   1388        rv = SECFailure;
   1389        goto loser;
   1390    }
   1391    salt.data = saltData;
   1392    salt.len = sizeof(saltData);
   1393    value.data = valueData;
   1394    value.len = sizeof(valueData);
   1395    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
   1396    if (crv == CKR_OK) {
   1397        rv = sftkdb_CheckPassword(keydb, oldPin, tokenRemoved);
   1398        if (rv == SECFailure) {
   1399            goto loser;
   1400        }
   1401    } else {
   1402        salt.len = 0;
   1403    }
   1404 
   1405    preferred_salt_length = SHA384_LENGTH;
   1406 
   1407    /* Prefer SHA-1 if the password is NULL */
   1408    if (!newPin || *newPin == 0) {
   1409        preferred_salt_length = SHA1_LENGTH;
   1410    }
   1411 
   1412    if (salt.len != preferred_salt_length) {
   1413        salt.len = preferred_salt_length;
   1414        RNG_GenerateGlobalRandomBytes(salt.data, salt.len);
   1415    }
   1416 
   1417    if (newPin && *newPin == 0) {
   1418        iterationCount = 1;
   1419    } else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) {
   1420        iterationCount = 1;
   1421    }
   1422 
   1423    rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
   1424    if (rv != SECSuccess) {
   1425        goto loser;
   1426    }
   1427 
   1428    /*
   1429     * convert encrypted entries here.
   1430     */
   1431    crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey, iterationCount);
   1432    if (crv != CKR_OK) {
   1433        rv = SECFailure;
   1434        goto loser;
   1435    }
   1436    /* fix up certdb macs */
   1437    certdb = keydb->peerDB;
   1438    if (certdb) {
   1439        CK_ATTRIBUTE objectType = { CKA_CLASS, 0, sizeof(CK_OBJECT_CLASS) };
   1440        CK_OBJECT_CLASS myClass = CKO_NSS_TRUST;
   1441 
   1442        objectType.pValue = &myClass;
   1443        crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey,
   1444                                    iterationCount);
   1445        if (crv != CKR_OK) {
   1446            rv = SECFailure;
   1447            goto loser;
   1448        }
   1449        myClass = CKO_PUBLIC_KEY;
   1450        crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey,
   1451                                    iterationCount);
   1452        if (crv != CKR_OK) {
   1453            rv = SECFailure;
   1454            goto loser;
   1455        }
   1456 
   1457        myClass = CKO_TRUST;
   1458        crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey,
   1459                                    iterationCount);
   1460        if (crv != CKR_OK) {
   1461            rv = SECFailure;
   1462            goto loser;
   1463        }
   1464    }
   1465 
   1466    plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
   1467    plainText.len = SFTK_PW_CHECK_LEN;
   1468 
   1469    rv = sftkdb_EncryptAttribute(NULL, keydb, keydb->db, &newKey,
   1470                                 iterationCount, CK_INVALID_HANDLE,
   1471                                 CKT_INVALID_TYPE, &plainText, &result);
   1472    if (rv != SECSuccess) {
   1473        goto loser;
   1474    }
   1475    value.data = result->data;
   1476    value.len = result->len;
   1477    crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value);
   1478    if (crv != CKR_OK) {
   1479        rv = SECFailure;
   1480        goto loser;
   1481    }
   1482    crv = (*keydb->db->sdb_Commit)(keydb->db);
   1483    if (crv != CKR_OK) {
   1484        rv = SECFailure;
   1485        goto loser;
   1486    }
   1487 
   1488    keydb->newKey = NULL;
   1489 
   1490    sftkdb_switchKeys(keydb, &newKey, iterationCount);
   1491 
   1492 loser:
   1493    if (newKey.data) {
   1494        PORT_ZFree(newKey.data, newKey.len);
   1495    }
   1496    if (result) {
   1497        SECITEM_FreeItem(result, PR_TRUE);
   1498    }
   1499    if (rv != SECSuccess) {
   1500        (*keydb->db->sdb_Abort)(keydb->db);
   1501    }
   1502 
   1503    return rv;
   1504 }
   1505 
   1506 /*
   1507 * lose our cached password
   1508 */
   1509 SECStatus
   1510 sftkdb_ClearPassword(SFTKDBHandle *keydb)
   1511 {
   1512    SECItem oldKey;
   1513    oldKey.data = NULL;
   1514    oldKey.len = 0;
   1515    sftkdb_switchKeys(keydb, &oldKey, 1);
   1516    if (oldKey.data) {
   1517        PORT_ZFree(oldKey.data, oldKey.len);
   1518    }
   1519    return SECSuccess;
   1520 }