Coverage Report

Created: 2026-02-05 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/softoken/sftkdb.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
/*
5
 *  The following code handles the storage of PKCS 11 modules used by the
6
 * NSS. For the rest of NSS, only one kind of database handle exists:
7
 *
8
 *     SFTKDBHandle
9
 *
10
 * There is one SFTKDBHandle for the each key database and one for each cert
11
 * database. These databases are opened as associated pairs, one pair per
12
 * slot. SFTKDBHandles are reference counted objects.
13
 *
14
 * Each SFTKDBHandle points to a low level database handle (SDB). This handle
15
 * represents the underlying physical database. These objects are not
16
 * reference counted, an are 'owned' by their respective SFTKDBHandles.
17
 *
18
 *
19
 */
20
#include "sftkdb.h"
21
#include "sftkdbti.h"
22
#include "pkcs11t.h"
23
#include "pkcs11i.h"
24
#include "sdb.h"
25
#include "prprf.h"
26
#include "pratom.h"
27
#include "lgglue.h"
28
#include "utilpars.h"
29
#include "secerr.h"
30
#include "softoken.h"
31
#if defined(_WIN32)
32
#include <windows.h>
33
#endif
34
35
/*
36
 * We want all databases to have the same binary representation independent of
37
 * endianness or length of the host architecture. In general PKCS #11 attributes
38
 * are endian/length independent except those attributes that pass CK_ULONG.
39
 *
40
 * The following functions fixes up the CK_ULONG type attributes so that the data
41
 * base sees a machine independent view. CK_ULONGs are stored as 4 byte network
42
 * byte order values (big endian).
43
 */
44
0
#define BBP 8
45
46
PRBool
47
sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type)
48
0
{
49
0
    switch (type) {
50
0
        case CKA_CERTIFICATE_CATEGORY:
51
0
        case CKA_CERTIFICATE_TYPE:
52
0
        case CKA_CLASS:
53
0
        case CKA_JAVA_MIDP_SECURITY_DOMAIN:
54
0
        case CKA_KEY_GEN_MECHANISM:
55
0
        case CKA_KEY_TYPE:
56
0
        case CKA_MECHANISM_TYPE:
57
0
        case CKA_MODULUS_BITS:
58
0
        case CKA_PRIME_BITS:
59
0
        case CKA_SUBPRIME_BITS:
60
0
        case CKA_VALUE_BITS:
61
0
        case CKA_VALUE_LEN:
62
63
0
        case CKA_PKCS_TRUST_SERVER_AUTH:
64
0
        case CKA_PKCS_TRUST_CLIENT_AUTH:
65
0
        case CKA_PKCS_TRUST_CODE_SIGNING:
66
0
        case CKA_PKCS_TRUST_EMAIL_PROTECTION:
67
0
        case CKA_TRUST_IPSEC_IKE:
68
0
        case CKA_PKCS_TRUST_TIME_STAMPING:
69
0
        case CKA_NAME_HASH_ALGORITHM:
70
71
0
        case CKA_NSS_TRUST_DIGITAL_SIGNATURE:
72
0
        case CKA_NSS_TRUST_NON_REPUDIATION:
73
0
        case CKA_NSS_TRUST_KEY_ENCIPHERMENT:
74
0
        case CKA_NSS_TRUST_DATA_ENCIPHERMENT:
75
0
        case CKA_NSS_TRUST_KEY_AGREEMENT:
76
0
        case CKA_NSS_TRUST_KEY_CERT_SIGN:
77
0
        case CKA_NSS_TRUST_CRL_SIGN:
78
79
0
        case CKA_NSS_TRUST_SERVER_AUTH:
80
0
        case CKA_NSS_TRUST_CLIENT_AUTH:
81
0
        case CKA_NSS_TRUST_CODE_SIGNING:
82
0
        case CKA_NSS_TRUST_EMAIL_PROTECTION:
83
0
        case CKA_NSS_TRUST_IPSEC_END_SYSTEM:
84
0
        case CKA_NSS_TRUST_IPSEC_TUNNEL:
85
0
        case CKA_NSS_TRUST_IPSEC_USER:
86
0
        case CKA_NSS_TRUST_TIME_STAMPING:
87
0
        case CKA_NSS_TRUST_STEP_UP_APPROVED:
88
0
            return PR_TRUE;
89
0
        default:
90
0
            break;
91
0
    }
92
0
    return PR_FALSE;
93
0
}
94
95
/* are the attributes private? */
96
static PRBool
97
sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type)
98
0
{
99
0
    switch (type) {
100
0
        case CKA_VALUE:
101
0
        case CKA_SEED:
102
0
        case CKA_PRIVATE_EXPONENT:
103
0
        case CKA_PRIME_1:
104
0
        case CKA_PRIME_2:
105
0
        case CKA_EXPONENT_1:
106
0
        case CKA_EXPONENT_2:
107
0
        case CKA_COEFFICIENT:
108
0
            return PR_TRUE;
109
0
        default:
110
0
            break;
111
0
    }
112
0
    return PR_FALSE;
113
0
}
114
115
/* These attributes must be authenticated with an hmac. */
116
static PRBool
117
sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type)
118
0
{
119
0
    switch (type) {
120
0
        case CKA_MODULUS:
121
0
        case CKA_PUBLIC_EXPONENT:
122
0
        case CKA_NSS_CERT_SHA1_HASH:
123
0
        case CKA_NSS_CERT_MD5_HASH:
124
0
        case CKA_NSS_TRUST_SERVER_AUTH:
125
0
        case CKA_NSS_TRUST_CLIENT_AUTH:
126
0
        case CKA_NSS_TRUST_EMAIL_PROTECTION:
127
0
        case CKA_NSS_TRUST_CODE_SIGNING:
128
0
        case CKA_NSS_TRUST_STEP_UP_APPROVED:
129
0
        case CKA_HASH_OF_CERTIFICATE:
130
0
        case CKA_NAME_HASH_ALGORITHM:
131
0
        case CKA_PKCS_TRUST_SERVER_AUTH:
132
0
        case CKA_PKCS_TRUST_CLIENT_AUTH:
133
0
        case CKA_PKCS_TRUST_EMAIL_PROTECTION:
134
0
        case CKA_PKCS_TRUST_CODE_SIGNING:
135
0
        case CKA_NSS_OVERRIDE_EXTENSIONS:
136
0
            return PR_TRUE;
137
0
        default:
138
0
            break;
139
0
    }
140
0
    return PR_FALSE;
141
0
}
142
/*
143
 * convert a native ULONG to a database ulong. Database ulong's
144
 * are all 4 byte big endian values.
145
 */
146
void
147
sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value)
148
0
{
149
0
    int i;
150
151
0
    for (i = 0; i < SDB_ULONG_SIZE; i++) {
152
0
        data[i] = (value >> (SDB_ULONG_SIZE - 1 - i) * BBP) & 0xff;
153
0
    }
154
0
}
155
156
/*
157
 * convert a database ulong back to a native ULONG. (reverse of the above
158
 * function).
159
 */
160
static CK_ULONG
161
sftk_SDBULong2ULong(unsigned char *data)
162
0
{
163
0
    int i;
164
0
    CK_ULONG value = 0;
165
166
0
    for (i = 0; i < SDB_ULONG_SIZE; i++) {
167
0
        value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * BBP);
168
0
    }
169
0
    return value;
170
0
}
171
172
/* certain trust records are default values, which are the values
173
 * returned if the signature check fails anyway.
174
 * In those cases, we can skip the signature check. */
175
PRBool
176
sftkdb_isNullTrust(const CK_ATTRIBUTE *template)
177
0
{
178
0
    switch (template->type) {
179
0
        case CKA_NSS_TRUST_SERVER_AUTH:
180
0
        case CKA_NSS_TRUST_CLIENT_AUTH:
181
0
        case CKA_NSS_TRUST_EMAIL_PROTECTION:
182
0
        case CKA_NSS_TRUST_CODE_SIGNING:
183
0
            if (template->ulValueLen != SDB_ULONG_SIZE) {
184
0
                break;
185
0
            }
186
0
            if (sftk_SDBULong2ULong(template->pValue) ==
187
0
                CKT_NSS_TRUST_UNKNOWN) {
188
0
                return PR_TRUE;
189
0
            }
190
0
            break;
191
0
        case CKA_PKCS_TRUST_SERVER_AUTH:
192
0
        case CKA_PKCS_TRUST_CLIENT_AUTH:
193
0
        case CKA_PKCS_TRUST_EMAIL_PROTECTION:
194
0
        case CKA_PKCS_TRUST_CODE_SIGNING:
195
0
            if (template->ulValueLen != SDB_ULONG_SIZE) {
196
0
                break;
197
0
            }
198
0
            if (sftk_SDBULong2ULong(template->pValue) ==
199
0
                CKT_TRUST_UNKNOWN) {
200
0
                return PR_TRUE;
201
0
            }
202
0
            break;
203
0
        case CKA_NSS_TRUST_STEP_UP_APPROVED:
204
0
            if (template->ulValueLen != 1) {
205
0
                break;
206
0
            }
207
0
            if (*((unsigned char *)(template->pValue)) == 0) {
208
0
                return PR_TRUE;
209
0
            }
210
0
            break;
211
0
        default:
212
0
            break;
213
0
    }
214
0
    return PR_FALSE;
215
0
}
216
217
/*
218
 * fix up the input templates. Our fixed up ints are stored in data and must
219
 * be freed by the caller. The new template must also be freed. If there are no
220
 * CK_ULONG attributes, the orignal template is passed in as is.
221
 */
222
static CK_ATTRIBUTE *
223
sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
224
                       unsigned char **dataOut, int *dataOutSize)
225
0
{
226
0
    int i;
227
0
    int ulongCount = 0;
228
0
    unsigned char *data;
229
0
    CK_ATTRIBUTE *ntemplate;
230
231
0
    *dataOut = NULL;
232
0
    *dataOutSize = 0;
233
234
    /* first count the number of CK_ULONG attributes */
235
0
    for (i = 0; i < count; i++) {
236
        /* Don't 'fixup' NULL values */
237
0
        if (!template[i].pValue) {
238
0
            continue;
239
0
        }
240
0
        if (template[i].ulValueLen == sizeof(CK_ULONG)) {
241
0
            if (sftkdb_isULONGAttribute(template[i].type)) {
242
0
                ulongCount++;
243
0
            }
244
0
        }
245
0
    }
246
    /* no attributes to fixup, just call on through */
247
0
    if (ulongCount == 0) {
248
0
        return (CK_ATTRIBUTE *)template;
249
0
    }
250
251
    /* allocate space for new ULONGS */
252
0
    data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE * ulongCount);
253
0
    if (!data) {
254
0
        return NULL;
255
0
    }
256
257
    /* allocate new template */
258
0
    ntemplate = PORT_NewArray(CK_ATTRIBUTE, count);
259
0
    if (!ntemplate) {
260
0
        PORT_Free(data);
261
0
        return NULL;
262
0
    }
263
0
    *dataOut = data;
264
0
    *dataOutSize = SDB_ULONG_SIZE * ulongCount;
265
    /* copy the old template, fixup the actual ulongs */
266
0
    for (i = 0; i < count; i++) {
267
0
        ntemplate[i] = template[i];
268
        /* Don't 'fixup' NULL values */
269
0
        if (!template[i].pValue) {
270
0
            continue;
271
0
        }
272
0
        if (template[i].ulValueLen == sizeof(CK_ULONG)) {
273
0
            if (sftkdb_isULONGAttribute(template[i].type)) {
274
0
                CK_ULONG value = *(CK_ULONG *)template[i].pValue;
275
0
                sftk_ULong2SDBULong(data, value);
276
0
                ntemplate[i].pValue = data;
277
0
                ntemplate[i].ulValueLen = SDB_ULONG_SIZE;
278
0
                data += SDB_ULONG_SIZE;
279
0
            }
280
0
        }
281
0
    }
282
0
    return ntemplate;
283
0
}
284
285
static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x";
286
287
/*
288
 * return a string describing the database type (key or cert)
289
 */
290
const char *
291
sftkdb_TypeString(SFTKDBHandle *handle)
292
0
{
293
0
    return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert";
294
0
}
295
296
/*
297
 * Some attributes are signed with an Hmac and a pbe key generated from
298
 * the password. This signature is stored indexed by object handle and
299
 * attribute type in the meta data table in the key database.
300
 *
301
 * Signature entries are indexed by the string
302
 * sig_[cert/key]_{ObjectID}_{Attribute}
303
 *
304
 * This function fetches that pkcs5 signature. Caller supplies a SECItem
305
 * pre-allocated to the appropriate size if the SECItem is too small the
306
 * function will fail with CKR_BUFFER_TOO_SMALL.
307
 */
308
static CK_RV
309
sftkdb_getRawAttributeSignature(SFTKDBHandle *handle, SDB *db,
310
                                CK_OBJECT_HANDLE objectID,
311
                                CK_ATTRIBUTE_TYPE type,
312
                                SECItem *signText)
313
0
{
314
0
    char id[30];
315
0
    CK_RV crv;
316
317
0
    snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE,
318
0
             sftkdb_TypeString(handle),
319
0
             (unsigned int)objectID, (unsigned int)type);
320
321
0
    crv = (*db->sdb_GetMetaData)(db, id, signText, NULL);
322
0
    return crv;
323
0
}
324
325
CK_RV
326
sftkdb_GetAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle,
327
                             CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
328
                             SECItem *signText)
329
0
{
330
0
    SDB *db = SFTK_GET_SDB(keyHandle);
331
0
    return sftkdb_getRawAttributeSignature(handle, db, objectID, type, signText);
332
0
}
333
334
CK_RV
335
sftkdb_DestroyAttributeSignature(SFTKDBHandle *handle, SDB *db,
336
                                 CK_OBJECT_HANDLE objectID,
337
                                 CK_ATTRIBUTE_TYPE type)
338
0
{
339
0
    char id[30];
340
0
    CK_RV crv;
341
342
0
    snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE,
343
0
             sftkdb_TypeString(handle),
344
0
             (unsigned int)objectID, (unsigned int)type);
345
346
0
    crv = (*db->sdb_DestroyMetaData)(db, id);
347
0
    return crv;
348
0
}
349
350
/*
351
 * Some attributes are signed with an Hmac and a pbe key generated from
352
 * the password. This signature is stored indexed by object handle and
353
 * attribute type in the meta data table in the key database.
354
 *
355
 * Signature entries are indexed by the string
356
 * sig_[cert/key]_{ObjectID}_{Attribute}
357
 *
358
 * This function stores that pkcs5 signature.
359
 */
360
CK_RV
361
sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget,
362
                             CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
363
                             SECItem *signText)
364
0
{
365
0
    char id[30];
366
0
    CK_RV crv;
367
368
0
    snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE,
369
0
             sftkdb_TypeString(handle),
370
0
             (unsigned int)objectID, (unsigned int)type);
371
372
0
    crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL);
373
0
    return crv;
374
0
}
375
376
/*
377
 * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated
378
 * separate data sections for the database ULONG values.
379
 */
380
static CK_RV
381
sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID,
382
                        CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle)
383
0
{
384
0
    int i;
385
0
    CK_RV crv = CKR_OK;
386
0
    SFTKDBHandle *keyHandle;
387
0
    PRBool checkSig = PR_TRUE;
388
0
    PRBool checkEnc = PR_TRUE;
389
390
0
    PORT_Assert(handle);
391
392
    /* find the key handle */
393
0
    keyHandle = handle;
394
0
    if (handle->type != SFTK_KEYDB_TYPE) {
395
0
        checkEnc = PR_FALSE;
396
0
        keyHandle = handle->peerDB;
397
0
    }
398
399
0
    if ((keyHandle == NULL) ||
400
0
        ((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0) ||
401
0
        (sftkdb_PWCached(keyHandle) != SECSuccess)) {
402
0
        checkSig = PR_FALSE;
403
0
    }
404
405
0
    for (i = 0; i < count; i++) {
406
0
        CK_ULONG length = template[i].ulValueLen;
407
0
        template[i].ulValueLen = ntemplate[i].ulValueLen;
408
        /* fixup ulongs */
409
0
        if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) {
410
0
            if (sftkdb_isULONGAttribute(template[i].type)) {
411
0
                if (template[i].pValue) {
412
0
                    CK_ULONG value;
413
414
0
                    value = sftk_SDBULong2ULong(ntemplate[i].pValue);
415
0
                    if (length < sizeof(CK_ULONG)) {
416
0
                        template[i].ulValueLen = -1;
417
0
                        crv = CKR_BUFFER_TOO_SMALL;
418
0
                        continue;
419
0
                    }
420
0
                    PORT_Memcpy(template[i].pValue, &value, sizeof(CK_ULONG));
421
0
                }
422
0
                template[i].ulValueLen = sizeof(CK_ULONG);
423
0
            }
424
0
        }
425
426
        /* if no data was retrieved, no need to process encrypted or signed
427
         * attributes */
428
0
        if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) {
429
0
            continue;
430
0
        }
431
432
        /* fixup private attributes */
433
0
        if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) {
434
            /* we have a private attribute */
435
            /* This code depends on the fact that the cipherText is bigger
436
             * than the plain text */
437
0
            SECItem cipherText;
438
0
            SECItem *plainText;
439
0
            SECStatus rv;
440
441
0
            cipherText.data = ntemplate[i].pValue;
442
0
            cipherText.len = ntemplate[i].ulValueLen;
443
0
            PZ_Lock(handle->passwordLock);
444
0
            if (handle->passwordKey.data == NULL) {
445
0
                PZ_Unlock(handle->passwordLock);
446
0
                template[i].ulValueLen = -1;
447
0
                crv = CKR_USER_NOT_LOGGED_IN;
448
0
                continue;
449
0
            }
450
0
            rv = sftkdb_DecryptAttribute(handle,
451
0
                                         &handle->passwordKey,
452
0
                                         objectID,
453
0
                                         ntemplate[i].type,
454
0
                                         &cipherText, &plainText);
455
0
            PZ_Unlock(handle->passwordLock);
456
0
            if (rv != SECSuccess) {
457
0
                PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
458
0
                template[i].ulValueLen = -1;
459
0
                crv = CKR_GENERAL_ERROR;
460
0
                continue;
461
0
            }
462
0
            PORT_Assert(template[i].ulValueLen >= plainText->len);
463
0
            if (template[i].ulValueLen < plainText->len) {
464
0
                SECITEM_ZfreeItem(plainText, PR_TRUE);
465
0
                PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
466
0
                template[i].ulValueLen = -1;
467
0
                crv = CKR_GENERAL_ERROR;
468
0
                continue;
469
0
            }
470
471
            /* copy the plain text back into the template */
472
0
            PORT_Memcpy(template[i].pValue, plainText->data, plainText->len);
473
0
            template[i].ulValueLen = plainText->len;
474
0
            SECITEM_ZfreeItem(plainText, PR_TRUE);
475
0
        }
476
        /* make sure signed attributes are valid */
477
0
        if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type) && !sftkdb_isNullTrust(&ntemplate[i])) {
478
0
            SECStatus rv;
479
0
            CK_RV local_crv;
480
0
            SECItem signText;
481
0
            SECItem plainText;
482
0
            unsigned char signData[SDB_MAX_META_DATA_LEN];
483
484
0
            signText.data = signData;
485
0
            signText.len = sizeof(signData);
486
487
            /* Use a local variable so that we don't clobber any already
488
             * set error. This function returns either CKR_OK or the last
489
             * found error in the template */
490
0
            local_crv = sftkdb_GetAttributeSignature(handle, keyHandle,
491
0
                                                     objectID,
492
0
                                                     ntemplate[i].type,
493
0
                                                     &signText);
494
0
            if (local_crv != CKR_OK) {
495
0
                PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
496
0
                template[i].ulValueLen = -1;
497
0
                crv = local_crv;
498
0
                continue;
499
0
            }
500
501
0
            plainText.data = ntemplate[i].pValue;
502
0
            plainText.len = ntemplate[i].ulValueLen;
503
504
            /*
505
             * we do a second check holding the lock just in case the user
506
             * loggout while we were trying to get the signature.
507
             */
508
0
            PZ_Lock(keyHandle->passwordLock);
509
0
            if (keyHandle->passwordKey.data == NULL) {
510
                /* if we are no longer logged in, no use checking the other
511
                 * Signatures either. */
512
0
                checkSig = PR_FALSE;
513
0
                PZ_Unlock(keyHandle->passwordLock);
514
0
                continue;
515
0
            }
516
517
0
            rv = sftkdb_VerifyAttribute(keyHandle,
518
0
                                        &keyHandle->passwordKey,
519
0
                                        objectID, ntemplate[i].type,
520
0
                                        &plainText, &signText);
521
0
            PZ_Unlock(keyHandle->passwordLock);
522
0
            if (rv != SECSuccess) {
523
0
                PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
524
0
                template[i].ulValueLen = -1;
525
0
                crv = CKR_SIGNATURE_INVALID; /* better error code? */
526
0
            }
527
            /* This Attribute is fine */
528
0
        }
529
0
    }
530
0
    return crv;
531
0
}
532
533
/*
534
 * Some attributes are signed with an HMAC and a pbe key generated from
535
 * the password. This signature is stored indexed by object handle and
536
 *
537
 * Those attributes are:
538
 * 1) Trust object hashes and trust values.
539
 * 2) public key values.
540
 *
541
 * Certs themselves are considered properly authenticated by virtue of their
542
 * signature, or their matching hash with the trust object.
543
 *
544
 * These signature is only checked for objects coming from shared databases.
545
 * Older dbm style databases have such no signature checks. HMACs are also
546
 * only checked when the token is logged in, as it requires a pbe generated
547
 * from the password.
548
 *
549
 * Tokens which have no key database (and therefore no master password) do not
550
 * have any stored signature values. Signature values are stored in the key
551
 * database, since the signature data is tightly coupled to the key database
552
 * password.
553
 *
554
 * This function takes a template of attributes that were either created or
555
 * modified. These attributes are checked to see if the need to be signed.
556
 * If they do, then this function signs the attributes and writes them
557
 * to the meta data store.
558
 *
559
 * This function can fail if there are attributes that must be signed, but
560
 * the token is not logged in.
561
 *
562
 * The caller is expected to abort any transaction he was in in the
563
 * event of a failure of this function.
564
 */
565
static CK_RV
566
sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle,
567
                  PRBool mayBeUpdateDB,
568
                  CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
569
                  CK_ULONG count)
570
0
{
571
0
    unsigned int i;
572
0
    CK_RV crv;
573
0
    SFTKDBHandle *keyHandle = handle;
574
0
    SDB *keyTarget = NULL;
575
0
    PRBool usingPeerDB = PR_FALSE;
576
0
    PRBool inPeerDBTransaction = PR_FALSE;
577
578
0
    PORT_Assert(handle);
579
580
0
    if (handle->type != SFTK_KEYDB_TYPE) {
581
0
        keyHandle = handle->peerDB;
582
0
        usingPeerDB = PR_TRUE;
583
0
    }
584
585
    /* no key DB defined? then no need to sign anything */
586
0
    if (keyHandle == NULL) {
587
0
        crv = CKR_OK;
588
0
        goto loser;
589
0
    }
590
591
    /* When we are in a middle of an update, we have an update database set,
592
     * but we want to write to the real database. The bool mayBeUpdateDB is
593
     * set to TRUE if it's possible that we want to write an update database
594
     * rather than a primary */
595
0
    keyTarget = (mayBeUpdateDB && keyHandle->update) ? keyHandle->update : keyHandle->db;
596
597
    /* skip the the database does not support meta data */
598
0
    if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
599
0
        crv = CKR_OK;
600
0
        goto loser;
601
0
    }
602
603
    /* If we had to switch databases, we need to initialize a transaction. */
604
0
    if (usingPeerDB) {
605
0
        crv = (*keyTarget->sdb_Begin)(keyTarget);
606
0
        if (crv != CKR_OK) {
607
0
            goto loser;
608
0
        }
609
0
        inPeerDBTransaction = PR_TRUE;
610
0
    }
611
612
0
    for (i = 0; i < count; i++) {
613
0
        if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
614
0
            SECStatus rv;
615
0
            SECItem *signText;
616
0
            SECItem plainText;
617
618
0
            plainText.data = template[i].pValue;
619
0
            plainText.len = template[i].ulValueLen;
620
0
            PZ_Lock(keyHandle->passwordLock);
621
0
            if (keyHandle->passwordKey.data == NULL) {
622
0
                PZ_Unlock(keyHandle->passwordLock);
623
0
                crv = CKR_USER_NOT_LOGGED_IN;
624
0
                goto loser;
625
0
            }
626
0
            rv = sftkdb_SignAttribute(arena, keyHandle, keyTarget,
627
0
                                      &keyHandle->passwordKey,
628
0
                                      keyHandle->defaultIterationCount,
629
0
                                      objectID, template[i].type,
630
0
                                      &plainText, &signText);
631
0
            PZ_Unlock(keyHandle->passwordLock);
632
0
            if (rv != SECSuccess) {
633
0
                crv = CKR_GENERAL_ERROR; /* better error code here? */
634
0
                goto loser;
635
0
            }
636
0
            crv = sftkdb_PutAttributeSignature(handle, keyTarget, objectID,
637
0
                                               template[i].type, signText);
638
0
            if (crv != CKR_OK) {
639
0
                goto loser;
640
0
            }
641
0
        }
642
0
    }
643
0
    crv = CKR_OK;
644
645
    /* If necessary, commit the transaction */
646
0
    if (inPeerDBTransaction) {
647
0
        crv = (*keyTarget->sdb_Commit)(keyTarget);
648
0
        if (crv != CKR_OK) {
649
0
            goto loser;
650
0
        }
651
0
        inPeerDBTransaction = PR_FALSE;
652
0
    }
653
654
0
loser:
655
0
    if (inPeerDBTransaction) {
656
        /* The transaction must have failed. Abort. */
657
0
        (*keyTarget->sdb_Abort)(keyTarget);
658
0
        PORT_Assert(crv != CKR_OK);
659
0
        if (crv == CKR_OK)
660
0
            crv = CKR_GENERAL_ERROR;
661
0
    }
662
0
    return crv;
663
0
}
664
665
static CK_RV
666
sftkdb_CreateObject(PLArenaPool *arena, SFTKDBHandle *handle,
667
                    SDB *db, CK_OBJECT_HANDLE *objectID,
668
                    CK_ATTRIBUTE *template, CK_ULONG count)
669
0
{
670
0
    CK_RV crv;
671
672
0
    crv = (*db->sdb_CreateObject)(db, objectID, template, count);
673
0
    if (crv != CKR_OK) {
674
0
        goto loser;
675
0
    }
676
0
    crv = sftk_signTemplate(arena, handle, (db == handle->update),
677
0
                            *objectID, template, count);
678
0
loser:
679
680
0
    return crv;
681
0
}
682
683
static CK_RV
684
sftkdb_fixupSignatures(SFTKDBHandle *handle,
685
                       SDB *db, CK_OBJECT_HANDLE oldID, CK_OBJECT_HANDLE newID,
686
                       CK_ATTRIBUTE *ptemplate, CK_ULONG max_attributes)
687
0
{
688
0
    unsigned int i;
689
0
    CK_RV crv = CKR_OK;
690
691
    /* if we don't have a meta table, we didn't write any signature objects  */
692
0
    if ((db->sdb_flags & SDB_HAS_META) == 0) {
693
0
        return CKR_OK;
694
0
    }
695
0
    for (i = 0; i < max_attributes; i++) {
696
0
        CK_ATTRIBUTE *att = &ptemplate[i];
697
0
        CK_ATTRIBUTE_TYPE type = att->type;
698
0
        if (sftkdb_isPrivateAttribute(type)) {
699
            /* move the signature from one object handle to another and delete
700
             * the old entry */
701
0
            SECItem signature;
702
0
            unsigned char signData[SDB_MAX_META_DATA_LEN];
703
704
0
            signature.data = signData;
705
0
            signature.len = sizeof(signData);
706
0
            crv = sftkdb_getRawAttributeSignature(handle, db, oldID, type,
707
0
                                                  &signature);
708
0
            if (crv != CKR_OK) {
709
                /* NOTE: if we ever change our default write from AES_CBC
710
                 * to AES_KW, We'll need to change this to a continue as
711
                 * we won't need the integrity record for AES_KW */
712
0
                break;
713
0
            }
714
0
            crv = sftkdb_PutAttributeSignature(handle, db, newID, type,
715
0
                                               &signature);
716
0
            if (crv != CKR_OK) {
717
0
                break;
718
0
            }
719
            /* now get rid of the old one */
720
0
            crv = sftkdb_DestroyAttributeSignature(handle, db, oldID, type);
721
0
            if (crv != CKR_OK) {
722
0
                break;
723
0
            }
724
0
        }
725
0
    }
726
0
    return crv;
727
0
}
728
729
CK_ATTRIBUTE *
730
sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
731
                     SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
732
                     SDB *db, CK_ULONG *pcount, CK_RV *crv)
733
0
{
734
0
    unsigned int count;
735
0
    CK_ATTRIBUTE *template;
736
0
    unsigned int i, templateIndex;
737
0
    SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
738
0
    PRBool doEnc = PR_TRUE;
739
740
0
    *crv = CKR_OK;
741
742
0
    if (sessObject == NULL) {
743
0
        *crv = CKR_GENERAL_ERROR; /* internal programming error */
744
0
        return NULL;
745
0
    }
746
747
0
    PORT_Assert(handle);
748
    /* find the key handle */
749
0
    if (handle->type != SFTK_KEYDB_TYPE) {
750
0
        doEnc = PR_FALSE;
751
0
    }
752
753
0
    PZ_Lock(sessObject->attributeLock);
754
0
    count = 0;
755
0
    for (i = 0; i < sessObject->hashSize; i++) {
756
0
        SFTKAttribute *attr;
757
0
        for (attr = sessObject->head[i]; attr; attr = attr->next) {
758
0
            count++;
759
0
        }
760
0
    }
761
0
    template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count);
762
0
    if (template == NULL) {
763
0
        PZ_Unlock(sessObject->attributeLock);
764
0
        *crv = CKR_HOST_MEMORY;
765
0
        return NULL;
766
0
    }
767
0
    templateIndex = 0;
768
0
    for (i = 0; i < sessObject->hashSize; i++) {
769
0
        SFTKAttribute *attr;
770
0
        for (attr = sessObject->head[i]; attr; attr = attr->next) {
771
0
            CK_ATTRIBUTE *tp = &template[templateIndex++];
772
            /* copy the attribute */
773
0
            *tp = attr->attrib;
774
775
            /* fixup  ULONG s */
776
0
            if ((tp->ulValueLen == sizeof(CK_ULONG)) &&
777
0
                (sftkdb_isULONGAttribute(tp->type))) {
778
0
                CK_ULONG value = *(CK_ULONG *)tp->pValue;
779
0
                unsigned char *data;
780
781
0
                tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE);
782
0
                data = (unsigned char *)tp->pValue;
783
0
                if (data == NULL) {
784
0
                    *crv = CKR_HOST_MEMORY;
785
0
                    break;
786
0
                }
787
0
                sftk_ULong2SDBULong(data, value);
788
0
                tp->ulValueLen = SDB_ULONG_SIZE;
789
0
            }
790
791
            /* encrypt private attributes */
792
0
            if (doEnc && sftkdb_isPrivateAttribute(tp->type)) {
793
                /* we have a private attribute */
794
0
                SECItem *cipherText;
795
0
                SECItem plainText;
796
0
                SECStatus rv;
797
798
0
                plainText.data = tp->pValue;
799
0
                plainText.len = tp->ulValueLen;
800
0
                PZ_Lock(handle->passwordLock);
801
0
                if (handle->passwordKey.data == NULL) {
802
0
                    PZ_Unlock(handle->passwordLock);
803
0
                    *crv = CKR_USER_NOT_LOGGED_IN;
804
0
                    break;
805
0
                }
806
0
                rv = sftkdb_EncryptAttribute(arena, handle, db,
807
0
                                             &handle->passwordKey,
808
0
                                             handle->defaultIterationCount,
809
0
                                             objectID,
810
0
                                             tp->type,
811
0
                                             &plainText, &cipherText);
812
0
                PZ_Unlock(handle->passwordLock);
813
0
                if (rv == SECSuccess) {
814
0
                    tp->pValue = cipherText->data;
815
0
                    tp->ulValueLen = cipherText->len;
816
0
                } else {
817
0
                    *crv = CKR_GENERAL_ERROR; /* better error code here? */
818
0
                    break;
819
0
                }
820
0
                PORT_Memset(plainText.data, 0, plainText.len);
821
0
            }
822
0
        }
823
0
    }
824
0
    PORT_Assert(templateIndex <= count);
825
0
    PZ_Unlock(sessObject->attributeLock);
826
827
0
    if (*crv != CKR_OK) {
828
0
        return NULL;
829
0
    }
830
0
    if (pcount) {
831
0
        *pcount = count;
832
0
    }
833
0
    return template;
834
0
}
835
836
/*
837
 * return a pointer to the attribute in the give template.
838
 * The return value is not const, as the caller may modify
839
 * the given attribute value, but such modifications will
840
 * modify the actual value in the template.
841
 */
842
static CK_ATTRIBUTE *
843
sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute,
844
                                CK_ATTRIBUTE *ptemplate, CK_ULONG len)
845
0
{
846
0
    CK_ULONG i;
847
848
0
    for (i = 0; i < len; i++) {
849
0
        if (attribute == ptemplate[i].type) {
850
0
            return &ptemplate[i];
851
0
        }
852
0
    }
853
0
    return NULL;
854
0
}
855
856
static const CK_ATTRIBUTE *
857
sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute,
858
                                     const CK_ATTRIBUTE *ptemplate, CK_ULONG len)
859
0
{
860
0
    CK_ULONG i;
861
862
0
    for (i = 0; i < len; i++) {
863
0
        if (attribute == ptemplate[i].type) {
864
0
            return &ptemplate[i];
865
0
        }
866
0
    }
867
0
    return NULL;
868
0
}
869
870
/*
871
 * fetch a template which identifies 'unique' entries based on object type
872
 */
873
static CK_RV
874
sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData,
875
                       CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount,
876
                       CK_ATTRIBUTE *ptemplate, int len)
877
0
{
878
0
    CK_ATTRIBUTE *attr;
879
0
    CK_ULONG count = 1;
880
881
0
    sftk_ULong2SDBULong(objTypeData, objectType);
882
0
    findTemplate[0].type = CKA_CLASS;
883
0
    findTemplate[0].pValue = objTypeData;
884
0
    findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
885
886
0
    switch (objectType) {
887
0
        case CKO_CERTIFICATE:
888
0
        case CKO_NSS_TRUST:
889
0
        case CKO_TRUST:
890
0
            attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len);
891
0
            if (attr == NULL) {
892
0
                return CKR_TEMPLATE_INCOMPLETE;
893
0
            }
894
0
            findTemplate[1] = *attr;
895
0
            attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER,
896
0
                                                   ptemplate, len);
897
0
            if (attr == NULL) {
898
0
                return CKR_TEMPLATE_INCOMPLETE;
899
0
            }
900
0
            findTemplate[2] = *attr;
901
0
            count = 3;
902
0
            break;
903
904
0
        case CKO_PRIVATE_KEY:
905
0
        case CKO_PUBLIC_KEY:
906
0
        case CKO_SECRET_KEY:
907
0
            attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len);
908
0
            if (attr == NULL) {
909
0
                return CKR_TEMPLATE_INCOMPLETE;
910
0
            }
911
0
            if (attr->ulValueLen == 0) {
912
                /* key is too generic to determine that it's unique, usually
913
                 * happens in the key gen case */
914
0
                return CKR_OBJECT_HANDLE_INVALID;
915
0
            }
916
0
            findTemplate[1] = *attr;
917
0
            attr = sftkdb_getAttributeFromTemplate(CKA_KEY_TYPE,
918
0
                                                   ptemplate, len);
919
0
            if (attr != NULL) {
920
0
                findTemplate[2] = *attr;
921
0
                count = 3;
922
0
            } else {
923
0
                count = 2;
924
0
            }
925
0
            break;
926
927
0
        case CKO_NSS_CRL:
928
0
            attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
929
0
            if (attr == NULL) {
930
0
                return CKR_TEMPLATE_INCOMPLETE;
931
0
            }
932
0
            findTemplate[1] = *attr;
933
0
            count = 2;
934
0
            break;
935
936
0
        case CKO_NSS_SMIME:
937
0
            attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
938
0
            if (attr == NULL) {
939
0
                return CKR_TEMPLATE_INCOMPLETE;
940
0
            }
941
0
            findTemplate[1] = *attr;
942
0
            attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len);
943
0
            if (attr == NULL) {
944
0
                return CKR_TEMPLATE_INCOMPLETE;
945
0
            }
946
0
            findTemplate[2] = *attr;
947
0
            count = 3;
948
0
            break;
949
0
        default:
950
0
            attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len);
951
0
            if (attr == NULL) {
952
0
                return CKR_TEMPLATE_INCOMPLETE;
953
0
            }
954
0
            findTemplate[1] = *attr;
955
0
            count = 2;
956
0
            break;
957
0
    }
958
0
    *findCount = count;
959
960
0
    return CKR_OK;
961
0
}
962
963
/*
964
 * look to see if this object already exists and return its object ID if
965
 * it does.
966
 */
967
static CK_RV
968
sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType,
969
                    CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len)
970
0
{
971
0
    CK_ATTRIBUTE findTemplate[3];
972
0
    CK_ULONG count = 1;
973
0
    CK_ULONG objCount = 0;
974
0
    SDBFind *find = NULL;
975
0
    unsigned char objTypeData[SDB_ULONG_SIZE];
976
0
    CK_RV crv;
977
978
0
    *id = CK_INVALID_HANDLE;
979
0
    if (objectType == CKO_NSS_CRL) {
980
0
        return CKR_OK;
981
0
    }
982
0
    crv = sftkdb_getFindTemplate(objectType, objTypeData,
983
0
                                 findTemplate, &count, ptemplate, len);
984
985
0
    if (crv == CKR_OBJECT_HANDLE_INVALID) {
986
        /* key is too generic to determine that it's unique, usually
987
         * happens in the key gen case, tell the caller to go ahead
988
         * and just create it */
989
0
        return CKR_OK;
990
0
    }
991
0
    if (crv != CKR_OK) {
992
0
        return crv;
993
0
    }
994
995
    /* use the raw find, so we get the correct database */
996
0
    crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find);
997
0
    if (crv != CKR_OK) {
998
0
        return crv;
999
0
    }
1000
0
    (*db->sdb_FindObjects)(db, find, id, 1, &objCount);
1001
0
    (*db->sdb_FindObjectsFinal)(db, find);
1002
1003
0
    if (objCount == 0) {
1004
0
        *id = CK_INVALID_HANDLE;
1005
0
    }
1006
0
    return CKR_OK;
1007
0
}
1008
1009
/*
1010
 * check to see if this template conflicts with others in our current database.
1011
 */
1012
static CK_RV
1013
sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType,
1014
                      const CK_ATTRIBUTE *ptemplate, CK_ULONG len,
1015
                      CK_OBJECT_HANDLE sourceID)
1016
0
{
1017
0
    CK_ATTRIBUTE findTemplate[2];
1018
0
    unsigned char objTypeData[SDB_ULONG_SIZE];
1019
    /* we may need to allocate some temporaries. Keep track of what was
1020
     * allocated so we can free it in the end */
1021
0
    unsigned char *temp1 = NULL;
1022
0
    unsigned char *temp2 = NULL;
1023
0
    CK_ULONG objCount = 0;
1024
0
    SDBFind *find = NULL;
1025
0
    CK_OBJECT_HANDLE id;
1026
0
    const CK_ATTRIBUTE *attr, *attr2;
1027
0
    CK_RV crv;
1028
0
    CK_ATTRIBUTE subject;
1029
1030
    /* Currently the only conflict is with nicknames pointing to the same
1031
     * subject when creating or modifying a certificate. */
1032
    /* If the object is not a cert, no problem. */
1033
0
    if (objectType != CKO_CERTIFICATE) {
1034
0
        return CKR_OK;
1035
0
    }
1036
    /* if not setting a nickname then there's still no problem */
1037
0
    attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len);
1038
0
    if ((attr == NULL) || (attr->ulValueLen == 0)) {
1039
0
        return CKR_OK;
1040
0
    }
1041
    /* fetch the subject of the source. For creation and merge, this should
1042
     * be found in the template */
1043
0
    attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len);
1044
0
    if (sourceID == CK_INVALID_HANDLE) {
1045
0
        if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) {
1046
0
            crv = CKR_TEMPLATE_INCOMPLETE;
1047
0
            goto done;
1048
0
        }
1049
0
    } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) {
1050
        /* sourceID is set if we are trying to modify an existing entry instead
1051
         * of creating a new one. In this case the subject may not be (probably
1052
         * isn't) in the template, we have to read it from the database */
1053
0
        subject.type = CKA_SUBJECT;
1054
0
        subject.pValue = NULL;
1055
0
        subject.ulValueLen = 0;
1056
0
        crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
1057
0
        if (crv != CKR_OK) {
1058
0
            goto done;
1059
0
        }
1060
0
        if ((CK_LONG)subject.ulValueLen < 0) {
1061
0
            crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */
1062
0
            goto done;
1063
0
        }
1064
0
        temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen);
1065
0
        if (temp1 == NULL) {
1066
0
            crv = CKR_HOST_MEMORY;
1067
0
            goto done;
1068
0
        }
1069
0
        crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
1070
0
        if (crv != CKR_OK) {
1071
0
            goto done;
1072
0
        }
1073
0
        attr2 = &subject;
1074
0
    }
1075
1076
    /* check for another cert in the database with the same nickname */
1077
0
    sftk_ULong2SDBULong(objTypeData, objectType);
1078
0
    findTemplate[0].type = CKA_CLASS;
1079
0
    findTemplate[0].pValue = objTypeData;
1080
0
    findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
1081
0
    findTemplate[1] = *attr;
1082
1083
0
    crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find);
1084
0
    if (crv != CKR_OK) {
1085
0
        goto done;
1086
0
    }
1087
0
    (*db->sdb_FindObjects)(db, find, &id, 1, &objCount);
1088
0
    (*db->sdb_FindObjectsFinal)(db, find);
1089
1090
    /* object count == 0 means no conflicting certs found,
1091
     * go on with the operation */
1092
0
    if (objCount == 0) {
1093
0
        crv = CKR_OK;
1094
0
        goto done;
1095
0
    }
1096
1097
    /* There is a least one cert that shares the nickname, make sure it also
1098
     * matches the subject. */
1099
0
    findTemplate[0] = *attr2;
1100
    /* we know how big the source subject was. Use that length to create the
1101
     * space for the target. If it's not enough space, then it means the
1102
     * source subject is too big, and therefore not a match. GetAttributeValue
1103
     * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough
1104
     * space (or enough space to be able to compare the result. */
1105
0
    temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen);
1106
0
    if (temp2 == NULL) {
1107
0
        crv = CKR_HOST_MEMORY;
1108
0
        goto done;
1109
0
    }
1110
0
    crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1);
1111
0
    if (crv != CKR_OK) {
1112
0
        if (crv == CKR_BUFFER_TOO_SMALL) {
1113
            /* if our buffer is too small, then the Subjects clearly do
1114
             * not match */
1115
0
            crv = CKR_ATTRIBUTE_VALUE_INVALID;
1116
0
            goto loser;
1117
0
        }
1118
        /* otherwise we couldn't get the value, just fail */
1119
0
        goto done;
1120
0
    }
1121
1122
    /* Ok, we have both subjects, make sure they are the same.
1123
     * Compare the subjects */
1124
0
    if ((findTemplate[0].ulValueLen != attr2->ulValueLen) ||
1125
0
        (attr2->ulValueLen > 0 &&
1126
0
         PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) != 0)) {
1127
0
        crv = CKR_ATTRIBUTE_VALUE_INVALID;
1128
0
        goto loser;
1129
0
    }
1130
0
    crv = CKR_OK;
1131
1132
0
done:
1133
    /* If we've failed for some other reason than a conflict, make sure we
1134
     * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID.
1135
     * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should
1136
     * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia).
1137
     */
1138
0
    if (crv == CKR_ATTRIBUTE_VALUE_INVALID) {
1139
0
        crv = CKR_GENERAL_ERROR; /* clearly a programming error */
1140
0
    }
1141
1142
/* exit point if we found a conflict */
1143
0
loser:
1144
0
    PORT_Free(temp1);
1145
0
    PORT_Free(temp2);
1146
0
    return crv;
1147
0
}
1148
1149
/*
1150
 * try to update the template to fix any errors. This is only done
1151
 * during update.
1152
 *
1153
 * NOTE: we must update the template or return an error, or the update caller
1154
 * will loop forever!
1155
 *
1156
 * Two copies of the source code for this algorithm exist in NSS.
1157
 * Changes must be made in both copies.
1158
 * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c.
1159
 *
1160
 */
1161
static CK_RV
1162
sftkdb_resolveConflicts(PLArenaPool *arena, CK_OBJECT_CLASS objectType,
1163
                        CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
1164
0
{
1165
0
    CK_ATTRIBUTE *attr;
1166
0
    char *nickname, *newNickname;
1167
0
    unsigned int end, digit;
1168
1169
    /* sanity checks. We should never get here with these errors */
1170
0
    if (objectType != CKO_CERTIFICATE) {
1171
0
        return CKR_GENERAL_ERROR; /* shouldn't happen */
1172
0
    }
1173
0
    attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
1174
0
    if ((attr == NULL) || (attr->ulValueLen == 0)) {
1175
0
        return CKR_GENERAL_ERROR; /* shouldn't happen */
1176
0
    }
1177
1178
    /* update the nickname */
1179
    /* is there a number at the end of the nickname already?
1180
     * if so just increment that number  */
1181
0
    nickname = (char *)attr->pValue;
1182
1183
    /* does nickname end with " #n*" ? */
1184
0
    for (end = attr->ulValueLen - 1;
1185
0
         end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0';
1186
0
         end--) /* just scan */
1187
0
        ;
1188
0
    if (attr->ulValueLen >= 3 &&
1189
0
        end < (attr->ulValueLen - 1) /* at least one digit */ &&
1190
0
        nickname[end] == '#' &&
1191
0
        nickname[end - 1] == ' ') {
1192
        /* Already has a suitable suffix string */
1193
0
    } else {
1194
        /* ... append " #2" to the name */
1195
0
        static const char num2[] = " #2";
1196
0
        newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2));
1197
0
        if (!newNickname) {
1198
0
            return CKR_HOST_MEMORY;
1199
0
        }
1200
0
        PORT_Memcpy(newNickname, nickname, attr->ulValueLen);
1201
0
        PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2));
1202
0
        attr->pValue = newNickname; /* modifies ptemplate */
1203
0
        attr->ulValueLen += 3;      /* 3 is strlen(num2)  */
1204
0
        return CKR_OK;
1205
0
    }
1206
1207
0
    for (end = attr->ulValueLen; end-- > 0;) {
1208
0
        digit = nickname[end];
1209
0
        if (digit > '9' || digit < '0') {
1210
0
            break;
1211
0
        }
1212
0
        if (digit < '9') {
1213
0
            nickname[end]++;
1214
0
            return CKR_OK;
1215
0
        }
1216
0
        nickname[end] = '0';
1217
0
    }
1218
1219
    /* we overflowed, insert a new '1' for a carry in front of the number */
1220
0
    newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1);
1221
0
    if (!newNickname) {
1222
0
        return CKR_HOST_MEMORY;
1223
0
    }
1224
    /* PORT_Memcpy should handle len of '0' */
1225
0
    PORT_Memcpy(newNickname, nickname, ++end);
1226
0
    newNickname[end] = '1';
1227
0
    PORT_Memset(&newNickname[end + 1], '0', attr->ulValueLen - end);
1228
0
    attr->pValue = newNickname;
1229
0
    attr->ulValueLen++;
1230
0
    return CKR_OK;
1231
0
}
1232
1233
/*
1234
 * set an attribute and sign it if necessary
1235
 */
1236
static CK_RV
1237
sftkdb_setAttributeValue(PLArenaPool *arena, SFTKDBHandle *handle,
1238
                         SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
1239
                         CK_ULONG count)
1240
0
{
1241
0
    CK_RV crv;
1242
0
    crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count);
1243
0
    if (crv != CKR_OK) {
1244
0
        return crv;
1245
0
    }
1246
0
    crv = sftk_signTemplate(arena, handle, db == handle->update,
1247
0
                            objectID, template, count);
1248
0
    return crv;
1249
0
}
1250
1251
/*
1252
 * write a softoken object out to the database.
1253
 */
1254
CK_RV
1255
sftkdb_write(SFTKDBHandle *handle, SFTKObject *object,
1256
             CK_OBJECT_HANDLE *objectID)
1257
0
{
1258
0
    CK_ATTRIBUTE *template;
1259
0
    PLArenaPool *arena;
1260
0
    CK_ULONG count;
1261
0
    CK_RV crv;
1262
0
    SDB *db;
1263
0
    PRBool inTransaction = PR_FALSE;
1264
0
    CK_OBJECT_HANDLE id, candidateID;
1265
1266
0
    *objectID = CK_INVALID_HANDLE;
1267
1268
0
    if (handle == NULL) {
1269
0
        return CKR_TOKEN_WRITE_PROTECTED;
1270
0
    }
1271
0
    db = SFTK_GET_SDB(handle);
1272
1273
    /*
1274
     * we have opened a new database, but we have not yet updated it. We are
1275
     * still running pointing to the old database (so the application can
1276
     * still read). We don't want to write to the old database at this point,
1277
     * however, since it leads to user confusion. So at this point we simply
1278
     * require a user login. Let NSS know this so it can prompt the user.
1279
     */
1280
0
    if (db == handle->update) {
1281
0
        return CKR_USER_NOT_LOGGED_IN;
1282
0
    }
1283
1284
0
    arena = PORT_NewArena(256);
1285
0
    if (arena == NULL) {
1286
0
        return CKR_HOST_MEMORY;
1287
0
    }
1288
1289
0
    crv = (*db->sdb_Begin)(db);
1290
0
    if (crv != CKR_OK) {
1291
0
        goto loser;
1292
0
    }
1293
0
    inTransaction = PR_TRUE;
1294
1295
0
    crv = (*db->sdb_GetNewObjectID)(db, &candidateID);
1296
0
    if (crv != CKR_OK) {
1297
0
        goto loser;
1298
0
    }
1299
1300
0
    template = sftk_ExtractTemplate(arena, object, handle, candidateID, db, &count, &crv);
1301
0
    if (!template) {
1302
0
        goto loser;
1303
0
    }
1304
1305
    /*
1306
     * We want to make the base database as free from object specific knowledge
1307
     * as possible. To maintain compatibility, keep some of the desirable
1308
     * object specific semantics of the old database.
1309
     *
1310
     * These were 2 fold:
1311
     *  1) there were certain conflicts (like trying to set the same nickname
1312
     * on two different subjects) that would return an error.
1313
     *  2) Importing the 'same' object would silently update that object.
1314
     *
1315
     * The following 2 functions mimic the desirable effects of these two
1316
     * semantics without pushing any object knowledge to the underlying database
1317
     * code.
1318
     */
1319
1320
    /* make sure we don't have attributes that conflict with the existing DB */
1321
0
    crv = sftkdb_checkConflicts(db, object->objclass, template, count,
1322
0
                                CK_INVALID_HANDLE);
1323
0
    if (crv != CKR_OK) {
1324
0
        goto loser;
1325
0
    }
1326
    /* Find any copies that match this particular object */
1327
0
    crv = sftkdb_lookupObject(db, object->objclass, &id, template, count);
1328
0
    if (crv != CKR_OK) {
1329
0
        goto loser;
1330
0
    }
1331
0
    if (id == CK_INVALID_HANDLE) {
1332
0
        *objectID = candidateID;
1333
0
        crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count);
1334
0
    } else {
1335
        /* object already exists, modify it's attributes */
1336
0
        *objectID = id;
1337
        /* The object ID changed from our candidate, we need to move any
1338
         * signature attribute signatures to the new object ID. */
1339
0
        crv = sftkdb_fixupSignatures(handle, db, candidateID, id,
1340
0
                                     template, count);
1341
0
        if (crv != CKR_OK) {
1342
0
            goto loser;
1343
0
        }
1344
0
        crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count);
1345
0
    }
1346
0
    if (crv != CKR_OK) {
1347
0
        goto loser;
1348
0
    }
1349
0
    crv = (*db->sdb_Commit)(db);
1350
0
    inTransaction = PR_FALSE;
1351
1352
0
loser:
1353
0
    if (inTransaction) {
1354
0
        (*db->sdb_Abort)(db);
1355
        /* It is trivial to show the following code cannot
1356
         * happen unless something is horribly wrong with our compilier or
1357
         * hardware */
1358
0
        PORT_Assert(crv != CKR_OK);
1359
0
        if (crv == CKR_OK)
1360
0
            crv = CKR_GENERAL_ERROR;
1361
0
    }
1362
1363
0
    if (arena) {
1364
0
        PORT_FreeArena(arena, PR_TRUE);
1365
0
    }
1366
0
    if (crv == CKR_OK) {
1367
0
        *objectID |= (handle->type | SFTK_TOKEN_TYPE);
1368
0
    }
1369
0
    return crv;
1370
0
}
1371
1372
CK_RV
1373
sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template,
1374
                       CK_ULONG count, SDBFind **find)
1375
1.20M
{
1376
1.20M
    unsigned char *data = NULL;
1377
1.20M
    CK_ATTRIBUTE *ntemplate = NULL;
1378
1.20M
    CK_RV crv;
1379
1.20M
    int dataSize;
1380
1.20M
    SDB *db;
1381
1382
1.20M
    if (handle == NULL) {
1383
1.20M
        return CKR_OK;
1384
1.20M
    }
1385
0
    db = SFTK_GET_SDB(handle);
1386
1387
0
    if (count != 0) {
1388
0
        ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize);
1389
0
        if (ntemplate == NULL) {
1390
0
            return CKR_HOST_MEMORY;
1391
0
        }
1392
0
    }
1393
1394
0
    crv = (*db->sdb_FindObjectsInit)(db, ntemplate,
1395
0
                                     count, find);
1396
0
    if (data) {
1397
0
        PORT_Free(ntemplate);
1398
0
        PORT_ZFree(data, dataSize);
1399
0
    }
1400
0
    return crv;
1401
0
}
1402
1403
CK_RV
1404
sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find,
1405
                   CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count)
1406
1.20M
{
1407
1.20M
    CK_RV crv;
1408
1.20M
    SDB *db;
1409
1410
1.20M
    if (handle == NULL) {
1411
1.20M
        *count = 0;
1412
1.20M
        return CKR_OK;
1413
1.20M
    }
1414
0
    db = SFTK_GET_SDB(handle);
1415
1416
0
    crv = (*db->sdb_FindObjects)(db, find, ids,
1417
0
                                 arraySize, count);
1418
0
    if (crv == CKR_OK) {
1419
0
        unsigned int i;
1420
0
        for (i = 0; i < *count; i++) {
1421
0
            ids[i] |= (handle->type | SFTK_TOKEN_TYPE);
1422
0
        }
1423
0
    }
1424
0
    return crv;
1425
1.20M
}
1426
1427
CK_RV
1428
sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find)
1429
1.20M
{
1430
1.20M
    SDB *db;
1431
1.20M
    if (handle == NULL) {
1432
1.20M
        return CKR_OK;
1433
1.20M
    }
1434
0
    db = SFTK_GET_SDB(handle);
1435
0
    return (*db->sdb_FindObjectsFinal)(db, find);
1436
1.20M
}
1437
1438
CK_RV
1439
sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
1440
                         CK_ATTRIBUTE *template, CK_ULONG count)
1441
0
{
1442
0
    CK_RV crv, crv2;
1443
0
    CK_ATTRIBUTE *ntemplate;
1444
0
    unsigned char *data = NULL;
1445
0
    int dataSize = 0;
1446
0
    SDB *db;
1447
1448
0
    if (handle == NULL) {
1449
0
        return CKR_GENERAL_ERROR;
1450
0
    }
1451
1452
    /* short circuit common attributes */
1453
0
    if (count == 1 &&
1454
0
        (template[0].type == CKA_TOKEN ||
1455
0
         template[0].type == CKA_PRIVATE ||
1456
0
         template[0].type == CKA_SENSITIVE)) {
1457
0
        CK_BBOOL boolVal = CK_TRUE;
1458
1459
0
        if (template[0].pValue == NULL) {
1460
0
            template[0].ulValueLen = sizeof(CK_BBOOL);
1461
0
            return CKR_OK;
1462
0
        }
1463
0
        if (template[0].ulValueLen < sizeof(CK_BBOOL)) {
1464
0
            template[0].ulValueLen = -1;
1465
0
            return CKR_BUFFER_TOO_SMALL;
1466
0
        }
1467
1468
0
        if ((template[0].type == CKA_PRIVATE) &&
1469
0
            (handle->type != SFTK_KEYDB_TYPE)) {
1470
0
            boolVal = CK_FALSE;
1471
0
        }
1472
0
        if ((template[0].type == CKA_SENSITIVE) &&
1473
0
            (handle->type != SFTK_KEYDB_TYPE)) {
1474
0
            boolVal = CK_FALSE;
1475
0
        }
1476
0
        *(CK_BBOOL *)template[0].pValue = boolVal;
1477
0
        template[0].ulValueLen = sizeof(CK_BBOOL);
1478
0
        return CKR_OK;
1479
0
    }
1480
1481
0
    db = SFTK_GET_SDB(handle);
1482
    /* nothing to do */
1483
0
    if (count == 0) {
1484
0
        return CKR_OK;
1485
0
    }
1486
0
    ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize);
1487
0
    if (ntemplate == NULL) {
1488
0
        return CKR_HOST_MEMORY;
1489
0
    }
1490
0
    objectID &= SFTK_OBJ_ID_MASK;
1491
0
    crv = (*db->sdb_GetAttributeValue)(db, objectID,
1492
0
                                       ntemplate, count);
1493
0
    crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate,
1494
0
                                   count, handle);
1495
0
    if (crv == CKR_OK)
1496
0
        crv = crv2;
1497
0
    if (data) {
1498
0
        PORT_Free(ntemplate);
1499
0
        PORT_ZFree(data, dataSize);
1500
0
    }
1501
0
    return crv;
1502
0
}
1503
1504
CK_RV
1505
sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object,
1506
                         const CK_ATTRIBUTE *template, CK_ULONG count)
1507
0
{
1508
0
    CK_ATTRIBUTE *ntemplate;
1509
0
    unsigned char *data = NULL;
1510
0
    PLArenaPool *arena = NULL;
1511
0
    SDB *db;
1512
0
    CK_RV crv = CKR_OK;
1513
0
    CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK);
1514
0
    PRBool inTransaction = PR_FALSE;
1515
0
    int dataSize;
1516
1517
0
    if (handle == NULL) {
1518
0
        return CKR_TOKEN_WRITE_PROTECTED;
1519
0
    }
1520
1521
0
    db = SFTK_GET_SDB(handle);
1522
    /* nothing to do */
1523
0
    if (count == 0) {
1524
0
        return CKR_OK;
1525
0
    }
1526
    /*
1527
     * we have opened a new database, but we have not yet updated it. We are
1528
     * still running  pointing to the old database (so the application can
1529
     * still read). We don't want to write to the old database at this point,
1530
     * however, since it leads to user confusion. So at this point we simply
1531
     * require a user login. Let NSS know this so it can prompt the user.
1532
     */
1533
0
    if (db == handle->update) {
1534
0
        return CKR_USER_NOT_LOGGED_IN;
1535
0
    }
1536
1537
0
    ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize);
1538
0
    if (ntemplate == NULL) {
1539
0
        return CKR_HOST_MEMORY;
1540
0
    }
1541
1542
    /* make sure we don't have attributes that conflict with the existing DB */
1543
0
    crv = sftkdb_checkConflicts(db, object->objclass, ntemplate, count,
1544
0
                                objectID);
1545
0
    if (crv != CKR_OK) {
1546
0
        goto loser;
1547
0
    }
1548
1549
0
    arena = PORT_NewArena(256);
1550
0
    if (arena == NULL) {
1551
0
        crv = CKR_HOST_MEMORY;
1552
0
        goto loser;
1553
0
    }
1554
1555
0
    crv = (*db->sdb_Begin)(db);
1556
0
    if (crv != CKR_OK) {
1557
0
        goto loser;
1558
0
    }
1559
0
    inTransaction = PR_TRUE;
1560
0
    crv = sftkdb_setAttributeValue(arena, handle, db, objectID, ntemplate,
1561
0
                                   count);
1562
0
    if (crv != CKR_OK) {
1563
0
        goto loser;
1564
0
    }
1565
0
    crv = (*db->sdb_Commit)(db);
1566
0
loser:
1567
0
    if (crv != CKR_OK && inTransaction) {
1568
0
        (*db->sdb_Abort)(db);
1569
0
    }
1570
0
    if (data) {
1571
0
        PORT_Free(ntemplate);
1572
0
        PORT_ZFree(data, dataSize);
1573
0
    }
1574
0
    if (arena) {
1575
0
        PORT_FreeArena(arena, PR_FALSE);
1576
0
    }
1577
0
    return crv;
1578
0
}
1579
1580
CK_RV
1581
sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
1582
                     CK_OBJECT_CLASS objclass)
1583
0
{
1584
0
    CK_RV crv = CKR_OK;
1585
0
    SDB *db;
1586
1587
0
    if (handle == NULL) {
1588
0
        return CKR_TOKEN_WRITE_PROTECTED;
1589
0
    }
1590
0
    db = SFTK_GET_SDB(handle);
1591
0
    objectID &= SFTK_OBJ_ID_MASK;
1592
1593
0
    crv = (*db->sdb_Begin)(db);
1594
0
    if (crv != CKR_OK) {
1595
0
        return crv;
1596
0
    }
1597
0
    crv = (*db->sdb_DestroyObject)(db, objectID);
1598
0
    if (crv != CKR_OK) {
1599
0
        goto loser;
1600
0
    }
1601
    /* if the database supports meta data, delete any old signatures
1602
     * that we may have added */
1603
0
    if ((db->sdb_flags & SDB_HAS_META) == SDB_HAS_META) {
1604
0
        SDB *keydb = db;
1605
0
        if (handle->type == SFTK_KEYDB_TYPE) {
1606
            /* delete any private attribute signatures that might exist */
1607
0
            (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1608
0
                                                   CKA_VALUE);
1609
0
            (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1610
0
                                                   CKA_PRIVATE_EXPONENT);
1611
0
            (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1612
0
                                                   CKA_PRIME_1);
1613
0
            (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1614
0
                                                   CKA_PRIME_2);
1615
0
            (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1616
0
                                                   CKA_EXPONENT_1);
1617
0
            (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1618
0
                                                   CKA_EXPONENT_2);
1619
0
            (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1620
0
                                                   CKA_COEFFICIENT);
1621
0
        } else {
1622
0
            keydb = SFTK_GET_SDB(handle->peerDB);
1623
0
        }
1624
        /* now destroy any authenticated attributes that may exist */
1625
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1626
0
                                               CKA_MODULUS);
1627
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1628
0
                                               CKA_PUBLIC_EXPONENT);
1629
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1630
0
                                               CKA_NSS_CERT_SHA1_HASH);
1631
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1632
0
                                               CKA_NSS_CERT_MD5_HASH);
1633
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1634
0
                                               CKA_HASH_OF_CERTIFICATE);
1635
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1636
0
                                               CKA_NAME_HASH_ALGORITHM);
1637
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1638
0
                                               CKA_NSS_TRUST_SERVER_AUTH);
1639
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1640
0
                                               CKA_NSS_TRUST_CLIENT_AUTH);
1641
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1642
0
                                               CKA_NSS_TRUST_EMAIL_PROTECTION);
1643
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1644
0
                                               CKA_NSS_TRUST_CODE_SIGNING);
1645
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1646
0
                                               CKA_NSS_TRUST_STEP_UP_APPROVED);
1647
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1648
0
                                               CKA_PKCS_TRUST_SERVER_AUTH);
1649
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1650
0
                                               CKA_PKCS_TRUST_CLIENT_AUTH);
1651
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1652
0
                                               CKA_PKCS_TRUST_EMAIL_PROTECTION);
1653
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1654
0
                                               CKA_PKCS_TRUST_CODE_SIGNING);
1655
0
        (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1656
0
                                               CKA_NSS_OVERRIDE_EXTENSIONS);
1657
0
    }
1658
0
    crv = (*db->sdb_Commit)(db);
1659
0
loser:
1660
0
    if (crv != CKR_OK) {
1661
0
        (*db->sdb_Abort)(db);
1662
0
    }
1663
0
    return crv;
1664
0
}
1665
1666
CK_RV
1667
sftkdb_CloseDB(SFTKDBHandle *handle)
1668
0
{
1669
0
#ifdef NO_FORK_CHECK
1670
0
    PRBool parentForkedAfterC_Initialize = PR_FALSE;
1671
0
#endif
1672
0
    if (handle == NULL) {
1673
0
        return CKR_OK;
1674
0
    }
1675
0
    if (handle->update) {
1676
0
        if (handle->db->sdb_SetForkState) {
1677
0
            (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
1678
0
        }
1679
0
        (*handle->update->sdb_Close)(handle->update);
1680
0
    }
1681
0
    if (handle->db) {
1682
0
        if (handle->db->sdb_SetForkState) {
1683
0
            (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
1684
0
        }
1685
0
        (*handle->db->sdb_Close)(handle->db);
1686
0
    }
1687
0
    if (handle->passwordLock) {
1688
0
        PZ_Lock(handle->passwordLock);
1689
0
    }
1690
0
    if (handle->passwordKey.data) {
1691
0
        SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE);
1692
0
    }
1693
0
    if (handle->passwordLock) {
1694
0
        PZ_Unlock(handle->passwordLock);
1695
0
        SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock));
1696
0
    }
1697
0
    if (handle->updatePasswordKey) {
1698
0
        SECITEM_ZfreeItem(handle->updatePasswordKey, PR_TRUE);
1699
0
    }
1700
0
    if (handle->updateID) {
1701
0
        PORT_Free(handle->updateID);
1702
0
    }
1703
0
    PORT_Free(handle);
1704
0
    return CKR_OK;
1705
0
}
1706
1707
/*
1708
 * reset a database to it's uninitialized state.
1709
 */
1710
static CK_RV
1711
sftkdb_ResetDB(SFTKDBHandle *handle)
1712
0
{
1713
0
    CK_RV crv = CKR_OK;
1714
0
    SDB *db;
1715
0
    if (handle == NULL) {
1716
0
        return CKR_TOKEN_WRITE_PROTECTED;
1717
0
    }
1718
0
    db = SFTK_GET_SDB(handle);
1719
0
    crv = (*db->sdb_Begin)(db);
1720
0
    if (crv != CKR_OK) {
1721
0
        goto loser;
1722
0
    }
1723
0
    crv = (*db->sdb_Reset)(db);
1724
0
    if (crv != CKR_OK) {
1725
0
        goto loser;
1726
0
    }
1727
0
    crv = (*db->sdb_Commit)(db);
1728
0
loser:
1729
0
    if (crv != CKR_OK) {
1730
0
        (*db->sdb_Abort)(db);
1731
0
    }
1732
0
    return crv;
1733
0
}
1734
1735
CK_RV
1736
sftkdb_Begin(SFTKDBHandle *handle)
1737
0
{
1738
0
    CK_RV crv = CKR_OK;
1739
0
    SDB *db;
1740
1741
0
    if (handle == NULL) {
1742
0
        return CKR_OK;
1743
0
    }
1744
0
    db = SFTK_GET_SDB(handle);
1745
0
    if (db) {
1746
0
        crv = (*db->sdb_Begin)(db);
1747
0
    }
1748
0
    return crv;
1749
0
}
1750
1751
CK_RV
1752
sftkdb_Commit(SFTKDBHandle *handle)
1753
0
{
1754
0
    CK_RV crv = CKR_OK;
1755
0
    SDB *db;
1756
1757
0
    if (handle == NULL) {
1758
0
        return CKR_OK;
1759
0
    }
1760
0
    db = SFTK_GET_SDB(handle);
1761
0
    if (db) {
1762
0
        (*db->sdb_Commit)(db);
1763
0
    }
1764
0
    return crv;
1765
0
}
1766
1767
CK_RV
1768
sftkdb_Abort(SFTKDBHandle *handle)
1769
0
{
1770
0
    CK_RV crv = CKR_OK;
1771
0
    SDB *db;
1772
1773
0
    if (handle == NULL) {
1774
0
        return CKR_OK;
1775
0
    }
1776
0
    db = SFTK_GET_SDB(handle);
1777
0
    if (db) {
1778
0
        crv = (db->sdb_Abort)(db);
1779
0
    }
1780
0
    return crv;
1781
0
}
1782
1783
/*
1784
 * functions to update the database from an old database
1785
 */
1786
1787
static CK_RV
1788
sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id,
1789
                         CK_ATTRIBUTE *ptemplate, CK_ULONG *max)
1790
0
{
1791
0
    unsigned int i, j;
1792
0
    CK_RV crv;
1793
1794
0
    if (*max < sftkdb_known_attributes_size) {
1795
0
        *max = sftkdb_known_attributes_size;
1796
0
        return CKR_BUFFER_TOO_SMALL;
1797
0
    }
1798
0
    for (i = 0; i < sftkdb_known_attributes_size; i++) {
1799
0
        ptemplate[i].type = sftkdb_known_attributes[i];
1800
0
        ptemplate[i].pValue = NULL;
1801
0
        ptemplate[i].ulValueLen = 0;
1802
0
    }
1803
1804
0
    crv = (*source->sdb_GetAttributeValue)(source, id,
1805
0
                                           ptemplate, sftkdb_known_attributes_size);
1806
1807
0
    if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
1808
0
        return crv;
1809
0
    }
1810
1811
0
    for (i = 0, j = 0; i < sftkdb_known_attributes_size; i++, j++) {
1812
0
        while (i < sftkdb_known_attributes_size && (ptemplate[i].ulValueLen == -1)) {
1813
0
            i++;
1814
0
        }
1815
0
        if (i >= sftkdb_known_attributes_size) {
1816
0
            break;
1817
0
        }
1818
        /* cheap optimization */
1819
0
        if (i == j) {
1820
0
            continue;
1821
0
        }
1822
0
        ptemplate[j] = ptemplate[i];
1823
0
    }
1824
0
    *max = j;
1825
0
    return CKR_OK;
1826
0
}
1827
1828
static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s";
1829
1830
/*
1831
 * check to see if we have already updated this database.
1832
 * a NULL updateID means we are trying to do an in place
1833
 * single database update. In that case we have already
1834
 * determined that an update was necessary.
1835
 */
1836
static PRBool
1837
sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID)
1838
0
{
1839
0
    char *id;
1840
0
    CK_RV crv;
1841
0
    SECItem dummy = { 0, NULL, 0 };
1842
0
    unsigned char dummyData[SDB_MAX_META_DATA_LEN];
1843
1844
0
    if (!updateID) {
1845
0
        return PR_FALSE;
1846
0
    }
1847
0
    id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
1848
0
    if (id == NULL) {
1849
0
        return PR_FALSE;
1850
0
    }
1851
0
    dummy.data = dummyData;
1852
0
    dummy.len = sizeof(dummyData);
1853
1854
0
    crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL);
1855
0
    PR_smprintf_free(id);
1856
0
    return crv == CKR_OK ? PR_TRUE : PR_FALSE;
1857
0
}
1858
1859
/*
1860
 * we just completed an update, store the update id
1861
 * so we don't need to do it again. If non was given,
1862
 * there is nothing to do.
1863
 */
1864
static CK_RV
1865
sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID)
1866
0
{
1867
0
    char *id;
1868
0
    CK_RV crv;
1869
0
    SECItem dummy = { 0, NULL, 0 };
1870
1871
    /* if no id was given, nothing to do */
1872
0
    if (updateID == NULL) {
1873
0
        return CKR_OK;
1874
0
    }
1875
1876
0
    dummy.data = (unsigned char *)updateID;
1877
0
    dummy.len = PORT_Strlen(updateID);
1878
1879
0
    id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
1880
0
    if (id == NULL) {
1881
0
        return PR_FALSE;
1882
0
    }
1883
1884
0
    crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL);
1885
0
    PR_smprintf_free(id);
1886
0
    return crv;
1887
0
}
1888
1889
/*
1890
 * get a ULong attribute from a template:
1891
 * NOTE: this is a raw templated stored in database order!
1892
 */
1893
static CK_ULONG
1894
sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type,
1895
                            CK_ATTRIBUTE *ptemplate, CK_ULONG len)
1896
0
{
1897
0
    CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type,
1898
0
                                                         ptemplate, len);
1899
1900
0
    if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) {
1901
0
        return sftk_SDBULong2ULong(attr->pValue);
1902
0
    }
1903
0
    return (CK_ULONG)-1;
1904
0
}
1905
1906
static CK_RV
1907
sftkdb_setULongInTemplate(CK_ATTRIBUTE *ptemplate, CK_ULONG value)
1908
0
{
1909
0
    if ((ptemplate->ulValueLen < SDB_ULONG_SIZE) || !ptemplate->pValue) {
1910
0
        return CKR_TEMPLATE_INCOMPLETE;
1911
0
    }
1912
0
    ptemplate->ulValueLen = SDB_ULONG_SIZE;
1913
0
    sftk_ULong2SDBULong(ptemplate->pValue, value);
1914
0
    return CKR_OK;
1915
0
}
1916
1917
/*
1918
 * we need to find a unique CKA_ID.
1919
 *  The basic idea is to just increment the lowest byte.
1920
 *  This code also handles the following corner cases:
1921
 *   1) the single byte overflows. On overflow we increment the next byte up
1922
 *    and so forth until we have overflowed the entire CKA_ID.
1923
 *   2) If we overflow the entire CKA_ID we expand it by one byte.
1924
 *   3) the CKA_ID is non-existant, we create a new one with one byte.
1925
 *    This means no matter what CKA_ID is passed, the result of this function
1926
 *    is always a new CKA_ID, and this function will never return the same
1927
 *    CKA_ID the it has returned in the passed.
1928
 */
1929
static CK_RV
1930
sftkdb_incrementCKAID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate)
1931
0
{
1932
0
    unsigned char *buf = ptemplate->pValue;
1933
0
    CK_ULONG len = ptemplate->ulValueLen;
1934
1935
0
    if (buf == NULL || len == (CK_ULONG)-1) {
1936
        /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
1937
0
        len = 0;
1938
0
    } else {
1939
0
        CK_ULONG i;
1940
1941
        /* walk from the back to front, incrementing
1942
         * the CKA_ID until we no longer have a carry,
1943
         * or have hit the front of the id. */
1944
0
        for (i = len; i != 0; i--) {
1945
0
            buf[i - 1]++;
1946
0
            if (buf[i - 1] != 0) {
1947
                /* no more carries, the increment is complete */
1948
0
                return CKR_OK;
1949
0
            }
1950
0
        }
1951
        /* we've now overflowed, fall through and expand the CKA_ID by
1952
         * one byte */
1953
0
    }
1954
0
    buf = PORT_ArenaAlloc(arena, len + 1);
1955
0
    if (!buf) {
1956
0
        return CKR_HOST_MEMORY;
1957
0
    }
1958
0
    if (len > 0) {
1959
0
        PORT_Memcpy(buf, ptemplate->pValue, len);
1960
0
    }
1961
0
    buf[len] = 0;
1962
0
    ptemplate->pValue = buf;
1963
0
    ptemplate->ulValueLen = len + 1;
1964
0
    return CKR_OK;
1965
0
}
1966
1967
/*
1968
 * drop an attribute from a template.
1969
 */
1970
void
1971
sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate,
1972
                     CK_ULONG *plen)
1973
0
{
1974
0
    CK_ULONG count = *plen;
1975
0
    CK_ULONG i;
1976
1977
0
    for (i = 0; i < count; i++) {
1978
0
        if (attr->type == ptemplate[i].type) {
1979
0
            break;
1980
0
        }
1981
0
    }
1982
1983
0
    if (i == count) {
1984
        /* attribute not found */
1985
0
        return;
1986
0
    }
1987
1988
    /* copy the remaining attributes up */
1989
0
    for (i++; i < count; i++) {
1990
0
        ptemplate[i - 1] = ptemplate[i];
1991
0
    }
1992
1993
    /* decrement the template size */
1994
0
    *plen = count - 1;
1995
0
}
1996
1997
/*
1998
 * create some defines for the following functions to document the meaning
1999
 * of true/false. (make's it easier to remember what means what.
2000
 */
2001
typedef enum {
2002
    SFTKDB_DO_NOTHING = 0,
2003
    SFTKDB_ADD_OBJECT,
2004
    SFTKDB_MODIFY_OBJECT,
2005
    SFTKDB_DROP_ATTRIBUTE
2006
} sftkdbUpdateStatus;
2007
2008
/*
2009
 * helper function to reconcile a single trust entry.
2010
 *   Identify which trust entry we want to keep.
2011
 *   If we don't need to do anything (the records are already equal).
2012
 *       return SFTKDB_DO_NOTHING.
2013
 *   If we want to use the source version,
2014
 *       return SFTKDB_MODIFY_OBJECT
2015
 *   If we want to use the target version,
2016
 *       return SFTKDB_DROP_ATTRIBUTE
2017
 *
2018
 *   In the end the caller will remove any attributes in the source
2019
 *   template when SFTKDB_DROP_ATTRIBUTE is specified, then use do a
2020
 *   set attributes with that template on the target if we received
2021
 *   any SFTKDB_MODIFY_OBJECT returns.
2022
 */
2023
sftkdbUpdateStatus
2024
sftkdb_reconcileTrustEntry(PLArenaPool *arena, CK_ATTRIBUTE *target,
2025
                           CK_ATTRIBUTE *source)
2026
0
{
2027
0
    CK_ULONG targetTrust = sftkdb_getULongFromTemplate(target->type,
2028
0
                                                       target, 1);
2029
0
    CK_ULONG sourceTrust = sftkdb_getULongFromTemplate(target->type,
2030
0
                                                       source, 1);
2031
2032
    /*
2033
     * try to pick the best solution between the source and the
2034
     * target. Update the source template if we want the target value
2035
     * to win out. Prefer cases where we don't actually update the
2036
     * trust entry.
2037
     */
2038
2039
    /* they are the same, everything is already kosher */
2040
0
    if (targetTrust == sourceTrust) {
2041
0
        return SFTKDB_DO_NOTHING;
2042
0
    }
2043
2044
    /* handle the case where the source Trust attribute may be a bit
2045
     * flakey */
2046
0
    if (sourceTrust == (CK_ULONG)-1) {
2047
        /*
2048
         * The source Trust is invalid. We know that the target Trust
2049
         * must be valid here, otherwise the above
2050
         * targetTrust == sourceTrust check would have succeeded.
2051
         */
2052
0
        return SFTKDB_DROP_ATTRIBUTE;
2053
0
    }
2054
2055
    /* target is invalid, use the source's idea of the trust value */
2056
0
    if (targetTrust == (CK_ULONG)-1) {
2057
        /* overwriting the target in this case is OK */
2058
0
        return SFTKDB_MODIFY_OBJECT;
2059
0
    }
2060
2061
    /* at this point we know that both attributes exist and have the
2062
     * appropriate length (SDB_ULONG_SIZE). We no longer need to check
2063
     * ulValueLen for either attribute.
2064
     */
2065
0
    if (sourceTrust == CKT_TRUST_UNKNOWN) {
2066
0
        return SFTKDB_DROP_ATTRIBUTE;
2067
0
    }
2068
2069
    /* target has no idea, use the source's idea of the trust value */
2070
0
    if (targetTrust == CKT_TRUST_UNKNOWN) {
2071
        /* overwriting the target in this case is OK */
2072
0
        return SFTKDB_MODIFY_OBJECT;
2073
0
    }
2074
2075
    /* so both the target and the source have some idea of what this
2076
     * trust attribute should be, and neither agree exactly.
2077
     * At this point, we prefer 'hard' attributes over 'soft' ones.
2078
     * 'hard' ones are CKT_TRUSTED, CKT_TRUST_ANCHOR, and
2079
     * CKT_NSS_NOT_TRUTED. Soft ones are ones which don't change the
2080
     * actual trust of the cert (CKT_TRUST_MUST_VERIFY_TRUST).
2081
     */
2082
0
    if (sourceTrust == CKT_TRUST_MUST_VERIFY_TRUST) {
2083
0
        return SFTKDB_DROP_ATTRIBUTE;
2084
0
    }
2085
0
    if (targetTrust == CKT_TRUST_MUST_VERIFY_TRUST) {
2086
        /* again, overwriting the target in this case is OK */
2087
0
        return SFTKDB_MODIFY_OBJECT;
2088
0
    }
2089
2090
    /* both have hard attributes, we have a conflict, let the target win. */
2091
0
    return SFTKDB_DROP_ATTRIBUTE;
2092
0
}
2093
2094
/* map the attribute types */
2095
CK_TRUST
2096
sftkdb_mapNSSTrustValueToPKCS11TrustValue(CK_TRUST trust)
2097
0
{
2098
0
    switch (trust) {
2099
0
        case CKT_NSS_TRUSTED:
2100
0
            return CKT_TRUSTED;
2101
0
        case CKT_NSS_TRUSTED_DELEGATOR:
2102
0
            return CKT_TRUST_ANCHOR;
2103
0
        case CKT_NSS_VALID_DELEGATOR:
2104
0
        case CKT_NSS_MUST_VERIFY_TRUST:
2105
0
            return CKT_TRUST_MUST_VERIFY_TRUST;
2106
0
        case CKT_NSS_NOT_TRUSTED:
2107
0
            return CKT_NOT_TRUSTED;
2108
0
        case CKT_NSS_TRUST_UNKNOWN:
2109
0
            return CKT_TRUST_UNKNOWN;
2110
0
        default:
2111
0
            break;
2112
0
    }
2113
0
    return CKT_TRUST_UNKNOWN; /* everything else, just copy */
2114
0
}
2115
2116
/* map the attribute types */
2117
CK_ATTRIBUTE_TYPE
2118
sftkdb_mapNSSTrustAttributeTypeToTrustAttributeType(CK_ATTRIBUTE_TYPE type)
2119
0
{
2120
0
    switch (type) {
2121
0
        case CKA_NSS_CERT_SHA1_HASH:
2122
0
            return CKA_HASH_OF_CERTIFICATE;
2123
0
        case CKA_NSS_TRUST_SERVER_AUTH:
2124
0
            return CKA_PKCS_TRUST_SERVER_AUTH;
2125
0
        case CKA_NSS_TRUST_CLIENT_AUTH:
2126
0
            return CKA_PKCS_TRUST_CLIENT_AUTH;
2127
0
        case CKA_NSS_TRUST_CODE_SIGNING:
2128
0
            return CKA_PKCS_TRUST_CODE_SIGNING;
2129
0
        case CKA_NSS_TRUST_EMAIL_PROTECTION:
2130
0
            return CKA_PKCS_TRUST_EMAIL_PROTECTION;
2131
0
        case CKA_NSS_TRUST_IPSEC_TUNNEL:
2132
0
            return CKA_TRUST_IPSEC_IKE;
2133
0
        case CKA_NSS_TRUST_TIME_STAMPING:
2134
0
            return CKA_PKCS_TRUST_TIME_STAMPING;
2135
0
        default:
2136
0
            break;
2137
0
    }
2138
0
    return type; /* everything else, just copy */
2139
0
}
2140
2141
/* these attributes have no mappings, just drop them */
2142
PRBool
2143
sftkdb_dropTrustAttribute(CK_ATTRIBUTE_TYPE type)
2144
0
{
2145
0
    switch (type) {
2146
0
        case CKA_NSS_CERT_MD5_HASH:
2147
0
        case CKA_NSS_TRUST_DIGITAL_SIGNATURE:
2148
0
        case CKA_NSS_TRUST_NON_REPUDIATION:
2149
0
        case CKA_NSS_TRUST_KEY_ENCIPHERMENT:
2150
0
        case CKA_NSS_TRUST_DATA_ENCIPHERMENT:
2151
0
        case CKA_NSS_TRUST_KEY_AGREEMENT:
2152
0
        case CKA_NSS_TRUST_KEY_CERT_SIGN:
2153
0
        case CKA_NSS_TRUST_CRL_SIGN:
2154
0
        case CKA_NSS_TRUST_IPSEC_END_SYSTEM:
2155
0
        case CKA_NSS_TRUST_IPSEC_USER:
2156
0
        case CKA_NSS_TRUST_STEP_UP_APPROVED:
2157
0
            return PR_TRUE;
2158
0
    }
2159
0
    return PR_FALSE;
2160
0
}
2161
2162
CK_RV
2163
sftkdb_mapTrustAttribute(CK_ATTRIBUTE *attr)
2164
0
{
2165
0
    CK_ATTRIBUTE_TYPE oldType = attr->type;
2166
0
    attr->type = sftkdb_mapNSSTrustAttributeTypeToTrustAttributeType(attr->type);
2167
0
    if ((attr->type != oldType) && (attr->ulValueLen == SDB_ULONG_SIZE)) {
2168
0
        CK_TRUST oldTrust = sftkdb_getULongFromTemplate(attr->type, attr, 1);
2169
0
        CK_TRUST newTrust = sftkdb_mapNSSTrustValueToPKCS11TrustValue(oldTrust);
2170
0
        return sftkdb_setULongInTemplate(attr, newTrust);
2171
0
    }
2172
0
    return CKR_OK;
2173
0
}
2174
2175
/*
2176
 * take an NSS vendor specific trust object and map it to the
2177
 * standard PKCS trust object. If the template includes attributes
2178
 * that have not be mapped to PKCS then those attributes may be dropped.
2179
 */
2180
CK_RV
2181
sftkdb_mapNSSTrustToPKCS11Trust(CK_ATTRIBUTE *trustTemplate,
2182
                                CK_ULONG *templateCountPtr)
2183
0
{
2184
0
    CK_ULONG i;
2185
0
    CK_ULONG originalCount = *templateCountPtr;
2186
0
    void *space = NULL;
2187
0
    int hasCertificateHash = 0;
2188
0
    CK_RV crv;
2189
2190
0
    for (i = 0; i < *templateCountPtr; i++) {
2191
0
        CK_ATTRIBUTE *attr = &trustTemplate[i];
2192
0
        if (sftkdb_dropTrustAttribute(attr->type)) {
2193
            /* if there's a enough space to store a ulong, hang
2194
             * onto it. We will probably need it tostore
2195
             * CKA_NAME_HASH_ALGORITHM */
2196
0
            if (!space && attr->ulValueLen >= SDB_ULONG_SIZE) {
2197
0
                space = attr->pValue;
2198
0
            }
2199
0
            sftkdb_dropAttribute(attr, trustTemplate, templateCountPtr);
2200
0
            continue;
2201
0
        }
2202
0
        crv = sftkdb_mapTrustAttribute(attr);
2203
0
        if (crv != CKR_OK) {
2204
0
            return crv;
2205
0
        }
2206
0
        if (attr->type == CKA_HASH_OF_CERTIFICATE) {
2207
0
            hasCertificateHash++;
2208
0
        }
2209
0
    }
2210
    /* if we have CKA_HASH_OF_CERTIFICATE, then we need to add
2211
     * CKA_NAME_HASH_ALGORITHM. We can only do that if we have dropped
2212
     * an attribute because we can't expand the template. This shouldn't
2213
     * be a problem because in a normal template we'll have a CKA_CERT_HASH_MD5
2214
     * attribute and a CKA_NSS_TRUST_STEP_UP_APPROVED attribute */
2215
0
    if (hasCertificateHash) {
2216
0
        if ((*templateCountPtr >= originalCount) || !space) {
2217
0
            return CKR_TEMPLATE_INCOMPLETE;
2218
0
        }
2219
0
        i = (*templateCountPtr)++;
2220
0
        trustTemplate[i].type = CKA_NAME_HASH_ALGORITHM;
2221
0
        trustTemplate[i].pValue = space;
2222
0
        trustTemplate[i].ulValueLen = SDB_ULONG_SIZE;
2223
0
        return sftkdb_setULongInTemplate(&trustTemplate[i], CKM_SHA_1);
2224
0
    }
2225
0
    return CKR_OK;
2226
0
}
2227
2228
const CK_ATTRIBUTE_TYPE sftkdb_nssTrustList[] = { CKA_NSS_TRUST_SERVER_AUTH,
2229
                                                  CKA_NSS_TRUST_CLIENT_AUTH,
2230
                                                  CKA_NSS_TRUST_CODE_SIGNING,
2231
                                                  CKA_NSS_TRUST_EMAIL_PROTECTION,
2232
                                                  CKA_NSS_TRUST_IPSEC_TUNNEL,
2233
                                                  CKA_NSS_TRUST_TIME_STAMPING };
2234
2235
const CK_ATTRIBUTE_TYPE sftkdb_trustList[] = { CKA_PKCS_TRUST_SERVER_AUTH,
2236
                                               CKA_PKCS_TRUST_CLIENT_AUTH,
2237
                                               CKA_PKCS_TRUST_CODE_SIGNING,
2238
                                               CKA_PKCS_TRUST_EMAIL_PROTECTION,
2239
                                               CKA_TRUST_IPSEC_IKE,
2240
                                               CKA_PKCS_TRUST_TIME_STAMPING };
2241
2242
#define SFTK_TRUST_TEMPLATE_COUNT \
2243
0
    (sizeof(sftkdb_trustList) / sizeof(sftkdb_trustList[0]))
2244
/*
2245
 * Run through the list of known trust types, and reconcile each trust
2246
 * entry one by one. Keep track of we really need to write out the source
2247
 * trust object (overwriting the existing one).
2248
 */
2249
static sftkdbUpdateStatus
2250
sftkdb_reconcileTrust(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id,
2251
                      PRBool useLegacy, CK_ATTRIBUTE *ptemplate,
2252
                      CK_ULONG *plen)
2253
0
{
2254
0
    CK_ATTRIBUTE trustTemplate[SFTK_TRUST_TEMPLATE_COUNT];
2255
0
    unsigned char trustData[SFTK_TRUST_TEMPLATE_COUNT * SDB_ULONG_SIZE];
2256
0
    sftkdbUpdateStatus update = useLegacy ? SFTKDB_DO_NOTHING
2257
0
                                          : SFTKDB_MODIFY_OBJECT;
2258
0
    const CK_ULONG templateCount = PR_ARRAY_SIZE(sftkdb_trustList);
2259
0
    CK_ULONG i;
2260
0
    CK_RV crv;
2261
2262
    /* make sure the two arrays are the same size */
2263
0
    PR_STATIC_ASSERT(PR_ARRAY_SIZE(sftkdb_trustList) == PR_ARRAY_SIZE(sftkdb_nssTrustList));
2264
0
    for (i = 0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) {
2265
0
        trustTemplate[i].type = useLegacy ? sftkdb_nssTrustList[i]
2266
0
                                          : sftkdb_trustList[i];
2267
0
        trustTemplate[i].pValue = &trustData[i * SDB_ULONG_SIZE];
2268
0
        trustTemplate[i].ulValueLen = SDB_ULONG_SIZE;
2269
0
    }
2270
0
    crv = (*db->sdb_GetAttributeValue)(db, id,
2271
0
                                       trustTemplate, templateCount);
2272
0
    if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
2273
        /* target trust has some problems, update it */
2274
0
        update = SFTKDB_MODIFY_OBJECT;
2275
0
        goto done;
2276
0
    }
2277
2278
0
    if (useLegacy) {
2279
0
        CK_ULONG count = templateCount;
2280
0
        crv = sftkdb_mapNSSTrustToPKCS11Trust(trustTemplate, &count);
2281
0
        PORT_Assert((count == templateCount) && (crv != CKR_OK));
2282
0
        if ((count == templateCount) && (crv != CKR_OK)) {
2283
0
            return SFTKDB_DO_NOTHING;
2284
0
        }
2285
0
    }
2286
2287
0
    for (i = 0; i < templateCount; i++) {
2288
0
        CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(
2289
0
            trustTemplate[i].type, ptemplate, *plen);
2290
0
        sftkdbUpdateStatus status;
2291
2292
        /* if target trust value doesn't exist, nothing to merge */
2293
0
        if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) {
2294
            /* if the source exists, then we want the source entry,
2295
             * go ahead and update */
2296
0
            if (attr && attr->ulValueLen != (CK_ULONG)-1) {
2297
0
                update = SFTKDB_MODIFY_OBJECT;
2298
0
            }
2299
0
            continue;
2300
0
        }
2301
2302
        /*
2303
         * the source doesn't have the attribute, go to the next attribute
2304
         */
2305
0
        if (attr == NULL) {
2306
0
            continue;
2307
0
        }
2308
0
        status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr);
2309
0
        if (useLegacy) {
2310
            /* in the legacy case we are always modifying the object because
2311
             * we are updating to the new attribute type */
2312
0
            if (status == SFTKDB_DROP_ATTRIBUTE) {
2313
                /* rather than drop the attribute, we need to copy the
2314
                 * updated destination attribute */
2315
0
                *attr = trustTemplate[i];
2316
0
            }
2317
            /* SFTKDB_MODIFY_OBJECT - we are already modifying the object,
2318
             * do nothing */
2319
            /* SFTKDB_NO_NOTHING, both source and target already have the
2320
             * correct attribute, so no need to copy */
2321
0
        } else {
2322
            /* not legacy, so the target will be updated in place
2323
             * if necessary */
2324
0
            if (status == SFTKDB_MODIFY_OBJECT) {
2325
                /* we need to write the source version of this attribute
2326
                 * to the target, we need to modify the object */
2327
0
                update = SFTKDB_MODIFY_OBJECT;
2328
0
            } else if (status == SFTKDB_DROP_ATTRIBUTE) {
2329
                /* drop the source copy of the attribute, we are going with
2330
                 * the target's version. This allows us to modify other
2331
                 * attributes if we need to. */
2332
0
                sftkdb_dropAttribute(attr, ptemplate, plen);
2333
0
            }
2334
            /* SFTKDB_NO_NOTHING, both source and target already have the
2335
             * correct attribute, so no need to or drop anything */
2336
0
        }
2337
0
    }
2338
2339
    /* we don't support step-up in the PKCS version, so don't do anything with
2340
     * step-up */
2341
2342
0
done:
2343
0
    return update;
2344
0
}
2345
2346
static sftkdbUpdateStatus
2347
sftkdb_handleIDAndName(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id,
2348
                       CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
2349
0
{
2350
0
    sftkdbUpdateStatus update = SFTKDB_DO_NOTHING;
2351
0
    CK_ATTRIBUTE *attr1, *attr2;
2352
0
    CK_ATTRIBUTE ttemplate[2] = {
2353
0
        { CKA_ID, NULL, 0 },
2354
0
        { CKA_LABEL, NULL, 0 }
2355
0
    };
2356
2357
0
    attr1 = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
2358
0
    attr2 = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen);
2359
2360
    /* if the source has neither an id nor label, don't bother updating */
2361
0
    if ((!attr1 || attr1->ulValueLen == 0) &&
2362
0
        (!attr2 || attr2->ulValueLen == 0)) {
2363
0
        return SFTKDB_DO_NOTHING;
2364
0
    }
2365
2366
    /* the source has either an id or a label, see what the target has */
2367
0
    (void)(*db->sdb_GetAttributeValue)(db, id, ttemplate, 2);
2368
2369
    /* if the target has neither, update from the source */
2370
0
    if (((ttemplate[0].ulValueLen == 0) ||
2371
0
         (ttemplate[0].ulValueLen == (CK_ULONG)-1)) &&
2372
0
        ((ttemplate[1].ulValueLen == 0) ||
2373
0
         (ttemplate[1].ulValueLen == (CK_ULONG)-1))) {
2374
0
        return SFTKDB_MODIFY_OBJECT;
2375
0
    }
2376
2377
    /* check the CKA_ID */
2378
0
    if ((ttemplate[0].ulValueLen != 0) &&
2379
0
        (ttemplate[0].ulValueLen != (CK_ULONG)-1)) {
2380
        /* we have a CKA_ID in the target, don't overwrite
2381
         * the target with an empty CKA_ID from the source*/
2382
0
        if (attr1 && attr1->ulValueLen == 0) {
2383
0
            sftkdb_dropAttribute(attr1, ptemplate, plen);
2384
0
        }
2385
0
    } else if (attr1 && attr1->ulValueLen != 0) {
2386
        /* source has a CKA_ID, but the target doesn't, update the target */
2387
0
        update = SFTKDB_MODIFY_OBJECT;
2388
0
    }
2389
2390
    /* check the nickname */
2391
0
    if ((ttemplate[1].ulValueLen != 0) &&
2392
0
        (ttemplate[1].ulValueLen != (CK_ULONG)-1)) {
2393
2394
        /* we have a nickname in the target, and we don't have to update
2395
         * the CKA_ID. We are done. NOTE: if we add addition attributes
2396
         * in this check, this shortcut can only go on the last of them. */
2397
0
        if (update == SFTKDB_DO_NOTHING) {
2398
0
            return update;
2399
0
        }
2400
        /* we have a nickname in the target, don't overwrite
2401
         * the target with an empty nickname from the source */
2402
0
        if (attr2 && attr2->ulValueLen == 0) {
2403
0
            sftkdb_dropAttribute(attr2, ptemplate, plen);
2404
0
        }
2405
0
    } else if (attr2 && attr2->ulValueLen != 0) {
2406
        /* source has a nickname, but the target doesn't, update the target */
2407
0
        update = SFTKDB_MODIFY_OBJECT;
2408
0
    }
2409
2410
0
    return update;
2411
0
}
2412
2413
/*
2414
 * This function updates the template before we write the object out.
2415
 *
2416
 * If we are going to skip updating this object, return PR_FALSE.
2417
 * If it should be updated we return PR_TRUE.
2418
 * To help readability, these have been defined
2419
 * as SFTK_DONT_UPDATE and SFTK_UPDATE respectively.
2420
 */
2421
static PRBool
2422
sftkdb_updateObjectTemplate(PLArenaPool *arena, SDB *db,
2423
                            CK_OBJECT_CLASS objectType,
2424
                            CK_ATTRIBUTE *ptemplate, CK_ULONG *plen,
2425
                            CK_OBJECT_HANDLE *targetID)
2426
0
{
2427
0
    PRBool done; /* should we repeat the loop? */
2428
0
    CK_OBJECT_HANDLE id;
2429
0
    CK_RV crv = CKR_OK;
2430
2431
0
    do {
2432
0
        crv = sftkdb_checkConflicts(db, objectType, ptemplate,
2433
0
                                    *plen, CK_INVALID_HANDLE);
2434
0
        if (crv != CKR_ATTRIBUTE_VALUE_INVALID) {
2435
0
            break;
2436
0
        }
2437
0
        crv = sftkdb_resolveConflicts(arena, objectType, ptemplate, plen);
2438
0
    } while (crv == CKR_OK);
2439
2440
0
    if (crv != CKR_OK) {
2441
0
        return SFTKDB_DO_NOTHING;
2442
0
    }
2443
2444
0
    if (objectType == CKO_NSS_TRUST) {
2445
0
        sftkdb_mapNSSTrustToPKCS11Trust(ptemplate, plen);
2446
0
        objectType = CKO_TRUST;
2447
0
    }
2448
2449
0
    do {
2450
0
        done = PR_TRUE;
2451
0
        crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen);
2452
0
        if (crv != CKR_OK) {
2453
0
            if (objectType == CKO_TRUST && id == CK_INVALID_HANDLE) {
2454
0
                objectType = CKO_NSS_TRUST;
2455
                /* didn't find a new PKCS #11 Trust object, look for
2456
                 * and NSS Vendor specific Trust Object */
2457
0
                crv = sftkdb_lookupObject(db, CKO_NSS_TRUST, &id,
2458
0
                                          ptemplate, *plen);
2459
0
            }
2460
0
            if (crv != CKR_OK) {
2461
0
                return SFTKDB_DO_NOTHING;
2462
0
            }
2463
0
        }
2464
2465
        /* This object already exists, merge it, don't update */
2466
0
        if (id != CK_INVALID_HANDLE) {
2467
0
            CK_ATTRIBUTE *attr = NULL;
2468
            /* special post processing for attributes */
2469
0
            switch (objectType) {
2470
0
                case CKO_CERTIFICATE:
2471
0
                case CKO_PUBLIC_KEY:
2472
0
                case CKO_PRIVATE_KEY:
2473
                    /* update target's CKA_ID and labels if they don't already
2474
                     * exist */
2475
0
                    *targetID = id;
2476
0
                    return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen);
2477
0
                case CKO_NSS_TRUST:
2478
                    /* if we have conflicting trust object types,
2479
                     * we need to reconcile them */
2480
0
                    *targetID = id;
2481
0
                    return sftkdb_reconcileTrust(arena, db, id, PR_TRUE,
2482
0
                                                 ptemplate, plen);
2483
0
                case CKO_TRUST:
2484
                    /* if we have conflicting trust object types,
2485
                     * we need to reconcile them */
2486
0
                    *targetID = id;
2487
0
                    return sftkdb_reconcileTrust(arena, db, id, PR_FALSE,
2488
0
                                                 ptemplate, plen);
2489
0
                case CKO_SECRET_KEY:
2490
                    /* secret keys in the old database are all sdr keys,
2491
                     * unfortunately they all appear to have the same CKA_ID,
2492
                     * even though they are truly different keys, so we always
2493
                     * want to update these keys, but we need to
2494
                     * give them a new CKA_ID */
2495
                    /* NOTE: this changes ptemplate */
2496
0
                    attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen);
2497
0
                    crv = attr ? sftkdb_incrementCKAID(arena, attr)
2498
0
                               : CKR_HOST_MEMORY;
2499
                    /* in the extremely rare event that we needed memory and
2500
                     * couldn't get it, just drop the key */
2501
0
                    if (crv != CKR_OK) {
2502
0
                        return SFTKDB_DO_NOTHING;
2503
0
                    }
2504
0
                    done = PR_FALSE; /* repeat this find loop */
2505
0
                    break;
2506
0
                default:
2507
                    /* for all other objects, if we found the equivalent object,
2508
                     * don't update it */
2509
0
                    return SFTKDB_DO_NOTHING;
2510
0
            }
2511
0
        }
2512
0
    } while (!done);
2513
2514
    /* this object doesn't exist, update it */
2515
0
    return SFTKDB_ADD_OBJECT;
2516
0
}
2517
2518
static CK_RV
2519
sftkdb_updateIntegrity(PLArenaPool *arena, SFTKDBHandle *handle,
2520
                       SDB *source, CK_OBJECT_HANDLE sourceID,
2521
                       SDB *target, CK_OBJECT_HANDLE targetID,
2522
                       CK_ATTRIBUTE *ptemplate, CK_ULONG max_attributes)
2523
0
{
2524
0
    unsigned int i;
2525
0
    CK_RV global_crv = CKR_OK;
2526
2527
    /* if the target doesn't have META data, don't need to do anything */
2528
0
    if ((target->sdb_flags & SDB_HAS_META) == 0) {
2529
0
        return CKR_OK;
2530
0
    }
2531
    /* if the source doesn't have meta data, then the record won't require
2532
     * integrity */
2533
0
    if ((source->sdb_flags & SDB_HAS_META) == 0) {
2534
0
        return CKR_OK;
2535
0
    }
2536
0
    for (i = 0; i < max_attributes; i++) {
2537
0
        CK_ATTRIBUTE *att = &ptemplate[i];
2538
0
        CK_ATTRIBUTE_TYPE type = att->type;
2539
0
        if (sftkdb_isPrivateAttribute(type)) {
2540
            /* copy integrity signatures associated with this record (if any) */
2541
0
            SECItem signature;
2542
0
            unsigned char signData[SDB_MAX_META_DATA_LEN];
2543
0
            CK_RV crv;
2544
2545
0
            signature.data = signData;
2546
0
            signature.len = sizeof(signData);
2547
0
            crv = sftkdb_getRawAttributeSignature(handle, source, sourceID, type,
2548
0
                                                  &signature);
2549
0
            if (crv != CKR_OK) {
2550
                /* old databases don't have signature IDs because they are
2551
                 * 3DES encrypted. Since we know not to look for integrity
2552
                 * for 3DES records it's OK not to find one here. A new record
2553
                 * will be created when we reencrypt using AES CBC */
2554
0
                continue;
2555
0
            }
2556
0
            crv = sftkdb_PutAttributeSignature(handle, target, targetID, type,
2557
0
                                               &signature);
2558
0
            if (crv != CKR_OK) {
2559
                /* we had a signature in the source db, but we couldn't store
2560
                 * it in the target, remember the error so we can report it. */
2561
0
                global_crv = crv;
2562
0
            }
2563
0
        }
2564
0
    }
2565
0
    return global_crv;
2566
0
}
2567
2568
0
#define MAX_ATTRIBUTES 500
2569
static CK_RV
2570
sftkdb_mergeObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id,
2571
                   SECItem *key)
2572
0
{
2573
0
    CK_ATTRIBUTE template[MAX_ATTRIBUTES];
2574
0
    CK_ATTRIBUTE *ptemplate;
2575
0
    CK_ULONG max_attributes = MAX_ATTRIBUTES;
2576
0
    CK_OBJECT_CLASS objectType;
2577
0
    SDB *source = handle->update;
2578
0
    SDB *target = handle->db;
2579
0
    unsigned int i;
2580
0
    CK_OBJECT_HANDLE newID = CK_INVALID_HANDLE;
2581
0
    CK_RV crv;
2582
0
    PLArenaPool *arena = NULL;
2583
2584
0
    arena = PORT_NewArena(256);
2585
0
    if (arena == NULL) {
2586
0
        return CKR_HOST_MEMORY;
2587
0
    }
2588
2589
0
    ptemplate = &template[0];
2590
0
    id &= SFTK_OBJ_ID_MASK;
2591
0
    crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes);
2592
0
    if (crv == CKR_BUFFER_TOO_SMALL) {
2593
0
        ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes);
2594
0
        if (ptemplate == NULL) {
2595
0
            crv = CKR_HOST_MEMORY;
2596
0
        } else {
2597
0
            crv = sftkdb_GetObjectTemplate(source, id,
2598
0
                                           ptemplate, &max_attributes);
2599
0
        }
2600
0
    }
2601
0
    if (crv != CKR_OK) {
2602
0
        goto loser;
2603
0
    }
2604
2605
0
    for (i = 0; i < max_attributes; i++) {
2606
0
        ptemplate[i].pValue = PORT_ArenaAlloc(arena, ptemplate[i].ulValueLen);
2607
0
        if (ptemplate[i].pValue == NULL) {
2608
0
            crv = CKR_HOST_MEMORY;
2609
0
            goto loser;
2610
0
        }
2611
0
    }
2612
0
    crv = (*source->sdb_GetAttributeValue)(source, id,
2613
0
                                           ptemplate, max_attributes);
2614
0
    if (crv != CKR_OK) {
2615
0
        goto loser;
2616
0
    }
2617
2618
0
    objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate,
2619
0
                                             max_attributes);
2620
    /*
2621
     * Update Object updates the object template if necessary then returns
2622
     * whether or not we need to actually write the object out to our target
2623
     * database.
2624
     */
2625
0
    if (!handle->updateID) {
2626
0
        crv = sftkdb_CreateObject(arena, handle, target, &newID,
2627
0
                                  ptemplate, max_attributes);
2628
0
    } else {
2629
0
        sftkdbUpdateStatus update_status;
2630
0
        update_status = sftkdb_updateObjectTemplate(arena, target,
2631
0
                                                    objectType, ptemplate, &max_attributes, &newID);
2632
0
        switch (update_status) {
2633
0
            case SFTKDB_ADD_OBJECT:
2634
0
                crv = sftkdb_CreateObject(arena, handle, target, &newID,
2635
0
                                          ptemplate, max_attributes);
2636
0
                break;
2637
0
            case SFTKDB_MODIFY_OBJECT:
2638
0
                crv = sftkdb_setAttributeValue(arena, handle, target,
2639
0
                                               newID, ptemplate, max_attributes);
2640
0
                break;
2641
0
            case SFTKDB_DO_NOTHING:
2642
0
            case SFTKDB_DROP_ATTRIBUTE:
2643
0
                break;
2644
0
        }
2645
0
    }
2646
2647
    /* if keyDB copy any meta data hashes to target, Update for the new
2648
     * object ID */
2649
0
    if (crv == CKR_OK) {
2650
0
        crv = sftkdb_updateIntegrity(arena, handle, source, id, target, newID,
2651
0
                                     ptemplate, max_attributes);
2652
0
    }
2653
2654
0
loser:
2655
0
    if (arena) {
2656
0
        PORT_FreeArena(arena, PR_TRUE);
2657
0
    }
2658
0
    return crv;
2659
0
}
2660
2661
0
#define MAX_IDS 10
2662
/*
2663
 * update a new database from an old one, now that we have the key
2664
 */
2665
CK_RV
2666
sftkdb_Update(SFTKDBHandle *handle, SECItem *key)
2667
0
{
2668
0
    SDBFind *find = NULL;
2669
0
    CK_ULONG idCount = MAX_IDS;
2670
0
    CK_OBJECT_HANDLE ids[MAX_IDS];
2671
0
    SECItem *updatePasswordKey = NULL;
2672
0
    CK_RV crv, crv2;
2673
0
    PRBool inTransaction = PR_FALSE;
2674
0
    unsigned int i;
2675
2676
0
    if (handle == NULL) {
2677
0
        return CKR_OK;
2678
0
    }
2679
0
    if (handle->update == NULL) {
2680
0
        return CKR_OK;
2681
0
    }
2682
    /*
2683
     * put the whole update under a transaction. This allows us to handle
2684
     * any possible race conditions between with the updateID check.
2685
     */
2686
0
    crv = (*handle->db->sdb_Begin)(handle->db);
2687
0
    if (crv != CKR_OK) {
2688
0
        return crv;
2689
0
    }
2690
0
    inTransaction = PR_TRUE;
2691
2692
    /* some one else has already updated this db */
2693
0
    if (sftkdb_hasUpdate(sftkdb_TypeString(handle),
2694
0
                         handle->db, handle->updateID)) {
2695
0
        crv = CKR_OK;
2696
0
        goto done;
2697
0
    }
2698
2699
0
    updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle);
2700
0
    if (updatePasswordKey) {
2701
        /* pass the source DB key to the legacy code,
2702
         * so it can decrypt things */
2703
0
        handle->oldKey = updatePasswordKey;
2704
0
    }
2705
2706
    /* find all the objects */
2707
0
    crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find);
2708
2709
0
    if (crv != CKR_OK) {
2710
0
        goto loser;
2711
0
    }
2712
0
    while ((crv == CKR_OK) && (idCount == MAX_IDS)) {
2713
0
        crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount);
2714
0
        for (i = 0; (crv == CKR_OK) && (i < idCount); i++) {
2715
0
            crv = sftkdb_mergeObject(handle, ids[i], key);
2716
0
        }
2717
0
    }
2718
0
    crv2 = sftkdb_FindObjectsFinal(handle, find);
2719
0
    if (crv == CKR_OK)
2720
0
        crv = crv2;
2721
2722
0
loser:
2723
    /* no longer need the old key value */
2724
0
    handle->oldKey = NULL;
2725
2726
    /* update the password - even if we didn't update objects */
2727
0
    if (handle->type == SFTK_KEYDB_TYPE) {
2728
0
        SECItem item1, item2;
2729
0
        unsigned char data1[SDB_MAX_META_DATA_LEN];
2730
0
        unsigned char data2[SDB_MAX_META_DATA_LEN];
2731
2732
0
        item1.data = data1;
2733
0
        item1.len = sizeof(data1);
2734
0
        item2.data = data2;
2735
0
        item2.len = sizeof(data2);
2736
2737
        /* if the target db already has a password, skip this. */
2738
0
        crv = (*handle->db->sdb_GetMetaData)(handle->db, "password",
2739
0
                                             &item1, &item2);
2740
0
        if (crv == CKR_OK) {
2741
0
            goto done;
2742
0
        }
2743
2744
        /* nope, update it from the source */
2745
0
        crv = (*handle->update->sdb_GetMetaData)(handle->update, "password",
2746
0
                                                 &item1, &item2);
2747
0
        if (crv != CKR_OK) {
2748
            /* if we get here, neither the source, nor the target has been initialized
2749
             * with a password entry. Create a metadata table now so that we don't
2750
             * mistake this for a partially updated database */
2751
0
            item1.data[0] = 0;
2752
0
            item2.data[0] = 0;
2753
0
            item1.len = item2.len = 1;
2754
0
            crv = (*handle->db->sdb_PutMetaData)(handle->db, "empty", &item1, &item2);
2755
0
            goto done;
2756
0
        }
2757
0
        crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1,
2758
0
                                             &item2);
2759
0
        if (crv != CKR_OK) {
2760
0
            goto done;
2761
0
        }
2762
0
    }
2763
2764
0
done:
2765
    /* finally mark this up to date db up to date */
2766
    /* some one else has already updated this db */
2767
0
    if (crv == CKR_OK) {
2768
0
        crv = sftkdb_putUpdate(sftkdb_TypeString(handle),
2769
0
                               handle->db, handle->updateID);
2770
0
    }
2771
2772
0
    if (inTransaction) {
2773
0
        if (crv == CKR_OK) {
2774
0
            crv = (*handle->db->sdb_Commit)(handle->db);
2775
0
        } else {
2776
0
            (*handle->db->sdb_Abort)(handle->db);
2777
0
        }
2778
0
    }
2779
0
    if (handle->update) {
2780
0
        (*handle->update->sdb_Close)(handle->update);
2781
0
        handle->update = NULL;
2782
0
    }
2783
0
    if (handle->updateID) {
2784
0
        PORT_Free(handle->updateID);
2785
0
        handle->updateID = NULL;
2786
0
    }
2787
0
    sftkdb_FreeUpdatePasswordKey(handle);
2788
0
    if (updatePasswordKey) {
2789
0
        SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE);
2790
0
    }
2791
0
    handle->updateDBIsInit = PR_FALSE;
2792
0
    return crv;
2793
0
}
2794
2795
/******************************************************************
2796
 * DB handle managing functions.
2797
 *
2798
 * These functions are called by softoken to initialize, acquire,
2799
 * and release database handles.
2800
 */
2801
2802
const char *
2803
sftkdb_GetUpdateID(SFTKDBHandle *handle)
2804
0
{
2805
0
    return handle->updateID;
2806
0
}
2807
2808
/* release a database handle */
2809
void
2810
sftk_freeDB(SFTKDBHandle *handle)
2811
1.20M
{
2812
1.20M
    PRInt32 ref;
2813
2814
1.20M
    if (!handle)
2815
1.20M
        return;
2816
0
    ref = PR_ATOMIC_DECREMENT(&handle->ref);
2817
0
    if (ref == 0) {
2818
0
        sftkdb_CloseDB(handle);
2819
0
    }
2820
0
    return;
2821
1.20M
}
2822
2823
/*
2824
 * acquire a database handle for a certificate db
2825
 * (database for public objects)
2826
 */
2827
SFTKDBHandle *
2828
sftk_getCertDB(SFTKSlot *slot)
2829
1.20M
{
2830
1.20M
    SFTKDBHandle *dbHandle;
2831
2832
1.20M
    PZ_Lock(slot->slotLock);
2833
1.20M
    dbHandle = slot->certDB;
2834
1.20M
    if (dbHandle) {
2835
0
        (void)PR_ATOMIC_INCREMENT(&dbHandle->ref);
2836
0
    }
2837
1.20M
    PZ_Unlock(slot->slotLock);
2838
1.20M
    return dbHandle;
2839
1.20M
}
2840
2841
/*
2842
 * acquire a database handle for a key database
2843
 * (database for private objects)
2844
 */
2845
SFTKDBHandle *
2846
sftk_getKeyDB(SFTKSlot *slot)
2847
1.92M
{
2848
1.92M
    SFTKDBHandle *dbHandle;
2849
2850
1.92M
    SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
2851
1.92M
    dbHandle = slot->keyDB;
2852
1.92M
    if (dbHandle) {
2853
0
        (void)PR_ATOMIC_INCREMENT(&dbHandle->ref);
2854
0
    }
2855
1.92M
    SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
2856
1.92M
    return dbHandle;
2857
1.92M
}
2858
2859
/*
2860
 * acquire the database for a specific object. NOTE: objectID must point
2861
 * to a Token object!
2862
 */
2863
SFTKDBHandle *
2864
sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID)
2865
0
{
2866
0
    SFTKDBHandle *dbHandle;
2867
2868
0
    PZ_Lock(slot->slotLock);
2869
0
    dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB;
2870
0
    if (dbHandle) {
2871
0
        (void)PR_ATOMIC_INCREMENT(&dbHandle->ref);
2872
0
    }
2873
0
    PZ_Unlock(slot->slotLock);
2874
0
    return dbHandle;
2875
0
}
2876
2877
/*
2878
 * initialize a new database handle
2879
 */
2880
static SFTKDBHandle *
2881
sftk_NewDBHandle(SDB *sdb, int type, PRBool legacy)
2882
0
{
2883
0
    SFTKDBHandle *handle = PORT_New(SFTKDBHandle);
2884
0
    handle->ref = 1;
2885
0
    handle->db = sdb;
2886
0
    handle->update = NULL;
2887
0
    handle->peerDB = NULL;
2888
0
    handle->newKey = NULL;
2889
0
    handle->oldKey = NULL;
2890
0
    handle->updatePasswordKey = NULL;
2891
0
    handle->updateID = NULL;
2892
0
    handle->type = type;
2893
0
    handle->usesLegacyStorage = legacy;
2894
0
    handle->passwordKey.data = NULL;
2895
0
    handle->passwordKey.len = 0;
2896
0
    handle->passwordLock = NULL;
2897
0
    if (type == SFTK_KEYDB_TYPE) {
2898
0
        handle->passwordLock = PZ_NewLock(nssILockAttribute);
2899
0
    }
2900
0
    sdb->app_private = handle;
2901
0
    return handle;
2902
0
}
2903
2904
/*
2905
 * reset the key database to it's uninitialized state. This call
2906
 * will clear all the key entried.
2907
 */
2908
SECStatus
2909
sftkdb_ResetKeyDB(SFTKDBHandle *handle)
2910
0
{
2911
0
    CK_RV crv;
2912
2913
    /* only rest the key db */
2914
0
    if (handle->type != SFTK_KEYDB_TYPE) {
2915
0
        return SECFailure;
2916
0
    }
2917
0
    crv = sftkdb_ResetDB(handle);
2918
0
    if (crv != CKR_OK) {
2919
        /* set error */
2920
0
        return SECFailure;
2921
0
    }
2922
0
    PZ_Lock(handle->passwordLock);
2923
0
    if (handle->passwordKey.data) {
2924
0
        SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE);
2925
0
        handle->passwordKey.data = NULL;
2926
0
    }
2927
0
    PZ_Unlock(handle->passwordLock);
2928
0
    return SECSuccess;
2929
0
}
2930
2931
#ifndef NSS_DISABLE_DBM
2932
static PRBool
2933
sftk_oldVersionExists(const char *dir, int version)
2934
{
2935
    int i;
2936
    PRStatus exists = PR_FAILURE;
2937
    char *file = NULL;
2938
2939
    for (i = version; i > 1; i--) {
2940
        file = PR_smprintf("%s%d.db", dir, i);
2941
        if (file == NULL) {
2942
            continue;
2943
        }
2944
        exists = PR_Access(file, PR_ACCESS_EXISTS);
2945
        PR_smprintf_free(file);
2946
        if (exists == PR_SUCCESS) {
2947
            return PR_TRUE;
2948
        }
2949
    }
2950
    return PR_FALSE;
2951
}
2952
2953
#if defined(_WIN32)
2954
/*
2955
 * Convert an sdb path (encoded in UTF-8) to a legacy path (encoded in the
2956
 * current system codepage). Fails if the path contains a character outside
2957
 * the current system codepage.
2958
 */
2959
static char *
2960
sftk_legacyPathFromSDBPath(const char *confdir)
2961
{
2962
    wchar_t *confdirWide;
2963
    DWORD size;
2964
    char *nconfdir;
2965
    BOOL unmappable;
2966
2967
    if (!confdir) {
2968
        return NULL;
2969
    }
2970
    confdirWide = _NSSUTIL_UTF8ToWide(confdir);
2971
    if (!confdirWide) {
2972
        return NULL;
2973
    }
2974
2975
    size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1,
2976
                               NULL, 0, NULL, &unmappable);
2977
    if (size == 0 || unmappable) {
2978
        PORT_Free(confdirWide);
2979
        return NULL;
2980
    }
2981
    nconfdir = PORT_Alloc(sizeof(char) * size);
2982
    if (!nconfdir) {
2983
        PORT_Free(confdirWide);
2984
        return NULL;
2985
    }
2986
    size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1,
2987
                               nconfdir, size, NULL, &unmappable);
2988
    PORT_Free(confdirWide);
2989
    if (size == 0 || unmappable) {
2990
        PORT_Free(nconfdir);
2991
        return NULL;
2992
    }
2993
2994
    return nconfdir;
2995
}
2996
#else
2997
#define sftk_legacyPathFromSDBPath(confdir) PORT_Strdup((confdir))
2998
#endif
2999
3000
static PRBool
3001
sftk_hasLegacyDB(const char *confdir, const char *certPrefix,
3002
                 const char *keyPrefix, int certVersion, int keyVersion)
3003
{
3004
    char *dir;
3005
    PRBool exists;
3006
3007
    if (certPrefix == NULL) {
3008
        certPrefix = "";
3009
    }
3010
3011
    if (keyPrefix == NULL) {
3012
        keyPrefix = "";
3013
    }
3014
3015
    dir = PR_smprintf("%s/%scert", confdir, certPrefix);
3016
    if (dir == NULL) {
3017
        return PR_FALSE;
3018
    }
3019
3020
    exists = sftk_oldVersionExists(dir, certVersion);
3021
    PR_smprintf_free(dir);
3022
    if (exists) {
3023
        return PR_TRUE;
3024
    }
3025
3026
    dir = PR_smprintf("%s/%skey", confdir, keyPrefix);
3027
    if (dir == NULL) {
3028
        return PR_FALSE;
3029
    }
3030
3031
    exists = sftk_oldVersionExists(dir, keyVersion);
3032
    PR_smprintf_free(dir);
3033
    return exists;
3034
}
3035
#endif /* NSS_DISABLE_DBM */
3036
3037
/*
3038
 * initialize certificate and key database handles as a pair.
3039
 *
3040
 * This function figures out what type of database we are opening and
3041
 * calls the appropriate low level function to open the database.
3042
 * It also figures out whether or not to setup up automatic update.
3043
 */
3044
CK_RV
3045
sftk_DBInit(const char *configdir, const char *certPrefix,
3046
            const char *keyPrefix, const char *updatedir,
3047
            const char *updCertPrefix, const char *updKeyPrefix,
3048
            const char *updateID, PRBool readOnly, PRBool noCertDB,
3049
            PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS,
3050
            SFTKDBHandle **certDB, SFTKDBHandle **keyDB)
3051
0
{
3052
0
    const char *confdir;
3053
0
    NSSDBType dbType = NSS_DB_TYPE_NONE;
3054
0
    char *appName = NULL;
3055
0
    SDB *keySDB, *certSDB;
3056
0
    CK_RV crv = CKR_OK;
3057
0
    int flags = SDB_RDONLY;
3058
0
    PRBool newInit = PR_FALSE;
3059
#ifndef NSS_DISABLE_DBM
3060
    PRBool needUpdate = PR_FALSE;
3061
#endif /* NSS_DISABLE_DBM */
3062
0
    char *nconfdir = NULL;
3063
0
    PRBool legacy = PR_TRUE;
3064
3065
0
    if (!readOnly) {
3066
0
        flags = SDB_CREATE;
3067
0
    }
3068
0
    if (isFIPS) {
3069
0
        flags |= SDB_FIPS;
3070
0
    }
3071
3072
0
    *certDB = NULL;
3073
0
    *keyDB = NULL;
3074
3075
0
    if (noKeyDB && noCertDB) {
3076
0
        return CKR_OK;
3077
0
    }
3078
0
    confdir = _NSSUTIL_EvaluateConfigDir(configdir, &dbType, &appName);
3079
3080
    /*
3081
     * now initialize the appropriate database
3082
     */
3083
0
    switch (dbType) {
3084
#ifndef NSS_DISABLE_DBM
3085
        case NSS_DB_TYPE_LEGACY:
3086
            crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags,
3087
                                  noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
3088
            break;
3089
        case NSS_DB_TYPE_MULTIACCESS:
3090
            crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags,
3091
                                  noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
3092
            break;
3093
#endif /* NSS_DISABLE_DBM */
3094
0
        case NSS_DB_TYPE_SQL:
3095
0
        case NSS_DB_TYPE_EXTERN: /* SHOULD open a loadable db */
3096
0
            crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags,
3097
0
                         noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit);
3098
0
            legacy = PR_FALSE;
3099
3100
#ifndef NSS_DISABLE_DBM
3101
            /*
3102
             * if we failed to open the DB's read only, use the old ones if
3103
             * the exists.
3104
             */
3105
            if (crv != CKR_OK) {
3106
                legacy = PR_TRUE;
3107
                if ((flags & SDB_RDONLY) == SDB_RDONLY) {
3108
                    nconfdir = sftk_legacyPathFromSDBPath(confdir);
3109
                }
3110
                if (nconfdir &&
3111
                    sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) {
3112
                    /* we have legacy databases, if we failed to open the new format
3113
                     * DB's read only, just use the legacy ones */
3114
                    crv = sftkdbCall_open(nconfdir, certPrefix,
3115
                                          keyPrefix, 8, 3, flags,
3116
                                          noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
3117
                }
3118
                /* Handle the database merge case.
3119
                 *
3120
                 * For the merge case, we need help from the application. Only
3121
                 * the application knows where the old database is, and what unique
3122
                 * identifier it has associated with it.
3123
                 *
3124
                 * If the client supplies these values, we use them to determine
3125
                 * if we need to update.
3126
                 */
3127
            } else if (
3128
                /* both update params have been supplied */
3129
                updatedir && *updatedir && updateID && *updateID
3130
                /* old dbs exist? */
3131
                && sftk_hasLegacyDB(updatedir, updCertPrefix, updKeyPrefix, 8, 3)
3132
                /* and they have not yet been updated? */
3133
                && ((noKeyDB || !sftkdb_hasUpdate("key", keySDB, updateID)) || (noCertDB || !sftkdb_hasUpdate("cert", certSDB, updateID)))) {
3134
                /* we need to update */
3135
                confdir = updatedir;
3136
                certPrefix = updCertPrefix;
3137
                keyPrefix = updKeyPrefix;
3138
                needUpdate = PR_TRUE;
3139
            } else if (newInit) {
3140
                /* if the new format DB was also a newly created DB, and we
3141
                 * succeeded, then need to update that new database with data
3142
                 * from the existing legacy DB */
3143
                nconfdir = sftk_legacyPathFromSDBPath(confdir);
3144
                if (nconfdir &&
3145
                    sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) {
3146
                    confdir = nconfdir;
3147
                    needUpdate = PR_TRUE;
3148
                }
3149
            }
3150
#endif /* NSS_DISABLE_DBM */
3151
0
            break;
3152
0
        default:
3153
0
            crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST
3154
                                      * return one of the types we already
3155
                                      * specified. */
3156
0
    }
3157
0
    if (crv != CKR_OK) {
3158
0
        goto done;
3159
0
    }
3160
0
    if (!noCertDB) {
3161
0
        *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE, legacy);
3162
0
    } else {
3163
0
        *certDB = NULL;
3164
0
    }
3165
0
    if (!noKeyDB) {
3166
0
        *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE, legacy);
3167
0
    } else {
3168
0
        *keyDB = NULL;
3169
0
    }
3170
3171
    /* link them together */
3172
0
    if (*certDB) {
3173
0
        (*certDB)->peerDB = *keyDB;
3174
0
    }
3175
0
    if (*keyDB) {
3176
0
        (*keyDB)->peerDB = *certDB;
3177
0
    }
3178
3179
#ifndef NSS_DISABLE_DBM
3180
    /*
3181
     * if we need to update, open the legacy database and
3182
     * mark the handle as needing update.
3183
     */
3184
    if (needUpdate) {
3185
        SDB *updateCert = NULL;
3186
        SDB *updateKey = NULL;
3187
        CK_RV crv2;
3188
3189
        crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags,
3190
                               noCertDB ? NULL : &updateCert,
3191
                               noKeyDB ? NULL : &updateKey);
3192
        if (crv2 == CKR_OK) {
3193
            if (*certDB) {
3194
                (*certDB)->update = updateCert;
3195
                (*certDB)->updateID = updateID && *updateID
3196
                                          ? PORT_Strdup(updateID)
3197
                                          : NULL;
3198
                updateCert->app_private = (*certDB);
3199
            }
3200
            if (*keyDB) {
3201
                PRBool tokenRemoved = PR_FALSE;
3202
                (*keyDB)->update = updateKey;
3203
                (*keyDB)->updateID = updateID && *updateID ? PORT_Strdup(updateID) : NULL;
3204
                updateKey->app_private = (*keyDB);
3205
                (*keyDB)->updateDBIsInit = PR_TRUE;
3206
                (*keyDB)->updateDBIsInit =
3207
                    (sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ? PR_TRUE : PR_FALSE;
3208
                /* if the password on the key db is NULL, kick off our update
3209
                 * chain of events */
3210
                sftkdb_CheckPasswordNull((*keyDB), &tokenRemoved);
3211
            } else {
3212
                /* we don't have a key DB, update the certificate DB now */
3213
                sftkdb_Update(*certDB, NULL);
3214
            }
3215
        }
3216
    }
3217
#endif /* NSS_DISABLE_DBM */
3218
3219
0
done:
3220
0
    if (appName) {
3221
0
        PORT_Free(appName);
3222
0
    }
3223
0
    if (nconfdir) {
3224
0
        PORT_Free(nconfdir);
3225
0
    }
3226
0
    return forceOpen ? CKR_OK : crv;
3227
0
}
3228
3229
CK_RV
3230
sftkdb_Shutdown(void)
3231
14
{
3232
14
    s_shutdown();
3233
#ifndef NSS_DISABLE_DBM
3234
    sftkdbCall_Shutdown();
3235
#endif /* NSS_DISABLE_DBM */
3236
14
    return CKR_OK;
3237
14
}