Coverage Report

Created: 2026-08-18 06:34

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