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