Coverage Report

Created: 2025-06-24 06:49

/src/nss/lib/pkcs12/p12d.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
#include "nssrenam.h"
6
#include "nss.h"
7
#include "p12t.h"
8
#include "p12.h"
9
#include "plarena.h"
10
#include "secitem.h"
11
#include "secoid.h"
12
#include "seccomon.h"
13
#include "secport.h"
14
#include "cert.h"
15
#include "secpkcs7.h"
16
#include "secasn1.h"
17
#include "secerr.h"
18
#include "pk11func.h"
19
#include "p12plcy.h"
20
#include "p12local.h"
21
#include "secder.h"
22
#include "secport.h"
23
24
#include "certdb.h"
25
26
#include "prcpucfg.h"
27
28
/* This belongs in secport.h */
29
#define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \
30
0
    (type *)PORT_ArenaGrow((poolp), (oldptr),                    \
31
0
                           (oldnum) * sizeof(type), (newnum) * sizeof(type))
32
33
typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext;
34
35
/* Opaque structure for decoding SafeContents.  These are used
36
 * for each authenticated safe as well as any nested safe contents.
37
 */
38
struct sec_PKCS12SafeContentsContextStr {
39
    /* the parent decoder context */
40
    SEC_PKCS12DecoderContext *p12dcx;
41
42
    /* memory arena to allocate space from */
43
    PLArenaPool *arena;
44
45
    /* decoder context and destination for decoding safe contents */
46
    SEC_ASN1DecoderContext *safeContentsA1Dcx;
47
    sec_PKCS12SafeContents safeContents;
48
49
    /* information for decoding safe bags within the safe contents.
50
     * these variables are updated for each safe bag decoded.
51
     */
52
    SEC_ASN1DecoderContext *currentSafeBagA1Dcx;
53
    sec_PKCS12SafeBag *currentSafeBag;
54
    PRBool skipCurrentSafeBag;
55
56
    /* if the safe contents is nested, the parent is pointed to here. */
57
    sec_PKCS12SafeContentsContext *nestedSafeContentsCtx;
58
};
59
60
/* opaque decoder context structure.  information for decoding a pkcs 12
61
 * PDU are stored here as well as decoding pointers for intermediary
62
 * structures which are part of the PKCS 12 PDU.  Upon a successful
63
 * decode, the safe bags containing certificates and keys encountered.
64
 */
65
struct SEC_PKCS12DecoderContextStr {
66
    PLArenaPool *arena;
67
    PK11SlotInfo *slot;
68
    void *wincx;
69
    PRBool error;
70
    int errorValue;
71
72
    /* password */
73
    SECItem *pwitem;
74
75
    /* used for decoding the PFX structure */
76
    SEC_ASN1DecoderContext *pfxA1Dcx;
77
    sec_PKCS12PFXItem pfx;
78
79
    /* safe bags found during decoding */
80
    sec_PKCS12SafeBag **safeBags;
81
    unsigned int safeBagCount;
82
83
    /* state variables for decoding authenticated safes. */
84
    SEC_PKCS7DecoderContext *currentASafeP7Dcx;
85
    SEC_ASN1DecoderContext *aSafeA1Dcx;
86
    SEC_PKCS7DecoderContext *aSafeP7Dcx;
87
    SEC_PKCS7ContentInfo *aSafeCinfo;
88
    sec_PKCS12AuthenticatedSafe authSafe;
89
    sec_PKCS12SafeContents safeContents;
90
91
    /* safe contents info */
92
    unsigned int safeContentsCnt;
93
    sec_PKCS12SafeContentsContext **safeContentsList;
94
95
    /* HMAC info */
96
    sec_PKCS12MacData macData;
97
98
    /* routines for reading back the data to be hmac'd */
99
    /* They are called as follows.
100
     *
101
     * Stage 1: decode the aSafes cinfo into a buffer in dArg,
102
     * which p12d.c sometimes refers to as the "temp file".
103
     * This occurs during SEC_PKCS12DecoderUpdate calls.
104
     *
105
     * dOpen(dArg, PR_FALSE)
106
     * dWrite(dArg, buf, len)
107
     * ...
108
     * dWrite(dArg, buf, len)
109
     * dClose(dArg, PR_FALSE)
110
     *
111
     * Stage 2: verify MAC
112
     * This occurs SEC_PKCS12DecoderVerify.
113
     *
114
     * dOpen(dArg, PR_TRUE)
115
     * dRead(dArg, buf, IN_BUF_LEN)
116
     * ...
117
     * dRead(dArg, buf, IN_BUF_LEN)
118
     * dClose(dArg, PR_TRUE)
119
     */
120
    digestOpenFn dOpen;
121
    digestCloseFn dClose;
122
    digestIOFn dRead, dWrite;
123
    void *dArg;
124
    PRBool dIsOpen; /* is the temp file created? */
125
126
    /* helper functions */
127
    SECKEYGetPasswordKey pwfn;
128
    void *pwfnarg;
129
    PRBool swapUnicodeBytes;
130
    PRBool forceUnicode;
131
132
    /* import information */
133
    PRBool bagsVerified;
134
135
    /* buffer management for the default callbacks implementation */
136
    void *buffer;       /* storage area */
137
    PRInt32 filesize;   /* actual data size */
138
    PRInt32 allocated;  /* total buffer size allocated */
139
    PRInt32 currentpos; /* position counter */
140
    SECPKCS12TargetTokenCAs tokenCAs;
141
    sec_PKCS12SafeBag **keyList; /* used by ...IterateNext() */
142
    unsigned int iteration;
143
    SEC_PKCS12DecoderItem decitem;
144
};
145
146
/* forward declarations of functions that are used when decoding
147
 * safeContents bags which are nested and when decoding the
148
 * authenticatedSafes.
149
 */
150
static SECStatus
151
sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
152
                                                  *safeContentsCtx);
153
static SECStatus
154
sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
155
                                                   *safeContentsCtx);
156
157
/* make sure that the PFX version being decoded is a version
158
 * which we support.
159
 */
160
static PRBool
161
sec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx)
162
0
{
163
    /* if no version, assume it is not supported */
164
0
    if (pfx->version.len == 0) {
165
0
        return PR_FALSE;
166
0
    }
167
168
0
    if (DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) {
169
0
        return PR_FALSE;
170
0
    }
171
172
0
    return PR_TRUE;
173
0
}
174
175
/* retrieve the key for decrypting the safe contents */
176
static PK11SymKey *
177
sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid)
178
0
{
179
0
    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
180
0
    PK11SlotInfo *slot;
181
0
    PK11SymKey *bulkKey;
182
0
    SECItem pwitem = { 0 };
183
0
    SECOidTag algorithm;
184
185
0
    if (!p12dcx) {
186
0
        return NULL;
187
0
    }
188
189
    /* if no slot specified, use the internal key slot */
190
0
    if (p12dcx->slot) {
191
0
        slot = PK11_ReferenceSlot(p12dcx->slot);
192
0
    } else {
193
0
        slot = PK11_GetInternalKeySlot();
194
0
    }
195
196
0
    algorithm = SECOID_GetAlgorithmTag(algid);
197
198
0
    if (p12dcx->forceUnicode) {
199
0
        if (SECITEM_CopyItem(NULL, &pwitem, p12dcx->pwitem) != SECSuccess) {
200
0
            PK11_FreeSlot(slot);
201
0
            return NULL;
202
0
        }
203
0
    } else {
204
0
        if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm, p12dcx->pwitem)) {
205
0
            PK11_FreeSlot(slot);
206
0
            return NULL;
207
0
        }
208
0
    }
209
210
0
    bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx);
211
    /* some tokens can't generate PBE keys on their own, generate the
212
     * key in the internal slot, and let the Import code deal with it,
213
     * (if the slot can't generate PBEs, then we need to use the internal
214
     * slot anyway to unwrap). */
215
0
    if (!bulkKey && !PK11_IsInternal(slot)) {
216
0
        PK11_FreeSlot(slot);
217
0
        slot = PK11_GetInternalKeySlot();
218
0
        bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx);
219
0
    }
220
0
    PK11_FreeSlot(slot);
221
222
    /* set the password data on the key */
223
0
    if (bulkKey) {
224
0
        PK11_SetSymKeyUserData(bulkKey, p12dcx->pwitem, NULL);
225
0
    }
226
227
0
    if (pwitem.data) {
228
0
        SECITEM_ZfreeItem(&pwitem, PR_FALSE);
229
0
    }
230
231
0
    return bulkKey;
232
0
}
233
234
/* XXX this needs to be modified to handle enveloped data.  most
235
 * likely, it should mirror the routines for SMIME in that regard.
236
 */
237
static PRBool
238
sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid,
239
                                      PK11SymKey *bulkkey)
240
0
{
241
0
    PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid);
242
243
0
    if (!decryptionAllowed) {
244
0
        PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
245
0
        return PR_FALSE;
246
0
    }
247
248
0
    return PR_TRUE;
249
0
}
250
251
/* when we encounter a new safe bag during the decoding, we need
252
 * to allocate space for the bag to be decoded to and set the
253
 * state variables appropriately.  all of the safe bags are allocated
254
 * in a buffer in the outer SEC_PKCS12DecoderContext, however,
255
 * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext
256
 * for the current bag.
257
 */
258
static SECStatus
259
sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext
260
                                         *safeContentsCtx)
261
0
{
262
0
    void *mark = NULL;
263
0
    SEC_PKCS12DecoderContext *p12dcx;
264
265
    /* make sure that the structures are defined, and there has
266
     * not been an error in the decoding
267
     */
268
0
    if (!safeContentsCtx || !safeContentsCtx->p12dcx || safeContentsCtx->p12dcx->error) {
269
0
        return SECFailure;
270
0
    }
271
272
0
    p12dcx = safeContentsCtx->p12dcx;
273
0
    mark = PORT_ArenaMark(p12dcx->arena);
274
275
    /* allocate a new safe bag, if bags already exist, grow the
276
     * list of bags, otherwise allocate a new list.  the list is
277
     * NULL terminated.
278
     */
279
0
    p12dcx->safeBags = (!p12dcx->safeBagCount)
280
0
                           ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
281
0
                           : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
282
0
                                                 sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
283
0
                                                 p12dcx->safeBagCount + 2);
284
285
0
    if (!p12dcx->safeBags) {
286
0
        p12dcx->errorValue = PORT_GetError();
287
0
        goto loser;
288
0
    }
289
290
    /* append the bag to the end of the list and update the reference
291
     * in the safeContentsCtx.
292
     */
293
0
    p12dcx->safeBags[p12dcx->safeBagCount] =
294
0
        safeContentsCtx->currentSafeBag =
295
0
            PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
296
0
    if (!safeContentsCtx->currentSafeBag) {
297
0
        p12dcx->errorValue = PORT_GetError();
298
0
        goto loser;
299
0
    }
300
0
    p12dcx->safeBags[++p12dcx->safeBagCount] = NULL;
301
302
0
    safeContentsCtx->currentSafeBag->slot = safeContentsCtx->p12dcx->slot;
303
0
    safeContentsCtx->currentSafeBag->pwitem = safeContentsCtx->p12dcx->pwitem;
304
0
    safeContentsCtx->currentSafeBag->swapUnicodeBytes =
305
0
        safeContentsCtx->p12dcx->swapUnicodeBytes;
306
0
    safeContentsCtx->currentSafeBag->arena = safeContentsCtx->p12dcx->arena;
307
0
    safeContentsCtx->currentSafeBag->tokenCAs =
308
0
        safeContentsCtx->p12dcx->tokenCAs;
309
310
0
    PORT_ArenaUnmark(p12dcx->arena, mark);
311
0
    return SECSuccess;
312
313
0
loser:
314
315
    /* if an error occurred, release the memory and set the error flag
316
     * the only possible errors triggered by this function are memory
317
     * related.
318
     */
319
0
    if (mark) {
320
0
        PORT_ArenaRelease(p12dcx->arena, mark);
321
0
    }
322
323
0
    p12dcx->error = PR_TRUE;
324
0
    return SECFailure;
325
0
}
326
327
/* A wrapper for updating the ASN1 context in which a safeBag is
328
 * being decoded.  This function is called as a callback from
329
 * secasn1d when decoding SafeContents structures.
330
 */
331
static void
332
sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data,
333
                                   unsigned long len, int depth,
334
                                   SEC_ASN1EncodingPart data_kind)
335
0
{
336
0
    sec_PKCS12SafeContentsContext *safeContentsCtx =
337
0
        (sec_PKCS12SafeContentsContext *)arg;
338
0
    SEC_PKCS12DecoderContext *p12dcx;
339
0
    SECStatus rv;
340
341
0
    if (!safeContentsCtx || !safeContentsCtx->p12dcx || !safeContentsCtx->currentSafeBagA1Dcx) {
342
0
        return;
343
0
    }
344
0
    p12dcx = safeContentsCtx->p12dcx;
345
346
    /* make sure that there are no errors and we are not skipping the current safeBag */
347
0
    if (p12dcx->error || safeContentsCtx->skipCurrentSafeBag) {
348
0
        goto loser;
349
0
    }
350
351
0
    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagA1Dcx, data, len);
352
0
    if (rv != SECSuccess) {
353
0
        p12dcx->errorValue = PORT_GetError();
354
0
        p12dcx->error = PR_TRUE;
355
0
        goto loser;
356
0
    }
357
358
    /* The update may have set safeContentsCtx->skipCurrentSafeBag, and we
359
     * may not get another opportunity to clean up the decoder context.
360
     */
361
0
    if (safeContentsCtx->skipCurrentSafeBag) {
362
0
        goto loser;
363
0
    }
364
365
0
    return;
366
367
0
loser:
368
    /* Finish the decoder context. Because there
369
     * is not a way of returning an error message, it may be worth
370
     * while to do a check higher up and finish any decoding contexts
371
     * that are still open.
372
     */
373
0
    SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
374
0
    safeContentsCtx->currentSafeBagA1Dcx = NULL;
375
0
    return;
376
0
}
377
378
/* notify function for decoding safeBags.  This function is
379
 * used to filter safeBag types which are not supported,
380
 * initiate the decoding of nested safe contents, and decode
381
 * safeBags in general.  this function is set when the decoder
382
 * context for the safeBag is first created.
383
 */
384
static void
385
sec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before,
386
                                   void *dest, int real_depth)
387
0
{
388
0
    sec_PKCS12SafeContentsContext *safeContentsCtx =
389
0
        (sec_PKCS12SafeContentsContext *)arg;
390
0
    SEC_PKCS12DecoderContext *p12dcx;
391
0
    sec_PKCS12SafeBag *bag;
392
0
    PRBool after;
393
394
    /* if an error is encountered, return */
395
0
    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
396
0
        safeContentsCtx->p12dcx->error) {
397
0
        return;
398
0
    }
399
0
    p12dcx = safeContentsCtx->p12dcx;
400
401
    /* to make things more readable */
402
0
    if (before)
403
0
        after = PR_FALSE;
404
0
    else
405
0
        after = PR_TRUE;
406
407
    /* have we determined the safeBagType yet? */
408
0
    bag = safeContentsCtx->currentSafeBag;
409
0
    if (bag->bagTypeTag == NULL) {
410
0
        if (after && (dest == &(bag->safeBagType))) {
411
0
            bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType));
412
0
            if (bag->bagTypeTag == NULL) {
413
0
                p12dcx->error = PR_TRUE;
414
0
                p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
415
0
            }
416
0
        }
417
0
        return;
418
0
    }
419
420
    /* process the safeBag depending on it's type.  those
421
     * which we do not support, are ignored.  we start a decoding
422
     * context for a nested safeContents.
423
     */
424
0
    switch (bag->bagTypeTag->offset) {
425
0
        case SEC_OID_PKCS12_V1_KEY_BAG_ID:
426
0
        case SEC_OID_PKCS12_V1_CERT_BAG_ID:
427
0
        case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
428
0
            break;
429
0
        case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
430
            /* if we are just starting to decode the safeContents, initialize
431
             * a new safeContentsCtx to process it.
432
             */
433
0
            if (before && (dest == &(bag->safeBagContent))) {
434
0
                sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx);
435
0
            } else if (after && (dest == &(bag->safeBagContent))) {
436
                /* clean up the nested decoding */
437
0
                sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx);
438
0
            }
439
0
            break;
440
0
        case SEC_OID_PKCS12_V1_CRL_BAG_ID:
441
0
        case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
442
0
        default:
443
            /* skip any safe bag types we don't understand or handle */
444
0
            safeContentsCtx->skipCurrentSafeBag = PR_TRUE;
445
0
            break;
446
0
    }
447
448
0
    return;
449
0
}
450
451
/* notify function for decoding safe contents.  each entry in the
452
 * safe contents is a safeBag which needs to be allocated and
453
 * the decoding context initialized at the beginning and then
454
 * the context needs to be closed and finished at the end.
455
 *
456
 * this function is set when the safeContents decode context is
457
 * initialized.
458
 */
459
static void
460
sec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before,
461
                                        void *dest, int real_depth)
462
0
{
463
0
    sec_PKCS12SafeContentsContext *safeContentsCtx =
464
0
        (sec_PKCS12SafeContentsContext *)arg;
465
0
    SEC_PKCS12DecoderContext *p12dcx;
466
0
    SECStatus rv;
467
468
    /* if there is an error we don't want to continue processing,
469
     * just return and keep going.
470
     */
471
0
    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
472
0
        safeContentsCtx->p12dcx->error) {
473
0
        return;
474
0
    }
475
0
    p12dcx = safeContentsCtx->p12dcx;
476
477
    /* if we are done with the current safeBag, then we need to
478
     * finish the context and set the state variables appropriately.
479
     */
480
0
    if (!before) {
481
0
        SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
482
0
        SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
483
0
        safeContentsCtx->currentSafeBagA1Dcx = NULL;
484
0
        safeContentsCtx->skipCurrentSafeBag = PR_FALSE;
485
0
    } else {
486
        /* we are starting a new safe bag.  we need to allocate space
487
         * for the bag and initialize the decoding context.
488
         */
489
0
        rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx);
490
0
        if (rv != SECSuccess) {
491
0
            goto loser;
492
0
        }
493
494
        /* set up the decoder context */
495
0
        safeContentsCtx->currentSafeBagA1Dcx =
496
0
            SEC_ASN1DecoderStart(p12dcx->arena,
497
0
                                 safeContentsCtx->currentSafeBag,
498
0
                                 sec_PKCS12SafeBagTemplate);
499
0
        if (!safeContentsCtx->currentSafeBagA1Dcx) {
500
0
            p12dcx->errorValue = PORT_GetError();
501
0
            goto loser;
502
0
        }
503
504
        /* set the notify and filter procs so that the safe bag
505
         * data gets sent to the proper location when decoding.
506
         */
507
0
        SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagA1Dcx,
508
0
                                     sec_pkcs12_decoder_safe_bag_notify,
509
0
                                     safeContentsCtx);
510
0
        SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsA1Dcx,
511
0
                                     sec_pkcs12_decoder_safe_bag_update,
512
0
                                     safeContentsCtx, PR_TRUE);
513
0
    }
514
515
0
    return;
516
517
0
loser:
518
    /* in the event of an error, we want to close the decoding
519
     * context and clear the filter and notify procedures.
520
     */
521
0
    p12dcx->error = PR_TRUE;
522
523
0
    if (safeContentsCtx->currentSafeBagA1Dcx) {
524
0
        SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
525
0
        safeContentsCtx->currentSafeBagA1Dcx = NULL;
526
0
    }
527
528
0
    SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsA1Dcx);
529
0
    SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
530
531
0
    return;
532
0
}
533
534
/* initialize the safeContents for decoding.  this routine
535
 * is used for authenticatedSafes as well as nested safeContents.
536
 */
537
static sec_PKCS12SafeContentsContext *
538
sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx,
539
                                             PRBool nestedSafe)
540
0
{
541
0
    sec_PKCS12SafeContentsContext *safeContentsCtx = NULL;
542
0
    const SEC_ASN1Template *theTemplate;
543
544
0
    if (!p12dcx || p12dcx->error) {
545
0
        return NULL;
546
0
    }
547
548
    /* allocate a new safeContents list or grow the existing list and
549
     * append the new safeContents onto the end.
550
     */
551
0
    p12dcx->safeContentsList = (!p12dcx->safeContentsCnt)
552
0
                                   ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeContentsContext *, 2)
553
0
                                   : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeContentsList,
554
0
                                                         sec_PKCS12SafeContentsContext *,
555
0
                                                         1 + p12dcx->safeContentsCnt,
556
0
                                                         2 + p12dcx->safeContentsCnt);
557
558
0
    if (!p12dcx->safeContentsList) {
559
0
        p12dcx->errorValue = PORT_GetError();
560
0
        goto loser;
561
0
    }
562
563
0
    p12dcx->safeContentsList[p12dcx->safeContentsCnt] = safeContentsCtx =
564
0
        PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeContentsContext);
565
0
    if (!p12dcx->safeContentsList[p12dcx->safeContentsCnt]) {
566
0
        p12dcx->errorValue = PORT_GetError();
567
0
        goto loser;
568
0
    }
569
0
    p12dcx->safeContentsList[++p12dcx->safeContentsCnt] = NULL;
570
571
    /* set up the state variables */
572
0
    safeContentsCtx->p12dcx = p12dcx;
573
0
    safeContentsCtx->arena = p12dcx->arena;
574
575
    /* begin the decoding -- the template is based on whether we are
576
     * decoding a nested safeContents or not.
577
     */
578
0
    if (nestedSafe == PR_TRUE) {
579
0
        theTemplate = sec_PKCS12NestedSafeContentsDecodeTemplate;
580
0
    } else {
581
0
        theTemplate = sec_PKCS12SafeContentsDecodeTemplate;
582
0
    }
583
584
    /* start the decoder context */
585
0
    safeContentsCtx->safeContentsA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena,
586
0
                                                              &safeContentsCtx->safeContents,
587
0
                                                              theTemplate);
588
589
0
    if (!safeContentsCtx->safeContentsA1Dcx) {
590
0
        p12dcx->errorValue = PORT_GetError();
591
0
        goto loser;
592
0
    }
593
594
    /* set the safeContents notify procedure to look for
595
     * and start the decode of safeBags.
596
     */
597
0
    SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->safeContentsA1Dcx,
598
0
                                 sec_pkcs12_decoder_safe_contents_notify,
599
0
                                 safeContentsCtx);
600
601
0
    return safeContentsCtx;
602
603
0
loser:
604
    /* in the case of an error, we want to finish the decoder
605
     * context and set the error flag.
606
     */
607
0
    if (safeContentsCtx && safeContentsCtx->safeContentsA1Dcx) {
608
0
        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
609
0
        safeContentsCtx->safeContentsA1Dcx = NULL;
610
0
    }
611
612
0
    p12dcx->error = PR_TRUE;
613
614
0
    return NULL;
615
0
}
616
617
/* wrapper for updating safeContents.  this is set as the filter of
618
 * safeBag when there is a nested safeContents.
619
 */
620
static void
621
sec_pkcs12_decoder_nested_safe_contents_update(void *arg, const char *buf,
622
                                               unsigned long len, int depth,
623
                                               SEC_ASN1EncodingPart data_kind)
624
0
{
625
0
    sec_PKCS12SafeContentsContext *safeContentsCtx =
626
0
        (sec_PKCS12SafeContentsContext *)arg;
627
0
    SEC_PKCS12DecoderContext *p12dcx;
628
0
    SECStatus rv;
629
630
    /* check for an error */
631
0
    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
632
0
        safeContentsCtx->p12dcx->error || !safeContentsCtx->safeContentsA1Dcx) {
633
0
        return;
634
0
    }
635
636
    /* no need to update if no data sent in */
637
0
    if (!len || !buf) {
638
0
        return;
639
0
    }
640
641
    /* update the decoding context */
642
0
    p12dcx = safeContentsCtx->p12dcx;
643
0
    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
644
0
    if (rv != SECSuccess) {
645
0
        p12dcx->errorValue = PORT_GetError();
646
0
        goto loser;
647
0
    }
648
649
0
    return;
650
651
0
loser:
652
    /* handle any errors.  If a decoding context is open, close it. */
653
0
    p12dcx->error = PR_TRUE;
654
0
    if (safeContentsCtx->safeContentsA1Dcx) {
655
0
        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
656
0
        safeContentsCtx->safeContentsA1Dcx = NULL;
657
0
    }
658
0
}
659
660
/* whenever a new safeContentsSafeBag is encountered, we need
661
 * to init a safeContentsContext.
662
 */
663
static SECStatus
664
sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
665
                                                  *safeContentsCtx)
666
0
{
667
    /* check for an error */
668
0
    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
669
0
        safeContentsCtx->p12dcx->error) {
670
0
        return SECFailure;
671
0
    }
672
673
0
    safeContentsCtx->nestedSafeContentsCtx =
674
0
        sec_pkcs12_decoder_safe_contents_init_decode(safeContentsCtx->p12dcx,
675
0
                                                     PR_TRUE);
676
0
    if (!safeContentsCtx->nestedSafeContentsCtx) {
677
0
        return SECFailure;
678
0
    }
679
680
    /* set up new filter proc */
681
0
    SEC_ASN1DecoderSetNotifyProc(
682
0
        safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx,
683
0
        sec_pkcs12_decoder_safe_contents_notify,
684
0
        safeContentsCtx->nestedSafeContentsCtx);
685
686
0
    SEC_ASN1DecoderSetFilterProc(safeContentsCtx->currentSafeBagA1Dcx,
687
0
                                 sec_pkcs12_decoder_nested_safe_contents_update,
688
0
                                 safeContentsCtx->nestedSafeContentsCtx,
689
0
                                 PR_TRUE);
690
691
0
    return SECSuccess;
692
0
}
693
694
/* when the safeContents is done decoding, we need to reset the
695
 * proper filter and notify procs and close the decoding context
696
 */
697
static SECStatus
698
sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
699
                                                   *safeContentsCtx)
700
0
{
701
    /* check for error */
702
0
    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
703
0
        safeContentsCtx->p12dcx->error) {
704
0
        return SECFailure;
705
0
    }
706
707
    /* clean up */
708
0
    SEC_ASN1DecoderClearFilterProc(safeContentsCtx->currentSafeBagA1Dcx);
709
0
    SEC_ASN1DecoderClearNotifyProc(
710
0
        safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
711
0
    SEC_ASN1DecoderFinish(
712
0
        safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
713
0
    safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx = NULL;
714
0
    safeContentsCtx->nestedSafeContentsCtx = NULL;
715
716
0
    return SECSuccess;
717
0
}
718
719
/* wrapper for updating safeContents.  This is used when decoding
720
 * the nested safeContents and any authenticatedSafes.
721
 */
722
static void
723
sec_pkcs12_decoder_safe_contents_callback(void *arg, const char *buf,
724
                                          unsigned long len)
725
0
{
726
0
    SECStatus rv;
727
0
    sec_PKCS12SafeContentsContext *safeContentsCtx =
728
0
        (sec_PKCS12SafeContentsContext *)arg;
729
0
    SEC_PKCS12DecoderContext *p12dcx;
730
731
    /* check for error */
732
0
    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
733
0
        safeContentsCtx->p12dcx->error || !safeContentsCtx->safeContentsA1Dcx) {
734
0
        return;
735
0
    }
736
0
    p12dcx = safeContentsCtx->p12dcx;
737
738
    /* update the decoder */
739
0
    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
740
0
    if (rv != SECSuccess) {
741
        /* if we fail while trying to decode a 'safe', it's probably because
742
         * we didn't have the correct password. */
743
0
        PORT_SetError(SEC_ERROR_BAD_PASSWORD);
744
0
        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
745
0
        SEC_PKCS7DecoderAbort(p12dcx->currentASafeP7Dcx, SEC_ERROR_BAD_PASSWORD);
746
0
        goto loser;
747
0
    }
748
749
0
    return;
750
751
0
loser:
752
    /* set the error and finish the context */
753
0
    p12dcx->error = PR_TRUE;
754
0
    if (safeContentsCtx->safeContentsA1Dcx) {
755
0
        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
756
0
        safeContentsCtx->safeContentsA1Dcx = NULL;
757
0
    }
758
759
0
    return;
760
0
}
761
762
/* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate
763
 */
764
static void
765
sec_pkcs12_decoder_wrap_p7_update(void *arg, const char *data,
766
                                  unsigned long len, int depth,
767
                                  SEC_ASN1EncodingPart data_kind)
768
0
{
769
0
    SEC_PKCS7DecoderContext *p7dcx = (SEC_PKCS7DecoderContext *)arg;
770
771
0
    SEC_PKCS7DecoderUpdate(p7dcx, data, len);
772
0
}
773
774
/* notify function for decoding aSafes.  at the beginning,
775
 * of an authenticatedSafe, we start a decode of a safeContents.
776
 * at the end, we clean up the safeContents decoder context and
777
 * reset state variables
778
 */
779
static void
780
sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest,
781
                                 int real_depth)
782
0
{
783
0
    SEC_PKCS12DecoderContext *p12dcx;
784
0
    sec_PKCS12SafeContentsContext *safeContentsCtx;
785
786
    /* make sure no error occurred. */
787
0
    p12dcx = (SEC_PKCS12DecoderContext *)arg;
788
0
    if (!p12dcx || p12dcx->error) {
789
0
        return;
790
0
    }
791
792
0
    if (before) {
793
794
        /* init a new safeContentsContext */
795
0
        safeContentsCtx = sec_pkcs12_decoder_safe_contents_init_decode(p12dcx,
796
0
                                                                       PR_FALSE);
797
0
        if (!safeContentsCtx) {
798
0
            goto loser;
799
0
        }
800
801
        /* initiate the PKCS7ContentInfo decode */
802
0
        p12dcx->currentASafeP7Dcx = SEC_PKCS7DecoderStart(
803
0
            sec_pkcs12_decoder_safe_contents_callback,
804
0
            safeContentsCtx,
805
0
            p12dcx->pwfn, p12dcx->pwfnarg,
806
0
            sec_pkcs12_decoder_get_decrypt_key, p12dcx,
807
0
            sec_pkcs12_decoder_decryption_allowed);
808
0
        if (!p12dcx->currentASafeP7Dcx) {
809
0
            p12dcx->errorValue = PORT_GetError();
810
0
            goto loser;
811
0
        }
812
0
        SEC_ASN1DecoderSetFilterProc(p12dcx->aSafeA1Dcx,
813
0
                                     sec_pkcs12_decoder_wrap_p7_update,
814
0
                                     p12dcx->currentASafeP7Dcx, PR_TRUE);
815
0
    }
816
817
0
    if (!before) {
818
        /* if one is being decoded, finish the decode */
819
0
        if (p12dcx->currentASafeP7Dcx != NULL) {
820
0
            SEC_PKCS7ContentInfo *cinfo;
821
0
            unsigned int cnt = p12dcx->safeContentsCnt - 1;
822
0
            safeContentsCtx = p12dcx->safeContentsList[cnt];
823
0
            if (safeContentsCtx->safeContentsA1Dcx) {
824
0
                SEC_ASN1DecoderClearFilterProc(p12dcx->aSafeA1Dcx);
825
0
                SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
826
0
                safeContentsCtx->safeContentsA1Dcx = NULL;
827
0
            }
828
0
            cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
829
0
            p12dcx->currentASafeP7Dcx = NULL;
830
0
            if (!cinfo) {
831
0
                p12dcx->errorValue = PORT_GetError();
832
0
                goto loser;
833
0
            }
834
0
            SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
835
0
        }
836
0
    }
837
838
0
    return;
839
840
0
loser:
841
    /* set the error flag */
842
0
    p12dcx->error = PR_TRUE;
843
0
    return;
844
0
}
845
846
/* wrapper for updating asafes decoding context.  this function
847
 * writes data being decoded to disk, so that a mac can be computed
848
 * later.
849
 */
850
static void
851
sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf,
852
                                   unsigned long len)
853
0
{
854
0
    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
855
0
    SECStatus rv;
856
857
0
    if (!p12dcx || p12dcx->error) {
858
0
        return;
859
0
    }
860
861
    /* update the context */
862
0
    rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeA1Dcx, buf, len);
863
0
    if (rv != SECSuccess) {
864
0
        p12dcx->errorValue = PORT_GetError();
865
0
        p12dcx->error = PR_TRUE;
866
0
        goto loser;
867
0
    }
868
869
    /* if we are writing to a file, write out the new information */
870
0
    if (p12dcx->dWrite) {
871
0
        unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg,
872
0
                                                   (unsigned char *)buf, len);
873
0
        if (writeLen != len) {
874
0
            p12dcx->errorValue = PORT_GetError();
875
0
            goto loser;
876
0
        }
877
0
    }
878
879
0
    return;
880
881
0
loser:
882
    /* set the error flag */
883
0
    p12dcx->error = PR_TRUE;
884
0
    SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
885
0
    p12dcx->aSafeA1Dcx = NULL;
886
887
0
    return;
888
0
}
889
890
/* start the decode of an authenticatedSafe contentInfo.
891
 */
892
static SECStatus
893
sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx)
894
0
{
895
0
    if (!p12dcx || p12dcx->error) {
896
0
        return SECFailure;
897
0
    }
898
899
    /* start the decode context */
900
0
    p12dcx->aSafeA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena,
901
0
                                              &p12dcx->authSafe,
902
0
                                              sec_PKCS12AuthenticatedSafeTemplate);
903
0
    if (!p12dcx->aSafeA1Dcx) {
904
0
        p12dcx->errorValue = PORT_GetError();
905
0
        goto loser;
906
0
    }
907
908
    /* set the notify function */
909
0
    SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeA1Dcx,
910
0
                                 sec_pkcs12_decoder_asafes_notify, p12dcx);
911
912
    /* begin the authSafe decoder context */
913
0
    p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart(
914
0
        sec_pkcs12_decoder_asafes_callback, p12dcx,
915
0
        p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL);
916
0
    if (!p12dcx->aSafeP7Dcx) {
917
0
        p12dcx->errorValue = PORT_GetError();
918
0
        goto loser;
919
0
    }
920
921
    /* open the temp file for writing, if the digest functions were set */
922
0
    if (p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE) != SECSuccess) {
923
0
        p12dcx->errorValue = PORT_GetError();
924
0
        goto loser;
925
0
    }
926
    /* dOpen(dArg, PR_FALSE) creates the temp file */
927
0
    p12dcx->dIsOpen = PR_TRUE;
928
929
0
    return SECSuccess;
930
931
0
loser:
932
0
    p12dcx->error = PR_TRUE;
933
934
0
    if (p12dcx->aSafeA1Dcx) {
935
0
        SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
936
0
        p12dcx->aSafeA1Dcx = NULL;
937
0
    }
938
939
0
    if (p12dcx->aSafeP7Dcx) {
940
0
        SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
941
0
        p12dcx->aSafeP7Dcx = NULL;
942
0
    }
943
944
0
    return SECFailure;
945
0
}
946
947
/* wrapper for updating the safeContents.  this function is used as
948
 * a filter for the pfx when decoding the authenticated safes
949
 */
950
static void
951
sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf,
952
                                      unsigned long len, int depth,
953
                                      SEC_ASN1EncodingPart data_kind)
954
0
{
955
0
    SEC_PKCS12DecoderContext *p12dcx;
956
0
    SECStatus rv;
957
958
0
    p12dcx = (SEC_PKCS12DecoderContext *)arg;
959
0
    if (!p12dcx || p12dcx->error) {
960
0
        return;
961
0
    }
962
963
    /* update the safeContents decoder */
964
0
    rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len);
965
0
    if (rv != SECSuccess) {
966
0
        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
967
0
        goto loser;
968
0
    }
969
970
0
    return;
971
972
0
loser:
973
974
    /* did we find an error?  if so, close the context and set the
975
     * error flag.
976
     */
977
0
    SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
978
0
    p12dcx->aSafeP7Dcx = NULL;
979
0
    p12dcx->error = PR_TRUE;
980
0
}
981
982
/* notify procedure used while decoding the pfx.  When we encounter
983
 * the authSafes, we want to trigger the decoding of authSafes as well
984
 * as when we encounter the macData, trigger the decoding of it.  we do
985
 * this because we we are streaming the decoder and not decoding in place.
986
 * the pfx which is the destination, only has the version decoded into it.
987
 */
988
static void
989
sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest,
990
                                   int real_depth)
991
0
{
992
0
    SECStatus rv;
993
0
    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
994
995
    /* if an error occurs, clear the notifyProc and the filterProc
996
     * and continue.
997
     */
998
0
    if (p12dcx->error) {
999
0
        SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxA1Dcx);
1000
0
        SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
1001
0
        return;
1002
0
    }
1003
1004
0
    if (before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
1005
1006
        /* we want to make sure this is a version we support */
1007
0
        if (!sec_pkcs12_proper_version(&p12dcx->pfx)) {
1008
0
            p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
1009
0
            goto loser;
1010
0
        }
1011
1012
        /* start the decode of the aSafes cinfo... */
1013
0
        rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx);
1014
0
        if (rv != SECSuccess) {
1015
0
            goto loser;
1016
0
        }
1017
1018
        /* set the filter proc to update the authenticated safes. */
1019
0
        SEC_ASN1DecoderSetFilterProc(p12dcx->pfxA1Dcx,
1020
0
                                     sec_pkcs12_decode_asafes_cinfo_update,
1021
0
                                     p12dcx, PR_TRUE);
1022
0
    }
1023
1024
0
    if (!before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
1025
1026
        /* we are done decoding the authenticatedSafes, so we need to
1027
         * finish the decoderContext and clear the filter proc
1028
         * and close the hmac callback, if present
1029
         */
1030
0
        p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
1031
0
        p12dcx->aSafeP7Dcx = NULL;
1032
0
        if (!p12dcx->aSafeCinfo) {
1033
0
            p12dcx->errorValue = PORT_GetError();
1034
0
            goto loser;
1035
0
        }
1036
0
        SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
1037
0
        if (p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) != SECSuccess)) {
1038
0
            p12dcx->errorValue = PORT_GetError();
1039
0
            goto loser;
1040
0
        }
1041
0
    }
1042
1043
0
    return;
1044
1045
0
loser:
1046
0
    p12dcx->error = PR_TRUE;
1047
0
}
1048
1049
/*  default implementations of the open/close/read/write functions for
1050
    SEC_PKCS12DecoderStart
1051
*/
1052
1053
0
#define DEFAULT_TEMP_SIZE 4096
1054
1055
static SECStatus
1056
p12u_DigestOpen(void *arg, PRBool readData)
1057
0
{
1058
0
    SEC_PKCS12DecoderContext *p12cxt = arg;
1059
1060
0
    p12cxt->currentpos = 0;
1061
1062
0
    if (PR_FALSE == readData) {
1063
        /* allocate an initial buffer */
1064
0
        p12cxt->filesize = 0;
1065
0
        p12cxt->allocated = DEFAULT_TEMP_SIZE;
1066
0
        p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE);
1067
0
        PR_ASSERT(p12cxt->buffer);
1068
0
    } else {
1069
0
        PR_ASSERT(p12cxt->buffer);
1070
0
        if (!p12cxt->buffer) {
1071
0
            return SECFailure; /* no data to read */
1072
0
        }
1073
0
    }
1074
1075
0
    return SECSuccess;
1076
0
}
1077
1078
static SECStatus
1079
p12u_DigestClose(void *arg, PRBool removeFile)
1080
0
{
1081
0
    SEC_PKCS12DecoderContext *p12cxt = arg;
1082
1083
0
    PR_ASSERT(p12cxt);
1084
0
    if (!p12cxt) {
1085
0
        return SECFailure;
1086
0
    }
1087
0
    p12cxt->currentpos = 0;
1088
1089
0
    if (PR_TRUE == removeFile) {
1090
0
        PR_ASSERT(p12cxt->buffer);
1091
0
        if (!p12cxt->buffer) {
1092
0
            return SECFailure;
1093
0
        }
1094
0
        if (p12cxt->buffer) {
1095
0
            PORT_Free(p12cxt->buffer);
1096
0
            p12cxt->buffer = NULL;
1097
0
            p12cxt->allocated = 0;
1098
0
            p12cxt->filesize = 0;
1099
0
        }
1100
0
    }
1101
1102
0
    return SECSuccess;
1103
0
}
1104
1105
static int
1106
p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
1107
0
{
1108
0
    int toread = len;
1109
0
    SEC_PKCS12DecoderContext *p12cxt = arg;
1110
1111
0
    if (!buf || len == 0 || !p12cxt->buffer) {
1112
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1113
0
        return -1;
1114
0
    }
1115
1116
0
    if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
1117
        /* trying to read past the end of the buffer */
1118
0
        toread = p12cxt->filesize - p12cxt->currentpos;
1119
0
    }
1120
0
    memcpy(buf, (char *)p12cxt->buffer + p12cxt->currentpos, toread);
1121
0
    p12cxt->currentpos += toread;
1122
0
    return toread;
1123
0
}
1124
1125
static int
1126
p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
1127
0
{
1128
0
    SEC_PKCS12DecoderContext *p12cxt = arg;
1129
1130
0
    if (!buf || len == 0) {
1131
0
        return -1;
1132
0
    }
1133
1134
0
    if (p12cxt->currentpos + (long)len > p12cxt->filesize) {
1135
0
        p12cxt->filesize = p12cxt->currentpos + len;
1136
0
    } else {
1137
0
        p12cxt->filesize += len;
1138
0
    }
1139
0
    if (p12cxt->filesize > p12cxt->allocated) {
1140
0
        void *newbuffer;
1141
0
        size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE;
1142
0
        newbuffer = PORT_Realloc(p12cxt->buffer, newsize);
1143
0
        if (NULL == newbuffer) {
1144
0
            return -1; /* can't extend the buffer */
1145
0
        }
1146
0
        p12cxt->buffer = newbuffer;
1147
0
        p12cxt->allocated = newsize;
1148
0
    }
1149
0
    PR_ASSERT(p12cxt->buffer);
1150
0
    memcpy((char *)p12cxt->buffer + p12cxt->currentpos, buf, len);
1151
0
    p12cxt->currentpos += len;
1152
0
    return len;
1153
0
}
1154
1155
/* SEC_PKCS12DecoderStart
1156
 *      Creates a decoder context for decoding a PKCS 12 PDU objct.
1157
 *      This function sets up the initial decoding context for the
1158
 *      PFX and sets the needed state variables.
1159
 *
1160
 *      pwitem - the password for the hMac and any encoded safes.
1161
 *               this should be changed to take a callback which retrieves
1162
 *               the password.  it may be possible for different safes to
1163
 *               have different passwords.  also, the password is already
1164
 *               in unicode.  it should probably be converted down below via
1165
 *               a unicode conversion callback.
1166
 *      slot - the slot to import the dataa into should multiple slots
1167
 *               be supported based on key type and cert type?
1168
 *      dOpen, dClose, dRead, dWrite - digest routines for writing data
1169
 *               to a file so it could be read back and the hmac recomputed
1170
 *               and verified.  doesn't seem to be a way for both encoding
1171
 *               and decoding to be single pass, thus the need for these
1172
 *               routines.
1173
 *      dArg - the argument for dOpen, etc.
1174
 *
1175
 *      if NULL == dOpen == dClose == dRead == dWrite == dArg, then default
1176
 *      implementations using a memory buffer are used
1177
 *
1178
 *      This function returns the decoder context, if it was successful.
1179
 *      Otherwise, null is returned.
1180
 */
1181
SEC_PKCS12DecoderContext *
1182
SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
1183
                       digestOpenFn dOpen, digestCloseFn dClose,
1184
                       digestIOFn dRead, digestIOFn dWrite, void *dArg)
1185
0
{
1186
0
    SEC_PKCS12DecoderContext *p12dcx;
1187
0
    PLArenaPool *arena;
1188
0
    PRInt32 forceUnicode = PR_FALSE;
1189
0
    SECStatus rv;
1190
1191
0
    arena = PORT_NewArena(2048); /* different size? */
1192
0
    if (!arena) {
1193
0
        return NULL; /* error is already set */
1194
0
    }
1195
1196
    /* allocate the decoder context and set the state variables */
1197
0
    p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
1198
0
    if (!p12dcx) {
1199
0
        goto loser; /* error is already set */
1200
0
    }
1201
1202
0
    if (!dOpen && !dClose && !dRead && !dWrite && !dArg) {
1203
        /* use default implementations */
1204
0
        dOpen = p12u_DigestOpen;
1205
0
        dClose = p12u_DigestClose;
1206
0
        dRead = p12u_DigestRead;
1207
0
        dWrite = p12u_DigestWrite;
1208
0
        dArg = (void *)p12dcx;
1209
0
    }
1210
1211
0
    p12dcx->arena = arena;
1212
0
    p12dcx->pwitem = pwitem;
1213
0
    p12dcx->slot = (slot ? PK11_ReferenceSlot(slot)
1214
0
                         : PK11_GetInternalKeySlot());
1215
0
    p12dcx->wincx = wincx;
1216
0
    p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
1217
0
#ifdef IS_LITTLE_ENDIAN
1218
0
    p12dcx->swapUnicodeBytes = PR_TRUE;
1219
#else
1220
    p12dcx->swapUnicodeBytes = PR_FALSE;
1221
#endif
1222
0
    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
1223
0
    if (rv != SECSuccess) {
1224
0
        goto loser;
1225
0
    }
1226
0
    p12dcx->forceUnicode = forceUnicode;
1227
0
    p12dcx->errorValue = 0;
1228
0
    p12dcx->error = PR_FALSE;
1229
1230
    /* start the decoding of the PFX and set the notify proc
1231
     * for the PFX item.
1232
     */
1233
0
    p12dcx->pfxA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx,
1234
0
                                            sec_PKCS12PFXItemTemplate);
1235
0
    if (!p12dcx->pfxA1Dcx) {
1236
0
        PK11_FreeSlot(p12dcx->slot);
1237
0
        goto loser;
1238
0
    }
1239
1240
0
    SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxA1Dcx,
1241
0
                                 sec_pkcs12_decoder_pfx_notify_proc,
1242
0
                                 p12dcx);
1243
1244
    /* set up digest functions */
1245
0
    p12dcx->dOpen = dOpen;
1246
0
    p12dcx->dWrite = dWrite;
1247
0
    p12dcx->dClose = dClose;
1248
0
    p12dcx->dRead = dRead;
1249
0
    p12dcx->dArg = dArg;
1250
0
    p12dcx->dIsOpen = PR_FALSE;
1251
1252
0
    p12dcx->keyList = NULL;
1253
0
    p12dcx->decitem.type = 0;
1254
0
    p12dcx->decitem.der = NULL;
1255
0
    p12dcx->decitem.hasKey = PR_FALSE;
1256
0
    p12dcx->decitem.friendlyName = NULL;
1257
0
    p12dcx->iteration = 0;
1258
1259
0
    return p12dcx;
1260
1261
0
loser:
1262
0
    PORT_FreeArena(arena, PR_TRUE);
1263
0
    return NULL;
1264
0
}
1265
1266
SECStatus
1267
SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx,
1268
                                   SECPKCS12TargetTokenCAs tokenCAs)
1269
0
{
1270
0
    if (!p12dcx || p12dcx->error) {
1271
0
        return SECFailure;
1272
0
    }
1273
0
    p12dcx->tokenCAs = tokenCAs;
1274
0
    return SECSuccess;
1275
0
}
1276
1277
/* SEC_PKCS12DecoderUpdate
1278
 *      Streaming update sending more data to the decoder.  If
1279
 *      an error occurs, SECFailure is returned.
1280
 *
1281
 *      p12dcx - the decoder context
1282
 *      data, len - the data buffer and length of data to send to
1283
 *              the update functions.
1284
 */
1285
SECStatus
1286
SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx,
1287
                        unsigned char *data, unsigned long len)
1288
0
{
1289
0
    SECStatus rv;
1290
1291
0
    if (!p12dcx || p12dcx->error) {
1292
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1293
0
        return SECFailure;
1294
0
    }
1295
1296
    /* update the PFX decoder context */
1297
0
    rv = SEC_ASN1DecoderUpdate(p12dcx->pfxA1Dcx, (const char *)data, len);
1298
0
    if (rv != SECSuccess) {
1299
0
        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
1300
0
        goto loser;
1301
0
    }
1302
1303
0
    return SECSuccess;
1304
1305
0
loser:
1306
1307
0
    p12dcx->error = PR_TRUE;
1308
0
    return SECFailure;
1309
0
}
1310
1311
/* This should be a nice sized buffer for reading in data (potentially large
1312
** amounts) to be MACed.  It should be MUCH larger than HASH_LENGTH_MAX.
1313
*/
1314
0
#define IN_BUF_LEN 1024
1315
#ifdef DEBUG
1316
static const char bufferEnd[] = { "BufferEnd" };
1317
#endif
1318
0
#define FUDGE 128 /* must be as large as bufferEnd or more. */
1319
1320
/* verify the hmac by reading the data from the temporary file
1321
 * using the routines specified when the decodingContext was
1322
 * created and return SECSuccess if the hmac matches.
1323
 */
1324
static SECStatus
1325
sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
1326
0
{
1327
0
    PK11Context *pk11cx = NULL;
1328
0
    PK11SymKey *symKey = NULL;
1329
0
    unsigned char *buf;
1330
0
    SECStatus rv = SECFailure;
1331
0
    SECStatus lrv;
1332
0
    unsigned int bufLen;
1333
0
    int bytesRead;
1334
0
    SECItem hmacRes;
1335
0
    SECItem ignore = { 0 };
1336
0
    CK_MECHANISM_TYPE hmacMech;
1337
1338
0
    if (!p12dcx || p12dcx->error) {
1339
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1340
0
        return SECFailure;
1341
0
    }
1342
0
    buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE);
1343
0
    if (!buf)
1344
0
        return SECFailure; /* error code has been set. */
1345
1346
0
#ifdef DEBUG
1347
0
    memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd);
1348
0
#endif
1349
1350
    /* generate hmac key */
1351
0
    symKey = sec_pkcs12_integrity_key(p12dcx->slot, &p12dcx->macData,
1352
0
                                      p12dcx->pwitem, &hmacMech, PR_TRUE,
1353
0
                                      p12dcx->wincx);
1354
0
    if (symKey == NULL) {
1355
0
        goto loser;
1356
0
    }
1357
1358
    /* init hmac */
1359
0
    pk11cx = PK11_CreateContextBySymKey(hmacMech, CKA_SIGN, symKey, &ignore);
1360
0
    if (!pk11cx) {
1361
0
        goto loser;
1362
0
    }
1363
0
    lrv = PK11_DigestBegin(pk11cx);
1364
0
    if (lrv == SECFailure) {
1365
0
        goto loser;
1366
0
    }
1367
1368
    /* try to open the data for readback */
1369
0
    if (p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) != SECSuccess)) {
1370
0
        goto loser;
1371
0
    }
1372
1373
    /* read the data back IN_BUF_LEN bytes at a time and recompute
1374
     * the hmac.  if fewer bytes are read than are requested, it is
1375
     * assumed that the end of file has been reached. if bytesRead
1376
     * is returned as -1, then an error occurred reading from the
1377
     * file.
1378
     */
1379
0
    do {
1380
0
        bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN);
1381
0
        if (bytesRead < 0) {
1382
0
            PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ);
1383
0
            goto loser;
1384
0
        }
1385
0
        PORT_Assert(bytesRead <= IN_BUF_LEN);
1386
0
        PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd));
1387
1388
0
        if (bytesRead > IN_BUF_LEN) {
1389
            /* dRead callback overflowed buffer. */
1390
0
            PORT_SetError(SEC_ERROR_INPUT_LEN);
1391
0
            goto loser;
1392
0
        }
1393
1394
0
        if (bytesRead) {
1395
0
            lrv = PK11_DigestOp(pk11cx, buf, bytesRead);
1396
0
            if (lrv == SECFailure) {
1397
0
                goto loser;
1398
0
            }
1399
0
        }
1400
0
    } while (bytesRead == IN_BUF_LEN);
1401
1402
    /* finish the hmac context */
1403
0
    lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN);
1404
0
    if (lrv == SECFailure) {
1405
0
        goto loser;
1406
0
    }
1407
1408
0
    hmacRes.data = buf;
1409
0
    hmacRes.len = bufLen;
1410
1411
    /* is the hmac computed the same as the hmac which was decoded? */
1412
0
    rv = SECSuccess;
1413
0
    if (SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) != SECEqual) {
1414
0
        PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
1415
0
        rv = SECFailure;
1416
0
    }
1417
1418
0
loser:
1419
    /* close the file and remove it */
1420
0
    if (p12dcx->dClose) {
1421
0
        (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
1422
0
        p12dcx->dIsOpen = PR_FALSE;
1423
0
    }
1424
1425
0
    if (pk11cx) {
1426
0
        PK11_DestroyContext(pk11cx, PR_TRUE);
1427
0
    }
1428
0
    if (symKey) {
1429
0
        PK11_FreeSymKey(symKey);
1430
0
    }
1431
0
    PORT_ZFree(buf, IN_BUF_LEN + FUDGE);
1432
1433
0
    return rv;
1434
0
}
1435
1436
/* SEC_PKCS12DecoderVerify
1437
 *      Verify the macData or the signature of the decoded PKCS 12 PDU.
1438
 *      If the signature or the macData do not match, SECFailure is
1439
 *      returned.
1440
 *
1441
 *      p12dcx - the decoder context
1442
 */
1443
SECStatus
1444
SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx)
1445
0
{
1446
0
    SECStatus rv = SECSuccess;
1447
1448
    /* make sure that no errors have occurred... */
1449
0
    if (!p12dcx) {
1450
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1451
0
        return SECFailure;
1452
0
    }
1453
0
    if (p12dcx->error) {
1454
        /* error code is already set! PORT_SetError(p12dcx->errorValue); */
1455
0
        return SECFailure;
1456
0
    }
1457
1458
0
    rv = SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
1459
0
    p12dcx->pfxA1Dcx = NULL;
1460
0
    if (rv != SECSuccess) {
1461
0
        return rv;
1462
0
    }
1463
1464
    /* check the signature or the mac depending on the type of
1465
     * integrity used.
1466
     */
1467
0
    if (p12dcx->pfx.encodedMacData.len) {
1468
0
        rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData,
1469
0
                                sec_PKCS12MacDataTemplate,
1470
0
                                &p12dcx->pfx.encodedMacData);
1471
0
        if (rv == SECSuccess) {
1472
0
            return sec_pkcs12_decoder_verify_mac(p12dcx);
1473
0
        }
1474
0
        return rv;
1475
0
    }
1476
0
    if (SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner,
1477
0
                                 PR_FALSE)) {
1478
0
        return SECSuccess;
1479
0
    }
1480
0
    PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
1481
0
    return SECFailure;
1482
0
}
1483
1484
/* SEC_PKCS12DecoderFinish
1485
 *      Free any open ASN1 or PKCS7 decoder contexts and then
1486
 *      free the arena pool which everything should be allocated
1487
 *      from.  This function should be called upon completion of
1488
 *      decoding and installing of a pfx pdu.  This should be
1489
 *      called even if an error occurs.
1490
 *
1491
 *      p12dcx - the decoder context
1492
 */
1493
void
1494
SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
1495
0
{
1496
0
    unsigned int i;
1497
1498
0
    if (!p12dcx) {
1499
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1500
0
        return;
1501
0
    }
1502
1503
0
    if (p12dcx->pfxA1Dcx) {
1504
0
        SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
1505
0
        p12dcx->pfxA1Dcx = NULL;
1506
0
    }
1507
1508
0
    if (p12dcx->aSafeA1Dcx) {
1509
0
        SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
1510
0
        p12dcx->aSafeA1Dcx = NULL;
1511
0
    }
1512
1513
    /* cleanup any old ASN1 decoder contexts */
1514
0
    for (i = 0; i < p12dcx->safeContentsCnt; ++i) {
1515
0
        sec_PKCS12SafeContentsContext *safeContentsCtx, *nested;
1516
0
        safeContentsCtx = p12dcx->safeContentsList[i];
1517
0
        if (safeContentsCtx) {
1518
0
            nested = safeContentsCtx->nestedSafeContentsCtx;
1519
0
            while (nested) {
1520
0
                if (nested->safeContentsA1Dcx) {
1521
0
                    SEC_ASN1DecoderFinish(nested->safeContentsA1Dcx);
1522
0
                    nested->safeContentsA1Dcx = NULL;
1523
0
                }
1524
0
                nested = nested->nestedSafeContentsCtx;
1525
0
            }
1526
0
            if (safeContentsCtx->safeContentsA1Dcx) {
1527
0
                SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
1528
0
                safeContentsCtx->safeContentsA1Dcx = NULL;
1529
0
            }
1530
0
        }
1531
0
    }
1532
1533
0
    if (p12dcx->currentASafeP7Dcx &&
1534
0
        p12dcx->currentASafeP7Dcx != p12dcx->aSafeP7Dcx) {
1535
0
        SEC_PKCS7ContentInfo *cinfo;
1536
0
        cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
1537
0
        if (cinfo) {
1538
0
            SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
1539
0
        }
1540
0
    }
1541
0
    p12dcx->currentASafeP7Dcx = NULL;
1542
1543
0
    if (p12dcx->aSafeP7Dcx) {
1544
0
        SEC_PKCS7ContentInfo *cinfo;
1545
0
        cinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
1546
0
        if (cinfo) {
1547
0
            SEC_PKCS7DestroyContentInfo(cinfo);
1548
0
        }
1549
0
        p12dcx->aSafeP7Dcx = NULL;
1550
0
    }
1551
1552
0
    if (p12dcx->aSafeCinfo) {
1553
0
        SEC_PKCS7DestroyContentInfo(p12dcx->aSafeCinfo);
1554
0
        p12dcx->aSafeCinfo = NULL;
1555
0
    }
1556
1557
0
    if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
1558
0
        SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
1559
0
    }
1560
0
    if (p12dcx->decitem.friendlyName != NULL) {
1561
0
        SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
1562
0
    }
1563
1564
0
    if (p12dcx->slot) {
1565
0
        PK11_FreeSlot(p12dcx->slot);
1566
0
        p12dcx->slot = NULL;
1567
0
    }
1568
1569
0
    if (p12dcx->dIsOpen && p12dcx->dClose) {
1570
0
        (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
1571
0
        p12dcx->dIsOpen = PR_FALSE;
1572
0
    }
1573
1574
0
    if (p12dcx->arena) {
1575
0
        PORT_FreeArena(p12dcx->arena, PR_TRUE);
1576
0
    }
1577
0
}
1578
1579
static SECStatus
1580
sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag,
1581
                                       SECOidTag attributeType,
1582
                                       SECItem *attrValue)
1583
0
{
1584
0
    int i = 0;
1585
0
    SECOidData *oid;
1586
1587
0
    if (!bag || !attrValue) {
1588
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1589
0
        return SECFailure;
1590
0
    }
1591
1592
0
    oid = SECOID_FindOIDByTag(attributeType);
1593
0
    if (!oid) {
1594
0
        return SECFailure;
1595
0
    }
1596
1597
0
    if (!bag->attribs) {
1598
0
        bag->attribs =
1599
0
            PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
1600
0
    } else {
1601
0
        while (bag->attribs[i])
1602
0
            i++;
1603
0
        bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
1604
0
                                           sec_PKCS12Attribute *, i + 1, i + 2);
1605
0
    }
1606
1607
0
    if (!bag->attribs) {
1608
0
        return SECFailure;
1609
0
    }
1610
1611
0
    bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1612
0
    if (!bag->attribs[i]) {
1613
0
        return SECFailure;
1614
0
    }
1615
1616
0
    bag->attribs[i]->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
1617
0
    if (!bag->attribs[i]->attrValue) {
1618
0
        return SECFailure;
1619
0
    }
1620
1621
0
    bag->attribs[i + 1] = NULL;
1622
0
    bag->attribs[i]->attrValue[0] = attrValue;
1623
0
    bag->attribs[i]->attrValue[1] = NULL;
1624
1625
0
    return SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid);
1626
0
}
1627
1628
static SECItem *
1629
sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag,
1630
                               SECOidTag attributeType)
1631
0
{
1632
0
    int i;
1633
1634
0
    if (!bag->attribs) {
1635
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1636
0
        return NULL;
1637
0
    }
1638
1639
0
    for (i = 0; bag->attribs[i] != NULL; i++) {
1640
0
        if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == attributeType) {
1641
0
            return bag->attribs[i]->attrValue[0];
1642
0
        }
1643
0
    }
1644
0
    return NULL;
1645
0
}
1646
1647
/* For now, this function will merely remove any ":"
1648
 * in the nickname which the PK11 functions may have
1649
 * placed there.  This will keep dual certs from appearing
1650
 * twice under "Your" certificates when imported onto smart
1651
 * cards.  Once with the name "Slot:Cert" and another with
1652
 * the nickname "Slot:Slot:Cert"
1653
 */
1654
static void
1655
sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
1656
0
{
1657
0
    char *nickname;
1658
0
    char *delimit;
1659
0
    int delimitlen;
1660
1661
0
    nickname = (char *)nick->data;
1662
0
    if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
1663
0
        char *slotName;
1664
0
        int slotNameLen;
1665
1666
0
        slotNameLen = delimit - nickname;
1667
0
        slotName = PORT_NewArray(char, (slotNameLen + 1));
1668
0
        PORT_Assert(slotName);
1669
0
        if (slotName == NULL) {
1670
            /* What else can we do?*/
1671
0
            return;
1672
0
        }
1673
0
        PORT_Memcpy(slotName, nickname, slotNameLen);
1674
0
        slotName[slotNameLen] = '\0';
1675
0
        if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
1676
0
            delimitlen = PORT_Strlen(delimit + 1);
1677
0
            PORT_Memmove(nickname, delimit + 1, delimitlen + 1);
1678
0
            nick->len = delimitlen;
1679
0
        }
1680
0
        PORT_Free(slotName);
1681
0
    }
1682
0
}
1683
1684
static SECItem *
1685
sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag)
1686
0
{
1687
0
    SECItem *src, *dest;
1688
1689
0
    if (!bag) {
1690
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1691
0
        return NULL;
1692
0
    }
1693
1694
0
    src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
1695
1696
    /* The return value src is 16-bit Unicode characters, in big-endian format.
1697
     * Check if it is NULL or empty name.
1698
     */
1699
0
    if (!src || !src->data || src->len < 2 || (!src->data[0] && !src->data[1])) {
1700
0
        return NULL;
1701
0
    }
1702
1703
0
    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1704
0
    if (!dest) {
1705
0
        goto loser;
1706
0
    }
1707
0
    if (!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE,
1708
0
                                            PR_FALSE, PR_FALSE)) {
1709
0
        goto loser;
1710
0
    }
1711
1712
0
    sec_pkcs12_sanitize_nickname(bag->slot, dest);
1713
1714
0
    return dest;
1715
1716
0
loser:
1717
0
    if (dest) {
1718
0
        SECITEM_ZfreeItem(dest, PR_TRUE);
1719
0
    }
1720
1721
0
    bag->problem = PR_TRUE;
1722
0
    bag->error = PORT_GetError();
1723
0
    return NULL;
1724
0
}
1725
1726
static SECStatus
1727
sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name)
1728
0
{
1729
0
    sec_PKCS12Attribute *attr = NULL;
1730
0
    SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME);
1731
1732
0
    if (!bag || !bag->arena || !name) {
1733
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1734
0
        return SECFailure;
1735
0
    }
1736
1737
0
    if (!bag->attribs) {
1738
0
        if (!oid) {
1739
0
            goto loser;
1740
0
        }
1741
1742
0
        bag->attribs =
1743
0
            PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
1744
0
        if (!bag->attribs) {
1745
0
            goto loser;
1746
0
        }
1747
0
        bag->attribs[0] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1748
0
        if (!bag->attribs[0]) {
1749
0
            goto loser;
1750
0
        }
1751
0
        bag->attribs[1] = NULL;
1752
1753
0
        attr = bag->attribs[0];
1754
0
        if (SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) != SECSuccess) {
1755
0
            goto loser;
1756
0
        }
1757
0
    } else {
1758
0
        int i;
1759
0
        for (i = 0; bag->attribs[i]; i++) {
1760
0
            if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == SEC_OID_PKCS9_FRIENDLY_NAME) {
1761
0
                attr = bag->attribs[i];
1762
0
                break;
1763
0
            }
1764
0
        }
1765
0
        if (!attr) {
1766
0
            if (!oid) {
1767
0
                goto loser;
1768
0
            }
1769
0
            bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
1770
0
                                               sec_PKCS12Attribute *, i + 1, i + 2);
1771
0
            if (!bag->attribs) {
1772
0
                goto loser;
1773
0
            }
1774
0
            bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1775
0
            if (!bag->attribs[i]) {
1776
0
                goto loser;
1777
0
            }
1778
0
            bag->attribs[i + 1] = NULL;
1779
0
            attr = bag->attribs[i];
1780
0
            if (SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) != SECSuccess) {
1781
0
                goto loser;
1782
0
            }
1783
0
        }
1784
0
    }
1785
1786
0
    PORT_Assert(attr);
1787
0
    if (!attr->attrValue) {
1788
0
        attr->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
1789
0
        if (!attr->attrValue) {
1790
0
            goto loser;
1791
0
        }
1792
0
        attr->attrValue[0] = PORT_ArenaZNew(bag->arena, SECItem);
1793
0
        if (!attr->attrValue[0]) {
1794
0
            goto loser;
1795
0
        }
1796
0
        attr->attrValue[1] = NULL;
1797
0
    }
1798
1799
0
    name->len = PORT_Strlen((char *)name->data);
1800
0
    if (!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0],
1801
0
                                            name, PR_FALSE, PR_FALSE, PR_TRUE)) {
1802
0
        goto loser;
1803
0
    }
1804
1805
0
    return SECSuccess;
1806
1807
0
loser:
1808
0
    bag->problem = PR_TRUE;
1809
0
    bag->error = PORT_GetError();
1810
0
    return SECFailure;
1811
0
}
1812
1813
static SECStatus
1814
sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key)
1815
0
{
1816
0
    int i = 0;
1817
0
    SECKEYPrivateKeyInfo *pki = NULL;
1818
1819
0
    if (!key) {
1820
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1821
0
        return SECFailure;
1822
0
    }
1823
1824
    /* if the bag does *not* contain an unencrypted PrivateKeyInfo
1825
     * then we cannot convert the attributes.  We are propagating
1826
     * attributes within the PrivateKeyInfo to the SafeBag level.
1827
     */
1828
0
    if (SECOID_FindOIDTag(&(key->safeBagType)) !=
1829
0
        SEC_OID_PKCS12_V1_KEY_BAG_ID) {
1830
0
        return SECSuccess;
1831
0
    }
1832
1833
0
    pki = key->safeBagContent.pkcs8KeyBag;
1834
1835
0
    if (!pki || !pki->attributes) {
1836
0
        return SECSuccess;
1837
0
    }
1838
1839
0
    while (pki->attributes[i]) {
1840
0
        SECOidTag tag = SECOID_FindOIDTag(&pki->attributes[i]->attrType);
1841
1842
0
        if (tag == SEC_OID_PKCS9_LOCAL_KEY_ID ||
1843
0
            tag == SEC_OID_PKCS9_FRIENDLY_NAME) {
1844
0
            SECItem *attrValue = sec_pkcs12_get_attribute_value(key, tag);
1845
0
            if (!attrValue) {
1846
0
                if (sec_pkcs12_decoder_set_attribute_value(key, tag,
1847
0
                                                           pki->attributes[i]->attrValue[0]) != SECSuccess) {
1848
0
                    key->problem = PR_TRUE;
1849
0
                    key->error = PORT_GetError();
1850
0
                    return SECFailure;
1851
0
                }
1852
0
            }
1853
0
        }
1854
0
        i++;
1855
0
    }
1856
1857
0
    return SECSuccess;
1858
0
}
1859
1860
/* retrieve the nickname for the certificate bag.  first look
1861
 * in the cert bag, otherwise get it from the key.
1862
 */
1863
static SECItem *
1864
sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert,
1865
                                 sec_PKCS12SafeBag *key)
1866
0
{
1867
0
    SECItem *nickname;
1868
1869
0
    if (!cert) {
1870
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1871
0
        return NULL;
1872
0
    }
1873
1874
0
    nickname = sec_pkcs12_get_nickname(cert);
1875
0
    if (nickname) {
1876
0
        return nickname;
1877
0
    }
1878
1879
0
    if (key) {
1880
0
        nickname = sec_pkcs12_get_nickname(key);
1881
1882
0
        if (nickname && sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
1883
0
            SECITEM_ZfreeItem(nickname, PR_TRUE);
1884
0
            return NULL;
1885
0
        }
1886
0
    }
1887
1888
0
    return nickname;
1889
0
}
1890
1891
/* set the nickname for the certificate */
1892
static SECStatus
1893
sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert,
1894
                                 sec_PKCS12SafeBag *key,
1895
                                 SECItem *nickname)
1896
0
{
1897
0
    if (!nickname || !cert) {
1898
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1899
0
        return SECFailure;
1900
0
    }
1901
1902
0
    if (sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
1903
0
        return SECFailure;
1904
0
    }
1905
1906
0
    if (key) {
1907
0
        if (sec_pkcs12_set_nickname(key, nickname) != SECSuccess) {
1908
0
            cert->problem = PR_TRUE;
1909
0
            cert->error = key->error;
1910
0
            return SECFailure;
1911
0
        }
1912
0
    }
1913
1914
0
    return SECSuccess;
1915
0
}
1916
1917
/* retrieve the DER cert from the cert bag */
1918
static SECItem *
1919
sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert)
1920
0
{
1921
0
    if (!cert || !cert->safeBagContent.certBag) {
1922
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1923
0
        return NULL;
1924
0
    }
1925
1926
0
    if (SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) {
1927
0
        return NULL;
1928
0
    }
1929
1930
    /* only support X509 certs not SDSI */
1931
0
    if (SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID) != SEC_OID_PKCS9_X509_CERT) {
1932
0
        return NULL;
1933
0
    }
1934
1935
0
    return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert));
1936
0
}
1937
1938
struct certNickInfo {
1939
    PLArenaPool *arena;
1940
    unsigned int nNicks;
1941
    SECItem **nickList;
1942
    unsigned int error;
1943
};
1944
1945
/* callback for traversing certificates to gather the nicknames
1946
 * used in a particular traversal.  for instance, when using
1947
 * CERT_TraversePermCertsForSubject, gather the nicknames and
1948
 * store them in the certNickInfo for a particular DN.
1949
 *
1950
 * this handles the case where multiple nicknames are allowed
1951
 * for the same dn, which is not currently allowed, but may be
1952
 * in the future.
1953
 */
1954
static SECStatus
1955
gatherNicknames(CERTCertificate *cert, void *arg)
1956
0
{
1957
0
    struct certNickInfo *nickArg = (struct certNickInfo *)arg;
1958
0
    SECItem tempNick;
1959
0
    unsigned int i;
1960
1961
0
    if (!cert || !nickArg || nickArg->error) {
1962
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1963
0
        return SECFailure;
1964
0
    }
1965
1966
0
    if (!cert->nickname) {
1967
0
        return SECSuccess;
1968
0
    }
1969
1970
0
    tempNick.data = (unsigned char *)cert->nickname;
1971
0
    tempNick.len = PORT_Strlen(cert->nickname) + 1;
1972
0
    tempNick.type = siAsciiString;
1973
1974
    /* do we already have the nickname in the list? */
1975
0
    if (nickArg->nNicks > 0) {
1976
1977
        /* nicknames have been encountered, but there is no list -- bad */
1978
0
        if (!nickArg->nickList) {
1979
0
            nickArg->error = SEC_ERROR_INVALID_ARGS;
1980
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
1981
0
            return SECFailure;
1982
0
        }
1983
1984
0
        for (i = 0; i < nickArg->nNicks; i++) {
1985
0
            if (SECITEM_CompareItem(nickArg->nickList[i], &tempNick) == SECEqual) {
1986
0
                return SECSuccess;
1987
0
            }
1988
0
        }
1989
0
    }
1990
1991
    /* add the nickname to the list */
1992
0
    nickArg->nickList = (nickArg->nNicks == 0)
1993
0
                            ? PORT_ArenaZNewArray(nickArg->arena, SECItem *, 2)
1994
0
                            : PORT_ArenaGrowArray(nickArg->arena, nickArg->nickList, SECItem *,
1995
0
                                                  nickArg->nNicks + 1, nickArg->nNicks + 2);
1996
1997
0
    if (!nickArg->nickList) {
1998
0
        nickArg->error = SEC_ERROR_NO_MEMORY;
1999
0
        return SECFailure;
2000
0
    }
2001
2002
0
    nickArg->nickList[nickArg->nNicks] =
2003
0
        PORT_ArenaZNew(nickArg->arena, SECItem);
2004
0
    if (!nickArg->nickList[nickArg->nNicks]) {
2005
0
        nickArg->error = PORT_GetError();
2006
0
        return SECFailure;
2007
0
    }
2008
2009
0
    if (SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks],
2010
0
                         &tempNick) != SECSuccess) {
2011
0
        nickArg->error = PORT_GetError();
2012
0
        return SECFailure;
2013
0
    }
2014
2015
0
    nickArg->nNicks++;
2016
2017
0
    return SECSuccess;
2018
0
}
2019
2020
/* traverses the certs in the data base or in the token for the
2021
 * DN to see if any certs currently have a nickname set.
2022
 * If so, return it.
2023
 */
2024
static SECItem *
2025
sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert)
2026
0
{
2027
0
    struct certNickInfo *nickArg = NULL;
2028
0
    SECItem *derCert, *returnDn = NULL;
2029
0
    PLArenaPool *arena = NULL;
2030
0
    CERTCertificate *tempCert;
2031
2032
0
    if (!cert) {
2033
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2034
0
        return NULL;
2035
0
    }
2036
2037
0
    derCert = sec_pkcs12_get_der_cert(cert);
2038
0
    if (!derCert) {
2039
0
        return NULL;
2040
0
    }
2041
2042
0
    tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
2043
0
    if (!tempCert) {
2044
0
        returnDn = NULL;
2045
0
        goto loser;
2046
0
    }
2047
2048
0
    arena = PORT_NewArena(1024);
2049
0
    if (!arena) {
2050
0
        returnDn = NULL;
2051
0
        goto loser;
2052
0
    }
2053
0
    nickArg = PORT_ArenaZNew(arena, struct certNickInfo);
2054
0
    if (!nickArg) {
2055
0
        returnDn = NULL;
2056
0
        goto loser;
2057
0
    }
2058
0
    nickArg->error = 0;
2059
0
    nickArg->nNicks = 0;
2060
0
    nickArg->nickList = NULL;
2061
0
    nickArg->arena = arena;
2062
2063
    /* if the token is local, first traverse the cert database
2064
     * then traverse the token.
2065
     */
2066
0
    if (PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames,
2067
0
                                           (void *)nickArg) != SECSuccess) {
2068
0
        returnDn = NULL;
2069
0
        goto loser;
2070
0
    }
2071
2072
0
    if (nickArg->error) {
2073
        /* XXX do we want to set the error? */
2074
0
        returnDn = NULL;
2075
0
        goto loser;
2076
0
    }
2077
2078
0
    if (nickArg->nNicks == 0) {
2079
0
        returnDn = NULL;
2080
0
        goto loser;
2081
0
    }
2082
2083
    /* set it to the first name, for now.  handle multiple names? */
2084
0
    returnDn = SECITEM_DupItem(nickArg->nickList[0]);
2085
2086
0
loser:
2087
0
    if (arena) {
2088
0
        PORT_FreeArena(arena, PR_TRUE);
2089
0
    }
2090
2091
0
    if (tempCert) {
2092
0
        CERT_DestroyCertificate(tempCert);
2093
0
    }
2094
2095
0
    if (derCert) {
2096
0
        SECITEM_FreeItem(derCert, PR_TRUE);
2097
0
    }
2098
2099
0
    return (returnDn);
2100
0
}
2101
2102
/* counts certificates found for a given traversal function */
2103
static SECStatus
2104
countCertificate(CERTCertificate *cert, void *arg)
2105
0
{
2106
0
    unsigned int *nCerts = (unsigned int *)arg;
2107
2108
0
    if (!cert || !arg) {
2109
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2110
0
        return SECFailure;
2111
0
    }
2112
2113
0
    (*nCerts)++;
2114
0
    return SECSuccess;
2115
0
}
2116
2117
static PRBool
2118
sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot)
2119
0
{
2120
0
    unsigned int nCerts = 0;
2121
2122
0
    if (!nickname || !slot) {
2123
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2124
0
        return PR_TRUE;
2125
0
    }
2126
2127
    /* we want to check the local database first if we are importing to it */
2128
0
    PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate,
2129
0
                                        (void *)&nCerts);
2130
0
    return (PRBool)(nCerts != 0);
2131
0
}
2132
2133
/* validate cert nickname such that there is a one-to-one relation
2134
 * between nicknames and dn's.  we want to enforce the case that the
2135
 * nickname is non-NULL and that there is only one nickname per DN.
2136
 *
2137
 * if there is a problem with a nickname or the nickname is not present,
2138
 * the user will be prompted for it.
2139
 */
2140
static void
2141
sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,
2142
                                  sec_PKCS12SafeBag *key,
2143
                                  SEC_PKCS12NicknameCollisionCallback nicknameCb,
2144
                                  CERTCertificate *leafCert)
2145
0
{
2146
0
    SECItem *certNickname, *existingDNNick;
2147
0
    PRBool setNickname = PR_FALSE, cancel = PR_FALSE;
2148
0
    SECItem *newNickname = NULL;
2149
2150
0
    if (!cert || !cert->hasKey) {
2151
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2152
0
        return;
2153
0
    }
2154
2155
0
    if (!nicknameCb) {
2156
0
        cert->problem = PR_TRUE;
2157
0
        cert->error = SEC_ERROR_INVALID_ARGS;
2158
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2159
0
        return;
2160
0
    }
2161
2162
0
    if (cert->hasKey && !key) {
2163
0
        cert->problem = PR_TRUE;
2164
0
        cert->error = SEC_ERROR_INVALID_ARGS;
2165
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2166
0
        return;
2167
0
    }
2168
2169
0
    certNickname = sec_pkcs12_get_nickname_for_cert(cert, key);
2170
0
    existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert);
2171
2172
    /* nickname is already used w/ this dn, so it is safe to return */
2173
0
    if (certNickname && existingDNNick &&
2174
0
        SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {
2175
0
        goto loser;
2176
0
    }
2177
2178
    /* nickname not set in pkcs 12 bags, but a nick is already used for
2179
     * this dn.  set the nicks in the p12 bags and finish.
2180
     */
2181
0
    if (existingDNNick) {
2182
0
        sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick);
2183
0
        goto loser;
2184
0
    }
2185
2186
    /* at this point, we have a certificate for which the DN is not located
2187
     * on the token.  the nickname specified may or may not be NULL.  if it
2188
     * is not null, we need to make sure that there are no other certificates
2189
     * with this nickname in the token for it to be valid.  this imposes a
2190
     * one to one relationship between DN and nickname.
2191
     *
2192
     * if the nickname is null, we need the user to enter a nickname for
2193
     * the certificate.
2194
     *
2195
     * once we have a nickname, we make sure that the nickname is unique
2196
     * for the DN.  if it is not, the user is reprompted to enter a new
2197
     * nickname.
2198
     *
2199
     * in order to exit this loop, the nickname entered is either unique
2200
     * or the user hits cancel and the certificate is not imported.
2201
     */
2202
0
    setNickname = PR_FALSE;
2203
0
    while (1) {
2204
        /* we will use the nickname so long as no other certs have the
2205
         * same nickname.  and the nickname is not NULL.
2206
         */
2207
0
        if (certNickname && certNickname->data &&
2208
0
            !sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {
2209
0
            if (setNickname) {
2210
0
                sec_pkcs12_set_nickname_for_cert(cert, key, certNickname);
2211
0
            }
2212
0
            break;
2213
0
        }
2214
2215
0
        setNickname = PR_FALSE;
2216
0
        newNickname = (*nicknameCb)(certNickname, &cancel, leafCert);
2217
0
        if (cancel) {
2218
0
            cert->problem = PR_TRUE;
2219
0
            cert->error = SEC_ERROR_USER_CANCELLED;
2220
0
            break;
2221
0
        }
2222
2223
0
        if (!newNickname) {
2224
0
            cert->problem = PR_TRUE;
2225
0
            cert->error = PORT_GetError();
2226
0
            break;
2227
0
        }
2228
2229
        /* at this point we have a new nickname, if we have an existing
2230
         * certNickname, we need to free it and assign the new nickname
2231
         * to it to avoid a memory leak.  happy?
2232
         */
2233
0
        if (certNickname) {
2234
0
            SECITEM_ZfreeItem(certNickname, PR_TRUE);
2235
0
            certNickname = NULL;
2236
0
        }
2237
2238
0
        certNickname = newNickname;
2239
0
        setNickname = PR_TRUE;
2240
        /* go back and recheck the new nickname */
2241
0
    }
2242
2243
0
loser:
2244
0
    if (certNickname) {
2245
0
        SECITEM_ZfreeItem(certNickname, PR_TRUE);
2246
0
    }
2247
2248
0
    if (existingDNNick) {
2249
0
        SECITEM_ZfreeItem(existingDNNick, PR_TRUE);
2250
0
    }
2251
0
}
2252
2253
static void
2254
sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,
2255
                         sec_PKCS12SafeBag *key,
2256
                         SEC_PKCS12NicknameCollisionCallback nicknameCb)
2257
0
{
2258
0
    CERTCertificate *leafCert;
2259
2260
0
    if (!cert) {
2261
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2262
0
        return;
2263
0
    }
2264
2265
0
    cert->validated = PR_TRUE;
2266
2267
0
    if (!nicknameCb) {
2268
0
        cert->noInstall = PR_TRUE;
2269
0
        cert->problem = PR_TRUE;
2270
0
        cert->error = SEC_ERROR_INVALID_ARGS;
2271
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2272
0
        return;
2273
0
    }
2274
2275
0
    if (!cert->safeBagContent.certBag) {
2276
0
        cert->noInstall = PR_TRUE;
2277
0
        cert->problem = PR_TRUE;
2278
0
        cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
2279
0
        return;
2280
0
    }
2281
2282
0
    cert->noInstall = PR_FALSE;
2283
0
    cert->unused = PR_FALSE;
2284
0
    cert->problem = PR_FALSE;
2285
0
    cert->error = 0;
2286
2287
0
    leafCert = CERT_DecodeDERCertificate(
2288
0
        &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
2289
0
    if (!leafCert) {
2290
0
        cert->noInstall = PR_TRUE;
2291
0
        cert->problem = PR_TRUE;
2292
0
        cert->error = PORT_GetError();
2293
0
        return;
2294
0
    }
2295
2296
0
    sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, leafCert);
2297
2298
0
    CERT_DestroyCertificate(leafCert);
2299
0
}
2300
2301
static void
2302
sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,
2303
                                void *wincx)
2304
0
{
2305
0
    CERTCertificate *leafCert;
2306
0
    SECKEYPrivateKey *privk;
2307
2308
0
    if (!key) {
2309
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2310
0
        return;
2311
0
    }
2312
2313
0
    key->validated = PR_TRUE;
2314
2315
0
    if (!cert) {
2316
0
        key->problem = PR_TRUE;
2317
0
        key->noInstall = PR_TRUE;
2318
0
        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2319
0
        return;
2320
0
    }
2321
2322
0
    leafCert = CERT_DecodeDERCertificate(
2323
0
        &(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL);
2324
0
    if (!leafCert) {
2325
0
        key->problem = PR_TRUE;
2326
0
        key->noInstall = PR_TRUE;
2327
0
        key->error = PORT_GetError();
2328
0
        return;
2329
0
    }
2330
2331
0
    privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);
2332
0
    if (!privk) {
2333
0
        privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);
2334
0
    }
2335
2336
0
    if (privk) {
2337
0
        SECKEY_DestroyPrivateKey(privk);
2338
0
        key->noInstall = PR_TRUE;
2339
0
    }
2340
2341
0
    CERT_DestroyCertificate(leafCert);
2342
0
}
2343
2344
static SECStatus
2345
sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx)
2346
0
{
2347
0
    SECItem *derCert, *nickName;
2348
0
    char *nickData = NULL;
2349
0
    PRBool isIntermediateCA;
2350
0
    SECStatus rv;
2351
2352
0
    if (!cert) {
2353
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2354
0
        return SECFailure;
2355
0
    }
2356
2357
0
    if (cert->problem || cert->noInstall || cert->installed) {
2358
0
        return SECSuccess;
2359
0
    }
2360
2361
0
    derCert = &cert->safeBagContent.certBag->value.x509Cert;
2362
2363
0
    PORT_Assert(!cert->problem && !cert->noInstall);
2364
2365
0
    nickName = sec_pkcs12_get_nickname(cert);
2366
0
    if (nickName) {
2367
0
        nickData = (char *)nickName->data;
2368
0
    }
2369
2370
0
    isIntermediateCA = CERT_IsCADERCert(derCert, NULL) &&
2371
0
                       !CERT_IsRootDERCert(derCert);
2372
2373
0
    if (keyExists) {
2374
0
        CERTCertificate *newCert;
2375
2376
0
        newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2377
0
                                          derCert, NULL, PR_FALSE, PR_FALSE);
2378
0
        if (!newCert) {
2379
0
            if (nickName)
2380
0
                SECITEM_ZfreeItem(nickName, PR_TRUE);
2381
0
            cert->error = PORT_GetError();
2382
0
            cert->problem = PR_TRUE;
2383
0
            return SECFailure;
2384
0
        }
2385
2386
0
        rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData,
2387
0
                                         PR_TRUE, wincx);
2388
0
        CERT_DestroyCertificate(newCert);
2389
0
    } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) ||
2390
0
               ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) &&
2391
0
                !isIntermediateCA)) {
2392
0
        SECItem *certList[2];
2393
0
        certList[0] = derCert;
2394
0
        certList[1] = NULL;
2395
2396
0
        rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,
2397
0
                              1, certList, NULL, PR_TRUE, PR_FALSE, nickData);
2398
0
    } else {
2399
0
        rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE,
2400
0
                                nickData, PR_FALSE);
2401
0
    }
2402
0
    if (rv) {
2403
0
        cert->problem = 1;
2404
0
        cert->error = PORT_GetError();
2405
0
    }
2406
0
    cert->installed = PR_TRUE;
2407
0
    if (nickName)
2408
0
        SECITEM_ZfreeItem(nickName, PR_TRUE);
2409
0
    return rv;
2410
0
}
2411
2412
static SECItem *
2413
sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey, KeyType *type);
2414
2415
static SECStatus
2416
sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECKEYPublicKey *pubKey,
2417
                   unsigned int keyUsage,
2418
                   SECItem *nickName, PRBool forceUnicode, void *wincx)
2419
0
{
2420
0
    SECStatus rv;
2421
0
    SECItem *publicValue = NULL;
2422
0
    KeyType keyType;
2423
2424
    /* We should always have values for "key" and "pubKey"
2425
       so they can be dereferenced later. */
2426
0
    if (!key || !pubKey) {
2427
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2428
0
        return SECFailure;
2429
0
    }
2430
2431
0
    if (key->problem || key->noInstall) {
2432
0
        return SECSuccess;
2433
0
    }
2434
2435
    /* get the value and type from the public key */
2436
0
    publicValue = sec_pkcs12_get_public_value_and_type(pubKey, &keyType);
2437
0
    if (!publicValue) {
2438
0
        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2439
0
        key->problem = PR_TRUE;
2440
0
        return SECFailure;
2441
0
    }
2442
2443
0
    switch (SECOID_FindOIDTag(&key->safeBagType)) {
2444
0
        case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2445
0
            rv = PK11_ImportPrivateKeyInfo(key->slot,
2446
0
                                           key->safeBagContent.pkcs8KeyBag,
2447
0
                                           nickName, publicValue, PR_TRUE, PR_TRUE,
2448
0
                                           keyUsage, wincx);
2449
0
            break;
2450
0
        case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: {
2451
0
            SECItem pwitem = { 0 };
2452
0
            SECAlgorithmID *algid =
2453
0
                &key->safeBagContent.pkcs8ShroudedKeyBag->algorithm;
2454
0
            SECOidTag algorithm = SECOID_GetAlgorithmTag(algid);
2455
2456
0
            if (!SEC_PKCS12DecryptionAllowed(algid)) {
2457
0
                key->error = SEC_ERROR_BAD_EXPORT_ALGORITHM;
2458
0
                key->problem = PR_TRUE;
2459
0
                return SECFailure;
2460
0
            }
2461
2462
0
            if (forceUnicode) {
2463
0
                if (SECITEM_CopyItem(NULL, &pwitem, key->pwitem) != SECSuccess) {
2464
0
                    key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2465
0
                    key->problem = PR_TRUE;
2466
0
                    return SECFailure;
2467
0
                }
2468
0
            } else {
2469
0
                if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm,
2470
0
                                                key->pwitem)) {
2471
0
                    key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2472
0
                    key->problem = PR_TRUE;
2473
0
                    return SECFailure;
2474
0
                }
2475
0
            }
2476
2477
0
            rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
2478
0
                                                    key->safeBagContent.pkcs8ShroudedKeyBag,
2479
0
                                                    &pwitem, nickName, publicValue,
2480
0
                                                    PR_TRUE, PR_TRUE, keyType, keyUsage,
2481
0
                                                    wincx);
2482
0
            if (pwitem.data) {
2483
0
                SECITEM_ZfreeItem(&pwitem, PR_FALSE);
2484
0
            }
2485
0
            break;
2486
0
        }
2487
0
        default:
2488
0
            key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
2489
0
            key->problem = PR_TRUE;
2490
0
            if (nickName) {
2491
0
                SECITEM_ZfreeItem(nickName, PR_TRUE);
2492
0
            }
2493
0
            return SECFailure;
2494
0
    }
2495
2496
0
    if (rv != SECSuccess) {
2497
0
        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2498
0
        key->problem = PR_TRUE;
2499
0
    } else {
2500
        /* try to import the public key. Failure to do so is not fatal,
2501
         * not all tokens can store the public key */
2502
0
        if (pubKey) {
2503
0
            PK11_ImportPublicKey(key->slot, pubKey, PR_TRUE);
2504
0
        }
2505
0
        key->installed = PR_TRUE;
2506
0
    }
2507
2508
0
    return rv;
2509
0
}
2510
2511
/*
2512
 * The correctness of the code in this file ABSOLUTELY REQUIRES
2513
 * that ALL BAGs share a single common arena.
2514
 *
2515
 * This function allocates the bag list from the arena of whatever bag
2516
 * happens to be passed to it.  Each time a new bag is handed to it,
2517
 * it grows (resizes) the arena of the bag that was handed to it.
2518
 * If the bags have different arenas, it will grow the wrong arena.
2519
 *
2520
 * Worse, if the bags had separate arenas, then while destroying the bags
2521
 * in a bag list, when the bag whose arena contained the bag list was
2522
 * destroyed, the baglist itself would be destroyed, making it difficult
2523
 * or impossible to continue to destroy the bags in the destroyed list.
2524
 */
2525
static SECStatus
2526
sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList,
2527
                                sec_PKCS12SafeBag *bag)
2528
0
{
2529
0
    sec_PKCS12SafeBag **newBagList = NULL;
2530
0
    int i = 0;
2531
2532
0
    if (!bagList || !bag) {
2533
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2534
0
        return SECFailure;
2535
0
    }
2536
2537
0
    if (!(*bagList)) {
2538
0
        newBagList = PORT_ArenaZNewArray(bag->arena, sec_PKCS12SafeBag *, 2);
2539
0
    } else {
2540
0
        while ((*bagList)[i])
2541
0
            i++;
2542
0
        newBagList = PORT_ArenaGrowArray(bag->arena, *bagList,
2543
0
                                         sec_PKCS12SafeBag *, i + 1, i + 2);
2544
0
    }
2545
2546
0
    if (!newBagList) {
2547
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
2548
0
        return SECFailure;
2549
0
    }
2550
2551
0
    newBagList[i] = bag;
2552
0
    newBagList[i + 1] = NULL;
2553
0
    *bagList = newBagList;
2554
2555
0
    return SECSuccess;
2556
0
}
2557
2558
static sec_PKCS12SafeBag **
2559
sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags,
2560
                              sec_PKCS12SafeBag *key)
2561
0
{
2562
0
    sec_PKCS12SafeBag **certList = NULL;
2563
0
    SECItem *keyId;
2564
0
    int i;
2565
2566
0
    if (!safeBags || !safeBags[0]) {
2567
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2568
0
        return NULL;
2569
0
    }
2570
2571
0
    keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);
2572
0
    if (!keyId) {
2573
0
        return NULL;
2574
0
    }
2575
2576
0
    for (i = 0; safeBags[i]; i++) {
2577
0
        if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2578
0
            SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],
2579
0
                                                                SEC_OID_PKCS9_LOCAL_KEY_ID);
2580
2581
0
            if (certKeyId && (SECITEM_CompareItem(certKeyId, keyId) == SECEqual)) {
2582
0
                if (sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i]) != SECSuccess) {
2583
                    /* This would leak the partial list of safeBags,
2584
                     * but that list is allocated from the arena of
2585
                     * one of the safebags, and will be destroyed when
2586
                     * that arena is destroyed.  So this is not a real leak.
2587
                     */
2588
0
                    return NULL;
2589
0
                }
2590
0
            }
2591
0
        }
2592
0
    }
2593
2594
0
    return certList;
2595
0
}
2596
2597
CERTCertList *
2598
SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx)
2599
0
{
2600
0
    CERTCertList *certList = NULL;
2601
0
    sec_PKCS12SafeBag **safeBags;
2602
0
    int i;
2603
2604
0
    if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) {
2605
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2606
0
        return NULL;
2607
0
    }
2608
2609
0
    safeBags = p12dcx->safeBags;
2610
0
    certList = CERT_NewCertList();
2611
2612
0
    if (certList == NULL) {
2613
0
        return NULL;
2614
0
    }
2615
2616
0
    for (i = 0; safeBags[i]; i++) {
2617
0
        if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2618
0
            SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]);
2619
0
            CERTCertificate *tempCert = NULL;
2620
2621
0
            if (derCert == NULL)
2622
0
                continue;
2623
0
            tempCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2624
0
                                               derCert, NULL,
2625
0
                                               PR_FALSE, PR_TRUE);
2626
2627
0
            if (tempCert) {
2628
0
                CERT_AddCertToListTail(certList, tempCert);
2629
0
            }
2630
0
            SECITEM_FreeItem(derCert, PR_TRUE);
2631
0
        }
2632
        /* fixed an infinite loop here, by ensuring that i gets incremented
2633
         * if derCert is NULL above.
2634
         */
2635
0
    }
2636
2637
0
    return certList;
2638
0
}
2639
static sec_PKCS12SafeBag **
2640
sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags)
2641
0
{
2642
0
    int i;
2643
0
    sec_PKCS12SafeBag **keyList = NULL;
2644
0
    SECOidTag bagType;
2645
2646
0
    if (!safeBags || !safeBags[0]) {
2647
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2648
0
        return NULL;
2649
0
    }
2650
2651
0
    for (i = 0; safeBags[i]; i++) {
2652
0
        bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
2653
0
        switch (bagType) {
2654
0
            case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2655
0
            case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2656
0
                if (sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i]) != SECSuccess) {
2657
                    /* This would leak, except that keyList is allocated
2658
                     * from the arena shared by all the safeBags.
2659
                     */
2660
0
                    return NULL;
2661
0
                }
2662
0
                break;
2663
0
            default:
2664
0
                break;
2665
0
        }
2666
0
    }
2667
2668
0
    return keyList;
2669
0
}
2670
2671
/* This function takes two passes over the bags, validating them
2672
 * The two passes are intended to mirror exactly the two passes in
2673
 * sec_pkcs12_install_bags.  But they don't. :(
2674
 */
2675
static SECStatus
2676
sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags,
2677
                         SEC_PKCS12NicknameCollisionCallback nicknameCb,
2678
                         void *wincx)
2679
0
{
2680
0
    sec_PKCS12SafeBag **keyList;
2681
0
    int i;
2682
2683
0
    if (!safeBags || !nicknameCb) {
2684
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2685
0
        return SECFailure;
2686
0
    }
2687
2688
0
    if (!safeBags[0]) {
2689
0
        return SECSuccess;
2690
0
    }
2691
2692
    /* First pass.  Find all the key bags.
2693
     * Find the matching cert(s) for each key.
2694
     */
2695
0
    keyList = sec_pkcs12_get_key_bags(safeBags);
2696
0
    if (keyList) {
2697
0
        for (i = 0; keyList[i]; ++i) {
2698
0
            sec_PKCS12SafeBag *key = keyList[i];
2699
0
            sec_PKCS12SafeBag **certList =
2700
0
                sec_pkcs12_find_certs_for_key(safeBags, key);
2701
2702
0
            if (certList) {
2703
0
                int j;
2704
2705
0
                if (SECOID_FindOIDTag(&(key->safeBagType)) ==
2706
0
                    SEC_OID_PKCS12_V1_KEY_BAG_ID) {
2707
                    /* if it is an unencrypted private key then make sure
2708
                     * the attributes are propageted to the appropriate
2709
                     * level
2710
                     */
2711
0
                    if (sec_pkcs12_get_key_info(key) != SECSuccess) {
2712
0
                        return SECFailure;
2713
0
                    }
2714
0
                }
2715
2716
0
                sec_pkcs12_validate_key_by_cert(certList[0], key, wincx);
2717
0
                for (j = 0; certList[j]; ++j) {
2718
0
                    sec_PKCS12SafeBag *cert = certList[j];
2719
0
                    cert->hasKey = PR_TRUE;
2720
0
                    if (key->problem) {
2721
0
                        cert->problem = PR_TRUE;
2722
0
                        cert->error = key->error;
2723
0
                        continue;
2724
0
                    }
2725
0
                    sec_pkcs12_validate_cert(cert, key, nicknameCb);
2726
0
                    if (cert->problem) {
2727
0
                        key->problem = cert->problem;
2728
0
                        key->error = cert->error;
2729
0
                    }
2730
0
                }
2731
0
            }
2732
0
        }
2733
0
    }
2734
2735
    /* Now take a second pass over the safebags and mark for installation any
2736
     * certs that were neither installed nor disqualified by the first pass.
2737
     */
2738
0
    for (i = 0; safeBags[i]; ++i) {
2739
0
        sec_PKCS12SafeBag *bag = safeBags[i];
2740
2741
0
        if (!bag->validated) {
2742
0
            SECOidTag bagType = SECOID_FindOIDTag(&bag->safeBagType);
2743
2744
0
            switch (bagType) {
2745
0
                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
2746
0
                    sec_pkcs12_validate_cert(bag, NULL, nicknameCb);
2747
0
                    break;
2748
0
                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2749
0
                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2750
0
                    bag->noInstall = PR_TRUE;
2751
0
                    bag->problem = PR_TRUE;
2752
0
                    bag->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2753
0
                    break;
2754
0
                default:
2755
0
                    bag->noInstall = PR_TRUE;
2756
0
            }
2757
0
        }
2758
0
    }
2759
2760
0
    return SECSuccess;
2761
0
}
2762
2763
SECStatus
2764
SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx,
2765
                              SEC_PKCS12NicknameCollisionCallback nicknameCb)
2766
0
{
2767
0
    SECStatus rv;
2768
0
    int i, probCnt, errorVal = 0;
2769
0
    if (!p12dcx || p12dcx->error || !p12dcx->safeBags) {
2770
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2771
0
        return SECFailure;
2772
0
    }
2773
2774
0
    rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx);
2775
0
    if (rv == SECSuccess) {
2776
0
        p12dcx->bagsVerified = PR_TRUE;
2777
0
    }
2778
2779
0
    probCnt = 0;
2780
0
    i = 0;
2781
0
    while (p12dcx->safeBags[i]) {
2782
0
        if (p12dcx->safeBags[i]->problem) {
2783
0
            probCnt++;
2784
0
            errorVal = p12dcx->safeBags[i]->error;
2785
0
        }
2786
0
        i++;
2787
0
    }
2788
2789
0
    if (probCnt) {
2790
0
        PORT_SetError(errorVal);
2791
0
        return SECFailure;
2792
0
    }
2793
2794
0
    return rv;
2795
0
}
2796
2797
SECStatus
2798
SEC_PKCS12DecoderRenameCertNicknames(SEC_PKCS12DecoderContext *p12dcx,
2799
                                     SEC_PKCS12NicknameRenameCallback nicknameCb,
2800
                                     void *arg)
2801
0
{
2802
0
    int i;
2803
0
    sec_PKCS12SafeBag *safeBag;
2804
0
    CERTCertificate *cert;
2805
0
    SECStatus srv;
2806
2807
0
    if (!p12dcx || p12dcx->error || !p12dcx->safeBags || !nicknameCb) {
2808
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2809
0
        return SECFailure;
2810
0
    }
2811
2812
0
    for (i = 0; (safeBag = p12dcx->safeBags[i]); i++) {
2813
0
        SECItem *newNickname = NULL;
2814
0
        SECItem *defaultNickname = NULL;
2815
0
        SECStatus rename_rv;
2816
2817
0
        if (SECOID_FindOIDTag(&(safeBag->safeBagType)) !=
2818
0
            SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2819
0
            continue;
2820
0
        }
2821
2822
0
        cert = CERT_DecodeDERCertificate(
2823
0
            &safeBag->safeBagContent.certBag->value.x509Cert,
2824
0
            PR_FALSE, NULL);
2825
0
        if (!cert) {
2826
0
            return SECFailure;
2827
0
        }
2828
2829
0
        defaultNickname = sec_pkcs12_get_nickname(safeBag);
2830
0
        rename_rv = (*nicknameCb)(cert, defaultNickname, &newNickname, arg);
2831
2832
0
        CERT_DestroyCertificate(cert);
2833
2834
0
        if (defaultNickname) {
2835
0
            SECITEM_ZfreeItem(defaultNickname, PR_TRUE);
2836
0
            defaultNickname = NULL;
2837
0
        }
2838
2839
0
        if (rename_rv != SECSuccess) {
2840
0
            return rename_rv;
2841
0
        }
2842
2843
0
        if (newNickname) {
2844
0
            srv = sec_pkcs12_set_nickname(safeBag, newNickname);
2845
0
            SECITEM_ZfreeItem(newNickname, PR_TRUE);
2846
0
            newNickname = NULL;
2847
0
            if (srv != SECSuccess) {
2848
0
                return SECFailure;
2849
0
            }
2850
0
        }
2851
0
    }
2852
2853
0
    return SECSuccess;
2854
0
}
2855
2856
static SECKEYPublicKey *
2857
sec_pkcs12_get_public_key_and_usage(sec_PKCS12SafeBag *certBag,
2858
                                    unsigned int *usage)
2859
0
{
2860
0
    SECKEYPublicKey *pubKey = NULL;
2861
0
    CERTCertificate *cert = NULL;
2862
2863
0
    if (!certBag || !usage) {
2864
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2865
0
        return NULL;
2866
0
    }
2867
2868
0
    *usage = 0;
2869
2870
0
    cert = CERT_DecodeDERCertificate(
2871
0
        &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
2872
0
    if (!cert) {
2873
0
        return NULL;
2874
0
    }
2875
2876
0
    *usage = cert->keyUsage;
2877
0
    pubKey = CERT_ExtractPublicKey(cert);
2878
0
    CERT_DestroyCertificate(cert);
2879
0
    return pubKey;
2880
0
}
2881
2882
static SECItem *
2883
sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey,
2884
                                     KeyType *type)
2885
0
{
2886
0
    SECItem *pubValue = NULL;
2887
2888
0
    if (!type || !pubKey) {
2889
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2890
0
        return NULL;
2891
0
    }
2892
2893
0
    *type = pubKey->keyType;
2894
0
    switch (pubKey->keyType) {
2895
0
        case dsaKey:
2896
0
            pubValue = &pubKey->u.dsa.publicValue;
2897
0
            break;
2898
0
        case dhKey:
2899
0
            pubValue = &pubKey->u.dh.publicValue;
2900
0
            break;
2901
0
        case rsaKey:
2902
0
            pubValue = &pubKey->u.rsa.modulus;
2903
0
            break;
2904
0
        case ecKey:
2905
0
            pubValue = &pubKey->u.ec.publicValue;
2906
0
            break;
2907
0
        default:
2908
0
            pubValue = NULL;
2909
0
    }
2910
2911
0
    return pubValue;
2912
0
}
2913
2914
/* This function takes two passes over the bags, installing them in the
2915
 * desired slot.  The two passes are intended to mirror exactly the
2916
 * two passes in sec_pkcs12_validate_bags.
2917
 */
2918
static SECStatus
2919
sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, PRBool forceUnicode,
2920
                        void *wincx)
2921
0
{
2922
0
    sec_PKCS12SafeBag **keyList;
2923
0
    int i;
2924
0
    int failedKeys = 0;
2925
2926
0
    if (!safeBags) {
2927
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2928
0
        return SECFailure;
2929
0
    }
2930
2931
0
    if (!safeBags[0]) {
2932
0
        return SECSuccess;
2933
0
    }
2934
2935
    /* First pass.  Find all the key bags.
2936
     * Try to install them, and any certs associated with them.
2937
     */
2938
0
    keyList = sec_pkcs12_get_key_bags(safeBags);
2939
0
    if (keyList) {
2940
0
        for (i = 0; keyList[i]; i++) {
2941
0
            SECStatus rv;
2942
0
            SECKEYPublicKey *pubKey = NULL;
2943
0
            SECItem *nickName = NULL;
2944
0
            sec_PKCS12SafeBag *key = keyList[i];
2945
0
            sec_PKCS12SafeBag **certList;
2946
0
            unsigned int keyUsage;
2947
2948
0
            if (key->problem) {
2949
0
                ++failedKeys;
2950
0
                continue;
2951
0
            }
2952
2953
0
            certList = sec_pkcs12_find_certs_for_key(safeBags, key);
2954
0
            if (certList && certList[0]) {
2955
0
                pubKey = sec_pkcs12_get_public_key_and_usage(certList[0],
2956
0
                                                             &keyUsage);
2957
                /* use the cert's nickname, if it has one, else use the
2958
                 * key's nickname, else fail.
2959
                 */
2960
0
                nickName = sec_pkcs12_get_nickname_for_cert(certList[0], key);
2961
0
            } else {
2962
0
                nickName = sec_pkcs12_get_nickname(key);
2963
0
            }
2964
0
            if (!nickName) {
2965
0
                key->error = SEC_ERROR_BAD_NICKNAME;
2966
0
                key->problem = PR_TRUE;
2967
0
                rv = SECFailure;
2968
0
            } else if (!pubKey) {
2969
0
                key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2970
0
                key->problem = PR_TRUE;
2971
0
                rv = SECFailure;
2972
0
            } else {
2973
0
                rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName,
2974
0
                                        forceUnicode, wincx);
2975
0
            }
2976
0
            if (pubKey) {
2977
0
                SECKEY_DestroyPublicKey(pubKey);
2978
0
                pubKey = NULL;
2979
0
            }
2980
0
            if (nickName) {
2981
0
                SECITEM_FreeItem(nickName, PR_TRUE);
2982
0
                nickName = NULL;
2983
0
            }
2984
0
            if (rv != SECSuccess) {
2985
0
                PORT_SetError(key->error);
2986
0
                ++failedKeys;
2987
0
            }
2988
2989
0
            if (certList) {
2990
0
                int j;
2991
2992
0
                for (j = 0; certList[j]; j++) {
2993
0
                    sec_PKCS12SafeBag *cert = certList[j];
2994
0
                    SECStatus certRv;
2995
2996
0
                    if (!cert)
2997
0
                        continue;
2998
0
                    if (rv != SECSuccess) {
2999
0
                        cert->problem = key->problem;
3000
0
                        cert->error = key->error;
3001
0
                        cert->noInstall = PR_TRUE;
3002
0
                        continue;
3003
0
                    }
3004
3005
0
                    certRv = sec_pkcs12_add_cert(cert, cert->hasKey, wincx);
3006
0
                    if (certRv != SECSuccess) {
3007
0
                        key->problem = cert->problem;
3008
0
                        key->error = cert->error;
3009
0
                        PORT_SetError(cert->error);
3010
0
                        return SECFailure;
3011
0
                    }
3012
0
                }
3013
0
            }
3014
0
        }
3015
0
    }
3016
0
    if (failedKeys)
3017
0
        return SECFailure;
3018
3019
    /* Now take a second pass over the safebags and install any certs
3020
     * that were neither installed nor disqualified by the first pass.
3021
     */
3022
0
    for (i = 0; safeBags[i]; i++) {
3023
0
        sec_PKCS12SafeBag *bag = safeBags[i];
3024
3025
0
        if (!bag->installed && !bag->problem && !bag->noInstall) {
3026
0
            SECStatus rv;
3027
0
            SECOidTag bagType = SECOID_FindOIDTag(&(bag->safeBagType));
3028
3029
0
            switch (bagType) {
3030
0
                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
3031
0
                    rv = sec_pkcs12_add_cert(bag, bag->hasKey, wincx);
3032
0
                    if (rv != SECSuccess) {
3033
0
                        PORT_SetError(bag->error);
3034
0
                        return SECFailure;
3035
0
                    }
3036
0
                    break;
3037
0
                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
3038
0
                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
3039
0
                default:
3040
0
                    break;
3041
0
            }
3042
0
        }
3043
0
    }
3044
3045
0
    return SECSuccess;
3046
0
}
3047
3048
SECStatus
3049
SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
3050
0
{
3051
0
    PRBool forceUnicode = PR_FALSE;
3052
0
    SECStatus rv;
3053
3054
0
    if (!p12dcx || p12dcx->error) {
3055
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3056
0
        return SECFailure;
3057
0
    }
3058
3059
0
    if (!p12dcx->bagsVerified) {
3060
0
        return SECFailure;
3061
0
    }
3062
3063
    /* We need to check the option here as well as in
3064
     * SEC_PKCS12DecoderStart, because different PBE's could be used
3065
     * for PKCS #7 and PKCS #8 */
3066
0
    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
3067
0
    if (rv != SECSuccess) {
3068
0
        return SECFailure;
3069
0
    }
3070
3071
0
    return sec_pkcs12_install_bags(p12dcx->safeBags, forceUnicode,
3072
0
                                   p12dcx->wincx);
3073
0
}
3074
3075
PRBool
3076
sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
3077
0
{
3078
0
    int i;
3079
0
    SECItem *keyId;
3080
0
    SECItem *certKeyId;
3081
3082
0
    certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
3083
0
    if (certKeyId == NULL) {
3084
0
        return PR_FALSE;
3085
0
    }
3086
3087
0
    for (i = 0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
3088
0
        keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
3089
0
                                               SEC_OID_PKCS9_LOCAL_KEY_ID);
3090
0
        if (!keyId) {
3091
0
            continue;
3092
0
        }
3093
0
        if (SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
3094
0
            return PR_TRUE;
3095
0
        }
3096
0
    }
3097
0
    return PR_FALSE;
3098
0
}
3099
3100
SECItem *
3101
sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
3102
0
{
3103
0
    SECItem *friendlyName;
3104
0
    SECItem *tempnm;
3105
3106
0
    tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
3107
0
    friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
3108
0
    if (friendlyName) {
3109
0
        if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
3110
0
                                                tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
3111
0
            SECITEM_FreeItem(friendlyName, PR_TRUE);
3112
0
            friendlyName = NULL;
3113
0
        }
3114
0
    }
3115
0
    return friendlyName;
3116
0
}
3117
3118
/* Following two functions provide access to selected portions of the safe bags.
3119
 * Iteration is implemented per decoder context and may be accessed after
3120
 * SEC_PKCS12DecoderVerify() returns success.
3121
 * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
3122
 * where item.type is always set; item.friendlyName is set if it is non-null;
3123
 * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
3124
 * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
3125
 * arguments are invalid; PORT_GetError() is 0 at end-of-list.
3126
 * Caller has read-only access to decoder items. Any SECItems generated are
3127
 * owned by the decoder context and are freed by ...DecoderFinish().
3128
 */
3129
SECStatus
3130
SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
3131
0
{
3132
0
    if (!p12dcx || p12dcx->error) {
3133
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3134
0
        return SECFailure;
3135
0
    }
3136
3137
0
    p12dcx->iteration = 0;
3138
0
    return SECSuccess;
3139
0
}
3140
3141
SECStatus
3142
SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
3143
                             const SEC_PKCS12DecoderItem **ipp)
3144
0
{
3145
0
    sec_PKCS12SafeBag *bag;
3146
3147
0
    if (!p12dcx || p12dcx->error) {
3148
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3149
0
        return SECFailure;
3150
0
    }
3151
3152
0
    if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
3153
0
        SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
3154
0
    }
3155
0
    if (p12dcx->decitem.shroudAlg != NULL) {
3156
0
        SECOID_DestroyAlgorithmID(p12dcx->decitem.shroudAlg, PR_TRUE);
3157
0
    }
3158
0
    if (p12dcx->decitem.friendlyName != NULL) {
3159
0
        SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
3160
0
    }
3161
0
    p12dcx->decitem.type = 0;
3162
0
    p12dcx->decitem.der = NULL;
3163
0
    p12dcx->decitem.shroudAlg = NULL;
3164
0
    p12dcx->decitem.friendlyName = NULL;
3165
0
    p12dcx->decitem.hasKey = PR_FALSE;
3166
0
    *ipp = NULL;
3167
0
    if (p12dcx->keyList == NULL) {
3168
0
        p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
3169
0
    }
3170
3171
0
    for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
3172
0
        bag = p12dcx->safeBags[p12dcx->iteration];
3173
0
        if (bag == NULL || bag->problem) {
3174
0
            continue;
3175
0
        }
3176
0
        p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
3177
0
        switch (p12dcx->decitem.type) {
3178
0
            case SEC_OID_PKCS12_V1_CERT_BAG_ID:
3179
0
                p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
3180
0
                p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
3181
0
                p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
3182
                /* if we don't understand the cert, or it's not parsable, skip it */
3183
                /* as per the comment above, friendlyName may be null legitimately */
3184
0
                if (!p12dcx->decitem.der) {
3185
0
                    p12dcx->decitem.type = 0; /* clear out the type we are ignoring */
3186
0
                    continue;
3187
0
                }
3188
0
                break;
3189
0
            case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
3190
0
                p12dcx->decitem.shroudAlg = PORT_ZNew(SECAlgorithmID);
3191
0
                if (p12dcx->decitem.shroudAlg) {
3192
0
                    SECOID_CopyAlgorithmID(NULL, p12dcx->decitem.shroudAlg,
3193
0
                                           &bag->safeBagContent.pkcs8ShroudedKeyBag->algorithm);
3194
0
                }
3195
            /* fall through */
3196
0
            case SEC_OID_PKCS12_V1_KEY_BAG_ID:
3197
0
                p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
3198
0
                break;
3199
0
            default:
3200
                /* return these even though we don't expect them */
3201
0
                break;
3202
0
            case SEC_OID_UNKNOWN:
3203
                /* ignore these */
3204
0
                p12dcx->decitem.type = 0; /* clear out the type we are ignoring */
3205
0
                continue;
3206
0
        }
3207
0
        *ipp = &p12dcx->decitem;
3208
0
        p12dcx->iteration++;
3209
0
        break; /* end for() */
3210
0
    }
3211
3212
0
    PORT_SetError(0); /* end-of-list is SECFailure with no PORT error */
3213
0
    return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
3214
0
}
3215
3216
static SECStatus
3217
sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
3218
                                         sec_PKCS12SafeBag *bag)
3219
0
{
3220
0
    if (!p12dcx || p12dcx->error) {
3221
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3222
0
        return SECFailure;
3223
0
    }
3224
3225
0
    p12dcx->safeBags = !p12dcx->safeBagCount
3226
0
                           ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
3227
0
                           : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
3228
0
                                                 sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
3229
0
                                                 p12dcx->safeBagCount + 2);
3230
3231
0
    if (!p12dcx->safeBags) {
3232
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3233
0
        return SECFailure;
3234
0
    }
3235
3236
0
    p12dcx->safeBags[p12dcx->safeBagCount] = bag;
3237
0
    p12dcx->safeBags[p12dcx->safeBagCount + 1] = NULL;
3238
0
    p12dcx->safeBagCount++;
3239
3240
0
    return SECSuccess;
3241
0
}
3242
3243
static sec_PKCS12SafeBag *
3244
sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx,
3245
                                   void *key, PRBool isEspvk)
3246
0
{
3247
0
    sec_PKCS12SafeBag *keyBag;
3248
0
    SECOidData *oid;
3249
0
    SECOidTag keyTag;
3250
0
    SECItem *keyID, *nickName, *newNickName;
3251
3252
0
    if (!p12dcx || p12dcx->error || !key) {
3253
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3254
0
        return NULL;
3255
0
    }
3256
3257
0
    newNickName = PORT_ArenaZNew(p12dcx->arena, SECItem);
3258
0
    keyBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
3259
0
    if (!keyBag || !newNickName) {
3260
0
        return NULL;
3261
0
    }
3262
3263
0
    keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
3264
0
    keyBag->slot = p12dcx->slot;
3265
0
    keyBag->arena = p12dcx->arena;
3266
0
    keyBag->pwitem = p12dcx->pwitem;
3267
0
    keyBag->tokenCAs = p12dcx->tokenCAs;
3268
0
    keyBag->oldBagType = PR_TRUE;
3269
3270
0
    keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID : SEC_OID_PKCS12_V1_KEY_BAG_ID;
3271
0
    oid = SECOID_FindOIDByTag(keyTag);
3272
0
    if (!oid) {
3273
0
        return NULL;
3274
0
    }
3275
3276
0
    if (SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid) != SECSuccess) {
3277
0
        return NULL;
3278
0
    }
3279
3280
0
    if (isEspvk) {
3281
0
        SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key;
3282
0
        keyBag->safeBagContent.pkcs8ShroudedKeyBag =
3283
0
            espvk->espvkCipherText.pkcs8KeyShroud;
3284
0
        nickName = &(espvk->espvkData.uniNickName);
3285
0
        if (!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) {
3286
0
            PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3287
0
            return NULL;
3288
0
        }
3289
0
        keyID = &espvk->espvkData.assocCerts[0]->digest;
3290
0
    } else {
3291
0
        SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key;
3292
0
        keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data;
3293
0
        nickName = &(pk->pvkData.uniNickName);
3294
0
        if (!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) {
3295
0
            PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3296
0
            return NULL;
3297
0
        }
3298
0
        keyID = &pk->pvkData.assocCerts[0]->digest;
3299
0
    }
3300
3301
0
    if (nickName->len) {
3302
0
        if (nickName->len >= 2) {
3303
0
            if (nickName->data[0] && nickName->data[1]) {
3304
0
                if (!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
3305
0
                                                        nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
3306
0
                    return NULL;
3307
0
                }
3308
0
                nickName = newNickName;
3309
0
            } else if (nickName->data[0] && !nickName->data[1]) {
3310
0
                unsigned int j = 0;
3311
0
                unsigned char t;
3312
0
                for (j = 0; j < nickName->len; j += 2) {
3313
0
                    t = nickName->data[j + 1];
3314
0
                    nickName->data[j + 1] = nickName->data[j];
3315
0
                    nickName->data[j] = t;
3316
0
                }
3317
0
            }
3318
0
        } else {
3319
0
            if (!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
3320
0
                                                    nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
3321
0
                return NULL;
3322
0
            }
3323
0
            nickName = newNickName;
3324
0
        }
3325
0
    }
3326
3327
0
    if (sec_pkcs12_decoder_set_attribute_value(keyBag,
3328
0
                                               SEC_OID_PKCS9_FRIENDLY_NAME,
3329
0
                                               nickName) != SECSuccess) {
3330
0
        return NULL;
3331
0
    }
3332
3333
0
    if (sec_pkcs12_decoder_set_attribute_value(keyBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
3334
0
                                               keyID) != SECSuccess) {
3335
0
        return NULL;
3336
0
    }
3337
3338
0
    return keyBag;
3339
0
}
3340
3341
static sec_PKCS12SafeBag *
3342
sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx,
3343
                               SECItem *derCert)
3344
0
{
3345
0
    sec_PKCS12SafeBag *certBag;
3346
0
    SECOidData *oid;
3347
0
    SGNDigestInfo *digest;
3348
0
    SECItem *keyId;
3349
0
    SECStatus rv;
3350
3351
0
    if (!p12dcx || p12dcx->error || !derCert) {
3352
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3353
0
        return NULL;
3354
0
    }
3355
3356
0
    keyId = PORT_ArenaZNew(p12dcx->arena, SECItem);
3357
0
    if (!keyId) {
3358
0
        return NULL;
3359
0
    }
3360
3361
0
    digest = sec_pkcs12_compute_thumbprint(derCert);
3362
0
    if (!digest) {
3363
0
        return NULL;
3364
0
    }
3365
3366
0
    rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest);
3367
0
    SGN_DestroyDigestInfo(digest);
3368
0
    if (rv != SECSuccess) {
3369
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3370
0
        return NULL;
3371
0
    }
3372
3373
0
    oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID);
3374
0
    certBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
3375
0
    if (!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena, &certBag->safeBagType, &oid->oid) != SECSuccess)) {
3376
0
        return NULL;
3377
0
    }
3378
3379
0
    certBag->slot = p12dcx->slot;
3380
0
    certBag->pwitem = p12dcx->pwitem;
3381
0
    certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
3382
0
    certBag->arena = p12dcx->arena;
3383
0
    certBag->tokenCAs = p12dcx->tokenCAs;
3384
3385
0
    oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT);
3386
0
    certBag->safeBagContent.certBag =
3387
0
        PORT_ArenaZNew(p12dcx->arena, sec_PKCS12CertBag);
3388
0
    if (!certBag->safeBagContent.certBag || !oid ||
3389
0
        (SECITEM_CopyItem(p12dcx->arena,
3390
0
                          &certBag->safeBagContent.certBag->bagID,
3391
0
                          &oid->oid) != SECSuccess)) {
3392
0
        return NULL;
3393
0
    }
3394
3395
0
    if (SECITEM_CopyItem(p12dcx->arena,
3396
0
                         &(certBag->safeBagContent.certBag->value.x509Cert),
3397
0
                         derCert) != SECSuccess) {
3398
0
        return NULL;
3399
0
    }
3400
3401
0
    if (sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
3402
0
                                               keyId) != SECSuccess) {
3403
0
        return NULL;
3404
0
    }
3405
3406
0
    return certBag;
3407
0
}
3408
3409
static sec_PKCS12SafeBag **
3410
sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx,
3411
                                    SEC_PKCS12CertAndCRL *oldCert)
3412
0
{
3413
0
    sec_PKCS12SafeBag **certList;
3414
0
    SECItem **derCertList;
3415
0
    int i, j;
3416
3417
0
    if (!p12dcx || p12dcx->error || !oldCert) {
3418
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3419
0
        return NULL;
3420
0
    }
3421
3422
0
    derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL);
3423
0
    if (!derCertList) {
3424
0
        return NULL;
3425
0
    }
3426
3427
0
    i = 0;
3428
0
    while (derCertList[i])
3429
0
        i++;
3430
3431
0
    certList = PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, (i + 1));
3432
0
    if (!certList) {
3433
0
        return NULL;
3434
0
    }
3435
3436
0
    for (j = 0; j < i; j++) {
3437
0
        certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]);
3438
0
        if (!certList[j]) {
3439
0
            return NULL;
3440
0
        }
3441
0
    }
3442
3443
0
    return certList;
3444
0
}
3445
3446
static SECStatus
3447
sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx,
3448
                                             void *oldKey, PRBool isEspvk,
3449
                                             SEC_PKCS12SafeContents *safe,
3450
                                             SEC_PKCS12Baggage *baggage)
3451
0
{
3452
0
    sec_PKCS12SafeBag *key, **certList;
3453
0
    SEC_PKCS12CertAndCRL *oldCert;
3454
0
    SEC_PKCS12PVKSupportingData *pvkData;
3455
0
    int i;
3456
0
    SECItem *keyName;
3457
3458
0
    if (!p12dcx || !oldKey) {
3459
0
        return SECFailure;
3460
0
    }
3461
3462
0
    if (isEspvk) {
3463
0
        pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData;
3464
0
    } else {
3465
0
        pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData;
3466
0
    }
3467
3468
0
    if (!pvkData->assocCerts || !pvkData->assocCerts[0]) {
3469
0
        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3470
0
        return SECFailure;
3471
0
    }
3472
3473
0
    oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
3474
0
                                                             SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL,
3475
0
                                                             pvkData->assocCerts[0]);
3476
0
    if (!oldCert) {
3477
0
        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3478
0
        return SECFailure;
3479
0
    }
3480
3481
0
    key = sec_pkcs12_decoder_convert_old_key(p12dcx, oldKey, isEspvk);
3482
0
    certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert);
3483
0
    if (!key || !certList) {
3484
0
        return SECFailure;
3485
0
    }
3486
3487
0
    if (sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) {
3488
0
        return SECFailure;
3489
0
    }
3490
3491
0
    keyName = sec_pkcs12_get_nickname(key);
3492
0
    if (!keyName) {
3493
0
        return SECFailure;
3494
0
    }
3495
3496
0
    i = 0;
3497
0
    while (certList[i]) {
3498
0
        if (sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i]) != SECSuccess) {
3499
0
            return SECFailure;
3500
0
        }
3501
0
        i++;
3502
0
    }
3503
3504
0
    certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key);
3505
0
    if (!certList) {
3506
0
        return SECFailure;
3507
0
    }
3508
3509
0
    i = 0;
3510
0
    while (certList[i] != 0) {
3511
0
        if (sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) {
3512
0
            return SECFailure;
3513
0
        }
3514
0
        i++;
3515
0
    }
3516
3517
0
    return SECSuccess;
3518
0
}
3519
3520
static SECStatus
3521
sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx,
3522
                                            SEC_PKCS12SafeContents *safe,
3523
                                            SEC_PKCS12Baggage *baggage)
3524
0
{
3525
0
    SECStatus rv;
3526
3527
0
    if (!p12dcx || p12dcx->error) {
3528
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3529
0
        return SECFailure;
3530
0
    }
3531
3532
0
    if (safe && safe->contents) {
3533
0
        int i = 0;
3534
0
        while (safe->contents[i] != NULL) {
3535
0
            if (SECOID_FindOIDTag(&safe->contents[i]->safeBagType) == SEC_OID_PKCS12_KEY_BAG_ID) {
3536
0
                int j = 0;
3537
0
                SEC_PKCS12PrivateKeyBag *privBag =
3538
0
                    safe->contents[i]->safeContent.keyBag;
3539
3540
0
                while (privBag->privateKeys[j] != NULL) {
3541
0
                    SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j];
3542
0
                    rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, pk,
3543
0
                                                                      PR_FALSE, safe, baggage);
3544
0
                    if (rv != SECSuccess) {
3545
0
                        goto loser;
3546
0
                    }
3547
0
                    j++;
3548
0
                }
3549
0
            }
3550
0
            i++;
3551
0
        }
3552
0
    }
3553
3554
0
    if (baggage && baggage->bags) {
3555
0
        int i = 0;
3556
0
        while (baggage->bags[i] != NULL) {
3557
0
            SEC_PKCS12BaggageItem *bag = baggage->bags[i];
3558
0
            int j = 0;
3559
3560
0
            if (!bag->espvks) {
3561
0
                i++;
3562
0
                continue;
3563
0
            }
3564
3565
0
            while (bag->espvks[j] != NULL) {
3566
0
                SEC_PKCS12ESPVKItem *espvk = bag->espvks[j];
3567
0
                rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk,
3568
0
                                                                  PR_TRUE, safe, baggage);
3569
0
                if (rv != SECSuccess) {
3570
0
                    goto loser;
3571
0
                }
3572
0
                j++;
3573
0
            }
3574
0
            i++;
3575
0
        }
3576
0
    }
3577
3578
0
    return SECSuccess;
3579
3580
0
loser:
3581
0
    return SECFailure;
3582
0
}
3583
3584
SEC_PKCS12DecoderContext *
3585
sec_PKCS12ConvertOldSafeToNew(PLArenaPool *arena, PK11SlotInfo *slot,
3586
                              PRBool swapUnicode, SECItem *pwitem,
3587
                              void *wincx, SEC_PKCS12SafeContents *safe,
3588
                              SEC_PKCS12Baggage *baggage)
3589
0
{
3590
0
    SEC_PKCS12DecoderContext *p12dcx;
3591
3592
0
    if (!arena || !slot || !pwitem) {
3593
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3594
0
        return NULL;
3595
0
    }
3596
3597
0
    if (!safe && !baggage) {
3598
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3599
0
        return NULL;
3600
0
    }
3601
3602
0
    p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
3603
0
    if (!p12dcx) {
3604
0
        return NULL;
3605
0
    }
3606
3607
0
    p12dcx->arena = arena;
3608
0
    p12dcx->slot = PK11_ReferenceSlot(slot);
3609
0
    p12dcx->wincx = wincx;
3610
0
    p12dcx->error = PR_FALSE;
3611
0
    p12dcx->swapUnicodeBytes = swapUnicode;
3612
0
    p12dcx->pwitem = pwitem;
3613
0
    p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
3614
3615
0
    if (sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage) != SECSuccess) {
3616
0
        p12dcx->error = PR_TRUE;
3617
0
        return NULL;
3618
0
    }
3619
3620
0
    return p12dcx;
3621
0
}