Coverage Report

Created: 2025-08-18 06:36

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