Coverage Report

Created: 2024-11-21 07:03

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