Coverage Report

Created: 2025-11-05 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/softoken/sftkpwd.c
Line
Count
Source
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
0
{
42
0
    int c = NSS_MP_PBE_ITERATION_COUNT;
43
44
0
    char *val = getenv("NSS_MIN_MP_PBE_ITERATION_COUNT");
45
0
    if (val && *val) {
46
0
        int minimum = atoi(val);
47
0
        if (c < minimum) {
48
0
            c = minimum;
49
0
        }
50
0
    }
51
52
0
    val = getenv("NSS_MAX_MP_PBE_ITERATION_COUNT");
53
0
    if (val && *val) {
54
0
        int maximum = atoi(val);
55
0
        if (c > maximum) {
56
0
            c = maximum;
57
0
        }
58
0
    }
59
    /* never let c be less than one, no matter what the environment
60
     * variable is set to */
61
0
    if (c < 1) {
62
0
        c = 1;
63
0
    }
64
0
    return c;
65
0
}
66
67
PRBool
68
sftk_isLegacyIterationCountAllowed(void)
69
0
{
70
0
    static const char *legacyCountEnvVar =
71
0
        "NSS_ALLOW_LEGACY_DBM_ITERATION_COUNT";
72
0
    char *iterEnv = getenv(legacyCountEnvVar);
73
0
    return (iterEnv && strcmp("0", iterEnv) != 0);
74
0
}
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
0
{
96
0
    HASH_HashType hType;
97
0
    const SECHashObject *hashObj;
98
0
    void *ctx = NULL;
99
0
    SECStatus rv = SECFailure;
100
101
0
    hType = salt->len == SHA384_LENGTH ? HASH_AlgSHA384 : HASH_AlgSHA1;
102
0
    hashObj = HASH_GetRawHashObject(hType);
103
104
0
    if (!pw) {
105
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
106
0
        return SECFailure;
107
0
    }
108
109
0
    key->data = PORT_Alloc(hashObj->length);
110
0
    if (key->data == NULL) {
111
0
        goto loser;
112
0
    }
113
0
    key->len = hashObj->length;
114
115
0
    ctx = hashObj->create();
116
0
    if (ctx == NULL) {
117
0
        goto loser;
118
0
    }
119
0
    hashObj->begin(ctx);
120
0
    if (salt && salt->data) {
121
0
        hashObj->update(ctx, salt->data, salt->len);
122
0
    }
123
0
    hashObj->update(ctx, (unsigned char *)pw, PORT_Strlen(pw));
124
0
    hashObj->end(ctx, key->data, &key->len, key->len);
125
0
    rv = SECSuccess;
126
127
0
loser:
128
0
    if (ctx) {
129
0
        hashObj->destroy(ctx, PR_TRUE);
130
0
    }
131
0
    if (rv != SECSuccess) {
132
0
        if (key->data != NULL) {
133
0
            PORT_ZFree(key->data, key->len);
134
0
        }
135
0
        key->data = NULL;
136
0
    }
137
0
    return rv;
138
0
}
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
0
{
186
0
    PLArenaPool *arena = NULL;
187
0
    SFTKDBEncryptedDataInfo edi;
188
0
    SECStatus rv;
189
190
0
    PORT_Assert(cipherValue);
191
0
    cipherValue->arena = NULL;
192
0
    cipherValue->param = NULL;
193
194
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
195
0
    if (arena == NULL) {
196
0
        return SECFailure;
197
0
    }
198
199
0
    rv = SEC_QuickDERDecodeItem(arena, &edi, sftkdb_EncryptedDataInfoTemplate,
200
0
                                cipherText);
201
0
    if (rv != SECSuccess) {
202
0
        goto loser;
203
0
    }
204
0
    cipherValue->alg = SECOID_GetAlgorithmTag(&edi.algorithm);
205
0
    cipherValue->param = nsspkcs5_AlgidToParam(&edi.algorithm);
206
0
    if (cipherValue->param == NULL) {
207
0
        goto loser;
208
0
    }
209
0
    cipherValue->value = edi.encryptedData;
210
0
    cipherValue->arena = arena;
211
212
0
    return SECSuccess;
213
0
loser:
214
0
    if (cipherValue->param) {
215
0
        nsspkcs5_DestroyPBEParameter(cipherValue->param);
216
0
        cipherValue->param = NULL;
217
0
    }
218
0
    if (arena) {
219
0
        PORT_FreeArena(arena, PR_FALSE);
220
0
    }
221
0
    return SECFailure;
222
0
}
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
0
{
233
0
    SFTKDBEncryptedDataInfo edi;
234
0
    SECAlgorithmID *algid;
235
0
    SECStatus rv;
236
0
    PLArenaPool *localArena = NULL;
237
238
0
    localArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
239
0
    if (localArena == NULL) {
240
0
        return SECFailure;
241
0
    }
242
243
0
    algid = nsspkcs5_CreateAlgorithmID(localArena, cipherValue->alg,
244
0
                                       cipherValue->param);
245
0
    if (algid == NULL) {
246
0
        rv = SECFailure;
247
0
        goto loser;
248
0
    }
249
0
    rv = SECOID_CopyAlgorithmID(localArena, &edi.algorithm, algid);
250
0
    SECOID_DestroyAlgorithmID(algid, PR_TRUE);
251
0
    if (rv != SECSuccess) {
252
0
        goto loser;
253
0
    }
254
0
    edi.encryptedData = cipherValue->value;
255
256
0
    *cipherText = SEC_ASN1EncodeItem(arena, NULL, &edi,
257
0
                                     sftkdb_EncryptedDataInfoTemplate);
258
0
    if (*cipherText == NULL) {
259
0
        rv = SECFailure;
260
0
    }
261
262
0
loser:
263
0
    if (localArena) {
264
0
        PORT_FreeArena(localArena, PR_TRUE);
265
0
    }
266
267
0
    return rv;
268
0
}
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
0
{
281
0
    SECStatus rv;
282
0
    sftkCipherValue cipherValue;
283
284
    /* First get the cipher type */
285
0
    *plain = NULL;
286
0
    rv = sftkdb_decodeCipherText(cipherText, &cipherValue);
287
0
    if (rv != SECSuccess) {
288
0
        goto loser;
289
0
    }
290
291
0
    *plain = nsspkcs5_CipherData(cipherValue.param, passKey, &cipherValue.value,
292
0
                                 PR_FALSE, NULL);
293
0
    if (*plain == NULL) {
294
0
        rv = SECFailure;
295
0
        goto loser;
296
0
    }
297
298
    /* If we are using aes 256, we need to check authentication as well.*/
299
0
    if ((type != CKT_INVALID_TYPE) &&
300
0
        (cipherValue.alg == SEC_OID_PKCS5_PBES2) &&
301
0
        (cipherValue.param->encAlg == SEC_OID_AES_256_CBC)) {
302
0
        SECItem signature;
303
0
        unsigned char signData[SDB_MAX_META_DATA_LEN];
304
0
        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
0
        if (handle == NULL) {
309
0
            rv = SECFailure;
310
0
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
311
0
            goto loser;
312
0
        }
313
314
0
        signature.data = signData;
315
0
        signature.len = sizeof(signData);
316
0
        rv = SECFailure;
317
        /* sign sftkdb_GetAttriibuteSignature returns a crv, not an rv */
318
0
        crv = sftkdb_GetAttributeSignature(handle, handle, id, type,
319
0
                                           &signature);
320
0
        if (crv == CKR_OK) {
321
0
            rv = sftkdb_VerifyAttribute(handle, passKey, CK_INVALID_HANDLE,
322
0
                                        type, *plain, &signature);
323
0
        }
324
0
        if (rv != SECSuccess) {
325
            /*  handle bug 1720226 where old versions of NSS misfiled the signature
326
             *  attribute on password update */
327
0
            id |= SFTK_KEYDB_TYPE | SFTK_TOKEN_TYPE;
328
0
            signature.len = sizeof(signData);
329
0
            crv = sftkdb_GetAttributeSignature(handle, handle, id, type,
330
0
                                               &signature);
331
0
            if (crv != CKR_OK) {
332
0
                rv = SECFailure;
333
0
                PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
334
0
                goto loser;
335
0
            }
336
0
            rv = sftkdb_VerifyAttribute(handle, passKey, CK_INVALID_HANDLE,
337
0
                                        type, *plain, &signature);
338
0
        }
339
0
    }
340
341
0
loser:
342
0
    if (cipherValue.param) {
343
0
        nsspkcs5_DestroyPBEParameter(cipherValue.param);
344
0
    }
345
0
    if (cipherValue.arena) {
346
0
        PORT_FreeArena(cipherValue.arena, PR_FALSE);
347
0
    }
348
    /* Item decrypted, but failed integrity, clear it out */
349
0
    if (*plain && rv != SECSuccess) {
350
0
        SECITEM_ZfreeItem(*plain, PR_TRUE);
351
0
        *plain = NULL;
352
0
    }
353
0
    return rv;
354
0
}
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
0
{
361
0
    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
0
        return PR_TRUE;
367
0
    }
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
0
    if ((db->sdb_flags & SDB_HAS_META) == 0) {
373
0
        return PR_TRUE;
374
0
    }
375
0
    return PR_FALSE;
376
0
}
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
0
{
390
0
    SECStatus rv;
391
0
    sftkCipherValue cipherValue;
392
0
    SECItem *cipher = NULL;
393
0
    NSSPKCS5PBEParameter *param = NULL;
394
0
    unsigned char saltData[HASH_LENGTH_MAX];
395
0
    SECItem *signature = NULL;
396
0
    HASH_HashType hashType = HASH_AlgNULL;
397
398
0
    if (sftkdb_useLegacyEncryption(handle, db)) {
399
0
        cipherValue.alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
400
0
        cipherValue.salt.len = SHA1_LENGTH;
401
0
        hashType = HASH_AlgSHA1;
402
0
    } else {
403
0
        cipherValue.alg = SEC_OID_AES_256_CBC;
404
0
        cipherValue.salt.len = SHA256_LENGTH;
405
0
        hashType = HASH_AlgSHA256;
406
0
    }
407
0
    cipherValue.salt.data = saltData;
408
0
    RNG_GenerateGlobalRandomBytes(saltData, cipherValue.salt.len);
409
410
0
    param = nsspkcs5_NewParam(cipherValue.alg, hashType, &cipherValue.salt,
411
0
                              iterationCount);
412
0
    if (param == NULL) {
413
0
        rv = SECFailure;
414
0
        goto loser;
415
0
    }
416
0
    cipher = nsspkcs5_CipherData(param, passKey, plainText, PR_TRUE, NULL);
417
0
    if (cipher == NULL) {
418
0
        rv = SECFailure;
419
0
        goto loser;
420
0
    }
421
0
    cipherValue.value = *cipher;
422
0
    cipherValue.param = param;
423
424
0
    rv = sftkdb_encodeCipherText(arena, &cipherValue, cipherText);
425
0
    if (rv != SECSuccess) {
426
0
        goto loser;
427
0
    }
428
429
    /* If we are using aes 256, we need to add authentication as well */
430
0
    if ((type != CKT_INVALID_TYPE) &&
431
0
        (cipherValue.param->encAlg == SEC_OID_AES_256_CBC)) {
432
0
        rv = sftkdb_SignAttribute(arena, handle, db, passKey, iterationCount,
433
0
                                  CK_INVALID_HANDLE, type, plainText,
434
0
                                  &signature);
435
0
        if (rv != SECSuccess) {
436
0
            goto loser;
437
0
        }
438
0
        rv = sftkdb_PutAttributeSignature(handle, db, id, type,
439
0
                                          signature);
440
0
        if (rv != SECSuccess) {
441
0
            goto loser;
442
0
        }
443
0
    }
444
445
0
loser:
446
0
    if ((arena == NULL) && signature) {
447
0
        SECITEM_ZfreeItem(signature, PR_TRUE);
448
0
    }
449
0
    if (cipher) {
450
0
        SECITEM_FreeItem(cipher, PR_TRUE);
451
0
    }
452
0
    if (param) {
453
0
        nsspkcs5_DestroyPBEParameter(param);
454
0
    }
455
0
    return rv;
456
0
}
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
0
{
470
0
    SECStatus rv = SECFailure;
471
0
    SECItem *key = NULL;
472
0
    HMACContext *hashCx = NULL;
473
0
    HASH_HashType hashType = HASH_AlgNULL;
474
0
    const SECHashObject *hashObj;
475
0
    unsigned char addressData[SDB_ULONG_SIZE];
476
0
    hashType = HASH_FromHMACOid(param->encAlg);
477
0
    if (hashType == HASH_AlgNULL) {
478
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
479
0
        return SECFailure;
480
0
    }
481
482
0
    hashObj = HASH_GetRawHashObject(hashType);
483
0
    if (hashObj == NULL) {
484
0
        goto loser;
485
0
    }
486
487
0
    key = nsspkcs5_ComputeKeyAndIV(param, passKey, NULL, PR_FALSE);
488
0
    if (!key) {
489
0
        goto loser;
490
0
    }
491
492
0
    hashCx = HMAC_Create(hashObj, key->data, key->len, PR_TRUE);
493
0
    if (!hashCx) {
494
0
        goto loser;
495
0
    }
496
0
    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
0
    sftk_ULong2SDBULong(addressData, objectID);
501
0
    HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
502
0
    sftk_ULong2SDBULong(addressData, attrType);
503
0
    HMAC_Update(hashCx, addressData, SDB_ULONG_SIZE);
504
505
0
    HMAC_Update(hashCx, plainText->data, plainText->len);
506
0
    rv = HMAC_Finish(hashCx, signData->data, &signData->len, signData->len);
507
508
0
loser:
509
0
    if (hashCx) {
510
0
        HMAC_Destroy(hashCx, PR_TRUE);
511
0
    }
512
0
    if (key) {
513
0
        SECITEM_ZfreeItem(key, PR_TRUE);
514
0
    }
515
0
    return rv;
516
0
}
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
0
{
529
0
    SECStatus rv;
530
0
    sftkCipherValue signValue;
531
0
    SECItem signature;
532
0
    unsigned char signData[HASH_LENGTH_MAX];
533
534
    /* First get the cipher type */
535
0
    rv = sftkdb_decodeCipherText(signText, &signValue);
536
0
    if (rv != SECSuccess) {
537
0
        goto loser;
538
0
    }
539
0
    signature.data = signData;
540
0
    signature.len = sizeof(signData);
541
542
0
    rv = sftkdb_pbehash(signValue.alg, passKey, signValue.param,
543
0
                        objectID, attrType, plainText, &signature);
544
0
    if (rv != SECSuccess) {
545
0
        goto loser;
546
0
    }
547
0
    if (SECITEM_CompareItem(&signValue.value, &signature) != 0) {
548
0
        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
549
0
        rv = SECFailure;
550
0
    }
551
552
0
loser:
553
0
    PORT_Memset(signData, 0, sizeof signData);
554
0
    if (signValue.param) {
555
0
        nsspkcs5_DestroyPBEParameter(signValue.param);
556
0
    }
557
0
    if (signValue.arena) {
558
0
        PORT_FreeArena(signValue.arena, PR_TRUE);
559
0
    }
560
0
    return rv;
561
0
}
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
0
{
574
0
    SECStatus rv;
575
0
    sftkCipherValue signValue;
576
0
    NSSPKCS5PBEParameter *param = NULL;
577
0
    unsigned char saltData[HASH_LENGTH_MAX];
578
0
    unsigned char signData[HASH_LENGTH_MAX];
579
0
    SECOidTag hmacAlg = SEC_OID_HMAC_SHA256; /* hash for authentication */
580
0
    SECOidTag prfAlg = SEC_OID_HMAC_SHA256;  /* hash for pb key generation */
581
0
    HASH_HashType prfType;
582
0
    unsigned int hmacLength;
583
0
    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
0
    prfType = HASH_FromHMACOid(prfAlg);
588
0
    PORT_Assert(prfType != HASH_AlgNULL);
589
0
    prfLength = HASH_GetRawHashObject(prfType)->length;
590
0
    PORT_Assert(prfLength <= HASH_LENGTH_MAX);
591
592
0
    hmacLength = HASH_GetRawHashObject(HASH_FromHMACOid(hmacAlg))->length;
593
0
    PORT_Assert(hmacLength <= HASH_LENGTH_MAX);
594
595
    /* initialize our CipherValue structure */
596
0
    signValue.alg = SEC_OID_PKCS5_PBMAC1;
597
0
    signValue.salt.len = prfLength;
598
0
    signValue.salt.data = saltData;
599
0
    signValue.value.data = signData;
600
0
    signValue.value.len = hmacLength;
601
0
    RNG_GenerateGlobalRandomBytes(saltData, prfLength);
602
603
    /* initialize our pkcs5 parameter */
604
0
    param = nsspkcs5_NewParam(signValue.alg, HASH_AlgSHA1, &signValue.salt,
605
0
                              iterationCount);
606
0
    if (param == NULL) {
607
0
        rv = SECFailure;
608
0
        goto loser;
609
0
    }
610
0
    param->keyID = pbeBitGenIntegrityKey;
611
    /* set the PKCS 5 v2 parameters, not extractable from the
612
     * data passed into nsspkcs5_NewParam */
613
0
    param->encAlg = hmacAlg;
614
0
    param->hashType = prfType;
615
0
    param->keyLen = hmacLength;
616
0
    rv = SECOID_SetAlgorithmID(param->poolp, &param->prfAlg, prfAlg, NULL);
617
0
    if (rv != SECSuccess) {
618
0
        goto loser;
619
0
    }
620
621
    /* calculate the mac */
622
0
    rv = sftkdb_pbehash(signValue.alg, passKey, param, objectID, attrType,
623
0
                        plainText, &signValue.value);
624
0
    if (rv != SECSuccess) {
625
0
        goto loser;
626
0
    }
627
0
    signValue.param = param;
628
629
    /* write it out */
630
0
    rv = sftkdb_encodeCipherText(arena, &signValue, signature);
631
0
    if (rv != SECSuccess) {
632
0
        goto loser;
633
0
    }
634
635
0
loser:
636
0
    PORT_Memset(signData, 0, sizeof signData);
637
0
    if (param) {
638
0
        nsspkcs5_DestroyPBEParameter(param);
639
0
    }
640
0
    return rv;
641
0
}
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
0
{
653
0
    unsigned char *data;
654
0
    int len;
655
656
0
    if (keydb->passwordLock == NULL) {
657
0
        PORT_Assert(keydb->type != SFTK_KEYDB_TYPE);
658
0
        return;
659
0
    }
660
661
    /* an atomic pointer set would be nice */
662
0
    SKIP_AFTER_FORK(PZ_Lock(keydb->passwordLock));
663
0
    data = keydb->passwordKey.data;
664
0
    len = keydb->passwordKey.len;
665
0
    keydb->passwordKey.data = passKey->data;
666
0
    keydb->passwordKey.len = passKey->len;
667
0
    keydb->defaultIterationCount = iterationCount;
668
0
    passKey->data = data;
669
0
    passKey->len = len;
670
0
    SKIP_AFTER_FORK(PZ_Unlock(keydb->passwordLock));
671
0
}
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
0
{
679
0
    return keydb->updateID ? PR_TRUE : PR_FALSE;
680
0
}
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
0
{
689
0
    if (!sftkdb_InUpdateMerge(keydb)) {
690
0
        return PR_FALSE;
691
0
    }
692
0
    if (keydb->updateDBIsInit && !keydb->updatePasswordKey) {
693
0
        return PR_TRUE;
694
0
    }
695
0
    return PR_FALSE;
696
0
}
697
698
/*
699
 * fetch an update password key from a handle.
700
 */
701
SECItem *
702
sftkdb_GetUpdatePasswordKey(SFTKDBHandle *handle)
703
0
{
704
0
    SECItem *key = NULL;
705
706
    /* if we're a cert db, fetch it from our peer key db */
707
0
    if (handle->type == SFTK_CERTDB_TYPE) {
708
0
        handle = handle->peerDB;
709
0
    }
710
711
    /* don't have one */
712
0
    if (!handle) {
713
0
        return NULL;
714
0
    }
715
716
0
    PZ_Lock(handle->passwordLock);
717
0
    if (handle->updatePasswordKey) {
718
0
        key = SECITEM_DupItem(handle->updatePasswordKey);
719
0
    }
720
0
    PZ_Unlock(handle->passwordLock);
721
722
0
    return key;
723
0
}
724
725
/*
726
 * free the update password key from a handle.
727
 */
728
void
729
sftkdb_FreeUpdatePasswordKey(SFTKDBHandle *handle)
730
0
{
731
0
    SECItem *key = NULL;
732
733
    /* don't have one */
734
0
    if (!handle) {
735
0
        return;
736
0
    }
737
738
    /* if we're a cert db, we don't have one */
739
0
    if (handle->type == SFTK_CERTDB_TYPE) {
740
0
        return;
741
0
    }
742
743
0
    PZ_Lock(handle->passwordLock);
744
0
    if (handle->updatePasswordKey) {
745
0
        key = handle->updatePasswordKey;
746
0
        handle->updatePasswordKey = NULL;
747
0
    }
748
0
    PZ_Unlock(handle->passwordLock);
749
750
0
    if (key) {
751
0
        SECITEM_ZfreeItem(key, PR_TRUE);
752
0
    }
753
754
0
    return;
755
0
}
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
0
{
769
0
    if (!keydb->update) {
770
0
        return keydb->db;
771
0
    }
772
0
    if (!sftkdb_InUpdateMerge(keydb)) {
773
0
        return keydb->update;
774
0
    }
775
0
    if (sftkdb_NeedUpdateDBPassword(keydb)) {
776
0
        return keydb->update;
777
0
    }
778
0
    return keydb->db;
779
0
}
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
0
{
789
0
    SECItem salt, value;
790
0
    unsigned char saltData[SDB_MAX_META_DATA_LEN];
791
0
    unsigned char valueData[SDB_MAX_META_DATA_LEN];
792
0
    CK_RV crv;
793
0
    SDB *db;
794
795
0
    if (keydb == NULL) {
796
0
        return SECFailure;
797
0
    }
798
799
0
    db = sftk_getPWSDB(keydb);
800
0
    if (db == NULL) {
801
0
        return SECFailure;
802
0
    }
803
804
0
    salt.data = saltData;
805
0
    salt.len = sizeof(saltData);
806
0
    value.data = valueData;
807
0
    value.len = sizeof(valueData);
808
0
    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
809
810
    /* If no password is set, we can update right away */
811
0
    if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update && crv != CKR_OK) {
812
        /* update the peer certdb if it exists */
813
0
        if (keydb->peerDB) {
814
0
            sftkdb_Update(keydb->peerDB, NULL);
815
0
        }
816
0
        sftkdb_Update(keydb, NULL);
817
0
    }
818
0
    return (crv == CKR_OK) ? SECSuccess : SECFailure;
819
0
}
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
0
{
836
    /* just like sftkdb_CheckPassowd, we get the salt and value, and
837
     * create a dbkey */
838
0
    SECStatus rv;
839
0
    SECItem salt, value;
840
0
    unsigned char saltData[SDB_MAX_META_DATA_LEN];
841
0
    unsigned char valueData[SDB_MAX_META_DATA_LEN];
842
0
    SECItem key;
843
0
    SDB *db;
844
0
    CK_RV crv;
845
0
    sftkCipherValue cipherValue;
846
847
0
    cipherValue.param = NULL;
848
0
    cipherValue.arena = NULL;
849
850
0
    if (keydb == NULL) {
851
0
        return SECFailure;
852
0
    }
853
854
0
    db = sftk_getPWSDB(keydb);
855
0
    if (db == NULL) {
856
0
        return SECFailure;
857
0
    }
858
859
0
    key.data = NULL;
860
0
    key.len = 0;
861
862
    /* get the entry from the database */
863
0
    salt.data = saltData;
864
0
    salt.len = sizeof(saltData);
865
0
    value.data = valueData;
866
0
    value.len = sizeof(valueData);
867
0
    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
868
0
    if (crv != CKR_OK) {
869
0
        rv = SECFailure;
870
0
        goto done;
871
0
    }
872
873
    /* get our intermediate key based on the entry salt value */
874
0
    rv = sftkdb_passwordToKey(keydb, &salt, "", &key);
875
0
    if (rv != SECSuccess) {
876
0
        goto done;
877
0
    }
878
879
    /* First get the cipher type */
880
0
    rv = sftkdb_decodeCipherText(&value, &cipherValue);
881
0
    if (rv != SECSuccess) {
882
0
        goto done;
883
0
    }
884
885
0
    if (cipherValue.param->iter != 1) {
886
0
        rv = SECFailure;
887
0
        goto done;
888
0
    }
889
890
0
    rv = sftkdb_finishPasswordCheck(keydb, &key, "", &value, tokenRemoved);
891
892
0
done:
893
0
    if (key.data) {
894
0
        PORT_ZFree(key.data, key.len);
895
0
    }
896
0
    if (cipherValue.param) {
897
0
        nsspkcs5_DestroyPBEParameter(cipherValue.param);
898
0
    }
899
0
    if (cipherValue.arena) {
900
0
        PORT_FreeArena(cipherValue.arena, PR_FALSE);
901
0
    }
902
0
    return rv;
903
0
}
904
905
0
#define SFTK_PW_CHECK_STRING "password-check"
906
0
#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
0
{
914
0
    SECStatus rv;
915
0
    SECItem salt, value;
916
0
    unsigned char saltData[SDB_MAX_META_DATA_LEN];
917
0
    unsigned char valueData[SDB_MAX_META_DATA_LEN];
918
0
    SECItem key;
919
0
    SDB *db;
920
0
    CK_RV crv;
921
922
0
    if (keydb == NULL) {
923
0
        return SECFailure;
924
0
    }
925
926
0
    db = sftk_getPWSDB(keydb);
927
0
    if (db == NULL) {
928
0
        return SECFailure;
929
0
    }
930
931
0
    key.data = NULL;
932
0
    key.len = 0;
933
934
0
    if (pw == NULL)
935
0
        pw = "";
936
937
    /* get the entry from the database */
938
0
    salt.data = saltData;
939
0
    salt.len = sizeof(saltData);
940
0
    value.data = valueData;
941
0
    value.len = sizeof(valueData);
942
0
    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
943
0
    if (crv != CKR_OK) {
944
0
        rv = SECFailure;
945
0
        goto done;
946
0
    }
947
948
    /* get our intermediate key based on the entry salt value */
949
0
    rv = sftkdb_passwordToKey(keydb, &salt, pw, &key);
950
0
    if (rv != SECSuccess) {
951
0
        goto done;
952
0
    }
953
954
0
    rv = sftkdb_finishPasswordCheck(keydb, &key, pw, &value, tokenRemoved);
955
956
0
done:
957
0
    if (key.data) {
958
0
        PORT_ZFree(key.data, key.len);
959
0
    }
960
0
    return rv;
961
0
}
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
0
{
969
0
    SECItem *result = NULL;
970
0
    SECStatus rv;
971
0
    int iterationCount = getPBEIterationCount();
972
973
0
    if (*pw == 0) {
974
0
        iterationCount = 1;
975
0
    } else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) {
976
0
        iterationCount = 1;
977
0
    }
978
979
    /* decrypt the entry value */
980
0
    rv = sftkdb_DecryptAttribute(keydb, key, CK_INVALID_HANDLE,
981
0
                                 CKT_INVALID_TYPE, value, &result);
982
0
    if (rv != SECSuccess) {
983
0
        goto done;
984
0
    }
985
986
    /* if it's what we expect, update our key in the database handle and
987
     * return Success */
988
0
    if ((result->len == SFTK_PW_CHECK_LEN) &&
989
0
        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
0
        PZ_Lock(keydb->passwordLock);
1016
0
        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
0
            keydb->updatePasswordKey = SECITEM_DupItem(key);
1023
0
            PZ_Unlock(keydb->passwordLock);
1024
0
            if (keydb->updatePasswordKey == NULL) {
1025
                /* PORT_Error set by SECITEM_DupItem */
1026
0
                rv = SECFailure;
1027
0
                goto done;
1028
0
            }
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
0
            *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
0
            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
0
                rv = sftkdb_CheckPassword(keydb, pw, tokenRemoved);
1052
0
                if (rv == SECSuccess) {
1053
                    /* source and target databases have the same password, we
1054
                     * are good to go */
1055
0
                    goto done;
1056
0
                }
1057
0
                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
0
                rv = SECSuccess;
1080
0
                goto done;
1081
0
            } 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
0
            }
1087
0
        } else {
1088
0
            PZ_Unlock(keydb->passwordLock);
1089
0
        }
1090
        /* load the keys, so the keydb can parse it's key set */
1091
0
        sftkdb_switchKeys(keydb, key, iterationCount);
1092
1093
        /* we need to update, do it now */
1094
0
        if (((keydb->db->sdb_flags & SDB_RDONLY) == 0) && keydb->update) {
1095
            /* update the peer certdb if it exists */
1096
0
            if (keydb->peerDB) {
1097
0
                sftkdb_Update(keydb->peerDB, key);
1098
0
            }
1099
0
            sftkdb_Update(keydb, key);
1100
0
        }
1101
0
    } else {
1102
0
        rv = SECFailure;
1103
        /*PORT_SetError( bad password); */
1104
0
    }
1105
1106
0
done:
1107
0
    if (result) {
1108
0
        SECITEM_ZfreeItem(result, PR_TRUE);
1109
0
    }
1110
0
    return rv;
1111
0
}
1112
1113
/*
1114
 * return Success if the there is a cached password key.
1115
 */
1116
SECStatus
1117
sftkdb_PWCached(SFTKDBHandle *keydb)
1118
0
{
1119
0
    SECStatus rv;
1120
0
    PZ_Lock(keydb->passwordLock);
1121
0
    rv = keydb->passwordKey.data ? SECSuccess : SECFailure;
1122
0
    PZ_Unlock(keydb->passwordLock);
1123
0
    return rv;
1124
0
}
1125
1126
static CK_RV
1127
sftk_updateMacs(PLArenaPool *arena, SFTKDBHandle *handle,
1128
                CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount)
1129
0
{
1130
0
    SFTKDBHandle *keyHandle = handle;
1131
0
    SDB *keyTarget = NULL;
1132
0
    if (handle->type != SFTK_KEYDB_TYPE) {
1133
0
        keyHandle = handle->peerDB;
1134
0
    }
1135
0
    if (keyHandle == NULL) {
1136
0
        return CKR_OK;
1137
0
    }
1138
    // Old DBs don't have metadata, so we can return early here.
1139
0
    keyTarget = SFTK_GET_SDB(keyHandle);
1140
0
    if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
1141
0
        return CKR_OK;
1142
0
    }
1143
1144
0
    id &= SFTK_OBJ_ID_MASK;
1145
1146
0
    CK_ATTRIBUTE_TYPE authAttrTypes[] = {
1147
0
        CKA_MODULUS,
1148
0
        CKA_PUBLIC_EXPONENT,
1149
0
        CKA_NSS_CERT_SHA1_HASH,
1150
0
        CKA_NSS_CERT_MD5_HASH,
1151
0
        CKA_NAME_HASH_ALGORITHM,
1152
0
        CKA_HASH_OF_CERTIFICATE,
1153
0
        CKA_PKCS_TRUST_SERVER_AUTH,
1154
0
        CKA_PKCS_TRUST_CLIENT_AUTH,
1155
0
        CKA_PKCS_TRUST_EMAIL_PROTECTION,
1156
0
        CKA_PKCS_TRUST_CODE_SIGNING,
1157
0
        CKA_NSS_TRUST_SERVER_AUTH,
1158
0
        CKA_NSS_TRUST_CLIENT_AUTH,
1159
0
        CKA_NSS_TRUST_EMAIL_PROTECTION,
1160
0
        CKA_NSS_TRUST_CODE_SIGNING,
1161
0
        CKA_NSS_TRUST_STEP_UP_APPROVED,
1162
0
        CKA_NSS_OVERRIDE_EXTENSIONS,
1163
0
    };
1164
0
    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
0
    unsigned int i;
1169
0
    for (i = 0; i < authAttrTypeCount; i++) {
1170
0
        CK_ATTRIBUTE authAttr = { authAttrTypes[i], NULL, 0 };
1171
0
        CK_RV rv = sftkdb_GetAttributeValue(handle, id, &authAttr, 1);
1172
0
        if (rv != CKR_OK) {
1173
0
            continue;
1174
0
        }
1175
0
        if ((authAttr.ulValueLen == -1) || (authAttr.ulValueLen == 0)) {
1176
0
            continue;
1177
0
        }
1178
0
        authAttr.pValue = PORT_ArenaAlloc(arena, authAttr.ulValueLen);
1179
0
        if (authAttr.pValue == NULL) {
1180
0
            return CKR_HOST_MEMORY;
1181
0
        }
1182
0
        rv = sftkdb_GetAttributeValue(handle, id, &authAttr, 1);
1183
0
        if (rv != CKR_OK) {
1184
0
            return rv;
1185
0
        }
1186
0
        if ((authAttr.ulValueLen == -1) || (authAttr.ulValueLen == 0)) {
1187
0
            return CKR_GENERAL_ERROR;
1188
0
        }
1189
        // GetAttributeValue just verified the old macs, so it is safe to write
1190
        // them out now.
1191
0
        if (authAttr.ulValueLen == sizeof(CK_ULONG) &&
1192
0
            sftkdb_isULONGAttribute(authAttr.type)) {
1193
0
            CK_ULONG value = *(CK_ULONG *)authAttr.pValue;
1194
0
            sftk_ULong2SDBULong(authAttr.pValue, value);
1195
0
            authAttr.ulValueLen = SDB_ULONG_SIZE;
1196
0
        }
1197
0
        SECItem *signText;
1198
0
        SECItem plainText;
1199
0
        plainText.data = authAttr.pValue;
1200
0
        plainText.len = authAttr.ulValueLen;
1201
0
        if (sftkdb_SignAttribute(arena, handle, keyTarget, newKey,
1202
0
                                 iterationCount, id, authAttr.type,
1203
0
                                 &plainText, &signText) != SECSuccess) {
1204
0
            return CKR_GENERAL_ERROR;
1205
0
        }
1206
0
        if (sftkdb_PutAttributeSignature(handle, keyTarget, id, authAttr.type,
1207
0
                                         signText) != SECSuccess) {
1208
0
            return CKR_GENERAL_ERROR;
1209
0
        }
1210
0
    }
1211
1212
0
    return CKR_OK;
1213
0
}
1214
1215
static CK_RV
1216
sftk_updateEncrypted(PLArenaPool *arena, SFTKDBHandle *keydb,
1217
                     CK_OBJECT_HANDLE id, SECItem *newKey, int iterationCount)
1218
0
{
1219
0
    CK_ATTRIBUTE_TYPE privAttrTypes[] = {
1220
0
        CKA_VALUE,
1221
0
        CKA_SEED,
1222
0
        CKA_PRIVATE_EXPONENT,
1223
0
        CKA_PRIME_1,
1224
0
        CKA_PRIME_2,
1225
0
        CKA_EXPONENT_1,
1226
0
        CKA_EXPONENT_2,
1227
0
        CKA_COEFFICIENT,
1228
0
    };
1229
0
    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
0
    unsigned int i;
1234
0
    for (i = 0; i < privAttrCount; i++) {
1235
        // Read the old attribute in the clear.
1236
0
        CK_OBJECT_HANDLE sdbId = id & SFTK_OBJ_ID_MASK;
1237
0
        CK_ATTRIBUTE privAttr = { privAttrTypes[i], NULL, 0 };
1238
0
        CK_RV crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1);
1239
0
        if (crv != CKR_OK) {
1240
0
            continue;
1241
0
        }
1242
0
        if ((privAttr.ulValueLen == -1) || (privAttr.ulValueLen == 0)) {
1243
0
            continue;
1244
0
        }
1245
0
        privAttr.pValue = PORT_ArenaAlloc(arena, privAttr.ulValueLen);
1246
0
        if (privAttr.pValue == NULL) {
1247
0
            return CKR_HOST_MEMORY;
1248
0
        }
1249
0
        crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1);
1250
0
        if (crv != CKR_OK) {
1251
0
            return crv;
1252
0
        }
1253
0
        if ((privAttr.ulValueLen == -1) || (privAttr.ulValueLen == 0)) {
1254
0
            return CKR_GENERAL_ERROR;
1255
0
        }
1256
0
        SECItem plainText;
1257
0
        SECItem *result;
1258
0
        plainText.data = privAttr.pValue;
1259
0
        plainText.len = privAttr.ulValueLen;
1260
0
        if (sftkdb_EncryptAttribute(arena, keydb, keydb->db, newKey,
1261
0
                                    iterationCount, sdbId, privAttr.type,
1262
0
                                    &plainText, &result) != SECSuccess) {
1263
0
            return CKR_GENERAL_ERROR;
1264
0
        }
1265
0
        privAttr.pValue = result->data;
1266
0
        privAttr.ulValueLen = result->len;
1267
        // Clear sensitive data.
1268
0
        PORT_Memset(plainText.data, 0, plainText.len);
1269
1270
        // Write the newly encrypted attributes out directly.
1271
0
        keydb->newKey = newKey;
1272
0
        keydb->newDefaultIterationCount = iterationCount;
1273
0
        crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, sdbId, &privAttr, 1);
1274
0
        keydb->newKey = NULL;
1275
0
        if (crv != CKR_OK) {
1276
0
            return crv;
1277
0
        }
1278
0
    }
1279
1280
0
    return CKR_OK;
1281
0
}
1282
1283
static CK_RV
1284
sftk_convertAttributes(SFTKDBHandle *handle, CK_OBJECT_HANDLE id,
1285
                       SECItem *newKey, int iterationCount)
1286
0
{
1287
0
    CK_RV crv = CKR_OK;
1288
0
    PLArenaPool *arena = NULL;
1289
1290
    /* get a new arena to simplify cleanup */
1291
0
    arena = PORT_NewArena(1024);
1292
0
    if (!arena) {
1293
0
        return CKR_HOST_MEMORY;
1294
0
    }
1295
1296
    /*
1297
     * first handle the MACS
1298
     */
1299
0
    crv = sftk_updateMacs(arena, handle, id, newKey, iterationCount);
1300
0
    if (crv != CKR_OK) {
1301
0
        goto loser;
1302
0
    }
1303
1304
0
    if (handle->type == SFTK_KEYDB_TYPE) {
1305
0
        crv = sftk_updateEncrypted(arena, handle, id, newKey,
1306
0
                                   iterationCount);
1307
0
        if (crv != CKR_OK) {
1308
0
            goto loser;
1309
0
        }
1310
0
    }
1311
1312
    /* free up our mess */
1313
0
    PORT_FreeArena(arena, PR_TRUE);
1314
0
    return CKR_OK;
1315
1316
0
loser:
1317
    /* there may be unencrypted data, clear it out down */
1318
0
    PORT_FreeArena(arena, PR_TRUE);
1319
0
    return crv;
1320
0
}
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
0
{
1329
0
    SDBFind *find = NULL;
1330
0
    CK_ULONG idCount = SFTK_MAX_IDS;
1331
0
    CK_OBJECT_HANDLE ids[SFTK_MAX_IDS];
1332
0
    CK_RV crv, crv2;
1333
0
    unsigned int i;
1334
1335
0
    crv = sftkdb_FindObjectsInit(handle, template, count, &find);
1336
1337
0
    if (crv != CKR_OK) {
1338
0
        return crv;
1339
0
    }
1340
0
    while ((crv == CKR_OK) && (idCount == SFTK_MAX_IDS)) {
1341
0
        crv = sftkdb_FindObjects(handle, find, ids, SFTK_MAX_IDS, &idCount);
1342
0
        for (i = 0; (crv == CKR_OK) && (i < idCount); i++) {
1343
0
            crv = sftk_convertAttributes(handle, ids[i], newKey,
1344
0
                                         iterationCount);
1345
0
        }
1346
0
    }
1347
0
    crv2 = sftkdb_FindObjectsFinal(handle, find);
1348
0
    if (crv == CKR_OK)
1349
0
        crv = crv2;
1350
1351
0
    return crv;
1352
0
}
1353
1354
/*
1355
 * change the database password.
1356
 */
1357
SECStatus
1358
sftkdb_ChangePassword(SFTKDBHandle *keydb,
1359
                      char *oldPin, char *newPin, PRBool *tokenRemoved)
1360
0
{
1361
0
    SECStatus rv = SECSuccess;
1362
0
    SECItem plainText;
1363
0
    SECItem newKey;
1364
0
    SECItem *result = NULL;
1365
0
    SECItem salt, value;
1366
0
    SFTKDBHandle *certdb;
1367
0
    unsigned char saltData[SDB_MAX_META_DATA_LEN];
1368
0
    unsigned char valueData[SDB_MAX_META_DATA_LEN];
1369
0
    int iterationCount = getPBEIterationCount();
1370
0
    int preferred_salt_length;
1371
0
    CK_RV crv;
1372
0
    SDB *db;
1373
1374
0
    if (keydb == NULL) {
1375
0
        return SECFailure;
1376
0
    }
1377
1378
0
    db = SFTK_GET_SDB(keydb);
1379
0
    if (db == NULL) {
1380
0
        return SECFailure;
1381
0
    }
1382
1383
0
    newKey.data = NULL;
1384
1385
    /* make sure we have a valid old pin */
1386
0
    crv = (*keydb->db->sdb_Begin)(keydb->db);
1387
0
    if (crv != CKR_OK) {
1388
0
        rv = SECFailure;
1389
0
        goto loser;
1390
0
    }
1391
0
    salt.data = saltData;
1392
0
    salt.len = sizeof(saltData);
1393
0
    value.data = valueData;
1394
0
    value.len = sizeof(valueData);
1395
0
    crv = (*db->sdb_GetMetaData)(db, "password", &salt, &value);
1396
0
    if (crv == CKR_OK) {
1397
0
        rv = sftkdb_CheckPassword(keydb, oldPin, tokenRemoved);
1398
0
        if (rv == SECFailure) {
1399
0
            goto loser;
1400
0
        }
1401
0
    } else {
1402
0
        salt.len = 0;
1403
0
    }
1404
1405
0
    preferred_salt_length = SHA384_LENGTH;
1406
1407
    /* Prefer SHA-1 if the password is NULL */
1408
0
    if (!newPin || *newPin == 0) {
1409
0
        preferred_salt_length = SHA1_LENGTH;
1410
0
    }
1411
1412
0
    if (salt.len != preferred_salt_length) {
1413
0
        salt.len = preferred_salt_length;
1414
0
        RNG_GenerateGlobalRandomBytes(salt.data, salt.len);
1415
0
    }
1416
1417
0
    if (newPin && *newPin == 0) {
1418
0
        iterationCount = 1;
1419
0
    } else if (keydb->usesLegacyStorage && !sftk_isLegacyIterationCountAllowed()) {
1420
0
        iterationCount = 1;
1421
0
    }
1422
1423
0
    rv = sftkdb_passwordToKey(keydb, &salt, newPin, &newKey);
1424
0
    if (rv != SECSuccess) {
1425
0
        goto loser;
1426
0
    }
1427
1428
    /*
1429
     * convert encrypted entries here.
1430
     */
1431
0
    crv = sftkdb_convertObjects(keydb, NULL, 0, &newKey, iterationCount);
1432
0
    if (crv != CKR_OK) {
1433
0
        rv = SECFailure;
1434
0
        goto loser;
1435
0
    }
1436
    /* fix up certdb macs */
1437
0
    certdb = keydb->peerDB;
1438
0
    if (certdb) {
1439
0
        CK_ATTRIBUTE objectType = { CKA_CLASS, 0, sizeof(CK_OBJECT_CLASS) };
1440
0
        CK_OBJECT_CLASS myClass = CKO_NSS_TRUST;
1441
1442
0
        objectType.pValue = &myClass;
1443
0
        crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey,
1444
0
                                    iterationCount);
1445
0
        if (crv != CKR_OK) {
1446
0
            rv = SECFailure;
1447
0
            goto loser;
1448
0
        }
1449
0
        myClass = CKO_PUBLIC_KEY;
1450
0
        crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey,
1451
0
                                    iterationCount);
1452
0
        if (crv != CKR_OK) {
1453
0
            rv = SECFailure;
1454
0
            goto loser;
1455
0
        }
1456
1457
0
        myClass = CKO_TRUST;
1458
0
        crv = sftkdb_convertObjects(certdb, &objectType, 1, &newKey,
1459
0
                                    iterationCount);
1460
0
        if (crv != CKR_OK) {
1461
0
            rv = SECFailure;
1462
0
            goto loser;
1463
0
        }
1464
0
    }
1465
1466
0
    plainText.data = (unsigned char *)SFTK_PW_CHECK_STRING;
1467
0
    plainText.len = SFTK_PW_CHECK_LEN;
1468
1469
0
    rv = sftkdb_EncryptAttribute(NULL, keydb, keydb->db, &newKey,
1470
0
                                 iterationCount, CK_INVALID_HANDLE,
1471
0
                                 CKT_INVALID_TYPE, &plainText, &result);
1472
0
    if (rv != SECSuccess) {
1473
0
        goto loser;
1474
0
    }
1475
0
    value.data = result->data;
1476
0
    value.len = result->len;
1477
0
    crv = (*keydb->db->sdb_PutMetaData)(keydb->db, "password", &salt, &value);
1478
0
    if (crv != CKR_OK) {
1479
0
        rv = SECFailure;
1480
0
        goto loser;
1481
0
    }
1482
0
    crv = (*keydb->db->sdb_Commit)(keydb->db);
1483
0
    if (crv != CKR_OK) {
1484
0
        rv = SECFailure;
1485
0
        goto loser;
1486
0
    }
1487
1488
0
    keydb->newKey = NULL;
1489
1490
0
    sftkdb_switchKeys(keydb, &newKey, iterationCount);
1491
1492
0
loser:
1493
0
    if (newKey.data) {
1494
0
        PORT_ZFree(newKey.data, newKey.len);
1495
0
    }
1496
0
    if (result) {
1497
0
        SECITEM_FreeItem(result, PR_TRUE);
1498
0
    }
1499
0
    if (rv != SECSuccess) {
1500
0
        (*keydb->db->sdb_Abort)(keydb->db);
1501
0
    }
1502
1503
0
    return rv;
1504
0
}
1505
1506
/*
1507
 * lose our cached password
1508
 */
1509
SECStatus
1510
sftkdb_ClearPassword(SFTKDBHandle *keydb)
1511
0
{
1512
0
    SECItem oldKey;
1513
0
    oldKey.data = NULL;
1514
0
    oldKey.len = 0;
1515
0
    sftkdb_switchKeys(keydb, &oldKey, 1);
1516
0
    if (oldKey.data) {
1517
0
        PORT_ZFree(oldKey.data, oldKey.len);
1518
0
    }
1519
0
    return SECSuccess;
1520
0
}