Coverage Report

Created: 2025-07-01 06:25

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