Coverage Report

Created: 2025-08-28 06:13

/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
            SEC_ASN1DecoderClearFilterProc(p12dcx->aSafeA1Dcx);
830
0
            p12dcx->currentASafeP7Dcx = NULL;
831
0
            if (!cinfo) {
832
0
                p12dcx->errorValue = PORT_GetError();
833
0
                goto loser;
834
0
            }
835
0
            SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
836
0
        }
837
0
    }
838
839
0
    return;
840
841
0
loser:
842
    /* set the error flag */
843
0
    p12dcx->error = PR_TRUE;
844
0
    return;
845
0
}
846
847
/* wrapper for updating asafes decoding context.  this function
848
 * writes data being decoded to disk, so that a mac can be computed
849
 * later.
850
 */
851
static void
852
sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf,
853
                                   unsigned long len)
854
0
{
855
0
    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
856
0
    SECStatus rv;
857
858
0
    if (!p12dcx || p12dcx->error) {
859
0
        return;
860
0
    }
861
862
    /* update the context */
863
0
    rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeA1Dcx, buf, len);
864
0
    if (rv != SECSuccess) {
865
0
        p12dcx->errorValue = PORT_GetError();
866
0
        p12dcx->error = PR_TRUE;
867
0
        goto loser;
868
0
    }
869
870
    /* if we are writing to a file, write out the new information */
871
0
    if (p12dcx->dWrite) {
872
0
        unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg,
873
0
                                                   (unsigned char *)buf, len);
874
0
        if (writeLen != len) {
875
0
            p12dcx->errorValue = PORT_GetError();
876
0
            goto loser;
877
0
        }
878
0
    }
879
880
0
    return;
881
882
0
loser:
883
    /* set the error flag */
884
0
    p12dcx->error = PR_TRUE;
885
0
    SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
886
0
    p12dcx->aSafeA1Dcx = NULL;
887
888
0
    return;
889
0
}
890
891
/* start the decode of an authenticatedSafe contentInfo.
892
 */
893
static SECStatus
894
sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx)
895
0
{
896
0
    if (!p12dcx || p12dcx->error) {
897
0
        return SECFailure;
898
0
    }
899
900
    /* start the decode context */
901
0
    p12dcx->aSafeA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena,
902
0
                                              &p12dcx->authSafe,
903
0
                                              sec_PKCS12AuthenticatedSafeTemplate);
904
0
    if (!p12dcx->aSafeA1Dcx) {
905
0
        p12dcx->errorValue = PORT_GetError();
906
0
        goto loser;
907
0
    }
908
909
    /* set the notify function */
910
0
    SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeA1Dcx,
911
0
                                 sec_pkcs12_decoder_asafes_notify, p12dcx);
912
913
    /* begin the authSafe decoder context */
914
0
    p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart(
915
0
        sec_pkcs12_decoder_asafes_callback, p12dcx,
916
0
        p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL);
917
0
    if (!p12dcx->aSafeP7Dcx) {
918
0
        p12dcx->errorValue = PORT_GetError();
919
0
        goto loser;
920
0
    }
921
922
    /* open the temp file for writing, if the digest functions were set */
923
0
    if (p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE) != SECSuccess) {
924
0
        p12dcx->errorValue = PORT_GetError();
925
0
        goto loser;
926
0
    }
927
    /* dOpen(dArg, PR_FALSE) creates the temp file */
928
0
    p12dcx->dIsOpen = PR_TRUE;
929
930
0
    return SECSuccess;
931
932
0
loser:
933
0
    p12dcx->error = PR_TRUE;
934
935
0
    if (p12dcx->aSafeA1Dcx) {
936
0
        SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
937
0
        p12dcx->aSafeA1Dcx = NULL;
938
0
    }
939
940
0
    if (p12dcx->aSafeP7Dcx) {
941
0
        SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
942
0
        p12dcx->aSafeP7Dcx = NULL;
943
0
    }
944
945
0
    return SECFailure;
946
0
}
947
948
/* wrapper for updating the safeContents.  this function is used as
949
 * a filter for the pfx when decoding the authenticated safes
950
 */
951
static void
952
sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf,
953
                                      unsigned long len, int depth,
954
                                      SEC_ASN1EncodingPart data_kind)
955
0
{
956
0
    SEC_PKCS12DecoderContext *p12dcx;
957
0
    SECStatus rv;
958
959
0
    p12dcx = (SEC_PKCS12DecoderContext *)arg;
960
0
    if (!p12dcx || p12dcx->error) {
961
0
        return;
962
0
    }
963
964
    /* update the safeContents decoder */
965
0
    rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len);
966
0
    if (rv != SECSuccess) {
967
0
        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
968
0
        goto loser;
969
0
    }
970
971
0
    return;
972
973
0
loser:
974
975
    /* did we find an error?  if so, close the context and set the
976
     * error flag.
977
     */
978
0
    SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
979
0
    p12dcx->aSafeP7Dcx = NULL;
980
0
    p12dcx->error = PR_TRUE;
981
0
}
982
983
/* notify procedure used while decoding the pfx.  When we encounter
984
 * the authSafes, we want to trigger the decoding of authSafes as well
985
 * as when we encounter the macData, trigger the decoding of it.  we do
986
 * this because we we are streaming the decoder and not decoding in place.
987
 * the pfx which is the destination, only has the version decoded into it.
988
 */
989
static void
990
sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest,
991
                                   int real_depth)
992
0
{
993
0
    SECStatus rv;
994
0
    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
995
996
    /* if an error occurs, clear the notifyProc and the filterProc
997
     * and continue.
998
     */
999
0
    if (p12dcx->error) {
1000
0
        SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxA1Dcx);
1001
0
        SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
1002
0
        return;
1003
0
    }
1004
1005
0
    if (before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
1006
1007
        /* we want to make sure this is a version we support */
1008
0
        if (!sec_pkcs12_proper_version(&p12dcx->pfx)) {
1009
0
            p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
1010
0
            goto loser;
1011
0
        }
1012
1013
        /* start the decode of the aSafes cinfo... */
1014
0
        rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx);
1015
0
        if (rv != SECSuccess) {
1016
0
            goto loser;
1017
0
        }
1018
1019
        /* set the filter proc to update the authenticated safes. */
1020
0
        SEC_ASN1DecoderSetFilterProc(p12dcx->pfxA1Dcx,
1021
0
                                     sec_pkcs12_decode_asafes_cinfo_update,
1022
0
                                     p12dcx, PR_TRUE);
1023
0
    }
1024
1025
0
    if (!before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
1026
1027
        /* we are done decoding the authenticatedSafes, so we need to
1028
         * finish the decoderContext and clear the filter proc
1029
         * and close the hmac callback, if present
1030
         */
1031
0
        p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
1032
0
        p12dcx->aSafeP7Dcx = NULL;
1033
0
        if (!p12dcx->aSafeCinfo) {
1034
0
            p12dcx->errorValue = PORT_GetError();
1035
0
            goto loser;
1036
0
        }
1037
0
        SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
1038
0
        if (p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) != SECSuccess)) {
1039
0
            p12dcx->errorValue = PORT_GetError();
1040
0
            goto loser;
1041
0
        }
1042
0
    }
1043
1044
0
    return;
1045
1046
0
loser:
1047
0
    p12dcx->error = PR_TRUE;
1048
0
}
1049
1050
/*  default implementations of the open/close/read/write functions for
1051
    SEC_PKCS12DecoderStart
1052
*/
1053
1054
0
#define DEFAULT_TEMP_SIZE 4096
1055
1056
static SECStatus
1057
p12u_DigestOpen(void *arg, PRBool readData)
1058
0
{
1059
0
    SEC_PKCS12DecoderContext *p12cxt = arg;
1060
1061
0
    p12cxt->currentpos = 0;
1062
1063
0
    if (PR_FALSE == readData) {
1064
        /* allocate an initial buffer */
1065
0
        p12cxt->filesize = 0;
1066
0
        p12cxt->allocated = DEFAULT_TEMP_SIZE;
1067
0
        p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE);
1068
0
        PR_ASSERT(p12cxt->buffer);
1069
0
    } else {
1070
0
        PR_ASSERT(p12cxt->buffer);
1071
0
        if (!p12cxt->buffer) {
1072
0
            return SECFailure; /* no data to read */
1073
0
        }
1074
0
    }
1075
1076
0
    return SECSuccess;
1077
0
}
1078
1079
static SECStatus
1080
p12u_DigestClose(void *arg, PRBool removeFile)
1081
0
{
1082
0
    SEC_PKCS12DecoderContext *p12cxt = arg;
1083
1084
0
    PR_ASSERT(p12cxt);
1085
0
    if (!p12cxt) {
1086
0
        return SECFailure;
1087
0
    }
1088
0
    p12cxt->currentpos = 0;
1089
1090
0
    if (PR_TRUE == removeFile) {
1091
0
        PR_ASSERT(p12cxt->buffer);
1092
0
        if (!p12cxt->buffer) {
1093
0
            return SECFailure;
1094
0
        }
1095
0
        if (p12cxt->buffer) {
1096
0
            PORT_Free(p12cxt->buffer);
1097
0
            p12cxt->buffer = NULL;
1098
0
            p12cxt->allocated = 0;
1099
0
            p12cxt->filesize = 0;
1100
0
        }
1101
0
    }
1102
1103
0
    return SECSuccess;
1104
0
}
1105
1106
static int
1107
p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
1108
0
{
1109
0
    int toread = len;
1110
0
    SEC_PKCS12DecoderContext *p12cxt = arg;
1111
1112
0
    if (!buf || len == 0 || !p12cxt->buffer) {
1113
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1114
0
        return -1;
1115
0
    }
1116
1117
0
    if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
1118
        /* trying to read past the end of the buffer */
1119
0
        toread = p12cxt->filesize - p12cxt->currentpos;
1120
0
    }
1121
0
    memcpy(buf, (char *)p12cxt->buffer + p12cxt->currentpos, toread);
1122
0
    p12cxt->currentpos += toread;
1123
0
    return toread;
1124
0
}
1125
1126
static int
1127
p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
1128
0
{
1129
0
    SEC_PKCS12DecoderContext *p12cxt = arg;
1130
1131
0
    if (!buf || len == 0) {
1132
0
        return -1;
1133
0
    }
1134
1135
0
    if (p12cxt->currentpos + (long)len > p12cxt->filesize) {
1136
0
        p12cxt->filesize = p12cxt->currentpos + len;
1137
0
    } else {
1138
0
        p12cxt->filesize += len;
1139
0
    }
1140
0
    if (p12cxt->filesize > p12cxt->allocated) {
1141
0
        void *newbuffer;
1142
0
        size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE;
1143
0
        newbuffer = PORT_Realloc(p12cxt->buffer, newsize);
1144
0
        if (NULL == newbuffer) {
1145
0
            return -1; /* can't extend the buffer */
1146
0
        }
1147
0
        p12cxt->buffer = newbuffer;
1148
0
        p12cxt->allocated = newsize;
1149
0
    }
1150
0
    PR_ASSERT(p12cxt->buffer);
1151
0
    memcpy((char *)p12cxt->buffer + p12cxt->currentpos, buf, len);
1152
0
    p12cxt->currentpos += len;
1153
0
    return len;
1154
0
}
1155
1156
/* SEC_PKCS12DecoderStart
1157
 *      Creates a decoder context for decoding a PKCS 12 PDU objct.
1158
 *      This function sets up the initial decoding context for the
1159
 *      PFX and sets the needed state variables.
1160
 *
1161
 *      pwitem - the password for the hMac and any encoded safes.
1162
 *               this should be changed to take a callback which retrieves
1163
 *               the password.  it may be possible for different safes to
1164
 *               have different passwords.  also, the password is already
1165
 *               in unicode.  it should probably be converted down below via
1166
 *               a unicode conversion callback.
1167
 *      slot - the slot to import the dataa into should multiple slots
1168
 *               be supported based on key type and cert type?
1169
 *      dOpen, dClose, dRead, dWrite - digest routines for writing data
1170
 *               to a file so it could be read back and the hmac recomputed
1171
 *               and verified.  doesn't seem to be a way for both encoding
1172
 *               and decoding to be single pass, thus the need for these
1173
 *               routines.
1174
 *      dArg - the argument for dOpen, etc.
1175
 *
1176
 *      if NULL == dOpen == dClose == dRead == dWrite == dArg, then default
1177
 *      implementations using a memory buffer are used
1178
 *
1179
 *      This function returns the decoder context, if it was successful.
1180
 *      Otherwise, null is returned.
1181
 */
1182
SEC_PKCS12DecoderContext *
1183
SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
1184
                       digestOpenFn dOpen, digestCloseFn dClose,
1185
                       digestIOFn dRead, digestIOFn dWrite, void *dArg)
1186
0
{
1187
0
    SEC_PKCS12DecoderContext *p12dcx;
1188
0
    PLArenaPool *arena;
1189
0
    PRInt32 forceUnicode = PR_FALSE;
1190
0
    SECStatus rv;
1191
1192
0
    arena = PORT_NewArena(2048); /* different size? */
1193
0
    if (!arena) {
1194
0
        return NULL; /* error is already set */
1195
0
    }
1196
1197
    /* allocate the decoder context and set the state variables */
1198
0
    p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
1199
0
    if (!p12dcx) {
1200
0
        goto loser; /* error is already set */
1201
0
    }
1202
1203
0
    if (!dOpen && !dClose && !dRead && !dWrite && !dArg) {
1204
        /* use default implementations */
1205
0
        dOpen = p12u_DigestOpen;
1206
0
        dClose = p12u_DigestClose;
1207
0
        dRead = p12u_DigestRead;
1208
0
        dWrite = p12u_DigestWrite;
1209
0
        dArg = (void *)p12dcx;
1210
0
    }
1211
1212
0
    p12dcx->arena = arena;
1213
0
    p12dcx->pwitem = pwitem;
1214
0
    p12dcx->slot = (slot ? PK11_ReferenceSlot(slot)
1215
0
                         : PK11_GetInternalKeySlot());
1216
0
    p12dcx->wincx = wincx;
1217
0
    p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
1218
0
#ifdef IS_LITTLE_ENDIAN
1219
0
    p12dcx->swapUnicodeBytes = PR_TRUE;
1220
#else
1221
    p12dcx->swapUnicodeBytes = PR_FALSE;
1222
#endif
1223
0
    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
1224
0
    if (rv != SECSuccess) {
1225
0
        goto loser;
1226
0
    }
1227
0
    p12dcx->forceUnicode = forceUnicode;
1228
0
    p12dcx->errorValue = 0;
1229
0
    p12dcx->error = PR_FALSE;
1230
1231
    /* start the decoding of the PFX and set the notify proc
1232
     * for the PFX item.
1233
     */
1234
0
    p12dcx->pfxA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx,
1235
0
                                            sec_PKCS12PFXItemTemplate);
1236
0
    if (!p12dcx->pfxA1Dcx) {
1237
0
        PK11_FreeSlot(p12dcx->slot);
1238
0
        goto loser;
1239
0
    }
1240
1241
0
    SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxA1Dcx,
1242
0
                                 sec_pkcs12_decoder_pfx_notify_proc,
1243
0
                                 p12dcx);
1244
1245
    /* set up digest functions */
1246
0
    p12dcx->dOpen = dOpen;
1247
0
    p12dcx->dWrite = dWrite;
1248
0
    p12dcx->dClose = dClose;
1249
0
    p12dcx->dRead = dRead;
1250
0
    p12dcx->dArg = dArg;
1251
0
    p12dcx->dIsOpen = PR_FALSE;
1252
1253
0
    p12dcx->keyList = NULL;
1254
0
    p12dcx->decitem.type = 0;
1255
0
    p12dcx->decitem.der = NULL;
1256
0
    p12dcx->decitem.hasKey = PR_FALSE;
1257
0
    p12dcx->decitem.friendlyName = NULL;
1258
0
    p12dcx->iteration = 0;
1259
1260
0
    return p12dcx;
1261
1262
0
loser:
1263
0
    PORT_FreeArena(arena, PR_TRUE);
1264
0
    return NULL;
1265
0
}
1266
1267
SECStatus
1268
SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx,
1269
                                   SECPKCS12TargetTokenCAs tokenCAs)
1270
0
{
1271
0
    if (!p12dcx || p12dcx->error) {
1272
0
        return SECFailure;
1273
0
    }
1274
0
    p12dcx->tokenCAs = tokenCAs;
1275
0
    return SECSuccess;
1276
0
}
1277
1278
/* SEC_PKCS12DecoderUpdate
1279
 *      Streaming update sending more data to the decoder.  If
1280
 *      an error occurs, SECFailure is returned.
1281
 *
1282
 *      p12dcx - the decoder context
1283
 *      data, len - the data buffer and length of data to send to
1284
 *              the update functions.
1285
 */
1286
SECStatus
1287
SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx,
1288
                        unsigned char *data, unsigned long len)
1289
0
{
1290
0
    SECStatus rv;
1291
1292
0
    if (!p12dcx || p12dcx->error) {
1293
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1294
0
        return SECFailure;
1295
0
    }
1296
1297
    /* update the PFX decoder context */
1298
0
    rv = SEC_ASN1DecoderUpdate(p12dcx->pfxA1Dcx, (const char *)data, len);
1299
0
    if (rv != SECSuccess) {
1300
0
        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
1301
0
        goto loser;
1302
0
    }
1303
1304
0
    return SECSuccess;
1305
1306
0
loser:
1307
1308
0
    p12dcx->error = PR_TRUE;
1309
0
    return SECFailure;
1310
0
}
1311
1312
/* This should be a nice sized buffer for reading in data (potentially large
1313
** amounts) to be MACed.  It should be MUCH larger than HASH_LENGTH_MAX.
1314
*/
1315
0
#define IN_BUF_LEN 1024
1316
#ifdef DEBUG
1317
static const char bufferEnd[] = { "BufferEnd" };
1318
#endif
1319
0
#define FUDGE 128 /* must be as large as bufferEnd or more. */
1320
1321
/* verify the hmac by reading the data from the temporary file
1322
 * using the routines specified when the decodingContext was
1323
 * created and return SECSuccess if the hmac matches.
1324
 */
1325
static SECStatus
1326
sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
1327
0
{
1328
0
    PK11Context *pk11cx = NULL;
1329
0
    PK11SymKey *symKey = NULL;
1330
0
    unsigned char *buf;
1331
0
    SECStatus rv = SECFailure;
1332
0
    SECStatus lrv;
1333
0
    unsigned int bufLen;
1334
0
    int bytesRead;
1335
0
    SECItem hmacRes;
1336
0
    SECItem ignore = { 0 };
1337
0
    CK_MECHANISM_TYPE hmacMech;
1338
1339
0
    if (!p12dcx || p12dcx->error) {
1340
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1341
0
        return SECFailure;
1342
0
    }
1343
0
    buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE);
1344
0
    if (!buf)
1345
0
        return SECFailure; /* error code has been set. */
1346
1347
0
#ifdef DEBUG
1348
0
    memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd);
1349
0
#endif
1350
1351
    /* generate hmac key */
1352
0
    symKey = sec_pkcs12_integrity_key(p12dcx->slot, &p12dcx->macData,
1353
0
                                      p12dcx->pwitem, &hmacMech, PR_TRUE,
1354
0
                                      p12dcx->wincx);
1355
0
    if (symKey == NULL) {
1356
0
        goto loser;
1357
0
    }
1358
1359
    /* init hmac */
1360
0
    pk11cx = PK11_CreateContextBySymKey(hmacMech, CKA_SIGN, symKey, &ignore);
1361
0
    if (!pk11cx) {
1362
0
        goto loser;
1363
0
    }
1364
0
    lrv = PK11_DigestBegin(pk11cx);
1365
0
    if (lrv == SECFailure) {
1366
0
        goto loser;
1367
0
    }
1368
1369
    /* try to open the data for readback */
1370
0
    if (p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) != SECSuccess)) {
1371
0
        goto loser;
1372
0
    }
1373
1374
    /* read the data back IN_BUF_LEN bytes at a time and recompute
1375
     * the hmac.  if fewer bytes are read than are requested, it is
1376
     * assumed that the end of file has been reached. if bytesRead
1377
     * is returned as -1, then an error occurred reading from the
1378
     * file.
1379
     */
1380
0
    do {
1381
0
        bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN);
1382
0
        if (bytesRead < 0) {
1383
0
            PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ);
1384
0
            goto loser;
1385
0
        }
1386
0
        PORT_Assert(bytesRead <= IN_BUF_LEN);
1387
0
        PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd));
1388
1389
0
        if (bytesRead > IN_BUF_LEN) {
1390
            /* dRead callback overflowed buffer. */
1391
0
            PORT_SetError(SEC_ERROR_INPUT_LEN);
1392
0
            goto loser;
1393
0
        }
1394
1395
0
        if (bytesRead) {
1396
0
            lrv = PK11_DigestOp(pk11cx, buf, bytesRead);
1397
0
            if (lrv == SECFailure) {
1398
0
                goto loser;
1399
0
            }
1400
0
        }
1401
0
    } while (bytesRead == IN_BUF_LEN);
1402
1403
    /* finish the hmac context */
1404
0
    lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN);
1405
0
    if (lrv == SECFailure) {
1406
0
        goto loser;
1407
0
    }
1408
1409
0
    hmacRes.data = buf;
1410
0
    hmacRes.len = bufLen;
1411
1412
    /* is the hmac computed the same as the hmac which was decoded? */
1413
0
    rv = SECSuccess;
1414
0
    if (SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) != SECEqual) {
1415
0
        PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
1416
0
        rv = SECFailure;
1417
0
    }
1418
1419
0
loser:
1420
    /* close the file and remove it */
1421
0
    if (p12dcx->dClose) {
1422
0
        (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
1423
0
        p12dcx->dIsOpen = PR_FALSE;
1424
0
    }
1425
1426
0
    if (pk11cx) {
1427
0
        PK11_DestroyContext(pk11cx, PR_TRUE);
1428
0
    }
1429
0
    if (symKey) {
1430
0
        PK11_FreeSymKey(symKey);
1431
0
    }
1432
0
    PORT_ZFree(buf, IN_BUF_LEN + FUDGE);
1433
1434
0
    return rv;
1435
0
}
1436
1437
/* SEC_PKCS12DecoderVerify
1438
 *      Verify the macData or the signature of the decoded PKCS 12 PDU.
1439
 *      If the signature or the macData do not match, SECFailure is
1440
 *      returned.
1441
 *
1442
 *      p12dcx - the decoder context
1443
 */
1444
SECStatus
1445
SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx)
1446
0
{
1447
0
    SECStatus rv = SECSuccess;
1448
1449
    /* make sure that no errors have occurred... */
1450
0
    if (!p12dcx) {
1451
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1452
0
        return SECFailure;
1453
0
    }
1454
0
    if (p12dcx->error) {
1455
        /* error code is already set! PORT_SetError(p12dcx->errorValue); */
1456
0
        return SECFailure;
1457
0
    }
1458
1459
0
    rv = SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
1460
0
    p12dcx->pfxA1Dcx = NULL;
1461
0
    if (rv != SECSuccess) {
1462
0
        return rv;
1463
0
    }
1464
1465
    /* check the signature or the mac depending on the type of
1466
     * integrity used.
1467
     */
1468
0
    if (p12dcx->pfx.encodedMacData.len) {
1469
0
        rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData,
1470
0
                                sec_PKCS12MacDataTemplate,
1471
0
                                &p12dcx->pfx.encodedMacData);
1472
0
        if (rv == SECSuccess) {
1473
0
            return sec_pkcs12_decoder_verify_mac(p12dcx);
1474
0
        }
1475
0
        return rv;
1476
0
    }
1477
0
    if (SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner,
1478
0
                                 PR_FALSE)) {
1479
0
        return SECSuccess;
1480
0
    }
1481
0
    PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
1482
0
    return SECFailure;
1483
0
}
1484
1485
/* SEC_PKCS12DecoderFinish
1486
 *      Free any open ASN1 or PKCS7 decoder contexts and then
1487
 *      free the arena pool which everything should be allocated
1488
 *      from.  This function should be called upon completion of
1489
 *      decoding and installing of a pfx pdu.  This should be
1490
 *      called even if an error occurs.
1491
 *
1492
 *      p12dcx - the decoder context
1493
 */
1494
void
1495
SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
1496
0
{
1497
0
    unsigned int i;
1498
1499
0
    if (!p12dcx) {
1500
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1501
0
        return;
1502
0
    }
1503
1504
0
    if (p12dcx->pfxA1Dcx) {
1505
0
        SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
1506
0
        p12dcx->pfxA1Dcx = NULL;
1507
0
    }
1508
1509
0
    if (p12dcx->aSafeA1Dcx) {
1510
0
        SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
1511
0
        p12dcx->aSafeA1Dcx = NULL;
1512
0
    }
1513
1514
    /* cleanup any old ASN1 decoder contexts */
1515
0
    for (i = 0; i < p12dcx->safeContentsCnt; ++i) {
1516
0
        sec_PKCS12SafeContentsContext *safeContentsCtx, *nested;
1517
0
        safeContentsCtx = p12dcx->safeContentsList[i];
1518
0
        if (safeContentsCtx) {
1519
0
            nested = safeContentsCtx->nestedSafeContentsCtx;
1520
0
            while (nested) {
1521
0
                if (nested->safeContentsA1Dcx) {
1522
0
                    SEC_ASN1DecoderFinish(nested->safeContentsA1Dcx);
1523
0
                    nested->safeContentsA1Dcx = NULL;
1524
0
                }
1525
0
                nested = nested->nestedSafeContentsCtx;
1526
0
            }
1527
0
            if (safeContentsCtx->safeContentsA1Dcx) {
1528
0
                SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
1529
0
                safeContentsCtx->safeContentsA1Dcx = NULL;
1530
0
            }
1531
0
        }
1532
0
    }
1533
1534
0
    if (p12dcx->currentASafeP7Dcx &&
1535
0
        p12dcx->currentASafeP7Dcx != p12dcx->aSafeP7Dcx) {
1536
0
        SEC_PKCS7ContentInfo *cinfo;
1537
0
        cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
1538
0
        if (cinfo) {
1539
0
            SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
1540
0
        }
1541
0
    }
1542
0
    p12dcx->currentASafeP7Dcx = NULL;
1543
1544
0
    if (p12dcx->aSafeP7Dcx) {
1545
0
        SEC_PKCS7ContentInfo *cinfo;
1546
0
        cinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
1547
0
        if (cinfo) {
1548
0
            SEC_PKCS7DestroyContentInfo(cinfo);
1549
0
        }
1550
0
        p12dcx->aSafeP7Dcx = NULL;
1551
0
    }
1552
1553
0
    if (p12dcx->aSafeCinfo) {
1554
0
        SEC_PKCS7DestroyContentInfo(p12dcx->aSafeCinfo);
1555
0
        p12dcx->aSafeCinfo = NULL;
1556
0
    }
1557
1558
0
    if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
1559
0
        SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
1560
0
    }
1561
0
    if (p12dcx->decitem.friendlyName != NULL) {
1562
0
        SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
1563
0
    }
1564
1565
0
    if (p12dcx->slot) {
1566
0
        PK11_FreeSlot(p12dcx->slot);
1567
0
        p12dcx->slot = NULL;
1568
0
    }
1569
1570
0
    if (p12dcx->dIsOpen && p12dcx->dClose) {
1571
0
        (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
1572
0
        p12dcx->dIsOpen = PR_FALSE;
1573
0
    }
1574
1575
0
    if (p12dcx->arena) {
1576
0
        PORT_FreeArena(p12dcx->arena, PR_TRUE);
1577
0
    }
1578
0
}
1579
1580
static SECStatus
1581
sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag,
1582
                                       SECOidTag attributeType,
1583
                                       SECItem *attrValue)
1584
0
{
1585
0
    int i = 0;
1586
0
    SECOidData *oid;
1587
1588
0
    if (!bag || !attrValue) {
1589
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1590
0
        return SECFailure;
1591
0
    }
1592
1593
0
    oid = SECOID_FindOIDByTag(attributeType);
1594
0
    if (!oid) {
1595
0
        return SECFailure;
1596
0
    }
1597
1598
0
    if (!bag->attribs) {
1599
0
        bag->attribs =
1600
0
            PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
1601
0
    } else {
1602
0
        while (bag->attribs[i])
1603
0
            i++;
1604
0
        bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
1605
0
                                           sec_PKCS12Attribute *, i + 1, i + 2);
1606
0
    }
1607
1608
0
    if (!bag->attribs) {
1609
0
        return SECFailure;
1610
0
    }
1611
1612
0
    bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1613
0
    if (!bag->attribs[i]) {
1614
0
        return SECFailure;
1615
0
    }
1616
1617
0
    bag->attribs[i]->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
1618
0
    if (!bag->attribs[i]->attrValue) {
1619
0
        return SECFailure;
1620
0
    }
1621
1622
0
    bag->attribs[i + 1] = NULL;
1623
0
    bag->attribs[i]->attrValue[0] = attrValue;
1624
0
    bag->attribs[i]->attrValue[1] = NULL;
1625
1626
0
    return SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid);
1627
0
}
1628
1629
static SECItem *
1630
sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag,
1631
                               SECOidTag attributeType)
1632
0
{
1633
0
    int i;
1634
1635
0
    if (!bag->attribs) {
1636
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1637
0
        return NULL;
1638
0
    }
1639
1640
0
    for (i = 0; bag->attribs[i] != NULL; i++) {
1641
0
        if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == attributeType) {
1642
0
            return bag->attribs[i]->attrValue[0];
1643
0
        }
1644
0
    }
1645
0
    return NULL;
1646
0
}
1647
1648
/* For now, this function will merely remove any ":"
1649
 * in the nickname which the PK11 functions may have
1650
 * placed there.  This will keep dual certs from appearing
1651
 * twice under "Your" certificates when imported onto smart
1652
 * cards.  Once with the name "Slot:Cert" and another with
1653
 * the nickname "Slot:Slot:Cert"
1654
 */
1655
static void
1656
sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
1657
0
{
1658
0
    char *nickname;
1659
0
    char *delimit;
1660
0
    int delimitlen;
1661
1662
0
    nickname = (char *)nick->data;
1663
0
    if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
1664
0
        char *slotName;
1665
0
        int slotNameLen;
1666
1667
0
        slotNameLen = delimit - nickname;
1668
0
        slotName = PORT_NewArray(char, (slotNameLen + 1));
1669
0
        PORT_Assert(slotName);
1670
0
        if (slotName == NULL) {
1671
            /* What else can we do?*/
1672
0
            return;
1673
0
        }
1674
0
        PORT_Memcpy(slotName, nickname, slotNameLen);
1675
0
        slotName[slotNameLen] = '\0';
1676
0
        if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
1677
0
            delimitlen = PORT_Strlen(delimit + 1);
1678
0
            PORT_Memmove(nickname, delimit + 1, delimitlen + 1);
1679
0
            nick->len = delimitlen;
1680
0
        }
1681
0
        PORT_Free(slotName);
1682
0
    }
1683
0
}
1684
1685
static SECItem *
1686
sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag)
1687
0
{
1688
0
    SECItem *src, *dest;
1689
1690
0
    if (!bag) {
1691
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1692
0
        return NULL;
1693
0
    }
1694
1695
0
    src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
1696
1697
    /* The return value src is 16-bit Unicode characters, in big-endian format.
1698
     * Check if it is NULL or empty name.
1699
     */
1700
0
    if (!src || !src->data || src->len < 2 || (!src->data[0] && !src->data[1])) {
1701
0
        return NULL;
1702
0
    }
1703
1704
0
    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1705
0
    if (!dest) {
1706
0
        goto loser;
1707
0
    }
1708
0
    if (!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE,
1709
0
                                            PR_FALSE, PR_FALSE)) {
1710
0
        goto loser;
1711
0
    }
1712
1713
0
    sec_pkcs12_sanitize_nickname(bag->slot, dest);
1714
1715
0
    return dest;
1716
1717
0
loser:
1718
0
    if (dest) {
1719
0
        SECITEM_ZfreeItem(dest, PR_TRUE);
1720
0
    }
1721
1722
0
    bag->problem = PR_TRUE;
1723
0
    bag->error = PORT_GetError();
1724
0
    return NULL;
1725
0
}
1726
1727
static SECStatus
1728
sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name)
1729
0
{
1730
0
    sec_PKCS12Attribute *attr = NULL;
1731
0
    SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME);
1732
1733
0
    if (!bag || !bag->arena || !name) {
1734
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1735
0
        return SECFailure;
1736
0
    }
1737
1738
0
    if (!bag->attribs) {
1739
0
        if (!oid) {
1740
0
            goto loser;
1741
0
        }
1742
1743
0
        bag->attribs =
1744
0
            PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
1745
0
        if (!bag->attribs) {
1746
0
            goto loser;
1747
0
        }
1748
0
        bag->attribs[0] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1749
0
        if (!bag->attribs[0]) {
1750
0
            goto loser;
1751
0
        }
1752
0
        bag->attribs[1] = NULL;
1753
1754
0
        attr = bag->attribs[0];
1755
0
        if (SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) != SECSuccess) {
1756
0
            goto loser;
1757
0
        }
1758
0
    } else {
1759
0
        int i;
1760
0
        for (i = 0; bag->attribs[i]; i++) {
1761
0
            if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == SEC_OID_PKCS9_FRIENDLY_NAME) {
1762
0
                attr = bag->attribs[i];
1763
0
                break;
1764
0
            }
1765
0
        }
1766
0
        if (!attr) {
1767
0
            if (!oid) {
1768
0
                goto loser;
1769
0
            }
1770
0
            bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
1771
0
                                               sec_PKCS12Attribute *, i + 1, i + 2);
1772
0
            if (!bag->attribs) {
1773
0
                goto loser;
1774
0
            }
1775
0
            bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
1776
0
            if (!bag->attribs[i]) {
1777
0
                goto loser;
1778
0
            }
1779
0
            bag->attribs[i + 1] = NULL;
1780
0
            attr = bag->attribs[i];
1781
0
            if (SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) != SECSuccess) {
1782
0
                goto loser;
1783
0
            }
1784
0
        }
1785
0
    }
1786
1787
0
    PORT_Assert(attr);
1788
0
    if (!attr->attrValue) {
1789
0
        attr->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
1790
0
        if (!attr->attrValue) {
1791
0
            goto loser;
1792
0
        }
1793
0
        attr->attrValue[0] = PORT_ArenaZNew(bag->arena, SECItem);
1794
0
        if (!attr->attrValue[0]) {
1795
0
            goto loser;
1796
0
        }
1797
0
        attr->attrValue[1] = NULL;
1798
0
    }
1799
1800
0
    name->len = PORT_Strlen((char *)name->data);
1801
0
    if (!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0],
1802
0
                                            name, PR_FALSE, PR_FALSE, PR_TRUE)) {
1803
0
        goto loser;
1804
0
    }
1805
1806
0
    return SECSuccess;
1807
1808
0
loser:
1809
0
    bag->problem = PR_TRUE;
1810
0
    bag->error = PORT_GetError();
1811
0
    return SECFailure;
1812
0
}
1813
1814
static SECStatus
1815
sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key)
1816
0
{
1817
0
    int i = 0;
1818
0
    SECKEYPrivateKeyInfo *pki = NULL;
1819
1820
0
    if (!key) {
1821
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1822
0
        return SECFailure;
1823
0
    }
1824
1825
    /* if the bag does *not* contain an unencrypted PrivateKeyInfo
1826
     * then we cannot convert the attributes.  We are propagating
1827
     * attributes within the PrivateKeyInfo to the SafeBag level.
1828
     */
1829
0
    if (SECOID_FindOIDTag(&(key->safeBagType)) !=
1830
0
        SEC_OID_PKCS12_V1_KEY_BAG_ID) {
1831
0
        return SECSuccess;
1832
0
    }
1833
1834
0
    pki = key->safeBagContent.pkcs8KeyBag;
1835
1836
0
    if (!pki || !pki->attributes) {
1837
0
        return SECSuccess;
1838
0
    }
1839
1840
0
    while (pki->attributes[i]) {
1841
0
        SECOidTag tag = SECOID_FindOIDTag(&pki->attributes[i]->attrType);
1842
1843
0
        if (tag == SEC_OID_PKCS9_LOCAL_KEY_ID ||
1844
0
            tag == SEC_OID_PKCS9_FRIENDLY_NAME) {
1845
0
            SECItem *attrValue = sec_pkcs12_get_attribute_value(key, tag);
1846
0
            if (!attrValue) {
1847
0
                if (sec_pkcs12_decoder_set_attribute_value(key, tag,
1848
0
                                                           pki->attributes[i]->attrValue[0]) != SECSuccess) {
1849
0
                    key->problem = PR_TRUE;
1850
0
                    key->error = PORT_GetError();
1851
0
                    return SECFailure;
1852
0
                }
1853
0
            }
1854
0
        }
1855
0
        i++;
1856
0
    }
1857
1858
0
    return SECSuccess;
1859
0
}
1860
1861
/* retrieve the nickname for the certificate bag.  first look
1862
 * in the cert bag, otherwise get it from the key.
1863
 */
1864
static SECItem *
1865
sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert,
1866
                                 sec_PKCS12SafeBag *key)
1867
0
{
1868
0
    SECItem *nickname;
1869
1870
0
    if (!cert) {
1871
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1872
0
        return NULL;
1873
0
    }
1874
1875
0
    nickname = sec_pkcs12_get_nickname(cert);
1876
0
    if (nickname) {
1877
0
        return nickname;
1878
0
    }
1879
1880
0
    if (key) {
1881
0
        nickname = sec_pkcs12_get_nickname(key);
1882
1883
0
        if (nickname && sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
1884
0
            SECITEM_ZfreeItem(nickname, PR_TRUE);
1885
0
            return NULL;
1886
0
        }
1887
0
    }
1888
1889
0
    return nickname;
1890
0
}
1891
1892
/* set the nickname for the certificate */
1893
static SECStatus
1894
sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert,
1895
                                 sec_PKCS12SafeBag *key,
1896
                                 SECItem *nickname)
1897
0
{
1898
0
    if (!nickname || !cert) {
1899
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1900
0
        return SECFailure;
1901
0
    }
1902
1903
0
    if (sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
1904
0
        return SECFailure;
1905
0
    }
1906
1907
0
    if (key) {
1908
0
        if (sec_pkcs12_set_nickname(key, nickname) != SECSuccess) {
1909
0
            cert->problem = PR_TRUE;
1910
0
            cert->error = key->error;
1911
0
            return SECFailure;
1912
0
        }
1913
0
    }
1914
1915
0
    return SECSuccess;
1916
0
}
1917
1918
/* retrieve the DER cert from the cert bag */
1919
static SECItem *
1920
sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert)
1921
0
{
1922
0
    if (!cert || !cert->safeBagContent.certBag) {
1923
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1924
0
        return NULL;
1925
0
    }
1926
1927
0
    if (SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) {
1928
0
        return NULL;
1929
0
    }
1930
1931
    /* only support X509 certs not SDSI */
1932
0
    if (SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID) != SEC_OID_PKCS9_X509_CERT) {
1933
0
        return NULL;
1934
0
    }
1935
1936
0
    return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert));
1937
0
}
1938
1939
struct certNickInfo {
1940
    PLArenaPool *arena;
1941
    unsigned int nNicks;
1942
    SECItem **nickList;
1943
    unsigned int error;
1944
};
1945
1946
/* callback for traversing certificates to gather the nicknames
1947
 * used in a particular traversal.  for instance, when using
1948
 * CERT_TraversePermCertsForSubject, gather the nicknames and
1949
 * store them in the certNickInfo for a particular DN.
1950
 *
1951
 * this handles the case where multiple nicknames are allowed
1952
 * for the same dn, which is not currently allowed, but may be
1953
 * in the future.
1954
 */
1955
static SECStatus
1956
gatherNicknames(CERTCertificate *cert, void *arg)
1957
0
{
1958
0
    struct certNickInfo *nickArg = (struct certNickInfo *)arg;
1959
0
    SECItem tempNick;
1960
0
    unsigned int i;
1961
1962
0
    if (!cert || !nickArg || nickArg->error) {
1963
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1964
0
        return SECFailure;
1965
0
    }
1966
1967
0
    if (!cert->nickname) {
1968
0
        return SECSuccess;
1969
0
    }
1970
1971
0
    tempNick.data = (unsigned char *)cert->nickname;
1972
0
    tempNick.len = PORT_Strlen(cert->nickname) + 1;
1973
0
    tempNick.type = siAsciiString;
1974
1975
    /* do we already have the nickname in the list? */
1976
0
    if (nickArg->nNicks > 0) {
1977
1978
        /* nicknames have been encountered, but there is no list -- bad */
1979
0
        if (!nickArg->nickList) {
1980
0
            nickArg->error = SEC_ERROR_INVALID_ARGS;
1981
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
1982
0
            return SECFailure;
1983
0
        }
1984
1985
0
        for (i = 0; i < nickArg->nNicks; i++) {
1986
0
            if (SECITEM_CompareItem(nickArg->nickList[i], &tempNick) == SECEqual) {
1987
0
                return SECSuccess;
1988
0
            }
1989
0
        }
1990
0
    }
1991
1992
    /* add the nickname to the list */
1993
0
    nickArg->nickList = (nickArg->nNicks == 0)
1994
0
                            ? PORT_ArenaZNewArray(nickArg->arena, SECItem *, 2)
1995
0
                            : PORT_ArenaGrowArray(nickArg->arena, nickArg->nickList, SECItem *,
1996
0
                                                  nickArg->nNicks + 1, nickArg->nNicks + 2);
1997
1998
0
    if (!nickArg->nickList) {
1999
0
        nickArg->error = SEC_ERROR_NO_MEMORY;
2000
0
        return SECFailure;
2001
0
    }
2002
2003
0
    nickArg->nickList[nickArg->nNicks] =
2004
0
        PORT_ArenaZNew(nickArg->arena, SECItem);
2005
0
    if (!nickArg->nickList[nickArg->nNicks]) {
2006
0
        nickArg->error = PORT_GetError();
2007
0
        return SECFailure;
2008
0
    }
2009
2010
0
    if (SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks],
2011
0
                         &tempNick) != SECSuccess) {
2012
0
        nickArg->error = PORT_GetError();
2013
0
        return SECFailure;
2014
0
    }
2015
2016
0
    nickArg->nNicks++;
2017
2018
0
    return SECSuccess;
2019
0
}
2020
2021
/* traverses the certs in the data base or in the token for the
2022
 * DN to see if any certs currently have a nickname set.
2023
 * If so, return it.
2024
 */
2025
static SECItem *
2026
sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert)
2027
0
{
2028
0
    struct certNickInfo *nickArg = NULL;
2029
0
    SECItem *derCert, *returnDn = NULL;
2030
0
    PLArenaPool *arena = NULL;
2031
0
    CERTCertificate *tempCert;
2032
2033
0
    if (!cert) {
2034
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2035
0
        return NULL;
2036
0
    }
2037
2038
0
    derCert = sec_pkcs12_get_der_cert(cert);
2039
0
    if (!derCert) {
2040
0
        return NULL;
2041
0
    }
2042
2043
0
    tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
2044
0
    if (!tempCert) {
2045
0
        returnDn = NULL;
2046
0
        goto loser;
2047
0
    }
2048
2049
0
    arena = PORT_NewArena(1024);
2050
0
    if (!arena) {
2051
0
        returnDn = NULL;
2052
0
        goto loser;
2053
0
    }
2054
0
    nickArg = PORT_ArenaZNew(arena, struct certNickInfo);
2055
0
    if (!nickArg) {
2056
0
        returnDn = NULL;
2057
0
        goto loser;
2058
0
    }
2059
0
    nickArg->error = 0;
2060
0
    nickArg->nNicks = 0;
2061
0
    nickArg->nickList = NULL;
2062
0
    nickArg->arena = arena;
2063
2064
    /* if the token is local, first traverse the cert database
2065
     * then traverse the token.
2066
     */
2067
0
    if (PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames,
2068
0
                                           (void *)nickArg) != SECSuccess) {
2069
0
        returnDn = NULL;
2070
0
        goto loser;
2071
0
    }
2072
2073
0
    if (nickArg->error) {
2074
        /* XXX do we want to set the error? */
2075
0
        returnDn = NULL;
2076
0
        goto loser;
2077
0
    }
2078
2079
0
    if (nickArg->nNicks == 0) {
2080
0
        returnDn = NULL;
2081
0
        goto loser;
2082
0
    }
2083
2084
    /* set it to the first name, for now.  handle multiple names? */
2085
0
    returnDn = SECITEM_DupItem(nickArg->nickList[0]);
2086
2087
0
loser:
2088
0
    if (arena) {
2089
0
        PORT_FreeArena(arena, PR_TRUE);
2090
0
    }
2091
2092
0
    if (tempCert) {
2093
0
        CERT_DestroyCertificate(tempCert);
2094
0
    }
2095
2096
0
    if (derCert) {
2097
0
        SECITEM_FreeItem(derCert, PR_TRUE);
2098
0
    }
2099
2100
0
    return (returnDn);
2101
0
}
2102
2103
/* counts certificates found for a given traversal function */
2104
static SECStatus
2105
countCertificate(CERTCertificate *cert, void *arg)
2106
0
{
2107
0
    unsigned int *nCerts = (unsigned int *)arg;
2108
2109
0
    if (!cert || !arg) {
2110
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2111
0
        return SECFailure;
2112
0
    }
2113
2114
0
    (*nCerts)++;
2115
0
    return SECSuccess;
2116
0
}
2117
2118
static PRBool
2119
sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot)
2120
0
{
2121
0
    unsigned int nCerts = 0;
2122
2123
0
    if (!nickname || !slot) {
2124
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2125
0
        return PR_TRUE;
2126
0
    }
2127
2128
    /* we want to check the local database first if we are importing to it */
2129
0
    PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate,
2130
0
                                        (void *)&nCerts);
2131
0
    return (PRBool)(nCerts != 0);
2132
0
}
2133
2134
/* validate cert nickname such that there is a one-to-one relation
2135
 * between nicknames and dn's.  we want to enforce the case that the
2136
 * nickname is non-NULL and that there is only one nickname per DN.
2137
 *
2138
 * if there is a problem with a nickname or the nickname is not present,
2139
 * the user will be prompted for it.
2140
 */
2141
static void
2142
sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,
2143
                                  sec_PKCS12SafeBag *key,
2144
                                  SEC_PKCS12NicknameCollisionCallback nicknameCb,
2145
                                  CERTCertificate *leafCert)
2146
0
{
2147
0
    SECItem *certNickname, *existingDNNick;
2148
0
    PRBool setNickname = PR_FALSE, cancel = PR_FALSE;
2149
0
    SECItem *newNickname = NULL;
2150
2151
0
    if (!cert || !cert->hasKey) {
2152
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2153
0
        return;
2154
0
    }
2155
2156
0
    if (!nicknameCb) {
2157
0
        cert->problem = PR_TRUE;
2158
0
        cert->error = SEC_ERROR_INVALID_ARGS;
2159
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2160
0
        return;
2161
0
    }
2162
2163
0
    if (cert->hasKey && !key) {
2164
0
        cert->problem = PR_TRUE;
2165
0
        cert->error = SEC_ERROR_INVALID_ARGS;
2166
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2167
0
        return;
2168
0
    }
2169
2170
0
    certNickname = sec_pkcs12_get_nickname_for_cert(cert, key);
2171
0
    existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert);
2172
2173
    /* nickname is already used w/ this dn, so it is safe to return */
2174
0
    if (certNickname && existingDNNick &&
2175
0
        SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {
2176
0
        goto loser;
2177
0
    }
2178
2179
    /* nickname not set in pkcs 12 bags, but a nick is already used for
2180
     * this dn.  set the nicks in the p12 bags and finish.
2181
     */
2182
0
    if (existingDNNick) {
2183
0
        sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick);
2184
0
        goto loser;
2185
0
    }
2186
2187
    /* at this point, we have a certificate for which the DN is not located
2188
     * on the token.  the nickname specified may or may not be NULL.  if it
2189
     * is not null, we need to make sure that there are no other certificates
2190
     * with this nickname in the token for it to be valid.  this imposes a
2191
     * one to one relationship between DN and nickname.
2192
     *
2193
     * if the nickname is null, we need the user to enter a nickname for
2194
     * the certificate.
2195
     *
2196
     * once we have a nickname, we make sure that the nickname is unique
2197
     * for the DN.  if it is not, the user is reprompted to enter a new
2198
     * nickname.
2199
     *
2200
     * in order to exit this loop, the nickname entered is either unique
2201
     * or the user hits cancel and the certificate is not imported.
2202
     */
2203
0
    setNickname = PR_FALSE;
2204
0
    while (1) {
2205
        /* we will use the nickname so long as no other certs have the
2206
         * same nickname.  and the nickname is not NULL.
2207
         */
2208
0
        if (certNickname && certNickname->data &&
2209
0
            !sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {
2210
0
            if (setNickname) {
2211
0
                sec_pkcs12_set_nickname_for_cert(cert, key, certNickname);
2212
0
            }
2213
0
            break;
2214
0
        }
2215
2216
0
        setNickname = PR_FALSE;
2217
0
        newNickname = (*nicknameCb)(certNickname, &cancel, leafCert);
2218
0
        if (cancel) {
2219
0
            cert->problem = PR_TRUE;
2220
0
            cert->error = SEC_ERROR_USER_CANCELLED;
2221
0
            break;
2222
0
        }
2223
2224
0
        if (!newNickname) {
2225
0
            cert->problem = PR_TRUE;
2226
0
            cert->error = PORT_GetError();
2227
0
            break;
2228
0
        }
2229
2230
        /* at this point we have a new nickname, if we have an existing
2231
         * certNickname, we need to free it and assign the new nickname
2232
         * to it to avoid a memory leak.  happy?
2233
         */
2234
0
        if (certNickname) {
2235
0
            SECITEM_ZfreeItem(certNickname, PR_TRUE);
2236
0
            certNickname = NULL;
2237
0
        }
2238
2239
0
        certNickname = newNickname;
2240
0
        setNickname = PR_TRUE;
2241
        /* go back and recheck the new nickname */
2242
0
    }
2243
2244
0
loser:
2245
0
    if (certNickname) {
2246
0
        SECITEM_ZfreeItem(certNickname, PR_TRUE);
2247
0
    }
2248
2249
0
    if (existingDNNick) {
2250
0
        SECITEM_ZfreeItem(existingDNNick, PR_TRUE);
2251
0
    }
2252
0
}
2253
2254
static void
2255
sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,
2256
                         sec_PKCS12SafeBag *key,
2257
                         SEC_PKCS12NicknameCollisionCallback nicknameCb)
2258
0
{
2259
0
    CERTCertificate *leafCert;
2260
2261
0
    if (!cert) {
2262
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2263
0
        return;
2264
0
    }
2265
2266
0
    cert->validated = PR_TRUE;
2267
2268
0
    if (!nicknameCb) {
2269
0
        cert->noInstall = PR_TRUE;
2270
0
        cert->problem = PR_TRUE;
2271
0
        cert->error = SEC_ERROR_INVALID_ARGS;
2272
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2273
0
        return;
2274
0
    }
2275
2276
0
    if (!cert->safeBagContent.certBag) {
2277
0
        cert->noInstall = PR_TRUE;
2278
0
        cert->problem = PR_TRUE;
2279
0
        cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
2280
0
        return;
2281
0
    }
2282
2283
0
    cert->noInstall = PR_FALSE;
2284
0
    cert->unused = PR_FALSE;
2285
0
    cert->problem = PR_FALSE;
2286
0
    cert->error = 0;
2287
2288
0
    leafCert = CERT_DecodeDERCertificate(
2289
0
        &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
2290
0
    if (!leafCert) {
2291
0
        cert->noInstall = PR_TRUE;
2292
0
        cert->problem = PR_TRUE;
2293
0
        cert->error = PORT_GetError();
2294
0
        return;
2295
0
    }
2296
2297
0
    sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, leafCert);
2298
2299
0
    CERT_DestroyCertificate(leafCert);
2300
0
}
2301
2302
static void
2303
sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,
2304
                                void *wincx)
2305
0
{
2306
0
    CERTCertificate *leafCert;
2307
0
    SECKEYPrivateKey *privk;
2308
2309
0
    if (!key) {
2310
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2311
0
        return;
2312
0
    }
2313
2314
0
    key->validated = PR_TRUE;
2315
2316
0
    if (!cert) {
2317
0
        key->problem = PR_TRUE;
2318
0
        key->noInstall = PR_TRUE;
2319
0
        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2320
0
        return;
2321
0
    }
2322
2323
0
    leafCert = CERT_DecodeDERCertificate(
2324
0
        &(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL);
2325
0
    if (!leafCert) {
2326
0
        key->problem = PR_TRUE;
2327
0
        key->noInstall = PR_TRUE;
2328
0
        key->error = PORT_GetError();
2329
0
        return;
2330
0
    }
2331
2332
0
    privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);
2333
0
    if (!privk) {
2334
0
        privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);
2335
0
    }
2336
2337
0
    if (privk) {
2338
0
        SECKEY_DestroyPrivateKey(privk);
2339
0
        key->noInstall = PR_TRUE;
2340
0
    }
2341
2342
0
    CERT_DestroyCertificate(leafCert);
2343
0
}
2344
2345
static SECStatus
2346
sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx)
2347
0
{
2348
0
    SECItem *derCert, *nickName;
2349
0
    char *nickData = NULL;
2350
0
    PRBool isIntermediateCA;
2351
0
    SECStatus rv;
2352
2353
0
    if (!cert) {
2354
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2355
0
        return SECFailure;
2356
0
    }
2357
2358
0
    if (cert->problem || cert->noInstall || cert->installed) {
2359
0
        return SECSuccess;
2360
0
    }
2361
2362
0
    derCert = &cert->safeBagContent.certBag->value.x509Cert;
2363
2364
0
    PORT_Assert(!cert->problem && !cert->noInstall);
2365
2366
0
    nickName = sec_pkcs12_get_nickname(cert);
2367
0
    if (nickName) {
2368
0
        nickData = (char *)nickName->data;
2369
0
    }
2370
2371
0
    isIntermediateCA = CERT_IsCADERCert(derCert, NULL) &&
2372
0
                       !CERT_IsRootDERCert(derCert);
2373
2374
0
    if (keyExists) {
2375
0
        CERTCertificate *newCert;
2376
2377
0
        newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2378
0
                                          derCert, NULL, PR_FALSE, PR_FALSE);
2379
0
        if (!newCert) {
2380
0
            if (nickName)
2381
0
                SECITEM_ZfreeItem(nickName, PR_TRUE);
2382
0
            cert->error = PORT_GetError();
2383
0
            cert->problem = PR_TRUE;
2384
0
            return SECFailure;
2385
0
        }
2386
2387
0
        rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData,
2388
0
                                         PR_TRUE, wincx);
2389
0
        CERT_DestroyCertificate(newCert);
2390
0
    } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) ||
2391
0
               ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) &&
2392
0
                !isIntermediateCA)) {
2393
0
        SECItem *certList[2];
2394
0
        certList[0] = derCert;
2395
0
        certList[1] = NULL;
2396
2397
0
        rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,
2398
0
                              1, certList, NULL, PR_TRUE, PR_FALSE, nickData);
2399
0
    } else {
2400
0
        rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE,
2401
0
                                nickData, PR_FALSE);
2402
0
    }
2403
0
    if (rv) {
2404
0
        cert->problem = 1;
2405
0
        cert->error = PORT_GetError();
2406
0
    }
2407
0
    cert->installed = PR_TRUE;
2408
0
    if (nickName)
2409
0
        SECITEM_ZfreeItem(nickName, PR_TRUE);
2410
0
    return rv;
2411
0
}
2412
2413
static SECItem *
2414
sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey, KeyType *type);
2415
2416
static SECStatus
2417
sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECKEYPublicKey *pubKey,
2418
                   unsigned int keyUsage,
2419
                   SECItem *nickName, PRBool forceUnicode, void *wincx)
2420
0
{
2421
0
    SECStatus rv;
2422
0
    SECItem *publicValue = NULL;
2423
0
    KeyType keyType;
2424
2425
    /* We should always have values for "key" and "pubKey"
2426
       so they can be dereferenced later. */
2427
0
    if (!key || !pubKey) {
2428
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2429
0
        return SECFailure;
2430
0
    }
2431
2432
0
    if (key->problem || key->noInstall) {
2433
0
        return SECSuccess;
2434
0
    }
2435
2436
    /* get the value and type from the public key */
2437
0
    publicValue = sec_pkcs12_get_public_value_and_type(pubKey, &keyType);
2438
0
    if (!publicValue) {
2439
0
        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2440
0
        key->problem = PR_TRUE;
2441
0
        return SECFailure;
2442
0
    }
2443
2444
0
    switch (SECOID_FindOIDTag(&key->safeBagType)) {
2445
0
        case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2446
0
            rv = PK11_ImportPrivateKeyInfo(key->slot,
2447
0
                                           key->safeBagContent.pkcs8KeyBag,
2448
0
                                           nickName, publicValue, PR_TRUE, PR_TRUE,
2449
0
                                           keyUsage, wincx);
2450
0
            break;
2451
0
        case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: {
2452
0
            SECItem pwitem = { 0 };
2453
0
            SECAlgorithmID *algid =
2454
0
                &key->safeBagContent.pkcs8ShroudedKeyBag->algorithm;
2455
0
            SECOidTag algorithm = SECOID_GetAlgorithmTag(algid);
2456
2457
0
            if (!SEC_PKCS12DecryptionAllowed(algid)) {
2458
0
                key->error = SEC_ERROR_BAD_EXPORT_ALGORITHM;
2459
0
                key->problem = PR_TRUE;
2460
0
                return SECFailure;
2461
0
            }
2462
2463
0
            if (forceUnicode) {
2464
0
                if (SECITEM_CopyItem(NULL, &pwitem, key->pwitem) != SECSuccess) {
2465
0
                    key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2466
0
                    key->problem = PR_TRUE;
2467
0
                    return SECFailure;
2468
0
                }
2469
0
            } else {
2470
0
                if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm,
2471
0
                                                key->pwitem)) {
2472
0
                    key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2473
0
                    key->problem = PR_TRUE;
2474
0
                    return SECFailure;
2475
0
                }
2476
0
            }
2477
2478
0
            rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
2479
0
                                                    key->safeBagContent.pkcs8ShroudedKeyBag,
2480
0
                                                    &pwitem, nickName, publicValue,
2481
0
                                                    PR_TRUE, PR_TRUE, keyType, keyUsage,
2482
0
                                                    wincx);
2483
0
            if (pwitem.data) {
2484
0
                SECITEM_ZfreeItem(&pwitem, PR_FALSE);
2485
0
            }
2486
0
            break;
2487
0
        }
2488
0
        default:
2489
0
            key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
2490
0
            key->problem = PR_TRUE;
2491
0
            if (nickName) {
2492
0
                SECITEM_ZfreeItem(nickName, PR_TRUE);
2493
0
            }
2494
0
            return SECFailure;
2495
0
    }
2496
2497
0
    if (rv != SECSuccess) {
2498
0
        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2499
0
        key->problem = PR_TRUE;
2500
0
    } else {
2501
        /* try to import the public key. Failure to do so is not fatal,
2502
         * not all tokens can store the public key */
2503
0
        if (pubKey) {
2504
0
            PK11_ImportPublicKey(key->slot, pubKey, PR_TRUE);
2505
0
        }
2506
0
        key->installed = PR_TRUE;
2507
0
    }
2508
2509
0
    return rv;
2510
0
}
2511
2512
/*
2513
 * The correctness of the code in this file ABSOLUTELY REQUIRES
2514
 * that ALL BAGs share a single common arena.
2515
 *
2516
 * This function allocates the bag list from the arena of whatever bag
2517
 * happens to be passed to it.  Each time a new bag is handed to it,
2518
 * it grows (resizes) the arena of the bag that was handed to it.
2519
 * If the bags have different arenas, it will grow the wrong arena.
2520
 *
2521
 * Worse, if the bags had separate arenas, then while destroying the bags
2522
 * in a bag list, when the bag whose arena contained the bag list was
2523
 * destroyed, the baglist itself would be destroyed, making it difficult
2524
 * or impossible to continue to destroy the bags in the destroyed list.
2525
 */
2526
static SECStatus
2527
sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList,
2528
                                sec_PKCS12SafeBag *bag)
2529
0
{
2530
0
    sec_PKCS12SafeBag **newBagList = NULL;
2531
0
    int i = 0;
2532
2533
0
    if (!bagList || !bag) {
2534
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2535
0
        return SECFailure;
2536
0
    }
2537
2538
0
    if (!(*bagList)) {
2539
0
        newBagList = PORT_ArenaZNewArray(bag->arena, sec_PKCS12SafeBag *, 2);
2540
0
    } else {
2541
0
        while ((*bagList)[i])
2542
0
            i++;
2543
0
        newBagList = PORT_ArenaGrowArray(bag->arena, *bagList,
2544
0
                                         sec_PKCS12SafeBag *, i + 1, i + 2);
2545
0
    }
2546
2547
0
    if (!newBagList) {
2548
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
2549
0
        return SECFailure;
2550
0
    }
2551
2552
0
    newBagList[i] = bag;
2553
0
    newBagList[i + 1] = NULL;
2554
0
    *bagList = newBagList;
2555
2556
0
    return SECSuccess;
2557
0
}
2558
2559
static sec_PKCS12SafeBag **
2560
sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags,
2561
                              sec_PKCS12SafeBag *key)
2562
0
{
2563
0
    sec_PKCS12SafeBag **certList = NULL;
2564
0
    SECItem *keyId;
2565
0
    int i;
2566
2567
0
    if (!safeBags || !safeBags[0]) {
2568
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2569
0
        return NULL;
2570
0
    }
2571
2572
0
    keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);
2573
0
    if (!keyId) {
2574
0
        return NULL;
2575
0
    }
2576
2577
0
    for (i = 0; safeBags[i]; i++) {
2578
0
        if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2579
0
            SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],
2580
0
                                                                SEC_OID_PKCS9_LOCAL_KEY_ID);
2581
2582
0
            if (certKeyId && (SECITEM_CompareItem(certKeyId, keyId) == SECEqual)) {
2583
0
                if (sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i]) != SECSuccess) {
2584
                    /* This would leak the partial list of safeBags,
2585
                     * but that list is allocated from the arena of
2586
                     * one of the safebags, and will be destroyed when
2587
                     * that arena is destroyed.  So this is not a real leak.
2588
                     */
2589
0
                    return NULL;
2590
0
                }
2591
0
            }
2592
0
        }
2593
0
    }
2594
2595
0
    return certList;
2596
0
}
2597
2598
CERTCertList *
2599
SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx)
2600
0
{
2601
0
    CERTCertList *certList = NULL;
2602
0
    sec_PKCS12SafeBag **safeBags;
2603
0
    int i;
2604
2605
0
    if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) {
2606
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2607
0
        return NULL;
2608
0
    }
2609
2610
0
    safeBags = p12dcx->safeBags;
2611
0
    certList = CERT_NewCertList();
2612
2613
0
    if (certList == NULL) {
2614
0
        return NULL;
2615
0
    }
2616
2617
0
    for (i = 0; safeBags[i]; i++) {
2618
0
        if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2619
0
            SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]);
2620
0
            CERTCertificate *tempCert = NULL;
2621
2622
0
            if (derCert == NULL)
2623
0
                continue;
2624
0
            tempCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2625
0
                                               derCert, NULL,
2626
0
                                               PR_FALSE, PR_TRUE);
2627
2628
0
            if (tempCert) {
2629
0
                CERT_AddCertToListTail(certList, tempCert);
2630
0
            }
2631
0
            SECITEM_FreeItem(derCert, PR_TRUE);
2632
0
        }
2633
        /* fixed an infinite loop here, by ensuring that i gets incremented
2634
         * if derCert is NULL above.
2635
         */
2636
0
    }
2637
2638
0
    return certList;
2639
0
}
2640
static sec_PKCS12SafeBag **
2641
sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags)
2642
0
{
2643
0
    int i;
2644
0
    sec_PKCS12SafeBag **keyList = NULL;
2645
0
    SECOidTag bagType;
2646
2647
0
    if (!safeBags || !safeBags[0]) {
2648
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2649
0
        return NULL;
2650
0
    }
2651
2652
0
    for (i = 0; safeBags[i]; i++) {
2653
0
        bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
2654
0
        switch (bagType) {
2655
0
            case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2656
0
            case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2657
0
                if (sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i]) != SECSuccess) {
2658
                    /* This would leak, except that keyList is allocated
2659
                     * from the arena shared by all the safeBags.
2660
                     */
2661
0
                    return NULL;
2662
0
                }
2663
0
                break;
2664
0
            default:
2665
0
                break;
2666
0
        }
2667
0
    }
2668
2669
0
    return keyList;
2670
0
}
2671
2672
/* This function takes two passes over the bags, validating them
2673
 * The two passes are intended to mirror exactly the two passes in
2674
 * sec_pkcs12_install_bags.  But they don't. :(
2675
 */
2676
static SECStatus
2677
sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags,
2678
                         SEC_PKCS12NicknameCollisionCallback nicknameCb,
2679
                         void *wincx)
2680
0
{
2681
0
    sec_PKCS12SafeBag **keyList;
2682
0
    int i;
2683
2684
0
    if (!safeBags || !nicknameCb) {
2685
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2686
0
        return SECFailure;
2687
0
    }
2688
2689
0
    if (!safeBags[0]) {
2690
0
        return SECSuccess;
2691
0
    }
2692
2693
    /* First pass.  Find all the key bags.
2694
     * Find the matching cert(s) for each key.
2695
     */
2696
0
    keyList = sec_pkcs12_get_key_bags(safeBags);
2697
0
    if (keyList) {
2698
0
        for (i = 0; keyList[i]; ++i) {
2699
0
            sec_PKCS12SafeBag *key = keyList[i];
2700
0
            sec_PKCS12SafeBag **certList =
2701
0
                sec_pkcs12_find_certs_for_key(safeBags, key);
2702
2703
0
            if (certList) {
2704
0
                int j;
2705
2706
0
                if (SECOID_FindOIDTag(&(key->safeBagType)) ==
2707
0
                    SEC_OID_PKCS12_V1_KEY_BAG_ID) {
2708
                    /* if it is an unencrypted private key then make sure
2709
                     * the attributes are propageted to the appropriate
2710
                     * level
2711
                     */
2712
0
                    if (sec_pkcs12_get_key_info(key) != SECSuccess) {
2713
0
                        return SECFailure;
2714
0
                    }
2715
0
                }
2716
2717
0
                sec_pkcs12_validate_key_by_cert(certList[0], key, wincx);
2718
0
                for (j = 0; certList[j]; ++j) {
2719
0
                    sec_PKCS12SafeBag *cert = certList[j];
2720
0
                    cert->hasKey = PR_TRUE;
2721
0
                    if (key->problem) {
2722
0
                        cert->problem = PR_TRUE;
2723
0
                        cert->error = key->error;
2724
0
                        continue;
2725
0
                    }
2726
0
                    sec_pkcs12_validate_cert(cert, key, nicknameCb);
2727
0
                    if (cert->problem) {
2728
0
                        key->problem = cert->problem;
2729
0
                        key->error = cert->error;
2730
0
                    }
2731
0
                }
2732
0
            }
2733
0
        }
2734
0
    }
2735
2736
    /* Now take a second pass over the safebags and mark for installation any
2737
     * certs that were neither installed nor disqualified by the first pass.
2738
     */
2739
0
    for (i = 0; safeBags[i]; ++i) {
2740
0
        sec_PKCS12SafeBag *bag = safeBags[i];
2741
2742
0
        if (!bag->validated) {
2743
0
            SECOidTag bagType = SECOID_FindOIDTag(&bag->safeBagType);
2744
2745
0
            switch (bagType) {
2746
0
                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
2747
0
                    sec_pkcs12_validate_cert(bag, NULL, nicknameCb);
2748
0
                    break;
2749
0
                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2750
0
                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2751
0
                    bag->noInstall = PR_TRUE;
2752
0
                    bag->problem = PR_TRUE;
2753
0
                    bag->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2754
0
                    break;
2755
0
                default:
2756
0
                    bag->noInstall = PR_TRUE;
2757
0
            }
2758
0
        }
2759
0
    }
2760
2761
0
    return SECSuccess;
2762
0
}
2763
2764
SECStatus
2765
SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx,
2766
                              SEC_PKCS12NicknameCollisionCallback nicknameCb)
2767
0
{
2768
0
    SECStatus rv;
2769
0
    int i, probCnt, errorVal = 0;
2770
0
    if (!p12dcx || p12dcx->error || !p12dcx->safeBags) {
2771
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2772
0
        return SECFailure;
2773
0
    }
2774
2775
0
    rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx);
2776
0
    if (rv == SECSuccess) {
2777
0
        p12dcx->bagsVerified = PR_TRUE;
2778
0
    }
2779
2780
0
    probCnt = 0;
2781
0
    i = 0;
2782
0
    while (p12dcx->safeBags[i]) {
2783
0
        if (p12dcx->safeBags[i]->problem) {
2784
0
            probCnt++;
2785
0
            errorVal = p12dcx->safeBags[i]->error;
2786
0
        }
2787
0
        i++;
2788
0
    }
2789
2790
0
    if (probCnt) {
2791
0
        PORT_SetError(errorVal);
2792
0
        return SECFailure;
2793
0
    }
2794
2795
0
    return rv;
2796
0
}
2797
2798
SECStatus
2799
SEC_PKCS12DecoderRenameCertNicknames(SEC_PKCS12DecoderContext *p12dcx,
2800
                                     SEC_PKCS12NicknameRenameCallback nicknameCb,
2801
                                     void *arg)
2802
0
{
2803
0
    int i;
2804
0
    sec_PKCS12SafeBag *safeBag;
2805
0
    CERTCertificate *cert;
2806
0
    SECStatus srv;
2807
2808
0
    if (!p12dcx || p12dcx->error || !p12dcx->safeBags || !nicknameCb) {
2809
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2810
0
        return SECFailure;
2811
0
    }
2812
2813
0
    for (i = 0; (safeBag = p12dcx->safeBags[i]); i++) {
2814
0
        SECItem *newNickname = NULL;
2815
0
        SECItem *defaultNickname = NULL;
2816
0
        SECStatus rename_rv;
2817
2818
0
        if (SECOID_FindOIDTag(&(safeBag->safeBagType)) !=
2819
0
            SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2820
0
            continue;
2821
0
        }
2822
2823
0
        cert = CERT_DecodeDERCertificate(
2824
0
            &safeBag->safeBagContent.certBag->value.x509Cert,
2825
0
            PR_FALSE, NULL);
2826
0
        if (!cert) {
2827
0
            return SECFailure;
2828
0
        }
2829
2830
0
        defaultNickname = sec_pkcs12_get_nickname(safeBag);
2831
0
        rename_rv = (*nicknameCb)(cert, defaultNickname, &newNickname, arg);
2832
2833
0
        CERT_DestroyCertificate(cert);
2834
2835
0
        if (defaultNickname) {
2836
0
            SECITEM_ZfreeItem(defaultNickname, PR_TRUE);
2837
0
            defaultNickname = NULL;
2838
0
        }
2839
2840
0
        if (rename_rv != SECSuccess) {
2841
0
            return rename_rv;
2842
0
        }
2843
2844
0
        if (newNickname) {
2845
0
            srv = sec_pkcs12_set_nickname(safeBag, newNickname);
2846
0
            SECITEM_ZfreeItem(newNickname, PR_TRUE);
2847
0
            newNickname = NULL;
2848
0
            if (srv != SECSuccess) {
2849
0
                return SECFailure;
2850
0
            }
2851
0
        }
2852
0
    }
2853
2854
0
    return SECSuccess;
2855
0
}
2856
2857
static SECKEYPublicKey *
2858
sec_pkcs12_get_public_key_and_usage(sec_PKCS12SafeBag *certBag,
2859
                                    unsigned int *usage)
2860
0
{
2861
0
    SECKEYPublicKey *pubKey = NULL;
2862
0
    CERTCertificate *cert = NULL;
2863
2864
0
    if (!certBag || !usage) {
2865
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2866
0
        return NULL;
2867
0
    }
2868
2869
0
    *usage = 0;
2870
2871
0
    cert = CERT_DecodeDERCertificate(
2872
0
        &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
2873
0
    if (!cert) {
2874
0
        return NULL;
2875
0
    }
2876
2877
0
    *usage = cert->keyUsage;
2878
0
    pubKey = CERT_ExtractPublicKey(cert);
2879
0
    CERT_DestroyCertificate(cert);
2880
0
    return pubKey;
2881
0
}
2882
2883
static SECItem *
2884
sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey,
2885
                                     KeyType *type)
2886
0
{
2887
0
    SECItem *pubValue = NULL;
2888
2889
0
    if (!type || !pubKey) {
2890
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2891
0
        return NULL;
2892
0
    }
2893
2894
0
    *type = pubKey->keyType;
2895
0
    switch (pubKey->keyType) {
2896
0
        case dsaKey:
2897
0
            pubValue = &pubKey->u.dsa.publicValue;
2898
0
            break;
2899
0
        case dhKey:
2900
0
            pubValue = &pubKey->u.dh.publicValue;
2901
0
            break;
2902
0
        case rsaKey:
2903
0
            pubValue = &pubKey->u.rsa.modulus;
2904
0
            break;
2905
0
        case ecKey:
2906
0
            pubValue = &pubKey->u.ec.publicValue;
2907
0
            break;
2908
0
        default:
2909
0
            pubValue = NULL;
2910
0
    }
2911
2912
0
    return pubValue;
2913
0
}
2914
2915
/* This function takes two passes over the bags, installing them in the
2916
 * desired slot.  The two passes are intended to mirror exactly the
2917
 * two passes in sec_pkcs12_validate_bags.
2918
 */
2919
static SECStatus
2920
sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, PRBool forceUnicode,
2921
                        void *wincx)
2922
0
{
2923
0
    sec_PKCS12SafeBag **keyList;
2924
0
    int i;
2925
0
    int failedKeys = 0;
2926
2927
0
    if (!safeBags) {
2928
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2929
0
        return SECFailure;
2930
0
    }
2931
2932
0
    if (!safeBags[0]) {
2933
0
        return SECSuccess;
2934
0
    }
2935
2936
    /* First pass.  Find all the key bags.
2937
     * Try to install them, and any certs associated with them.
2938
     */
2939
0
    keyList = sec_pkcs12_get_key_bags(safeBags);
2940
0
    if (keyList) {
2941
0
        for (i = 0; keyList[i]; i++) {
2942
0
            SECStatus rv;
2943
0
            SECKEYPublicKey *pubKey = NULL;
2944
0
            SECItem *nickName = NULL;
2945
0
            sec_PKCS12SafeBag *key = keyList[i];
2946
0
            sec_PKCS12SafeBag **certList;
2947
0
            unsigned int keyUsage;
2948
2949
0
            if (key->problem) {
2950
0
                ++failedKeys;
2951
0
                continue;
2952
0
            }
2953
2954
0
            certList = sec_pkcs12_find_certs_for_key(safeBags, key);
2955
0
            if (certList && certList[0]) {
2956
0
                pubKey = sec_pkcs12_get_public_key_and_usage(certList[0],
2957
0
                                                             &keyUsage);
2958
                /* use the cert's nickname, if it has one, else use the
2959
                 * key's nickname, else fail.
2960
                 */
2961
0
                nickName = sec_pkcs12_get_nickname_for_cert(certList[0], key);
2962
0
            } else {
2963
0
                nickName = sec_pkcs12_get_nickname(key);
2964
0
            }
2965
0
            if (!nickName) {
2966
0
                key->error = SEC_ERROR_BAD_NICKNAME;
2967
0
                key->problem = PR_TRUE;
2968
0
                rv = SECFailure;
2969
0
            } else if (!pubKey) {
2970
0
                key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2971
0
                key->problem = PR_TRUE;
2972
0
                rv = SECFailure;
2973
0
            } else {
2974
0
                rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName,
2975
0
                                        forceUnicode, wincx);
2976
0
            }
2977
0
            if (pubKey) {
2978
0
                SECKEY_DestroyPublicKey(pubKey);
2979
0
                pubKey = NULL;
2980
0
            }
2981
0
            if (nickName) {
2982
0
                SECITEM_FreeItem(nickName, PR_TRUE);
2983
0
                nickName = NULL;
2984
0
            }
2985
0
            if (rv != SECSuccess) {
2986
0
                PORT_SetError(key->error);
2987
0
                ++failedKeys;
2988
0
            }
2989
2990
0
            if (certList) {
2991
0
                int j;
2992
2993
0
                for (j = 0; certList[j]; j++) {
2994
0
                    sec_PKCS12SafeBag *cert = certList[j];
2995
0
                    SECStatus certRv;
2996
2997
0
                    if (!cert)
2998
0
                        continue;
2999
0
                    if (rv != SECSuccess) {
3000
0
                        cert->problem = key->problem;
3001
0
                        cert->error = key->error;
3002
0
                        cert->noInstall = PR_TRUE;
3003
0
                        continue;
3004
0
                    }
3005
3006
0
                    certRv = sec_pkcs12_add_cert(cert, cert->hasKey, wincx);
3007
0
                    if (certRv != SECSuccess) {
3008
0
                        key->problem = cert->problem;
3009
0
                        key->error = cert->error;
3010
0
                        PORT_SetError(cert->error);
3011
0
                        return SECFailure;
3012
0
                    }
3013
0
                }
3014
0
            }
3015
0
        }
3016
0
    }
3017
0
    if (failedKeys)
3018
0
        return SECFailure;
3019
3020
    /* Now take a second pass over the safebags and install any certs
3021
     * that were neither installed nor disqualified by the first pass.
3022
     */
3023
0
    for (i = 0; safeBags[i]; i++) {
3024
0
        sec_PKCS12SafeBag *bag = safeBags[i];
3025
3026
0
        if (!bag->installed && !bag->problem && !bag->noInstall) {
3027
0
            SECStatus rv;
3028
0
            SECOidTag bagType = SECOID_FindOIDTag(&(bag->safeBagType));
3029
3030
0
            switch (bagType) {
3031
0
                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
3032
0
                    rv = sec_pkcs12_add_cert(bag, bag->hasKey, wincx);
3033
0
                    if (rv != SECSuccess) {
3034
0
                        PORT_SetError(bag->error);
3035
0
                        return SECFailure;
3036
0
                    }
3037
0
                    break;
3038
0
                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
3039
0
                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
3040
0
                default:
3041
0
                    break;
3042
0
            }
3043
0
        }
3044
0
    }
3045
3046
0
    return SECSuccess;
3047
0
}
3048
3049
SECStatus
3050
SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
3051
0
{
3052
0
    PRBool forceUnicode = PR_FALSE;
3053
0
    SECStatus rv;
3054
3055
0
    if (!p12dcx || p12dcx->error) {
3056
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3057
0
        return SECFailure;
3058
0
    }
3059
3060
0
    if (!p12dcx->bagsVerified) {
3061
0
        return SECFailure;
3062
0
    }
3063
3064
    /* We need to check the option here as well as in
3065
     * SEC_PKCS12DecoderStart, because different PBE's could be used
3066
     * for PKCS #7 and PKCS #8 */
3067
0
    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
3068
0
    if (rv != SECSuccess) {
3069
0
        return SECFailure;
3070
0
    }
3071
3072
0
    return sec_pkcs12_install_bags(p12dcx->safeBags, forceUnicode,
3073
0
                                   p12dcx->wincx);
3074
0
}
3075
3076
PRBool
3077
sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
3078
0
{
3079
0
    int i;
3080
0
    SECItem *keyId;
3081
0
    SECItem *certKeyId;
3082
3083
0
    certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
3084
0
    if (certKeyId == NULL) {
3085
0
        return PR_FALSE;
3086
0
    }
3087
3088
0
    for (i = 0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
3089
0
        keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
3090
0
                                               SEC_OID_PKCS9_LOCAL_KEY_ID);
3091
0
        if (!keyId) {
3092
0
            continue;
3093
0
        }
3094
0
        if (SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
3095
0
            return PR_TRUE;
3096
0
        }
3097
0
    }
3098
0
    return PR_FALSE;
3099
0
}
3100
3101
SECItem *
3102
sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
3103
0
{
3104
0
    SECItem *friendlyName;
3105
0
    SECItem *tempnm;
3106
3107
0
    tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
3108
0
    friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
3109
0
    if (friendlyName) {
3110
0
        if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
3111
0
                                                tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
3112
0
            SECITEM_FreeItem(friendlyName, PR_TRUE);
3113
0
            friendlyName = NULL;
3114
0
        }
3115
0
    }
3116
0
    return friendlyName;
3117
0
}
3118
3119
/* Following two functions provide access to selected portions of the safe bags.
3120
 * Iteration is implemented per decoder context and may be accessed after
3121
 * SEC_PKCS12DecoderVerify() returns success.
3122
 * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
3123
 * where item.type is always set; item.friendlyName is set if it is non-null;
3124
 * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
3125
 * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
3126
 * arguments are invalid; PORT_GetError() is 0 at end-of-list.
3127
 * Caller has read-only access to decoder items. Any SECItems generated are
3128
 * owned by the decoder context and are freed by ...DecoderFinish().
3129
 */
3130
SECStatus
3131
SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
3132
0
{
3133
0
    if (!p12dcx || p12dcx->error) {
3134
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3135
0
        return SECFailure;
3136
0
    }
3137
3138
0
    p12dcx->iteration = 0;
3139
0
    return SECSuccess;
3140
0
}
3141
3142
SECStatus
3143
SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
3144
                             const SEC_PKCS12DecoderItem **ipp)
3145
0
{
3146
0
    sec_PKCS12SafeBag *bag;
3147
3148
0
    if (!p12dcx || p12dcx->error) {
3149
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3150
0
        return SECFailure;
3151
0
    }
3152
3153
0
    if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
3154
0
        SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
3155
0
    }
3156
0
    if (p12dcx->decitem.shroudAlg != NULL) {
3157
0
        SECOID_DestroyAlgorithmID(p12dcx->decitem.shroudAlg, PR_TRUE);
3158
0
    }
3159
0
    if (p12dcx->decitem.friendlyName != NULL) {
3160
0
        SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
3161
0
    }
3162
0
    p12dcx->decitem.type = 0;
3163
0
    p12dcx->decitem.der = NULL;
3164
0
    p12dcx->decitem.shroudAlg = NULL;
3165
0
    p12dcx->decitem.friendlyName = NULL;
3166
0
    p12dcx->decitem.hasKey = PR_FALSE;
3167
0
    *ipp = NULL;
3168
0
    if (p12dcx->keyList == NULL) {
3169
0
        p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
3170
0
    }
3171
3172
0
    for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
3173
0
        bag = p12dcx->safeBags[p12dcx->iteration];
3174
0
        if (bag == NULL || bag->problem) {
3175
0
            continue;
3176
0
        }
3177
0
        p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
3178
0
        switch (p12dcx->decitem.type) {
3179
0
            case SEC_OID_PKCS12_V1_CERT_BAG_ID:
3180
0
                p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
3181
0
                p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
3182
0
                p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
3183
                /* if we don't understand the cert, or it's not parsable, skip it */
3184
                /* as per the comment above, friendlyName may be null legitimately */
3185
0
                if (!p12dcx->decitem.der) {
3186
0
                    p12dcx->decitem.type = 0; /* clear out the type we are ignoring */
3187
0
                    continue;
3188
0
                }
3189
0
                break;
3190
0
            case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
3191
0
                p12dcx->decitem.shroudAlg = PORT_ZNew(SECAlgorithmID);
3192
0
                if (p12dcx->decitem.shroudAlg) {
3193
0
                    SECOID_CopyAlgorithmID(NULL, p12dcx->decitem.shroudAlg,
3194
0
                                           &bag->safeBagContent.pkcs8ShroudedKeyBag->algorithm);
3195
0
                }
3196
            /* fall through */
3197
0
            case SEC_OID_PKCS12_V1_KEY_BAG_ID:
3198
0
                p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
3199
0
                break;
3200
0
            default:
3201
                /* return these even though we don't expect them */
3202
0
                break;
3203
0
            case SEC_OID_UNKNOWN:
3204
                /* ignore these */
3205
0
                p12dcx->decitem.type = 0; /* clear out the type we are ignoring */
3206
0
                continue;
3207
0
        }
3208
0
        *ipp = &p12dcx->decitem;
3209
0
        p12dcx->iteration++;
3210
0
        break; /* end for() */
3211
0
    }
3212
3213
0
    PORT_SetError(0); /* end-of-list is SECFailure with no PORT error */
3214
0
    return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
3215
0
}
3216
3217
static SECStatus
3218
sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
3219
                                         sec_PKCS12SafeBag *bag)
3220
0
{
3221
0
    if (!p12dcx || p12dcx->error) {
3222
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3223
0
        return SECFailure;
3224
0
    }
3225
3226
0
    p12dcx->safeBags = !p12dcx->safeBagCount
3227
0
                           ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
3228
0
                           : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
3229
0
                                                 sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
3230
0
                                                 p12dcx->safeBagCount + 2);
3231
3232
0
    if (!p12dcx->safeBags) {
3233
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3234
0
        return SECFailure;
3235
0
    }
3236
3237
0
    p12dcx->safeBags[p12dcx->safeBagCount] = bag;
3238
0
    p12dcx->safeBags[p12dcx->safeBagCount + 1] = NULL;
3239
0
    p12dcx->safeBagCount++;
3240
3241
0
    return SECSuccess;
3242
0
}
3243
3244
static sec_PKCS12SafeBag *
3245
sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx,
3246
                                   void *key, PRBool isEspvk)
3247
0
{
3248
0
    sec_PKCS12SafeBag *keyBag;
3249
0
    SECOidData *oid;
3250
0
    SECOidTag keyTag;
3251
0
    SECItem *keyID, *nickName, *newNickName;
3252
3253
0
    if (!p12dcx || p12dcx->error || !key) {
3254
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3255
0
        return NULL;
3256
0
    }
3257
3258
0
    newNickName = PORT_ArenaZNew(p12dcx->arena, SECItem);
3259
0
    keyBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
3260
0
    if (!keyBag || !newNickName) {
3261
0
        return NULL;
3262
0
    }
3263
3264
0
    keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
3265
0
    keyBag->slot = p12dcx->slot;
3266
0
    keyBag->arena = p12dcx->arena;
3267
0
    keyBag->pwitem = p12dcx->pwitem;
3268
0
    keyBag->tokenCAs = p12dcx->tokenCAs;
3269
0
    keyBag->oldBagType = PR_TRUE;
3270
3271
0
    keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID : SEC_OID_PKCS12_V1_KEY_BAG_ID;
3272
0
    oid = SECOID_FindOIDByTag(keyTag);
3273
0
    if (!oid) {
3274
0
        return NULL;
3275
0
    }
3276
3277
0
    if (SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid) != SECSuccess) {
3278
0
        return NULL;
3279
0
    }
3280
3281
0
    if (isEspvk) {
3282
0
        SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key;
3283
0
        keyBag->safeBagContent.pkcs8ShroudedKeyBag =
3284
0
            espvk->espvkCipherText.pkcs8KeyShroud;
3285
0
        nickName = &(espvk->espvkData.uniNickName);
3286
0
        if (!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) {
3287
0
            PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3288
0
            return NULL;
3289
0
        }
3290
0
        keyID = &espvk->espvkData.assocCerts[0]->digest;
3291
0
    } else {
3292
0
        SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key;
3293
0
        keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data;
3294
0
        nickName = &(pk->pvkData.uniNickName);
3295
0
        if (!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) {
3296
0
            PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3297
0
            return NULL;
3298
0
        }
3299
0
        keyID = &pk->pvkData.assocCerts[0]->digest;
3300
0
    }
3301
3302
0
    if (nickName->len) {
3303
0
        if (nickName->len >= 2) {
3304
0
            if (nickName->data[0] && nickName->data[1]) {
3305
0
                if (!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
3306
0
                                                        nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
3307
0
                    return NULL;
3308
0
                }
3309
0
                nickName = newNickName;
3310
0
            } else if (nickName->data[0] && !nickName->data[1]) {
3311
0
                unsigned int j = 0;
3312
0
                unsigned char t;
3313
0
                for (j = 0; j < nickName->len; j += 2) {
3314
0
                    t = nickName->data[j + 1];
3315
0
                    nickName->data[j + 1] = nickName->data[j];
3316
0
                    nickName->data[j] = t;
3317
0
                }
3318
0
            }
3319
0
        } else {
3320
0
            if (!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
3321
0
                                                    nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
3322
0
                return NULL;
3323
0
            }
3324
0
            nickName = newNickName;
3325
0
        }
3326
0
    }
3327
3328
0
    if (sec_pkcs12_decoder_set_attribute_value(keyBag,
3329
0
                                               SEC_OID_PKCS9_FRIENDLY_NAME,
3330
0
                                               nickName) != SECSuccess) {
3331
0
        return NULL;
3332
0
    }
3333
3334
0
    if (sec_pkcs12_decoder_set_attribute_value(keyBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
3335
0
                                               keyID) != SECSuccess) {
3336
0
        return NULL;
3337
0
    }
3338
3339
0
    return keyBag;
3340
0
}
3341
3342
static sec_PKCS12SafeBag *
3343
sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx,
3344
                               SECItem *derCert)
3345
0
{
3346
0
    sec_PKCS12SafeBag *certBag;
3347
0
    SECOidData *oid;
3348
0
    SGNDigestInfo *digest;
3349
0
    SECItem *keyId;
3350
0
    SECStatus rv;
3351
3352
0
    if (!p12dcx || p12dcx->error || !derCert) {
3353
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3354
0
        return NULL;
3355
0
    }
3356
3357
0
    keyId = PORT_ArenaZNew(p12dcx->arena, SECItem);
3358
0
    if (!keyId) {
3359
0
        return NULL;
3360
0
    }
3361
3362
0
    digest = sec_pkcs12_compute_thumbprint(derCert);
3363
0
    if (!digest) {
3364
0
        return NULL;
3365
0
    }
3366
3367
0
    rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest);
3368
0
    SGN_DestroyDigestInfo(digest);
3369
0
    if (rv != SECSuccess) {
3370
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
3371
0
        return NULL;
3372
0
    }
3373
3374
0
    oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID);
3375
0
    certBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
3376
0
    if (!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena, &certBag->safeBagType, &oid->oid) != SECSuccess)) {
3377
0
        return NULL;
3378
0
    }
3379
3380
0
    certBag->slot = p12dcx->slot;
3381
0
    certBag->pwitem = p12dcx->pwitem;
3382
0
    certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
3383
0
    certBag->arena = p12dcx->arena;
3384
0
    certBag->tokenCAs = p12dcx->tokenCAs;
3385
3386
0
    oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT);
3387
0
    certBag->safeBagContent.certBag =
3388
0
        PORT_ArenaZNew(p12dcx->arena, sec_PKCS12CertBag);
3389
0
    if (!certBag->safeBagContent.certBag || !oid ||
3390
0
        (SECITEM_CopyItem(p12dcx->arena,
3391
0
                          &certBag->safeBagContent.certBag->bagID,
3392
0
                          &oid->oid) != SECSuccess)) {
3393
0
        return NULL;
3394
0
    }
3395
3396
0
    if (SECITEM_CopyItem(p12dcx->arena,
3397
0
                         &(certBag->safeBagContent.certBag->value.x509Cert),
3398
0
                         derCert) != SECSuccess) {
3399
0
        return NULL;
3400
0
    }
3401
3402
0
    if (sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
3403
0
                                               keyId) != SECSuccess) {
3404
0
        return NULL;
3405
0
    }
3406
3407
0
    return certBag;
3408
0
}
3409
3410
static sec_PKCS12SafeBag **
3411
sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx,
3412
                                    SEC_PKCS12CertAndCRL *oldCert)
3413
0
{
3414
0
    sec_PKCS12SafeBag **certList;
3415
0
    SECItem **derCertList;
3416
0
    int i, j;
3417
3418
0
    if (!p12dcx || p12dcx->error || !oldCert) {
3419
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3420
0
        return NULL;
3421
0
    }
3422
3423
0
    derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL);
3424
0
    if (!derCertList) {
3425
0
        return NULL;
3426
0
    }
3427
3428
0
    i = 0;
3429
0
    while (derCertList[i])
3430
0
        i++;
3431
3432
0
    certList = PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, (i + 1));
3433
0
    if (!certList) {
3434
0
        return NULL;
3435
0
    }
3436
3437
0
    for (j = 0; j < i; j++) {
3438
0
        certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]);
3439
0
        if (!certList[j]) {
3440
0
            return NULL;
3441
0
        }
3442
0
    }
3443
3444
0
    return certList;
3445
0
}
3446
3447
static SECStatus
3448
sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx,
3449
                                             void *oldKey, PRBool isEspvk,
3450
                                             SEC_PKCS12SafeContents *safe,
3451
                                             SEC_PKCS12Baggage *baggage)
3452
0
{
3453
0
    sec_PKCS12SafeBag *key, **certList;
3454
0
    SEC_PKCS12CertAndCRL *oldCert;
3455
0
    SEC_PKCS12PVKSupportingData *pvkData;
3456
0
    int i;
3457
0
    SECItem *keyName;
3458
3459
0
    if (!p12dcx || !oldKey) {
3460
0
        return SECFailure;
3461
0
    }
3462
3463
0
    if (isEspvk) {
3464
0
        pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData;
3465
0
    } else {
3466
0
        pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData;
3467
0
    }
3468
3469
0
    if (!pvkData->assocCerts || !pvkData->assocCerts[0]) {
3470
0
        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3471
0
        return SECFailure;
3472
0
    }
3473
3474
0
    oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
3475
0
                                                             SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL,
3476
0
                                                             pvkData->assocCerts[0]);
3477
0
    if (!oldCert) {
3478
0
        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3479
0
        return SECFailure;
3480
0
    }
3481
3482
0
    key = sec_pkcs12_decoder_convert_old_key(p12dcx, oldKey, isEspvk);
3483
0
    certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert);
3484
0
    if (!key || !certList) {
3485
0
        return SECFailure;
3486
0
    }
3487
3488
0
    if (sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) {
3489
0
        return SECFailure;
3490
0
    }
3491
3492
0
    keyName = sec_pkcs12_get_nickname(key);
3493
0
    if (!keyName) {
3494
0
        return SECFailure;
3495
0
    }
3496
3497
0
    i = 0;
3498
0
    while (certList[i]) {
3499
0
        if (sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i]) != SECSuccess) {
3500
0
            return SECFailure;
3501
0
        }
3502
0
        i++;
3503
0
    }
3504
3505
0
    certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key);
3506
0
    if (!certList) {
3507
0
        return SECFailure;
3508
0
    }
3509
3510
0
    i = 0;
3511
0
    while (certList[i] != 0) {
3512
0
        if (sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) {
3513
0
            return SECFailure;
3514
0
        }
3515
0
        i++;
3516
0
    }
3517
3518
0
    return SECSuccess;
3519
0
}
3520
3521
static SECStatus
3522
sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx,
3523
                                            SEC_PKCS12SafeContents *safe,
3524
                                            SEC_PKCS12Baggage *baggage)
3525
0
{
3526
0
    SECStatus rv;
3527
3528
0
    if (!p12dcx || p12dcx->error) {
3529
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3530
0
        return SECFailure;
3531
0
    }
3532
3533
0
    if (safe && safe->contents) {
3534
0
        int i = 0;
3535
0
        while (safe->contents[i] != NULL) {
3536
0
            if (SECOID_FindOIDTag(&safe->contents[i]->safeBagType) == SEC_OID_PKCS12_KEY_BAG_ID) {
3537
0
                int j = 0;
3538
0
                SEC_PKCS12PrivateKeyBag *privBag =
3539
0
                    safe->contents[i]->safeContent.keyBag;
3540
3541
0
                while (privBag->privateKeys[j] != NULL) {
3542
0
                    SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j];
3543
0
                    rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, pk,
3544
0
                                                                      PR_FALSE, safe, baggage);
3545
0
                    if (rv != SECSuccess) {
3546
0
                        goto loser;
3547
0
                    }
3548
0
                    j++;
3549
0
                }
3550
0
            }
3551
0
            i++;
3552
0
        }
3553
0
    }
3554
3555
0
    if (baggage && baggage->bags) {
3556
0
        int i = 0;
3557
0
        while (baggage->bags[i] != NULL) {
3558
0
            SEC_PKCS12BaggageItem *bag = baggage->bags[i];
3559
0
            int j = 0;
3560
3561
0
            if (!bag->espvks) {
3562
0
                i++;
3563
0
                continue;
3564
0
            }
3565
3566
0
            while (bag->espvks[j] != NULL) {
3567
0
                SEC_PKCS12ESPVKItem *espvk = bag->espvks[j];
3568
0
                rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk,
3569
0
                                                                  PR_TRUE, safe, baggage);
3570
0
                if (rv != SECSuccess) {
3571
0
                    goto loser;
3572
0
                }
3573
0
                j++;
3574
0
            }
3575
0
            i++;
3576
0
        }
3577
0
    }
3578
3579
0
    return SECSuccess;
3580
3581
0
loser:
3582
0
    return SECFailure;
3583
0
}
3584
3585
SEC_PKCS12DecoderContext *
3586
sec_PKCS12ConvertOldSafeToNew(PLArenaPool *arena, PK11SlotInfo *slot,
3587
                              PRBool swapUnicode, SECItem *pwitem,
3588
                              void *wincx, SEC_PKCS12SafeContents *safe,
3589
                              SEC_PKCS12Baggage *baggage)
3590
0
{
3591
0
    SEC_PKCS12DecoderContext *p12dcx;
3592
3593
0
    if (!arena || !slot || !pwitem) {
3594
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3595
0
        return NULL;
3596
0
    }
3597
3598
0
    if (!safe && !baggage) {
3599
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
3600
0
        return NULL;
3601
0
    }
3602
3603
0
    p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
3604
0
    if (!p12dcx) {
3605
0
        return NULL;
3606
0
    }
3607
3608
0
    p12dcx->arena = arena;
3609
0
    p12dcx->slot = PK11_ReferenceSlot(slot);
3610
0
    p12dcx->wincx = wincx;
3611
0
    p12dcx->error = PR_FALSE;
3612
0
    p12dcx->swapUnicodeBytes = swapUnicode;
3613
0
    p12dcx->pwitem = pwitem;
3614
0
    p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
3615
3616
0
    if (sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage) != SECSuccess) {
3617
0
        p12dcx->error = PR_TRUE;
3618
0
        return NULL;
3619
0
    }
3620
3621
0
    return p12dcx;
3622
0
}