Coverage Report

Created: 2018-09-25 14:53

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