Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/pk11wrap/pk11merge.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
/*
6
 * Merge the source token into the target token.
7
 */
8
9
#include "secmod.h"
10
#include "secmodi.h"
11
#include "secmodti.h"
12
#include "pk11pub.h"
13
#include "pk11priv.h"
14
#include "pkcs11.h"
15
#include "seccomon.h"
16
#include "secerr.h"
17
#include "keyhi.h"
18
#include "hasht.h"
19
#include "cert.h"
20
#include "certdb.h"
21
22
/*************************************************************************
23
 *
24
 *             short utilities to aid in the merge
25
 *
26
 *************************************************************************/
27
28
/*
29
 * write a bunch of attributes out to an existing object.
30
 */
31
static SECStatus
32
pk11_setAttributes(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
33
                   CK_ATTRIBUTE *setTemplate, CK_ULONG setTemplCount)
34
0
{
35
0
    CK_RV crv;
36
0
    CK_SESSION_HANDLE rwsession;
37
0
38
0
    rwsession = PK11_GetRWSession(slot);
39
0
    if (rwsession == CK_INVALID_SESSION) {
40
0
        PORT_SetError(SEC_ERROR_BAD_DATA);
41
0
        return SECFailure;
42
0
    }
43
0
    crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
44
0
                                                 setTemplate, setTemplCount);
45
0
    PK11_RestoreROSession(slot, rwsession);
46
0
    if (crv != CKR_OK) {
47
0
        PORT_SetError(PK11_MapError(crv));
48
0
        return SECFailure;
49
0
    }
50
0
    return SECSuccess;
51
0
}
52
53
/*
54
 * copy a template of attributes from a source object to a target object.
55
 * if target object is not given, create it.
56
 */
57
static SECStatus
58
pk11_copyAttributes(PLArenaPool *arena,
59
                    PK11SlotInfo *targetSlot, CK_OBJECT_HANDLE targetID,
60
                    PK11SlotInfo *sourceSlot, CK_OBJECT_HANDLE sourceID,
61
                    CK_ATTRIBUTE *copyTemplate, CK_ULONG copyTemplateCount)
62
0
{
63
0
    SECStatus rv;
64
0
    CK_ATTRIBUTE *newTemplate = NULL;
65
0
    CK_RV crv;
66
0
67
0
    crv = PK11_GetAttributes(arena, sourceSlot, sourceID,
68
0
                             copyTemplate, copyTemplateCount);
69
0
    /* if we have missing attributes, just skip them and create the object */
70
0
    if (crv == CKR_ATTRIBUTE_TYPE_INVALID) {
71
0
        CK_ULONG i, j;
72
0
        newTemplate = PORT_NewArray(CK_ATTRIBUTE, copyTemplateCount);
73
0
        if (!newTemplate) {
74
0
            return SECFailure;
75
0
        }
76
0
        /* remove the unknown attributes. If we don't have enough attributes
77
0
         * PK11_CreateNewObject() will fail */
78
0
        for (i = 0, j = 0; i < copyTemplateCount; i++) {
79
0
            if (copyTemplate[i].ulValueLen != -1) {
80
0
                newTemplate[j] = copyTemplate[i];
81
0
                j++;
82
0
            }
83
0
        }
84
0
        copyTemplate = newTemplate;
85
0
        copyTemplateCount = j;
86
0
        crv = PK11_GetAttributes(arena, sourceSlot, sourceID,
87
0
                                 copyTemplate, copyTemplateCount);
88
0
    }
89
0
    if (crv != CKR_OK) {
90
0
        PORT_SetError(PK11_MapError(crv));
91
0
        PORT_Free(newTemplate);
92
0
        return SECFailure;
93
0
    }
94
0
    if (targetID == CK_INVALID_HANDLE) {
95
0
        /* we need to create the object */
96
0
        rv = PK11_CreateNewObject(targetSlot, CK_INVALID_SESSION,
97
0
                                  copyTemplate, copyTemplateCount, PR_TRUE, &targetID);
98
0
    } else {
99
0
        /* update the existing object with the new attributes */
100
0
        rv = pk11_setAttributes(targetSlot, targetID,
101
0
                                copyTemplate, copyTemplateCount);
102
0
    }
103
0
    if (newTemplate) {
104
0
        PORT_Free(newTemplate);
105
0
    }
106
0
    return rv;
107
0
}
108
109
/*
110
 * look for a matching object across tokens.
111
 */
112
static SECStatus
113
pk11_matchAcrossTokens(PLArenaPool *arena, PK11SlotInfo *targetSlot,
114
                       PK11SlotInfo *sourceSlot,
115
                       CK_ATTRIBUTE *template, CK_ULONG tsize,
116
                       CK_OBJECT_HANDLE id, CK_OBJECT_HANDLE *peer)
117
0
{
118
0
119
0
    CK_RV crv;
120
0
    *peer = CK_INVALID_HANDLE;
121
0
122
0
    crv = PK11_GetAttributes(arena, sourceSlot, id, template, tsize);
123
0
    if (crv != CKR_OK) {
124
0
        PORT_SetError(PK11_MapError(crv));
125
0
        goto loser;
126
0
    }
127
0
128
0
    if (template[0].ulValueLen == -1) {
129
0
        crv = CKR_ATTRIBUTE_TYPE_INVALID;
130
0
        PORT_SetError(PK11_MapError(crv));
131
0
        goto loser;
132
0
    }
133
0
134
0
    *peer = pk11_FindObjectByTemplate(targetSlot, template, tsize);
135
0
    return SECSuccess;
136
0
137
0
loser:
138
0
    return SECFailure;
139
0
}
140
141
/*
142
 * Encrypt using key and parameters
143
 */
144
SECStatus
145
pk11_encrypt(PK11SymKey *symKey, CK_MECHANISM_TYPE mechType, SECItem *param,
146
             SECItem *input, SECItem **output)
147
0
{
148
0
    PK11Context *ctxt = NULL;
149
0
    SECStatus rv = SECSuccess;
150
0
151
0
    if (*output) {
152
0
        SECITEM_FreeItem(*output, PR_TRUE);
153
0
    }
154
0
    *output = SECITEM_AllocItem(NULL, NULL, input->len + 20 /*slop*/);
155
0
    if (!*output) {
156
0
        rv = SECFailure;
157
0
        goto done;
158
0
    }
159
0
160
0
    ctxt = PK11_CreateContextBySymKey(mechType, CKA_ENCRYPT, symKey, param);
161
0
    if (ctxt == NULL) {
162
0
        rv = SECFailure;
163
0
        goto done;
164
0
    }
165
0
166
0
    rv = PK11_CipherOp(ctxt, (*output)->data,
167
0
                       (int *)&((*output)->len),
168
0
                       (*output)->len, input->data, input->len);
169
0
170
0
done:
171
0
    if (ctxt) {
172
0
        PK11_Finalize(ctxt);
173
0
        PK11_DestroyContext(ctxt, PR_TRUE);
174
0
    }
175
0
    if (rv != SECSuccess) {
176
0
        if (*output) {
177
0
            SECITEM_FreeItem(*output, PR_TRUE);
178
0
            *output = NULL;
179
0
        }
180
0
    }
181
0
    return rv;
182
0
}
183
184
/*************************************************************************
185
 *
186
 *            Private Keys
187
 *
188
 *************************************************************************/
189
190
/*
191
 * Fetch the key usage based on the pkcs #11 flags
192
 */
193
unsigned int
194
pk11_getPrivateKeyUsage(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
195
0
{
196
0
    unsigned int usage = 0;
197
0
198
0
    if ((PK11_HasAttributeSet(slot, id, CKA_UNWRAP, PR_FALSE) ||
199
0
         PK11_HasAttributeSet(slot, id, CKA_DECRYPT, PR_FALSE))) {
200
0
        usage |= KU_KEY_ENCIPHERMENT;
201
0
    }
202
0
    if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) {
203
0
        usage |= KU_KEY_AGREEMENT;
204
0
    }
205
0
    if ((PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE) ||
206
0
         PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE))) {
207
0
        usage |= KU_DIGITAL_SIGNATURE;
208
0
    }
209
0
    return usage;
210
0
}
211
212
/*
213
 * merge a private key,
214
 *
215
 * Private keys are merged using PBE wrapped keys with a random
216
 * value as the 'password'. Once the base key is moved, The remaining
217
 * attributes (SUBJECT) is copied.
218
 */
219
static SECStatus
220
pk11_mergePrivateKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
221
                     CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
222
0
{
223
0
    SECKEYPrivateKey *sourceKey = NULL;
224
0
    CK_OBJECT_HANDLE targetKeyID;
225
0
    SECKEYEncryptedPrivateKeyInfo *epki = NULL;
226
0
    char *nickname = NULL;
227
0
    SECItem nickItem;
228
0
    SECItem pwitem;
229
0
    SECItem publicValue;
230
0
    PLArenaPool *arena = NULL;
231
0
    SECStatus rv = SECSuccess;
232
0
    unsigned int keyUsage;
233
0
    unsigned char randomData[SHA1_LENGTH];
234
0
    SECOidTag algTag = SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC;
235
0
    CK_ATTRIBUTE privTemplate[] = {
236
0
        { CKA_ID, NULL, 0 },
237
0
        { CKA_CLASS, NULL, 0 }
238
0
    };
239
0
    CK_ULONG privTemplateCount = sizeof(privTemplate) / sizeof(privTemplate[0]);
240
0
    CK_ATTRIBUTE privCopyTemplate[] = {
241
0
        { CKA_SUBJECT, NULL, 0 }
242
0
    };
243
0
    CK_ULONG privCopyTemplateCount =
244
0
        sizeof(privCopyTemplate) / sizeof(privCopyTemplate[0]);
245
0
246
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
247
0
    if (arena == NULL) {
248
0
        rv = SECFailure;
249
0
        goto done;
250
0
    }
251
0
252
0
    /* check to see if the key is already in the target slot */
253
0
    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate,
254
0
                                privTemplateCount, id, &targetKeyID);
255
0
    if (rv != SECSuccess) {
256
0
        goto done;
257
0
    }
258
0
259
0
    if (targetKeyID != CK_INVALID_HANDLE) {
260
0
        /* match found,  not an error ... */
261
0
        goto done;
262
0
    }
263
0
264
0
    /* get an NSS representation of our source key */
265
0
    sourceKey = PK11_MakePrivKey(sourceSlot, nullKey, PR_FALSE,
266
0
                                 id, sourcePwArg);
267
0
    if (sourceKey == NULL) {
268
0
        rv = SECFailure;
269
0
        goto done;
270
0
    }
271
0
272
0
    /* Load the private key */
273
0
    /* generate a random pwitem */
274
0
    rv = PK11_GenerateRandom(randomData, sizeof(randomData));
275
0
    if (rv != SECSuccess) {
276
0
        goto done;
277
0
    }
278
0
    pwitem.data = randomData;
279
0
    pwitem.len = sizeof(randomData);
280
0
    /* fetch the private key encrypted */
281
0
    epki = PK11_ExportEncryptedPrivKeyInfo(sourceSlot, algTag, &pwitem,
282
0
                                           sourceKey, 1, sourcePwArg);
283
0
    if (epki == NULL) {
284
0
        rv = SECFailure;
285
0
        goto done;
286
0
    }
287
0
    nickname = PK11_GetObjectNickname(sourceSlot, id);
288
0
    /* NULL nickanme is fine (in fact is often normal) */
289
0
    if (nickname) {
290
0
        nickItem.data = (unsigned char *)nickname;
291
0
        nickItem.len = PORT_Strlen(nickname);
292
0
    }
293
0
    keyUsage = pk11_getPrivateKeyUsage(sourceSlot, id);
294
0
    /* pass in the CKA_ID */
295
0
    publicValue.data = privTemplate[0].pValue;
296
0
    publicValue.len = privTemplate[0].ulValueLen;
297
0
    rv = PK11_ImportEncryptedPrivateKeyInfo(targetSlot, epki, &pwitem,
298
0
                                            nickname ? &nickItem : NULL, &publicValue,
299
0
                                            PR_TRUE, PR_TRUE, sourceKey->keyType, keyUsage,
300
0
                                            targetPwArg);
301
0
    if (rv != SECSuccess) {
302
0
        goto done;
303
0
    }
304
0
305
0
    /* make sure it made it */
306
0
    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, privTemplate,
307
0
                                privTemplateCount, id, &targetKeyID);
308
0
    if (rv != SECSuccess) {
309
0
        goto done;
310
0
    }
311
0
312
0
    if (targetKeyID == CK_INVALID_HANDLE) {
313
0
        /* this time the key should exist */
314
0
        rv = SECFailure;
315
0
        goto done;
316
0
    }
317
0
318
0
    /* fill in remaining attributes */
319
0
    rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id,
320
0
                             privCopyTemplate, privCopyTemplateCount);
321
0
done:
322
0
    /* make sure the 'key' is cleared */
323
0
    PORT_Memset(randomData, 0, sizeof(randomData));
324
0
    if (nickname) {
325
0
        PORT_Free(nickname);
326
0
    }
327
0
    if (sourceKey) {
328
0
        SECKEY_DestroyPrivateKey(sourceKey);
329
0
    }
330
0
    if (epki) {
331
0
        SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
332
0
    }
333
0
    if (arena) {
334
0
        PORT_FreeArena(arena, PR_FALSE);
335
0
    }
336
0
    return rv;
337
0
}
338
339
/*************************************************************************
340
 *
341
 *            Secret Keys
342
 *
343
 *************************************************************************/
344
345
/*
346
 * we need to find a unique CKA_ID.
347
 *  The basic idea is to just increment the lowest byte.
348
 *  This code also handles the following corner cases:
349
 *   1) the single byte overflows. On overflow we increment the next byte up
350
 *    and so forth until we have overflowed the entire CKA_ID.
351
 *   2) If we overflow the entire CKA_ID we expand it by one byte.
352
 *   3) the CKA_ID is non-existent, we create a new one with one byte.
353
 *    This means no matter what CKA_ID is passed, the result of this function
354
 *    is always a new CKA_ID, and this function will never return the same
355
 *    CKA_ID the it has returned in the passed.
356
 */
357
static SECStatus
358
pk11_incrementID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate)
359
0
{
360
0
    unsigned char *buf = ptemplate->pValue;
361
0
    CK_ULONG len = ptemplate->ulValueLen;
362
0
363
0
    if (buf == NULL || len == (CK_ULONG)-1) {
364
0
        /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
365
0
        len = 0;
366
0
    } else {
367
0
        CK_ULONG i;
368
0
369
0
        /* walk from the back to front, incrementing
370
0
         * the CKA_ID until we no longer have a carry,
371
0
         * or have hit the front of the id. */
372
0
        for (i = len; i != 0; i--) {
373
0
            buf[i - 1]++;
374
0
            if (buf[i - 1] != 0) {
375
0
                /* no more carries, the increment is complete */
376
0
                return SECSuccess;
377
0
            }
378
0
        }
379
0
        /* we've now overflowed, fall through and expand the CKA_ID by
380
0
         * one byte */
381
0
    }
382
0
    /* if we are here we've run the counter to zero (indicating an overflow).
383
0
     * create an CKA_ID that is all zeros, but has one more zero than
384
0
     * the previous CKA_ID */
385
0
    buf = PORT_ArenaZAlloc(arena, len + 1);
386
0
    if (buf == NULL) {
387
0
        return SECFailure;
388
0
    }
389
0
    ptemplate->pValue = buf;
390
0
    ptemplate->ulValueLen = len + 1;
391
0
    return SECSuccess;
392
0
}
393
394
static CK_FLAGS
395
pk11_getSecretKeyFlags(PK11SlotInfo *slot, CK_OBJECT_HANDLE id)
396
0
{
397
0
    CK_FLAGS flags = 0;
398
0
399
0
    if (PK11_HasAttributeSet(slot, id, CKA_UNWRAP, PR_FALSE)) {
400
0
        flags |= CKF_UNWRAP;
401
0
    }
402
0
    if (PK11_HasAttributeSet(slot, id, CKA_WRAP, PR_FALSE)) {
403
0
        flags |= CKF_WRAP;
404
0
    }
405
0
    if (PK11_HasAttributeSet(slot, id, CKA_ENCRYPT, PR_FALSE)) {
406
0
        flags |= CKF_ENCRYPT;
407
0
    }
408
0
    if (PK11_HasAttributeSet(slot, id, CKA_DECRYPT, PR_FALSE)) {
409
0
        flags |= CKF_DECRYPT;
410
0
    }
411
0
    if (PK11_HasAttributeSet(slot, id, CKA_DERIVE, PR_FALSE)) {
412
0
        flags |= CKF_DERIVE;
413
0
    }
414
0
    if (PK11_HasAttributeSet(slot, id, CKA_SIGN, PR_FALSE)) {
415
0
        flags |= CKF_SIGN;
416
0
    }
417
0
    if (PK11_HasAttributeSet(slot, id, CKA_SIGN_RECOVER, PR_FALSE)) {
418
0
        flags |= CKF_SIGN_RECOVER;
419
0
    }
420
0
    if (PK11_HasAttributeSet(slot, id, CKA_VERIFY, PR_FALSE)) {
421
0
        flags |= CKF_VERIFY;
422
0
    }
423
0
    if (PK11_HasAttributeSet(slot, id, CKA_VERIFY_RECOVER, PR_FALSE)) {
424
0
        flags |= CKF_VERIFY_RECOVER;
425
0
    }
426
0
    return flags;
427
0
}
428
429
static const char testString[] =
430
    "My Encrytion Test Data (should be at least 32 bytes long)";
431
/*
432
 * merge a secret key,
433
 *
434
 * Secret keys may collide by CKA_ID as we merge 2 token. If we collide
435
 * on the CKA_ID, we need to make sure we are dealing with different keys.
436
 * The reason for this is it is possible that we've merged this database
437
 * before, and this key could have been merged already.  If the keys are
438
 * the same, we are done. If they are not, we need to update the CKA_ID of
439
 * the source key and try again.
440
 *
441
 * Once we know we have a unique key to merge in, we use NSS's underlying
442
 * key Move function which will do a key exchange if necessary to move
443
 * the key from one token to another. Then we set the CKA_ID and additional
444
 * pkcs #11 attributes.
445
 */
446
static SECStatus
447
pk11_mergeSecretKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
448
                    CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
449
0
{
450
0
    PK11SymKey *sourceKey = NULL;
451
0
    PK11SymKey *targetKey = NULL;
452
0
    SECItem *sourceOutput = NULL;
453
0
    SECItem *targetOutput = NULL;
454
0
    SECItem *param = NULL;
455
0
    int blockSize;
456
0
    SECItem input;
457
0
    CK_OBJECT_HANDLE targetKeyID;
458
0
    CK_FLAGS flags;
459
0
    PLArenaPool *arena = NULL;
460
0
    SECStatus rv = SECSuccess;
461
0
    CK_MECHANISM_TYPE keyMechType, cryptoMechType;
462
0
    CK_KEY_TYPE sourceKeyType, targetKeyType;
463
0
    CK_ATTRIBUTE symTemplate[] = {
464
0
        { CKA_ID, NULL, 0 },
465
0
        { CKA_CLASS, NULL, 0 }
466
0
    };
467
0
    CK_ULONG symTemplateCount = sizeof(symTemplate) / sizeof(symTemplate[0]);
468
0
    CK_ATTRIBUTE symCopyTemplate[] = {
469
0
        { CKA_LABEL, NULL, 0 }
470
0
    };
471
0
    CK_ULONG symCopyTemplateCount =
472
0
        sizeof(symCopyTemplate) / sizeof(symCopyTemplate[0]);
473
0
474
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
475
0
    if (arena == NULL) {
476
0
        rv = SECFailure;
477
0
        goto done;
478
0
    }
479
0
480
0
    sourceKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE);
481
0
    if (sourceKeyType == (CK_ULONG)-1) {
482
0
        rv = SECFailure;
483
0
        goto done;
484
0
    }
485
0
486
0
    /* get the key mechanism */
487
0
    keyMechType = PK11_GetKeyMechanism(sourceKeyType);
488
0
    /* get a mechanism suitable to encryption.
489
0
     * PK11_GetKeyMechanism returns a mechanism that is unique to the key
490
0
     * type. It tries to return encryption/decryption mechanisms, however
491
0
     * CKM_DES3_CBC uses and abmiguous keyType, so keyMechType is returned as
492
0
     * 'keygen' mechanism. Detect that case here */
493
0
    cryptoMechType = keyMechType;
494
0
    if ((keyMechType == CKM_DES3_KEY_GEN) ||
495
0
        (keyMechType == CKM_DES2_KEY_GEN)) {
496
0
        cryptoMechType = CKM_DES3_CBC;
497
0
    }
498
0
499
0
    sourceKey = PK11_SymKeyFromHandle(sourceSlot, NULL, PK11_OriginDerive,
500
0
                                      keyMechType, id, PR_FALSE, sourcePwArg);
501
0
    if (sourceKey == NULL) {
502
0
        rv = SECFailure;
503
0
        goto done;
504
0
    }
505
0
506
0
    /* check to see a key with the same CKA_ID  already exists in
507
0
     * the target slot. If it does, then we need to verify if the keys
508
0
     * really matches. If they don't import the key with a new CKA_ID
509
0
     * value. */
510
0
    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot,
511
0
                                symTemplate, symTemplateCount, id, &targetKeyID);
512
0
    if (rv != SECSuccess) {
513
0
        goto done;
514
0
    }
515
0
516
0
    /* set up the input test */
517
0
    input.data = (unsigned char *)testString;
518
0
    blockSize = PK11_GetBlockSize(cryptoMechType, NULL);
519
0
    if (blockSize < 0) {
520
0
        rv = SECFailure;
521
0
        goto done;
522
0
    }
523
0
    input.len = blockSize;
524
0
    if (input.len == 0) {
525
0
        input.len = sizeof(testString);
526
0
    }
527
0
    while (targetKeyID != CK_INVALID_HANDLE) {
528
0
        /* test to see if the keys are identical */
529
0
        targetKeyType = PK11_ReadULongAttribute(sourceSlot, id, CKA_KEY_TYPE);
530
0
        if (targetKeyType == sourceKeyType) {
531
0
            /* same keyType  - see if it's the same key */
532
0
            targetKey = PK11_SymKeyFromHandle(targetSlot, NULL,
533
0
                                              PK11_OriginDerive, keyMechType, targetKeyID, PR_FALSE,
534
0
                                              targetPwArg);
535
0
            /* get a parameter if we don't already have one */
536
0
            if (!param) {
537
0
                param = PK11_GenerateNewParam(cryptoMechType, sourceKey);
538
0
                if (param == NULL) {
539
0
                    rv = SECFailure;
540
0
                    goto done;
541
0
                }
542
0
            }
543
0
            /* use the source key to encrypt a reference */
544
0
            if (!sourceOutput) {
545
0
                rv = pk11_encrypt(sourceKey, cryptoMechType, param, &input,
546
0
                                  &sourceOutput);
547
0
                if (rv != SECSuccess) {
548
0
                    goto done;
549
0
                }
550
0
            }
551
0
            /* encrypt the reference with the target key */
552
0
            rv = pk11_encrypt(targetKey, cryptoMechType, param, &input,
553
0
                              &targetOutput);
554
0
            if (rv == SECSuccess) {
555
0
                if (SECITEM_ItemsAreEqual(sourceOutput, targetOutput)) {
556
0
                    /* they produce the same output, they must be the
557
0
                     * same key */
558
0
                    goto done;
559
0
                }
560
0
                SECITEM_FreeItem(targetOutput, PR_TRUE);
561
0
                targetOutput = NULL;
562
0
            }
563
0
            PK11_FreeSymKey(targetKey);
564
0
            targetKey = NULL;
565
0
        }
566
0
        /* keys aren't equal, update the KEY_ID and look again */
567
0
        rv = pk11_incrementID(arena, &symTemplate[0]);
568
0
        if (rv != SECSuccess) {
569
0
            goto done;
570
0
        }
571
0
        targetKeyID = pk11_FindObjectByTemplate(targetSlot,
572
0
                                                symTemplate, symTemplateCount);
573
0
    }
574
0
575
0
    /* we didn't find a matching key, import this one with the new
576
0
     * CKAID */
577
0
    flags = pk11_getSecretKeyFlags(sourceSlot, id);
578
0
    targetKey = PK11_MoveSymKey(targetSlot, PK11_OriginDerive, flags, PR_TRUE,
579
0
                                sourceKey);
580
0
    if (targetKey == NULL) {
581
0
        rv = SECFailure;
582
0
        goto done;
583
0
    }
584
0
    /* set the key new CKAID */
585
0
    rv = pk11_setAttributes(targetSlot, targetKey->objectID, symTemplate, 1);
586
0
    if (rv != SECSuccess) {
587
0
        goto done;
588
0
    }
589
0
590
0
    /* fill in remaining attributes */
591
0
    rv = pk11_copyAttributes(arena, targetSlot, targetKey->objectID,
592
0
                             sourceSlot, id, symCopyTemplate, symCopyTemplateCount);
593
0
done:
594
0
    if (sourceKey) {
595
0
        PK11_FreeSymKey(sourceKey);
596
0
    }
597
0
    if (targetKey) {
598
0
        PK11_FreeSymKey(targetKey);
599
0
    }
600
0
    if (sourceOutput) {
601
0
        SECITEM_FreeItem(sourceOutput, PR_TRUE);
602
0
    }
603
0
    if (targetOutput) {
604
0
        SECITEM_FreeItem(targetOutput, PR_TRUE);
605
0
    }
606
0
    if (param) {
607
0
        SECITEM_FreeItem(param, PR_TRUE);
608
0
    }
609
0
    if (arena) {
610
0
        PORT_FreeArena(arena, PR_FALSE);
611
0
    }
612
0
    return rv;
613
0
}
614
615
/*************************************************************************
616
 *
617
 *            Public Keys
618
 *
619
 *************************************************************************/
620
621
/*
622
 * Merge public key
623
 *
624
 * Use the high level NSS calls to extract the public key and import it
625
 * into the token. Extra attributes are then copied to the new token.
626
 */
627
static SECStatus
628
pk11_mergePublicKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
629
                    CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
630
0
{
631
0
    SECKEYPublicKey *sourceKey = NULL;
632
0
    CK_OBJECT_HANDLE targetKeyID;
633
0
    PLArenaPool *arena = NULL;
634
0
    SECStatus rv = SECSuccess;
635
0
    CK_ATTRIBUTE pubTemplate[] = {
636
0
        { CKA_ID, NULL, 0 },
637
0
        { CKA_CLASS, NULL, 0 }
638
0
    };
639
0
    CK_ULONG pubTemplateCount = sizeof(pubTemplate) / sizeof(pubTemplate[0]);
640
0
    CK_ATTRIBUTE pubCopyTemplate[] = {
641
0
        { CKA_ID, NULL, 0 },
642
0
        { CKA_LABEL, NULL, 0 },
643
0
        { CKA_SUBJECT, NULL, 0 }
644
0
    };
645
0
    CK_ULONG pubCopyTemplateCount =
646
0
        sizeof(pubCopyTemplate) / sizeof(pubCopyTemplate[0]);
647
0
648
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
649
0
    if (arena == NULL) {
650
0
        rv = SECFailure;
651
0
        goto done;
652
0
    }
653
0
654
0
    /* check to see if the key is already in the target slot */
655
0
    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, pubTemplate,
656
0
                                pubTemplateCount, id, &targetKeyID);
657
0
    if (rv != SECSuccess) {
658
0
        goto done;
659
0
    }
660
0
661
0
    /* Key is already in the target slot */
662
0
    if (targetKeyID != CK_INVALID_HANDLE) {
663
0
        /* not an error ... */
664
0
        goto done;
665
0
    }
666
0
667
0
    /* fetch an NSS representation of the public key */
668
0
    sourceKey = PK11_ExtractPublicKey(sourceSlot, nullKey, id);
669
0
    if (sourceKey == NULL) {
670
0
        rv = SECFailure;
671
0
        goto done;
672
0
    }
673
0
674
0
    /* load the public key into the target token. */
675
0
    targetKeyID = PK11_ImportPublicKey(targetSlot, sourceKey, PR_TRUE);
676
0
    if (targetKeyID == CK_INVALID_HANDLE) {
677
0
        rv = SECFailure;
678
0
        goto done;
679
0
    }
680
0
681
0
    /* fill in remaining attributes */
682
0
    rv = pk11_copyAttributes(arena, targetSlot, targetKeyID, sourceSlot, id,
683
0
                             pubCopyTemplate, pubCopyTemplateCount);
684
0
685
0
done:
686
0
    if (sourceKey) {
687
0
        SECKEY_DestroyPublicKey(sourceKey);
688
0
    }
689
0
    if (arena) {
690
0
        PORT_FreeArena(arena, PR_FALSE);
691
0
    }
692
0
    return rv;
693
0
}
694
695
/*************************************************************************
696
 *
697
 *            Certificates
698
 *
699
 *************************************************************************/
700
701
/*
702
 * Two copies of the source code for this algorithm exist in NSS.
703
 * Changes must be made in both copies.
704
 * The other copy is in sftkdb_resolveConflicts() in softoken/sftkdb.c.
705
 */
706
static char *
707
pk11_IncrementNickname(char *nickname)
708
0
{
709
0
    char *newNickname = NULL;
710
0
    int end;
711
0
    int digit;
712
0
    int len = strlen(nickname);
713
0
714
0
    /* does nickname end with " #n*" ? */
715
0
    for (end = len - 1;
716
0
         end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0';
717
0
         end--) /* just scan */
718
0
        ;
719
0
    if (len >= 3 &&
720
0
        end < (len - 1) /* at least one digit */ &&
721
0
        nickname[end] == '#' &&
722
0
        nickname[end - 1] == ' ') {
723
0
        /* Already has a suitable suffix string */
724
0
    } else {
725
0
        /* ... append " #2" to the name */
726
0
        static const char num2[] = " #2";
727
0
        newNickname = PORT_Realloc(nickname, len + sizeof(num2));
728
0
        if (newNickname) {
729
0
            PORT_Strcat(newNickname, num2);
730
0
        } else {
731
0
            PORT_Free(nickname);
732
0
        }
733
0
        return newNickname;
734
0
    }
735
0
736
0
    for (end = len - 1;
737
0
         end >= 0 && (digit = nickname[end]) <= '9' && digit >= '0';
738
0
         end--) {
739
0
        if (digit < '9') {
740
0
            nickname[end]++;
741
0
            return nickname;
742
0
        }
743
0
        nickname[end] = '0';
744
0
    }
745
0
746
0
    /* we overflowed, insert a new '1' for a carry in front of the number */
747
0
    newNickname = PORT_Realloc(nickname, len + 2);
748
0
    if (newNickname) {
749
0
        newNickname[++end] = '1';
750
0
        PORT_Memset(&newNickname[end + 1], '0', len - end);
751
0
        newNickname[len + 1] = 0;
752
0
    } else {
753
0
        PORT_Free(nickname);
754
0
    }
755
0
    return newNickname;
756
0
}
757
758
/*
759
 * merge a certificate object
760
 *
761
 * Use the high level NSS calls to extract and import the certificate.
762
 */
763
static SECStatus
764
pk11_mergeCert(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
765
               CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
766
0
{
767
0
    CERTCertificate *sourceCert = NULL;
768
0
    CK_OBJECT_HANDLE targetCertID = CK_INVALID_HANDLE;
769
0
    char *nickname = NULL;
770
0
    SECStatus rv = SECSuccess;
771
0
    PLArenaPool *arena = NULL;
772
0
    CK_ATTRIBUTE sourceCKAID = { CKA_ID, NULL, 0 };
773
0
    CK_ATTRIBUTE targetCKAID = { CKA_ID, NULL, 0 };
774
0
    SECStatus lrv = SECSuccess;
775
0
    int error = SEC_ERROR_LIBRARY_FAILURE;
776
0
777
0
    sourceCert = PK11_MakeCertFromHandle(sourceSlot, id, NULL);
778
0
    if (sourceCert == NULL) {
779
0
        rv = SECFailure;
780
0
        goto done;
781
0
    }
782
0
783
0
    nickname = PK11_GetObjectNickname(sourceSlot, id);
784
0
785
0
    /* The database code will prevent nickname collisions for certs with
786
0
     * different subjects. This code will prevent us from getting
787
0
     * actual import errors */
788
0
    if (nickname) {
789
0
        const char *tokenName = PK11_GetTokenName(targetSlot);
790
0
        char *tokenNickname = NULL;
791
0
792
0
        do {
793
0
            tokenNickname = PR_smprintf("%s:%s", tokenName, nickname);
794
0
            if (!tokenNickname) {
795
0
                break;
796
0
            }
797
0
            if (!SEC_CertNicknameConflict(tokenNickname,
798
0
                                          &sourceCert->derSubject, CERT_GetDefaultCertDB())) {
799
0
                break;
800
0
            }
801
0
            nickname = pk11_IncrementNickname(nickname);
802
0
            if (!nickname) {
803
0
                break;
804
0
            }
805
0
            PR_smprintf_free(tokenNickname);
806
0
        } while (1);
807
0
        if (tokenNickname) {
808
0
            PR_smprintf_free(tokenNickname);
809
0
        }
810
0
    }
811
0
812
0
    /* see if the cert is already there */
813
0
    targetCertID = PK11_FindCertInSlot(targetSlot, sourceCert, targetPwArg);
814
0
    if (targetCertID == CK_INVALID_HANDLE) {
815
0
        /* cert doesn't exist load the cert in. */
816
0
        /* OK for the nickname to be NULL, not all certs have nicknames */
817
0
        rv = PK11_ImportCert(targetSlot, sourceCert, CK_INVALID_HANDLE,
818
0
                             nickname, PR_FALSE);
819
0
        goto done;
820
0
    }
821
0
822
0
    /* the cert already exists, see if the nickname and/or  CKA_ID need
823
0
     * to be updated */
824
0
825
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
826
0
    if (arena == NULL) {
827
0
        rv = SECFailure;
828
0
        goto done;
829
0
    }
830
0
831
0
    /* does our source have a CKA_ID ? */
832
0
    rv = PK11_GetAttributes(arena, sourceSlot, id, &sourceCKAID, 1);
833
0
    if (rv != SECSuccess) {
834
0
        sourceCKAID.ulValueLen = 0;
835
0
    }
836
0
837
0
    /* if we have a source CKA_ID, see of we need to update the
838
0
     * target's CKA_ID */
839
0
    if (sourceCKAID.ulValueLen != 0) {
840
0
        rv = PK11_GetAttributes(arena, targetSlot, targetCertID,
841
0
                                &targetCKAID, 1);
842
0
        if (rv != SECSuccess) {
843
0
            targetCKAID.ulValueLen = 0;
844
0
        }
845
0
        /* if the target has no CKA_ID, update it from the source */
846
0
        if (targetCKAID.ulValueLen == 0) {
847
0
            lrv = pk11_setAttributes(targetSlot, targetCertID, &sourceCKAID, 1);
848
0
            if (lrv != SECSuccess) {
849
0
                error = PORT_GetError();
850
0
            }
851
0
        }
852
0
    }
853
0
    rv = SECSuccess;
854
0
855
0
    /* now check if we need to update the nickname */
856
0
    if (nickname && *nickname) {
857
0
        char *targetname;
858
0
        targetname = PK11_GetObjectNickname(targetSlot, targetCertID);
859
0
        if (!targetname || !*targetname) {
860
0
            /* target has no nickname, or it's empty, update it */
861
0
            rv = PK11_SetObjectNickname(targetSlot, targetCertID, nickname);
862
0
        }
863
0
        if (targetname) {
864
0
            PORT_Free(targetname);
865
0
        }
866
0
    }
867
0
868
0
    /* restore the error code if CKA_ID failed, but nickname didn't */
869
0
    if ((rv == SECSuccess) && (lrv != SECSuccess)) {
870
0
        rv = lrv;
871
0
        PORT_SetError(error);
872
0
    }
873
0
874
0
done:
875
0
    if (nickname) {
876
0
        PORT_Free(nickname);
877
0
    }
878
0
    if (sourceCert) {
879
0
        CERT_DestroyCertificate(sourceCert);
880
0
    }
881
0
    if (arena) {
882
0
        PORT_FreeArena(arena, PR_FALSE);
883
0
    }
884
0
    return rv;
885
0
}
886
887
/*************************************************************************
888
 *
889
 *            Crls
890
 *
891
 *************************************************************************/
892
893
/*
894
 * Use the raw PKCS #11 interface to merge the CRLs.
895
 *
896
 * In the case where of collision, choose the newest CRL that is valid.
897
 */
898
static SECStatus
899
pk11_mergeCrl(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
900
              CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
901
0
{
902
0
    CK_OBJECT_HANDLE targetCrlID;
903
0
    PLArenaPool *arena = NULL;
904
0
    SECStatus rv = SECSuccess;
905
0
    CK_ATTRIBUTE crlTemplate[] = {
906
0
        { CKA_SUBJECT, NULL, 0 },
907
0
        { CKA_CLASS, NULL, 0 },
908
0
        { CKA_NSS_KRL, NULL, 0 }
909
0
    };
910
0
    CK_ULONG crlTemplateCount = sizeof(crlTemplate) / sizeof(crlTemplate[0]);
911
0
    CK_ATTRIBUTE crlCopyTemplate[] = {
912
0
        { CKA_CLASS, NULL, 0 },
913
0
        { CKA_TOKEN, NULL, 0 },
914
0
        { CKA_LABEL, NULL, 0 },
915
0
        { CKA_PRIVATE, NULL, 0 },
916
0
        { CKA_MODIFIABLE, NULL, 0 },
917
0
        { CKA_SUBJECT, NULL, 0 },
918
0
        { CKA_NSS_KRL, NULL, 0 },
919
0
        { CKA_NSS_URL, NULL, 0 },
920
0
        { CKA_VALUE, NULL, 0 }
921
0
    };
922
0
    CK_ULONG crlCopyTemplateCount =
923
0
        sizeof(crlCopyTemplate) / sizeof(crlCopyTemplate[0]);
924
0
925
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
926
0
    if (arena == NULL) {
927
0
        rv = SECFailure;
928
0
        goto done;
929
0
    }
930
0
    /* check to see if the crl is already in the target slot */
931
0
    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, crlTemplate,
932
0
                                crlTemplateCount, id, &targetCrlID);
933
0
    if (rv != SECSuccess) {
934
0
        goto done;
935
0
    }
936
0
    if (targetCrlID != CK_INVALID_HANDLE) {
937
0
        /* we already have a CRL, check to see which is more up-to-date. */
938
0
        goto done;
939
0
    }
940
0
941
0
    /* load the CRL into the target token. */
942
0
    rv = pk11_copyAttributes(arena, targetSlot, targetCrlID, sourceSlot, id,
943
0
                             crlCopyTemplate, crlCopyTemplateCount);
944
0
done:
945
0
    if (arena) {
946
0
        PORT_FreeArena(arena, PR_FALSE);
947
0
    }
948
0
    return rv;
949
0
}
950
951
/*************************************************************************
952
 *
953
 *            SMIME objects
954
 *
955
 *************************************************************************/
956
957
/*
958
 * use the raw PKCS #11 interface to merge the S/MIME records
959
 */
960
static SECStatus
961
pk11_mergeSmime(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
962
                CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
963
0
{
964
0
    CK_OBJECT_HANDLE targetSmimeID;
965
0
    PLArenaPool *arena = NULL;
966
0
    SECStatus rv = SECSuccess;
967
0
    CK_ATTRIBUTE smimeTemplate[] = {
968
0
        { CKA_SUBJECT, NULL, 0 },
969
0
        { CKA_NSS_EMAIL, NULL, 0 },
970
0
        { CKA_CLASS, NULL, 0 },
971
0
    };
972
0
    CK_ULONG smimeTemplateCount =
973
0
        sizeof(smimeTemplate) / sizeof(smimeTemplate[0]);
974
0
    CK_ATTRIBUTE smimeCopyTemplate[] = {
975
0
        { CKA_CLASS, NULL, 0 },
976
0
        { CKA_TOKEN, NULL, 0 },
977
0
        { CKA_LABEL, NULL, 0 },
978
0
        { CKA_PRIVATE, NULL, 0 },
979
0
        { CKA_MODIFIABLE, NULL, 0 },
980
0
        { CKA_SUBJECT, NULL, 0 },
981
0
        { CKA_NSS_EMAIL, NULL, 0 },
982
0
        { CKA_NSS_SMIME_TIMESTAMP, NULL, 0 },
983
0
        { CKA_VALUE, NULL, 0 }
984
0
    };
985
0
    CK_ULONG smimeCopyTemplateCount =
986
0
        sizeof(smimeCopyTemplate) / sizeof(smimeCopyTemplate[0]);
987
0
988
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
989
0
    if (arena == NULL) {
990
0
        rv = SECFailure;
991
0
        goto done;
992
0
    }
993
0
    /* check to see if the crl is already in the target slot */
994
0
    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, smimeTemplate,
995
0
                                smimeTemplateCount, id, &targetSmimeID);
996
0
    if (rv != SECSuccess) {
997
0
        goto done;
998
0
    }
999
0
    if (targetSmimeID != CK_INVALID_HANDLE) {
1000
0
        /* we already have a SMIME record */
1001
0
        goto done;
1002
0
    }
1003
0
1004
0
    /* load the SMime Record into the target token. */
1005
0
    rv = pk11_copyAttributes(arena, targetSlot, targetSmimeID, sourceSlot, id,
1006
0
                             smimeCopyTemplate, smimeCopyTemplateCount);
1007
0
done:
1008
0
    if (arena) {
1009
0
        PORT_FreeArena(arena, PR_FALSE);
1010
0
    }
1011
0
    return rv;
1012
0
}
1013
1014
/*************************************************************************
1015
 *
1016
 *            Trust Objects
1017
 *
1018
 *************************************************************************/
1019
1020
/*
1021
 * decide which trust record entry wins. PR_TRUE (source) or PR_FALSE (target)
1022
 */
1023
0
#define USE_TARGET PR_FALSE
1024
0
#define USE_SOURCE PR_TRUE
1025
PRBool
1026
pk11_mergeTrustEntry(CK_ATTRIBUTE *target, CK_ATTRIBUTE *source)
1027
0
{
1028
0
    CK_ULONG targetTrust = (target->ulValueLen == sizeof(CK_LONG)) ? *(CK_ULONG *)target->pValue
1029
0
                                                                   : CKT_NSS_TRUST_UNKNOWN;
1030
0
    CK_ULONG sourceTrust = (source->ulValueLen == sizeof(CK_LONG)) ? *(CK_ULONG *)source->pValue
1031
0
                                                                   : CKT_NSS_TRUST_UNKNOWN;
1032
0
1033
0
    /*
1034
0
     * Examine a single entry and deside if the source or target version
1035
0
     * should win out. When all the entries have been checked, if there is
1036
0
     * any case we need to update, we will write the whole source record
1037
0
     * to the target database. That means for each individual record, if the
1038
0
     * target wins, we need to update the source (in case later we have a
1039
0
     * case where the source wins). If the source wins, it already
1040
0
     */
1041
0
    if (sourceTrust == targetTrust) {
1042
0
        return USE_TARGET; /* which equates to 'do nothing' */
1043
0
    }
1044
0
1045
0
    if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) {
1046
0
        return USE_TARGET;
1047
0
    }
1048
0
1049
0
    /* target has no idea, use the source's idea of the trust value */
1050
0
    if (targetTrust == CKT_NSS_TRUST_UNKNOWN) {
1051
0
        /* source overwrites the target */
1052
0
        return USE_SOURCE;
1053
0
    }
1054
0
1055
0
    /* so both the target and the source have some idea of what this
1056
0
     * trust attribute should be, and neither agree exactly.
1057
0
     * At this point, we prefer 'hard' attributes over 'soft' ones.
1058
0
     * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and
1059
0
     * CKT_NSS_UNTRUTED. Soft ones are ones which don't change the
1060
0
     * actual trust of the cert (CKT_MUST_VERIFY, CKT_NSS_VALID,
1061
0
     * CKT_NSS_VALID_DELEGATOR).
1062
0
     */
1063
0
    if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) ||
1064
0
        (sourceTrust == CKT_NSS_VALID_DELEGATOR)) {
1065
0
        return USE_TARGET;
1066
0
    }
1067
0
    if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST) ||
1068
0
        (targetTrust == CKT_NSS_VALID_DELEGATOR)) {
1069
0
        /* source overrites the target */
1070
0
        return USE_SOURCE;
1071
0
    }
1072
0
1073
0
    /* both have hard attributes, we have a conflict, let the target win. */
1074
0
    return USE_TARGET;
1075
0
}
1076
/*
1077
 * use the raw PKCS #11 interface to merge the S/MIME records
1078
 */
1079
static SECStatus
1080
pk11_mergeTrust(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
1081
                CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
1082
0
{
1083
0
    CK_OBJECT_HANDLE targetTrustID;
1084
0
    PLArenaPool *arena = NULL;
1085
0
    SECStatus rv = SECSuccess;
1086
0
    int error = 0;
1087
0
    CK_ATTRIBUTE trustTemplate[] = {
1088
0
        { CKA_ISSUER, NULL, 0 },
1089
0
        { CKA_SERIAL_NUMBER, NULL, 0 },
1090
0
        { CKA_CLASS, NULL, 0 },
1091
0
    };
1092
0
    CK_ULONG trustTemplateCount =
1093
0
        sizeof(trustTemplate) / sizeof(trustTemplate[0]);
1094
0
    CK_ATTRIBUTE trustCopyTemplate[] = {
1095
0
        { CKA_CLASS, NULL, 0 },
1096
0
        { CKA_TOKEN, NULL, 0 },
1097
0
        { CKA_LABEL, NULL, 0 },
1098
0
        { CKA_PRIVATE, NULL, 0 },
1099
0
        { CKA_MODIFIABLE, NULL, 0 },
1100
0
        { CKA_ISSUER, NULL, 0 },
1101
0
        { CKA_SERIAL_NUMBER, NULL, 0 },
1102
0
        { CKA_CERT_SHA1_HASH, NULL, 0 },
1103
0
        { CKA_CERT_MD5_HASH, NULL, 0 },
1104
0
        { CKA_TRUST_SERVER_AUTH, NULL, 0 },
1105
0
        { CKA_TRUST_CLIENT_AUTH, NULL, 0 },
1106
0
        { CKA_TRUST_CODE_SIGNING, NULL, 0 },
1107
0
        { CKA_TRUST_EMAIL_PROTECTION, NULL, 0 },
1108
0
        { CKA_TRUST_STEP_UP_APPROVED, NULL, 0 }
1109
0
    };
1110
0
    CK_ULONG trustCopyTemplateCount =
1111
0
        sizeof(trustCopyTemplate) / sizeof(trustCopyTemplate[0]);
1112
0
1113
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1114
0
    if (arena == NULL) {
1115
0
        rv = SECFailure;
1116
0
        goto done;
1117
0
    }
1118
0
    /* check to see if the crl is already in the target slot */
1119
0
    rv = pk11_matchAcrossTokens(arena, targetSlot, sourceSlot, trustTemplate,
1120
0
                                trustTemplateCount, id, &targetTrustID);
1121
0
    if (rv != SECSuccess) {
1122
0
        goto done;
1123
0
    }
1124
0
    if (targetTrustID != CK_INVALID_HANDLE) {
1125
0
        /* a matching trust record already exists, merge it in */
1126
0
        CK_ATTRIBUTE_TYPE trustAttrs[] = {
1127
0
            CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH,
1128
0
            CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION,
1129
0
            CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER,
1130
0
            CKA_TRUST_TIME_STAMPING
1131
0
        };
1132
0
        CK_ULONG trustAttrsCount =
1133
0
            sizeof(trustAttrs) / sizeof(trustAttrs[0]);
1134
0
1135
0
        CK_ULONG i;
1136
0
        CK_ATTRIBUTE targetTemplate, sourceTemplate;
1137
0
1138
0
        /* existing trust record, merge the two together */
1139
0
        for (i = 0; i < trustAttrsCount; i++) {
1140
0
            targetTemplate.type = sourceTemplate.type = trustAttrs[i];
1141
0
            targetTemplate.pValue = sourceTemplate.pValue = NULL;
1142
0
            targetTemplate.ulValueLen = sourceTemplate.ulValueLen = 0;
1143
0
            PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1);
1144
0
            PK11_GetAttributes(arena, targetSlot, targetTrustID,
1145
0
                               &targetTemplate, 1);
1146
0
            if (pk11_mergeTrustEntry(&targetTemplate, &sourceTemplate)) {
1147
0
                /* source wins, write out the source attribute to the target */
1148
0
                SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID,
1149
0
                                                   &sourceTemplate, 1);
1150
0
                if (lrv != SECSuccess) {
1151
0
                    rv = SECFailure;
1152
0
                    error = PORT_GetError();
1153
0
                }
1154
0
            }
1155
0
        }
1156
0
1157
0
        /* handle step */
1158
0
        sourceTemplate.type = CKA_TRUST_STEP_UP_APPROVED;
1159
0
        sourceTemplate.pValue = NULL;
1160
0
        sourceTemplate.ulValueLen = 0;
1161
0
1162
0
        /* if the source has steup set, then set it in the target */
1163
0
        PK11_GetAttributes(arena, sourceSlot, id, &sourceTemplate, 1);
1164
0
        if ((sourceTemplate.ulValueLen == sizeof(CK_BBOOL)) &&
1165
0
            (sourceTemplate.pValue) &&
1166
0
            (*(CK_BBOOL *)sourceTemplate.pValue == CK_TRUE)) {
1167
0
            SECStatus lrv = pk11_setAttributes(targetSlot, targetTrustID,
1168
0
                                               &sourceTemplate, 1);
1169
0
            if (lrv != SECSuccess) {
1170
0
                rv = SECFailure;
1171
0
                error = PORT_GetError();
1172
0
            }
1173
0
        }
1174
0
1175
0
        goto done;
1176
0
    }
1177
0
1178
0
    /* load the new trust Record into the target token. */
1179
0
    rv = pk11_copyAttributes(arena, targetSlot, targetTrustID, sourceSlot, id,
1180
0
                             trustCopyTemplate, trustCopyTemplateCount);
1181
0
done:
1182
0
    if (arena) {
1183
0
        PORT_FreeArena(arena, PR_FALSE);
1184
0
    }
1185
0
1186
0
    /* restore the error code */
1187
0
    if (rv == SECFailure && error) {
1188
0
        PORT_SetError(error);
1189
0
    }
1190
0
1191
0
    return rv;
1192
0
}
1193
1194
/*************************************************************************
1195
 *
1196
 *            Central merge code
1197
 *
1198
 *************************************************************************/
1199
/*
1200
 * merge a single object from sourceToken to targetToken
1201
 */
1202
static SECStatus
1203
pk11_mergeObject(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
1204
                 CK_OBJECT_HANDLE id, void *targetPwArg, void *sourcePwArg)
1205
0
{
1206
0
1207
0
    CK_OBJECT_CLASS objClass;
1208
0
1209
0
    objClass = PK11_ReadULongAttribute(sourceSlot, id, CKA_CLASS);
1210
0
    if (objClass == (CK_ULONG)-1) {
1211
0
        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
1212
0
        return SECFailure;
1213
0
    }
1214
0
1215
0
    switch (objClass) {
1216
0
        case CKO_CERTIFICATE:
1217
0
            return pk11_mergeCert(targetSlot, sourceSlot, id,
1218
0
                                  targetPwArg, sourcePwArg);
1219
0
        case CKO_NSS_TRUST:
1220
0
            return pk11_mergeTrust(targetSlot, sourceSlot, id,
1221
0
                                   targetPwArg, sourcePwArg);
1222
0
        case CKO_PUBLIC_KEY:
1223
0
            return pk11_mergePublicKey(targetSlot, sourceSlot, id,
1224
0
                                       targetPwArg, sourcePwArg);
1225
0
        case CKO_PRIVATE_KEY:
1226
0
            return pk11_mergePrivateKey(targetSlot, sourceSlot, id,
1227
0
                                        targetPwArg, sourcePwArg);
1228
0
        case CKO_SECRET_KEY:
1229
0
            return pk11_mergeSecretKey(targetSlot, sourceSlot, id,
1230
0
                                       targetPwArg, sourcePwArg);
1231
0
        case CKO_NSS_CRL:
1232
0
            return pk11_mergeCrl(targetSlot, sourceSlot, id,
1233
0
                                 targetPwArg, sourcePwArg);
1234
0
        case CKO_NSS_SMIME:
1235
0
            return pk11_mergeSmime(targetSlot, sourceSlot, id,
1236
0
                                   targetPwArg, sourcePwArg);
1237
0
        default:
1238
0
            break;
1239
0
    }
1240
0
1241
0
    PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
1242
0
    return SECFailure;
1243
0
}
1244
1245
PK11MergeLogNode *
1246
pk11_newMergeLogNode(PLArenaPool *arena,
1247
                     PK11SlotInfo *slot, CK_OBJECT_HANDLE id, int error)
1248
0
{
1249
0
    PK11MergeLogNode *newLog;
1250
0
    PK11GenericObject *obj;
1251
0
1252
0
    newLog = PORT_ArenaZNew(arena, PK11MergeLogNode);
1253
0
    if (newLog == NULL) {
1254
0
        return NULL;
1255
0
    }
1256
0
1257
0
    obj = PORT_ArenaZNew(arena, PK11GenericObject);
1258
0
    if (!obj) {
1259
0
        return NULL;
1260
0
    }
1261
0
1262
0
    /* initialize it */
1263
0
    obj->slot = slot;
1264
0
    obj->objectID = id;
1265
0
    obj->owner = PR_FALSE;
1266
0
1267
0
    newLog->object = obj;
1268
0
    newLog->error = error;
1269
0
    return newLog;
1270
0
}
1271
1272
/*
1273
 * walk down each entry and merge it. keep track of the errors in the log
1274
 */
1275
static SECStatus
1276
pk11_mergeByObjectIDs(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
1277
                      CK_OBJECT_HANDLE *objectIDs, int count,
1278
                      PK11MergeLog *log, void *targetPwArg, void *sourcePwArg)
1279
0
{
1280
0
    SECStatus rv = SECSuccess;
1281
0
    int error = SEC_ERROR_LIBRARY_FAILURE;
1282
0
    int i;
1283
0
1284
0
    for (i = 0; i < count; i++) {
1285
0
        /* try to update the entire database. On failure, keep going,
1286
0
         * but remember the error to report back to the caller */
1287
0
        SECStatus lrv;
1288
0
        PK11MergeLogNode *newLog;
1289
0
1290
0
        lrv = pk11_mergeObject(targetSlot, sourceSlot, objectIDs[i],
1291
0
                               targetPwArg, sourcePwArg);
1292
0
        if (lrv == SECSuccess) {
1293
0
            /* merged with no problem, go to next object */
1294
0
            continue;
1295
0
        }
1296
0
1297
0
        /* remember that we failed and why */
1298
0
        rv = SECFailure;
1299
0
        error = PORT_GetError();
1300
0
1301
0
        /* log the errors */
1302
0
        if (!log) {
1303
0
            /* not logging, go to next entry */
1304
0
            continue;
1305
0
        }
1306
0
        newLog = pk11_newMergeLogNode(log->arena, sourceSlot,
1307
0
                                      objectIDs[i], error);
1308
0
        if (!newLog) {
1309
0
            /* failed to allocate entry, just keep going */
1310
0
            continue;
1311
0
        }
1312
0
1313
0
        /* link in the errorlog entry */
1314
0
        newLog->next = NULL;
1315
0
        if (log->tail) {
1316
0
            log->tail->next = newLog;
1317
0
        } else {
1318
0
            log->head = newLog;
1319
0
        }
1320
0
        newLog->prev = log->tail;
1321
0
        log->tail = newLog;
1322
0
    }
1323
0
1324
0
    /* restore the last error code */
1325
0
    if (rv != SECSuccess) {
1326
0
        PORT_SetError(error);
1327
0
    }
1328
0
    return rv;
1329
0
}
1330
1331
/*
1332
 * Merge all the records in sourceSlot that aren't in targetSlot
1333
 *
1334
 *   This function will return failure if not all the objects
1335
 *   successfully merged.
1336
 *
1337
 *   Applications can pass in an optional error log which will record
1338
 *   each failing object and why it failed to import. PK11MergeLog
1339
 *   is modelled after the CERTVerifyLog.
1340
 */
1341
SECStatus
1342
PK11_MergeTokens(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
1343
                 PK11MergeLog *log, void *targetPwArg, void *sourcePwArg)
1344
0
{
1345
0
    SECStatus rv = SECSuccess, lrv = SECSuccess;
1346
0
    int error = SEC_ERROR_LIBRARY_FAILURE;
1347
0
    int count = 0;
1348
0
    CK_ATTRIBUTE search[2];
1349
0
    CK_OBJECT_HANDLE *objectIDs = NULL;
1350
0
    CK_BBOOL ck_true = CK_TRUE;
1351
0
    CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY;
1352
0
1353
0
    PK11_SETATTRS(&search[0], CKA_TOKEN, &ck_true, sizeof(ck_true));
1354
0
    PK11_SETATTRS(&search[1], CKA_CLASS, &privKey, sizeof(privKey));
1355
0
    /*
1356
0
     * make sure both tokens are already authenticated if need be.
1357
0
     */
1358
0
    rv = PK11_Authenticate(targetSlot, PR_TRUE, targetPwArg);
1359
0
    if (rv != SECSuccess) {
1360
0
        goto loser;
1361
0
    }
1362
0
    rv = PK11_Authenticate(sourceSlot, PR_TRUE, sourcePwArg);
1363
0
    if (rv != SECSuccess) {
1364
0
        goto loser;
1365
0
    }
1366
0
1367
0
    /* turns out the old DB's are rather fragile if the private keys aren't
1368
0
     * merged in first, so do the private keys explicity. */
1369
0
    objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 2, &count);
1370
0
    if (objectIDs) {
1371
0
        lrv = pk11_mergeByObjectIDs(targetSlot, sourceSlot,
1372
0
                                    objectIDs, count, log,
1373
0
                                    targetPwArg, sourcePwArg);
1374
0
        if (lrv != SECSuccess) {
1375
0
            error = PORT_GetError();
1376
0
        }
1377
0
        PORT_Free(objectIDs);
1378
0
        count = 0;
1379
0
    }
1380
0
1381
0
    /* now do the rest  (NOTE: this will repeat the private keys, but
1382
0
     * that shouldnt' be an issue as we will notice they are already
1383
0
     * merged in */
1384
0
    objectIDs = pk11_FindObjectsByTemplate(sourceSlot, search, 1, &count);
1385
0
    if (!objectIDs) {
1386
0
        rv = SECFailure;
1387
0
        goto loser;
1388
0
    }
1389
0
1390
0
    rv = pk11_mergeByObjectIDs(targetSlot, sourceSlot, objectIDs, count, log,
1391
0
                               targetPwArg, sourcePwArg);
1392
0
    if (rv == SECSuccess) {
1393
0
        /* if private keys failed, but the rest succeeded, be sure to let
1394
0
         * the caller know that private keys failed and why.
1395
0
         * NOTE: this is highly unlikely since the same keys that failed
1396
0
         * in the previous merge call will most likely fail in this one */
1397
0
        if (lrv != SECSuccess) {
1398
0
            rv = lrv;
1399
0
            PORT_SetError(error);
1400
0
        }
1401
0
    }
1402
0
1403
0
loser:
1404
0
    if (objectIDs) {
1405
0
        PORT_Free(objectIDs);
1406
0
    }
1407
0
    return rv;
1408
0
}
1409
1410
PK11MergeLog *
1411
PK11_CreateMergeLog(void)
1412
0
{
1413
0
    PLArenaPool *arena;
1414
0
    PK11MergeLog *log;
1415
0
1416
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1417
0
    if (arena == NULL) {
1418
0
        return NULL;
1419
0
    }
1420
0
1421
0
    log = PORT_ArenaZNew(arena, PK11MergeLog);
1422
0
    if (log == NULL) {
1423
0
        PORT_FreeArena(arena, PR_FALSE);
1424
0
        return NULL;
1425
0
    }
1426
0
    log->arena = arena;
1427
0
    log->version = 1;
1428
0
    return log;
1429
0
}
1430
1431
void
1432
PK11_DestroyMergeLog(PK11MergeLog *log)
1433
0
{
1434
0
    if (log && log->arena) {
1435
0
        PORT_FreeArena(log->arena, PR_FALSE);
1436
0
    }
1437
0
}