Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / pkcs12 / p12d.c
blob6985f565f4c2ccd39548e30fa1b607d2ebf2799f
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 #include "nssrenam.h"
40 #include "p12t.h"
41 #include "p12.h"
42 #include "plarena.h"
43 #include "secitem.h"
44 #include "secoid.h"
45 #include "seccomon.h"
46 #include "secport.h"
47 #include "cert.h"
48 #include "secpkcs7.h"
49 #include "secasn1.h"
50 #include "secerr.h"
51 #include "pk11func.h"
52 #include "p12plcy.h"
53 #include "p12local.h"
54 #include "secder.h"
55 #include "secport.h"
57 #include "certdb.h"
59 #include "prcpucfg.h"
61 typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext;
63 /* Opaque structure for decoding SafeContents. These are used
64 * for each authenticated safe as well as any nested safe contents.
66 struct sec_PKCS12SafeContentsContextStr {
67 /* the parent decoder context */
68 SEC_PKCS12DecoderContext *p12dcx;
70 /* memory arena to allocate space from */
71 PRArenaPool *arena;
73 /* decoder context and destination for decoding safe contents */
74 SEC_ASN1DecoderContext *safeContentsDcx;
75 sec_PKCS12SafeContents safeContents;
77 /* information for decoding safe bags within the safe contents.
78 * these variables are updated for each safe bag decoded.
80 SEC_ASN1DecoderContext *currentSafeBagDcx;
81 sec_PKCS12SafeBag *currentSafeBag;
82 PRBool skipCurrentSafeBag;
84 /* if the safe contents is nested, the parent is pointed to here. */
85 sec_PKCS12SafeContentsContext *nestedCtx;
88 /* opaque decoder context structure. information for decoding a pkcs 12
89 * PDU are stored here as well as decoding pointers for intermediary
90 * structures which are part of the PKCS 12 PDU. Upon a successful
91 * decode, the safe bags containing certificates and keys encountered.
92 */
93 struct SEC_PKCS12DecoderContextStr {
94 PRArenaPool *arena;
95 PK11SlotInfo *slot;
96 void *wincx;
97 PRBool error;
98 int errorValue;
100 /* password */
101 SECItem *pwitem;
103 /* used for decoding the PFX structure */
104 SEC_ASN1DecoderContext *pfxDcx;
105 sec_PKCS12PFXItem pfx;
107 /* safe bags found during decoding */
108 sec_PKCS12SafeBag **safeBags;
109 unsigned int safeBagCount;
111 /* state variables for decoding authenticated safes. */
112 SEC_PKCS7DecoderContext *currentASafeP7Dcx;
113 SEC_ASN1DecoderContext *aSafeDcx;
114 SEC_PKCS7DecoderContext *aSafeP7Dcx;
115 sec_PKCS12AuthenticatedSafe authSafe;
116 SEC_PKCS7ContentInfo *aSafeCinfo;
117 sec_PKCS12SafeContents safeContents;
119 /* safe contents info */
120 unsigned int safeContentsCnt;
121 sec_PKCS12SafeContentsContext **safeContentsList;
123 /* HMAC info */
124 sec_PKCS12MacData macData;
125 SEC_ASN1DecoderContext *hmacDcx;
127 /* routines for reading back the data to be hmac'd */
128 digestOpenFn dOpen;
129 digestCloseFn dClose;
130 digestIOFn dRead, dWrite;
131 void *dArg;
133 /* helper functions */
134 SECKEYGetPasswordKey pwfn;
135 void *pwfnarg;
136 PRBool swapUnicodeBytes;
138 /* import information */
139 PRBool bagsVerified;
141 /* buffer management for the default callbacks implementation */
142 void *buffer; /* storage area */
143 PRInt32 filesize; /* actual data size */
144 PRInt32 allocated; /* total buffer size allocated */
145 PRInt32 currentpos; /* position counter */
146 SECPKCS12TargetTokenCAs tokenCAs;
147 sec_PKCS12SafeBag **keyList;/* used by ...IterateNext() */
148 unsigned int iteration;
149 SEC_PKCS12DecoderItem decitem;
153 /* make sure that the PFX version being decoded is a version
154 * which we support.
156 static PRBool
157 sec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx)
159 /* if no version, assume it is not supported */
160 if(pfx->version.len == 0) {
161 return PR_FALSE;
164 if(DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) {
165 return PR_FALSE;
168 return PR_TRUE;
171 /* retrieve the key for decrypting the safe contents */
172 static PK11SymKey *
173 sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid)
175 SEC_PKCS12DecoderContext *p12dcx =
176 (SEC_PKCS12DecoderContext *) arg;
177 PK11SlotInfo *slot;
178 PK11SymKey *bulkKey;
180 if(!p12dcx) {
181 return NULL;
184 /* if no slot specified, use the internal key slot */
185 if(p12dcx->slot) {
186 slot = PK11_ReferenceSlot(p12dcx->slot);
187 } else {
188 slot = PK11_GetInternalKeySlot();
191 bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem,
192 PR_FALSE, p12dcx->wincx);
193 /* some tokens can't generate PBE keys on their own, generate the
194 * key in the internal slot, and let the Import code deal with it,
195 * (if the slot can't generate PBEs, then we need to use the internal
196 * slot anyway to unwrap). */
197 if (!bulkKey && !PK11_IsInternal(slot)) {
198 PK11_FreeSlot(slot);
199 slot = PK11_GetInternalKeySlot();
200 bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem,
201 PR_FALSE, p12dcx->wincx);
203 PK11_FreeSlot(slot);
205 /* set the password data on the key */
206 if (bulkKey) {
207 PK11_SetSymKeyUserData(bulkKey,p12dcx->pwitem, NULL);
211 return bulkKey;
214 /* XXX this needs to be modified to handle enveloped data. most
215 * likely, it should mirror the routines for SMIME in that regard.
217 static PRBool
218 sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid,
219 PK11SymKey *bulkkey)
221 PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid);
223 if(!decryptionAllowed) {
224 return PR_FALSE;
227 return PR_TRUE;
230 /* when we encounter a new safe bag during the decoding, we need
231 * to allocate space for the bag to be decoded to and set the
232 * state variables appropriately. all of the safe bags are allocated
233 * in a buffer in the outer SEC_PKCS12DecoderContext, however,
234 * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext
235 * for the current bag.
237 static SECStatus
238 sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext
239 *safeContentsCtx)
241 void *mark = NULL;
242 SEC_PKCS12DecoderContext *p12dcx;
244 /* make sure that the structures are defined, and there has
245 * not been an error in the decoding
247 if(!safeContentsCtx || !safeContentsCtx->p12dcx
248 || safeContentsCtx->p12dcx->error) {
249 return SECFailure;
252 p12dcx = safeContentsCtx->p12dcx;
253 mark = PORT_ArenaMark(p12dcx->arena);
255 /* allocate a new safe bag, if bags already exist, grow the
256 * list of bags, otherwise allocate a new list. the list is
257 * NULL terminated.
259 if(p12dcx->safeBagCount) {
260 p12dcx->safeBags =
261 (sec_PKCS12SafeBag**)PORT_ArenaGrow(p12dcx->arena,p12dcx->safeBags,
262 (p12dcx->safeBagCount + 1) * sizeof(sec_PKCS12SafeBag *),
263 (p12dcx->safeBagCount + 2) * sizeof(sec_PKCS12SafeBag *));
264 } else {
265 p12dcx->safeBags = (sec_PKCS12SafeBag**)PORT_ArenaZAlloc(p12dcx->arena,
266 2 * sizeof(sec_PKCS12SafeBag *));
268 if(!p12dcx->safeBags) {
269 p12dcx->errorValue = PORT_GetError();
270 goto loser;
273 /* append the bag to the end of the list and update the reference
274 * in the safeContentsCtx.
276 p12dcx->safeBags[p12dcx->safeBagCount] =
277 safeContentsCtx->currentSafeBag =
278 (sec_PKCS12SafeBag*)PORT_ArenaZAlloc(p12dcx->arena,
279 sizeof(sec_PKCS12SafeBag));
280 if(!safeContentsCtx->currentSafeBag) {
281 p12dcx->errorValue = PORT_GetError();
282 goto loser;
284 p12dcx->safeBags[++p12dcx->safeBagCount] = NULL;
286 safeContentsCtx->currentSafeBag->slot = safeContentsCtx->p12dcx->slot;
287 safeContentsCtx->currentSafeBag->pwitem = safeContentsCtx->p12dcx->pwitem;
288 safeContentsCtx->currentSafeBag->swapUnicodeBytes =
289 safeContentsCtx->p12dcx->swapUnicodeBytes;
290 safeContentsCtx->currentSafeBag->arena = safeContentsCtx->p12dcx->arena;
291 safeContentsCtx->currentSafeBag->tokenCAs =
292 safeContentsCtx->p12dcx->tokenCAs;
294 PORT_ArenaUnmark(p12dcx->arena, mark);
295 return SECSuccess;
297 loser:
299 /* if an error occurred, release the memory and set the error flag
300 * the only possible errors triggered by this function are memory
301 * related.
303 if(mark) {
304 PORT_ArenaRelease(p12dcx->arena, mark);
307 p12dcx->error = PR_TRUE;
308 return SECFailure;
311 /* A wrapper for updating the ASN1 context in which a safeBag is
312 * being decoded. This function is called as a callback from
313 * secasn1d when decoding SafeContents structures.
315 static void
316 sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data,
317 unsigned long len, int depth,
318 SEC_ASN1EncodingPart data_kind)
320 sec_PKCS12SafeContentsContext *safeContentsCtx =
321 (sec_PKCS12SafeContentsContext *)arg;
322 SEC_PKCS12DecoderContext *p12dcx;
323 SECStatus rv;
325 /* make sure that we are not skipping the current safeBag,
326 * and that there are no errors. If so, just return rather
327 * than continuing to process.
329 if(!safeContentsCtx || !safeContentsCtx->p12dcx
330 || safeContentsCtx->p12dcx->error
331 || safeContentsCtx->skipCurrentSafeBag) {
332 return;
334 p12dcx = safeContentsCtx->p12dcx;
336 rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagDcx, data, len);
337 if(rv != SECSuccess) {
338 p12dcx->errorValue = PORT_GetError();
339 goto loser;
342 return;
344 loser:
345 /* set the error, and finish the decoder context. because there
346 * is not a way of returning an error message, it may be worth
347 * while to do a check higher up and finish any decoding contexts
348 * that are still open.
350 p12dcx->error = PR_TRUE;
351 SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);
352 safeContentsCtx->currentSafeBagDcx = NULL;
353 return;
356 /* forward declarations of functions that are used when decoding
357 * safeContents bags which are nested and when decoding the
358 * authenticatedSafes.
360 static SECStatus
361 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
362 *safeContentsCtx);
363 static SECStatus
364 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
365 *safeContentsCtx);
366 static void
367 sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data,
368 unsigned long len, int depth,
369 SEC_ASN1EncodingPart data_kind);
371 /* notify function for decoding safeBags. This function is
372 * used to filter safeBag types which are not supported,
373 * initiate the decoding of nested safe contents, and decode
374 * safeBags in general. this function is set when the decoder
375 * context for the safeBag is first created.
377 static void
378 sec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before,
379 void *dest, int real_depth)
381 sec_PKCS12SafeContentsContext *safeContentsCtx =
382 (sec_PKCS12SafeContentsContext *)arg;
383 SEC_PKCS12DecoderContext *p12dcx;
384 sec_PKCS12SafeBag *bag;
385 PRBool after;
387 /* if an error is encountered, return */
388 if(!safeContentsCtx || !safeContentsCtx->p12dcx ||
389 safeContentsCtx->p12dcx->error) {
390 return;
392 p12dcx = safeContentsCtx->p12dcx;
394 /* to make things more readable */
395 if(before)
396 after = PR_FALSE;
397 else
398 after = PR_TRUE;
400 /* have we determined the safeBagType yet? */
401 bag = safeContentsCtx->currentSafeBag;
402 if(bag->bagTypeTag == NULL) {
403 if(after && (dest == &(bag->safeBagType))) {
404 bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType));
405 if(bag->bagTypeTag == NULL) {
406 p12dcx->error = PR_TRUE;
407 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
410 return;
413 /* process the safeBag depending on it's type. those
414 * which we do not support, are ignored. we start a decoding
415 * context for a nested safeContents.
417 switch(bag->bagTypeTag->offset) {
418 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
419 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
420 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
421 break;
422 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
423 /* if we are just starting to decode the safeContents, initialize
424 * a new safeContentsCtx to process it.
426 if(before && (dest == &(bag->safeBagContent))) {
427 sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx);
428 } else if(after && (dest == &(bag->safeBagContent))) {
429 /* clean up the nested decoding */
430 sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx);
432 break;
433 case SEC_OID_PKCS12_V1_CRL_BAG_ID:
434 case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
435 default:
436 /* skip any safe bag types we don't understand or handle */
437 safeContentsCtx->skipCurrentSafeBag = PR_TRUE;
438 break;
441 return;
444 /* notify function for decoding safe contents. each entry in the
445 * safe contents is a safeBag which needs to be allocated and
446 * the decoding context initialized at the beginning and then
447 * the context needs to be closed and finished at the end.
449 * this function is set when the safeContents decode context is
450 * initialized.
452 static void
453 sec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before,
454 void *dest, int real_depth)
456 sec_PKCS12SafeContentsContext *safeContentsCtx =
457 (sec_PKCS12SafeContentsContext*)arg;
458 SEC_PKCS12DecoderContext *p12dcx;
459 SECStatus rv;
461 /* if there is an error we don't want to continue processing,
462 * just return and keep going.
464 if(!safeContentsCtx || !safeContentsCtx->p12dcx
465 || safeContentsCtx->p12dcx->error) {
466 return;
468 p12dcx = safeContentsCtx->p12dcx;
470 /* if we are done with the current safeBag, then we need to
471 * finish the context and set the state variables appropriately.
473 if(!before) {
474 SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsDcx);
475 SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);
476 safeContentsCtx->currentSafeBagDcx = NULL;
477 safeContentsCtx->skipCurrentSafeBag = PR_FALSE;
478 } else {
479 /* we are starting a new safe bag. we need to allocate space
480 * for the bag and initialize the decoding context.
482 rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx);
483 if(rv != SECSuccess) {
484 goto loser;
487 /* set up the decoder context */
488 safeContentsCtx->currentSafeBagDcx = SEC_ASN1DecoderStart(p12dcx->arena,
489 safeContentsCtx->currentSafeBag,
490 sec_PKCS12SafeBagTemplate);
491 if(!safeContentsCtx->currentSafeBagDcx) {
492 p12dcx->errorValue = PORT_GetError();
493 goto loser;
496 /* set the notify and filter procs so that the safe bag
497 * data gets sent to the proper location when decoding.
499 SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagDcx,
500 sec_pkcs12_decoder_safe_bag_notify,
501 safeContentsCtx);
502 SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsDcx,
503 sec_pkcs12_decoder_safe_bag_update,
504 safeContentsCtx, PR_TRUE);
507 return;
509 loser:
510 /* in the event of an error, we want to close the decoding
511 * context and clear the filter and notify procedures.
513 p12dcx->error = PR_TRUE;
515 if(safeContentsCtx->currentSafeBagDcx) {
516 SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagDcx);
517 safeContentsCtx->currentSafeBagDcx = NULL;
520 SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsDcx);
521 SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsDcx);
523 return;
526 /* initialize the safeContents for decoding. this routine
527 * is used for authenticatedSafes as well as nested safeContents.
529 static sec_PKCS12SafeContentsContext *
530 sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx,
531 PRBool nestedSafe)
533 sec_PKCS12SafeContentsContext *safeContentsCtx = NULL;
534 const SEC_ASN1Template *theTemplate;
536 if(!p12dcx || p12dcx->error) {
537 return NULL;
540 /* allocate a new safeContents list or grow the existing list and
541 * append the new safeContents onto the end.
543 if(!p12dcx->safeContentsCnt) {
544 p12dcx->safeContentsList =
545 (sec_PKCS12SafeContentsContext**)PORT_ArenaZAlloc(p12dcx->arena,
546 2 * sizeof(sec_PKCS12SafeContentsContext *));
547 } else {
548 p12dcx->safeContentsList =
549 (sec_PKCS12SafeContentsContext **) PORT_ArenaGrow(p12dcx->arena,
550 p12dcx->safeContentsList,
551 (1 + p12dcx->safeContentsCnt) *
552 sizeof(sec_PKCS12SafeContentsContext *),
553 (2 + p12dcx->safeContentsCnt) *
554 sizeof(sec_PKCS12SafeContentsContext *));
556 if(!p12dcx->safeContentsList) {
557 p12dcx->errorValue = PORT_GetError();
558 goto loser;
561 p12dcx->safeContentsList[p12dcx->safeContentsCnt] = safeContentsCtx =
562 (sec_PKCS12SafeContentsContext*)PORT_ArenaZAlloc(
563 p12dcx->arena,
564 sizeof(sec_PKCS12SafeContentsContext));
565 if(!p12dcx->safeContentsList[p12dcx->safeContentsCnt]) {
566 p12dcx->errorValue = PORT_GetError();
567 goto loser;
569 p12dcx->safeContentsList[++p12dcx->safeContentsCnt] = NULL;
571 /* set up the state variables */
572 safeContentsCtx->p12dcx = p12dcx;
573 safeContentsCtx->arena = p12dcx->arena;
575 /* begin the decoding -- the template is based on whether we are
576 * decoding a nested safeContents or not.
578 if(nestedSafe == PR_TRUE) {
579 theTemplate = sec_PKCS12NestedSafeContentsDecodeTemplate;
580 } else {
581 theTemplate = sec_PKCS12SafeContentsDecodeTemplate;
584 /* start the decoder context */
585 safeContentsCtx->safeContentsDcx = SEC_ASN1DecoderStart(p12dcx->arena,
586 &safeContentsCtx->safeContents,
587 theTemplate);
589 if(!safeContentsCtx->safeContentsDcx) {
590 p12dcx->errorValue = PORT_GetError();
591 goto loser;
594 /* set the safeContents notify procedure to look for
595 * and start the decode of safeBags.
597 SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->safeContentsDcx,
598 sec_pkcs12_decoder_safe_contents_notify,
599 safeContentsCtx);
601 return safeContentsCtx;
603 loser:
604 /* in the case of an error, we want to finish the decoder
605 * context and set the error flag.
607 if(safeContentsCtx && safeContentsCtx->safeContentsDcx) {
608 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsDcx);
609 safeContentsCtx->safeContentsDcx = NULL;
612 p12dcx->error = PR_TRUE;
614 return NULL;
617 /* wrapper for updating safeContents. this is set as the filter of
618 * safeBag when there is a nested safeContents.
620 static void
621 sec_pkcs12_decoder_nested_safe_contents_update(void *arg, const char *buf,
622 unsigned long len, int depth,
623 SEC_ASN1EncodingPart data_kind)
625 sec_PKCS12SafeContentsContext *safeContentsCtx =
626 (sec_PKCS12SafeContentsContext *)arg;
627 SEC_PKCS12DecoderContext *p12dcx;
628 SECStatus rv;
630 /* check for an error */
631 if(!safeContentsCtx || !safeContentsCtx->p12dcx
632 || safeContentsCtx->p12dcx->error
633 || !safeContentsCtx->safeContentsDcx) {
634 return;
637 /* no need to update if no data sent in */
638 if(!len || !buf) {
639 return;
642 /* update the decoding context */
643 p12dcx = safeContentsCtx->p12dcx;
644 rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsDcx, buf, len);
645 if(rv != SECSuccess) {
646 p12dcx->errorValue = PORT_GetError();
647 goto loser;
650 return;
652 loser:
653 /* handle any errors. If a decoding context is open, close it. */
654 p12dcx->error = PR_TRUE;
655 if(safeContentsCtx->safeContentsDcx) {
656 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsDcx);
657 safeContentsCtx->safeContentsDcx = NULL;
661 /* whenever a new safeContentsSafeBag is encountered, we need
662 * to init a safeContentsContext.
664 static SECStatus
665 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
666 *safeContentsCtx)
668 /* check for an error */
669 if(!safeContentsCtx || !safeContentsCtx->p12dcx ||
670 safeContentsCtx->p12dcx->error) {
671 return SECFailure;
674 safeContentsCtx->nestedCtx = sec_pkcs12_decoder_safe_contents_init_decode(
675 safeContentsCtx->p12dcx,
676 PR_TRUE);
677 if(!safeContentsCtx->nestedCtx) {
678 return SECFailure;
681 /* set up new filter proc */
682 SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->nestedCtx->safeContentsDcx,
683 sec_pkcs12_decoder_safe_contents_notify,
684 safeContentsCtx->nestedCtx);
685 SEC_ASN1DecoderSetFilterProc(safeContentsCtx->currentSafeBagDcx,
686 sec_pkcs12_decoder_nested_safe_contents_update,
687 safeContentsCtx->nestedCtx, PR_TRUE);
689 return SECSuccess;
692 /* when the safeContents is done decoding, we need to reset the
693 * proper filter and notify procs and close the decoding context
695 static SECStatus
696 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
697 *safeContentsCtx)
699 /* check for error */
700 if(!safeContentsCtx || !safeContentsCtx->p12dcx ||
701 safeContentsCtx->p12dcx->error) {
702 return SECFailure;
705 /* clean up */
706 SEC_ASN1DecoderClearFilterProc(safeContentsCtx->currentSafeBagDcx);
707 SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->nestedCtx->safeContentsDcx);
708 SEC_ASN1DecoderFinish(safeContentsCtx->nestedCtx->safeContentsDcx);
709 safeContentsCtx->nestedCtx->safeContentsDcx = NULL;
710 safeContentsCtx->nestedCtx = NULL;
712 return SECSuccess;
715 /* wrapper for updating safeContents. This is used when decoding
716 * the nested safeContents and any authenticatedSafes.
718 static void
719 sec_pkcs12_decoder_safe_contents_callback(void *arg, const char *buf,
720 unsigned long len)
722 SECStatus rv;
723 sec_PKCS12SafeContentsContext *safeContentsCtx =
724 (sec_PKCS12SafeContentsContext *)arg;
725 SEC_PKCS12DecoderContext *p12dcx;
727 /* check for error */
728 if(!safeContentsCtx || !safeContentsCtx->p12dcx
729 || safeContentsCtx->p12dcx->error
730 || !safeContentsCtx->safeContentsDcx) {
731 return;
733 p12dcx = safeContentsCtx->p12dcx;
735 /* update the decoder */
736 rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsDcx, buf, len);
737 if(rv != SECSuccess) {
738 /* if we fail while trying to decode a 'safe', it's probably because
739 * we didn't have the correct password. */
740 PORT_SetError(SEC_ERROR_BAD_PASSWORD);
741 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
742 SEC_PKCS7DecoderAbort(p12dcx->currentASafeP7Dcx,SEC_ERROR_BAD_PASSWORD);
743 goto loser;
746 return;
748 loser:
749 /* set the error and finish the context */
750 p12dcx->error = PR_TRUE;
751 if(safeContentsCtx->safeContentsDcx) {
752 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsDcx);
753 safeContentsCtx->safeContentsDcx = NULL;
756 return;
759 /* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate
761 static void
762 sec_pkcs12_decoder_wrap_p7_update(void *arg, const char *data,
763 unsigned long len, int depth,
764 SEC_ASN1EncodingPart data_kind)
766 SEC_PKCS7DecoderContext *p7dcx = (SEC_PKCS7DecoderContext *)arg;
768 SEC_PKCS7DecoderUpdate(p7dcx, data, len);
771 /* notify function for decoding aSafes. at the beginning,
772 * of an authenticatedSafe, we start a decode of a safeContents.
773 * at the end, we clean up the safeContents decoder context and
774 * reset state variables
776 static void
777 sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest,
778 int real_depth)
780 SEC_PKCS12DecoderContext *p12dcx;
781 sec_PKCS12SafeContentsContext *safeContentsCtx;
783 /* make sure no error occurred. */
784 p12dcx = (SEC_PKCS12DecoderContext *)arg;
785 if(!p12dcx || p12dcx->error) {
786 return;
789 if(before) {
791 /* init a new safeContentsContext */
792 safeContentsCtx = sec_pkcs12_decoder_safe_contents_init_decode(p12dcx,
793 PR_FALSE);
794 if(!safeContentsCtx) {
795 goto loser;
798 /* initiate the PKCS7ContentInfo decode */
799 p12dcx->currentASafeP7Dcx = SEC_PKCS7DecoderStart(
800 sec_pkcs12_decoder_safe_contents_callback,
801 safeContentsCtx,
802 p12dcx->pwfn, p12dcx->pwfnarg,
803 sec_pkcs12_decoder_get_decrypt_key, p12dcx,
804 sec_pkcs12_decoder_decryption_allowed);
805 if(!p12dcx->currentASafeP7Dcx) {
806 p12dcx->errorValue = PORT_GetError();
807 goto loser;
809 SEC_ASN1DecoderSetFilterProc(p12dcx->aSafeDcx,
810 sec_pkcs12_decoder_wrap_p7_update,
811 p12dcx->currentASafeP7Dcx, PR_TRUE);
814 if(!before) {
815 /* if one is being decoded, finish the decode */
816 if(p12dcx->currentASafeP7Dcx != NULL) {
817 if(!SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx)) {
818 p12dcx->currentASafeP7Dcx = NULL;
819 p12dcx->errorValue = PORT_GetError();
820 goto loser;
822 p12dcx->currentASafeP7Dcx = NULL;
827 return;
829 loser:
830 /* set the error flag */
831 p12dcx->error = PR_TRUE;
832 return;
835 /* wrapper for updating asafes decoding context. this function
836 * writes data being decoded to disk, so that a mac can be computed
837 * later.
839 static void
840 sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf,
841 unsigned long len)
843 SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
844 SECStatus rv;
846 if(!p12dcx || p12dcx->error) {
847 return;
850 /* update the context */
851 rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeDcx, buf, len);
852 if(rv != SECSuccess) {
853 p12dcx->errorValue = PORT_GetError();
854 p12dcx->error = PR_TRUE;
855 goto loser;
858 /* if we are writing to a file, write out the new information */
859 if(p12dcx->dWrite) {
860 unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg,
861 (unsigned char *)buf, len);
862 if(writeLen != len) {
863 p12dcx->errorValue = PORT_GetError();
864 goto loser;
868 return;
870 loser:
871 /* set the error flag */
872 p12dcx->error = PR_TRUE;
873 SEC_ASN1DecoderFinish(p12dcx->aSafeDcx);
874 p12dcx->aSafeDcx = NULL;
876 return;
879 /* start the decode of an authenticatedSafe contentInfo.
881 static SECStatus
882 sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx)
884 if(!p12dcx || p12dcx->error) {
885 return SECFailure;
888 /* start the decode context */
889 p12dcx->aSafeDcx = SEC_ASN1DecoderStart(p12dcx->arena,
890 &p12dcx->authSafe,
891 sec_PKCS12AuthenticatedSafeTemplate);
892 if(!p12dcx->aSafeDcx) {
893 p12dcx->errorValue = PORT_GetError();
894 goto loser;
897 /* set the notify function */
898 SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeDcx,
899 sec_pkcs12_decoder_asafes_notify, p12dcx);
901 /* begin the authSafe decoder context */
902 p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart(
903 sec_pkcs12_decoder_asafes_callback, p12dcx,
904 p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL);
905 if(!p12dcx->aSafeP7Dcx) {
906 p12dcx->errorValue = PORT_GetError();
907 goto loser;
910 /* open the temp file for writing, if the filter functions were set */
911 if(p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE)
912 != SECSuccess) {
913 p12dcx->errorValue = PORT_GetError();
914 goto loser;
917 return SECSuccess;
919 loser:
920 p12dcx->error = PR_TRUE;
922 if(p12dcx->aSafeDcx) {
923 SEC_ASN1DecoderFinish(p12dcx->aSafeDcx);
924 p12dcx->aSafeDcx = NULL;
927 if(p12dcx->aSafeP7Dcx) {
928 SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
929 p12dcx->aSafeP7Dcx = NULL;
932 return SECFailure;
935 /* wrapper for updating the safeContents. this function is used as
936 * a filter for the pfx when decoding the authenticated safes
938 static void
939 sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf,
940 unsigned long len, int depth,
941 SEC_ASN1EncodingPart data_kind)
943 SEC_PKCS12DecoderContext *p12dcx;
944 SECStatus rv;
946 p12dcx = (SEC_PKCS12DecoderContext*)arg;
947 if(!p12dcx || p12dcx->error) {
948 return;
951 /* update the safeContents decoder */
952 rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len);
953 if(rv != SECSuccess) {
954 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
955 goto loser;
958 return;
960 loser:
962 /* did we find an error? if so, close the context and set the
963 * error flag.
965 SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
966 p12dcx->aSafeP7Dcx = NULL;
967 p12dcx->error = PR_TRUE;
970 /* notify procedure used while decoding the pfx. When we encounter
971 * the authSafes, we want to trigger the decoding of authSafes as well
972 * as when we encounter the macData, trigger the decoding of it. we do
973 * this because we we are streaming the decoder and not decoding in place.
974 * the pfx which is the destination, only has the version decoded into it.
976 static void
977 sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest,
978 int real_depth)
980 SECStatus rv;
981 SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext*)arg;
983 /* if an error occurrs, clear the notifyProc and the filterProc
984 * and continue.
986 if(p12dcx->error) {
987 SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxDcx);
988 SEC_ASN1DecoderClearFilterProc(p12dcx->pfxDcx);
989 return;
992 if(before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
994 /* we want to make sure this is a version we support */
995 if(!sec_pkcs12_proper_version(&p12dcx->pfx)) {
996 p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
997 goto loser;
1000 /* start the decode of the aSafes cinfo... */
1001 rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx);
1002 if(rv != SECSuccess) {
1003 goto loser;
1006 /* set the filter proc to update the authenticated safes. */
1007 SEC_ASN1DecoderSetFilterProc(p12dcx->pfxDcx,
1008 sec_pkcs12_decode_asafes_cinfo_update,
1009 p12dcx, PR_TRUE);
1012 if(!before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
1014 /* we are done decoding the authenticatedSafes, so we need to
1015 * finish the decoderContext and clear the filter proc
1016 * and close the hmac callback, if present
1018 p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
1019 p12dcx->aSafeP7Dcx = NULL;
1020 if(!p12dcx->aSafeCinfo) {
1021 p12dcx->errorValue = PORT_GetError();
1022 goto loser;
1024 SEC_ASN1DecoderClearFilterProc(p12dcx->pfxDcx);
1025 if(p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE)
1026 != SECSuccess)) {
1027 p12dcx->errorValue = PORT_GetError();
1028 goto loser;
1033 return;
1035 loser:
1036 p12dcx->error = PR_TRUE;
1039 /* default implementations of the open/close/read/write functions for
1040 SEC_PKCS12DecoderStart
1043 #define DEFAULT_TEMP_SIZE 4096
1045 static SECStatus
1046 p12u_DigestOpen(void *arg, PRBool readData)
1048 SEC_PKCS12DecoderContext* p12cxt = arg;
1050 p12cxt->currentpos = 0;
1052 if (PR_FALSE == readData) {
1053 /* allocate an initial buffer */
1054 p12cxt->filesize = 0;
1055 p12cxt->allocated = DEFAULT_TEMP_SIZE;
1056 p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE);
1057 PR_ASSERT(p12cxt->buffer);
1059 else
1061 PR_ASSERT(p12cxt->buffer);
1062 if (!p12cxt->buffer) {
1063 return SECFailure; /* no data to read */
1067 return SECSuccess;
1070 static SECStatus
1071 p12u_DigestClose(void *arg, PRBool removeFile)
1073 SEC_PKCS12DecoderContext* p12cxt = arg;
1075 PR_ASSERT(p12cxt);
1076 if (!p12cxt) {
1077 return SECFailure;
1079 p12cxt->currentpos = 0;
1081 if (PR_TRUE == removeFile) {
1082 PR_ASSERT(p12cxt->buffer);
1083 if (!p12cxt->buffer) {
1084 return SECFailure;
1086 if (p12cxt->buffer) {
1087 PORT_Free(p12cxt->buffer);
1088 p12cxt->buffer = NULL;
1089 p12cxt->allocated = 0;
1090 p12cxt->filesize = 0;
1094 return SECSuccess;
1097 static int
1098 p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
1100 int toread = len;
1101 SEC_PKCS12DecoderContext* p12cxt = arg;
1103 if(!buf || len == 0 || !p12cxt->buffer) {
1104 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1105 return -1;
1108 if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
1109 /* trying to read past the end of the buffer */
1110 toread = p12cxt->filesize - p12cxt->currentpos;
1112 memcpy(buf, (char*)p12cxt->buffer + p12cxt->currentpos, toread);
1113 p12cxt->currentpos += toread;
1114 return toread;
1117 static int
1118 p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
1120 SEC_PKCS12DecoderContext* p12cxt = arg;
1122 if(!buf || len == 0) {
1123 return -1;
1126 if (p12cxt->currentpos+(long)len > p12cxt->filesize) {
1127 p12cxt->filesize = p12cxt->currentpos + len;
1129 else {
1130 p12cxt->filesize += len;
1132 if (p12cxt->filesize > p12cxt->allocated) {
1133 void* newbuffer;
1134 size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE;
1135 newbuffer = PORT_Realloc(p12cxt->buffer, newsize);
1136 if (NULL == newbuffer) {
1137 return -1; /* can't extend the buffer */
1139 p12cxt->buffer = newbuffer;
1140 p12cxt->allocated = newsize;
1142 PR_ASSERT(p12cxt->buffer);
1143 memcpy((char*)p12cxt->buffer + p12cxt->currentpos, buf, len);
1144 p12cxt->currentpos += len;
1145 return len;
1148 /* SEC_PKCS12DecoderStart
1149 * Creates a decoder context for decoding a PKCS 12 PDU objct.
1150 * This function sets up the initial decoding context for the
1151 * PFX and sets the needed state variables.
1153 * pwitem - the password for the hMac and any encoded safes.
1154 * this should be changed to take a callback which retrieves
1155 * the password. it may be possible for different safes to
1156 * have different passwords. also, the password is already
1157 * in unicode. it should probably be converted down below via
1158 * a unicode conversion callback.
1159 * slot - the slot to import the dataa into should multiple slots
1160 * be supported based on key type and cert type?
1161 * dOpen, dClose, dRead, dWrite - digest routines for writing data
1162 * to a file so it could be read back and the hmack recomputed
1163 * and verified. doesn't seem to be away for both encoding
1164 * and decoding to be single pass, thus the need for these
1165 * routines.
1166 * dArg - the argument for dOpen, etc.
1168 * if NULL == dOpen == dClose == dRead == dWrite == dArg, then default
1169 * implementations using a memory buffer are used
1171 * This function returns the decoder context, if it was successful.
1172 * Otherwise, null is returned.
1174 SEC_PKCS12DecoderContext *
1175 SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
1176 digestOpenFn dOpen, digestCloseFn dClose,
1177 digestIOFn dRead, digestIOFn dWrite, void *dArg)
1179 SEC_PKCS12DecoderContext *p12dcx;
1180 PRArenaPool *arena;
1182 arena = PORT_NewArena(2048); /* different size? */
1183 if(!arena) {
1184 return NULL; /* error is already set */
1187 /* allocate the decoder context and set the state variables */
1188 p12dcx = (SEC_PKCS12DecoderContext*)PORT_ArenaZAlloc(arena, sizeof(SEC_PKCS12DecoderContext));
1189 if(!p12dcx) {
1190 goto loser; /* error is already set */
1193 if (!dOpen && !dClose && !dRead && !dWrite && !dArg) {
1194 /* use default implementations */
1195 dOpen = p12u_DigestOpen;
1196 dClose = p12u_DigestClose;
1197 dRead = p12u_DigestRead;
1198 dWrite = p12u_DigestWrite;
1199 dArg = (void*)p12dcx;
1202 p12dcx->arena = arena;
1203 p12dcx->pwitem = pwitem;
1204 p12dcx->slot = (slot ? PK11_ReferenceSlot(slot)
1205 : PK11_GetInternalKeySlot());
1206 p12dcx->wincx = wincx;
1207 p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
1208 #ifdef IS_LITTLE_ENDIAN
1209 p12dcx->swapUnicodeBytes = PR_TRUE;
1210 #else
1211 p12dcx->swapUnicodeBytes = PR_FALSE;
1212 #endif
1213 p12dcx->errorValue = 0;
1214 p12dcx->error = PR_FALSE;
1216 /* start the decoding of the PFX and set the notify proc
1217 * for the PFX item.
1219 p12dcx->pfxDcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx,
1220 sec_PKCS12PFXItemTemplate);
1221 if(!p12dcx->pfxDcx) {
1222 PK11_FreeSlot(p12dcx->slot);
1223 goto loser;
1226 SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxDcx,
1227 sec_pkcs12_decoder_pfx_notify_proc,
1228 p12dcx);
1230 /* set up digest functions */
1231 p12dcx->dOpen = dOpen;
1232 p12dcx->dWrite = dWrite;
1233 p12dcx->dClose = dClose;
1234 p12dcx->dRead = dRead;
1235 p12dcx->dArg = dArg;
1237 p12dcx->keyList = NULL;
1238 p12dcx->decitem.type = 0;
1239 p12dcx->decitem.der = NULL;
1240 p12dcx->decitem.hasKey = PR_FALSE;
1241 p12dcx->decitem.friendlyName = NULL;
1242 p12dcx->iteration = 0;
1244 return p12dcx;
1246 loser:
1247 PORT_FreeArena(arena, PR_TRUE);
1248 return NULL;
1251 SECStatus
1252 SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx,
1253 SECPKCS12TargetTokenCAs tokenCAs)
1255 if (!p12dcx || p12dcx->error) {
1256 return SECFailure;
1258 p12dcx->tokenCAs = tokenCAs;
1259 return SECSuccess;
1263 /* SEC_PKCS12DecoderUpdate
1264 * Streaming update sending more data to the decoder. If
1265 * an error occurs, SECFailure is returned.
1267 * p12dcx - the decoder context
1268 * data, len - the data buffer and length of data to send to
1269 * the update functions.
1271 SECStatus
1272 SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx,
1273 unsigned char *data, unsigned long len)
1275 SECStatus rv;
1277 if(!p12dcx || p12dcx->error) {
1278 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1279 return SECFailure;
1282 /* update the PFX decoder context */
1283 rv = SEC_ASN1DecoderUpdate(p12dcx->pfxDcx, (const char *)data, len);
1284 if(rv != SECSuccess) {
1285 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
1286 goto loser;
1289 return SECSuccess;
1291 loser:
1293 p12dcx->error = PR_TRUE;
1294 return SECFailure;
1297 /* This should be a nice sized buffer for reading in data (potentially large
1298 ** amounts) to be MACed. It should be MUCH larger than HASH_LENGTH_MAX.
1300 #define IN_BUF_LEN 1024
1301 #ifdef DEBUG
1302 static const char bufferEnd[] = { "BufferEnd" } ;
1303 #endif
1304 #define FUDGE 128 /* must be as large as bufferEnd or more. */
1306 /* verify the hmac by reading the data from the temporary file
1307 * using the routines specified when the decodingContext was
1308 * created and return SECSuccess if the hmac matches.
1310 static SECStatus
1311 sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
1313 PK11Context * pk11cx = NULL;
1314 PK11SymKey * symKey = NULL;
1315 SECItem * params = NULL;
1316 unsigned char * buf;
1317 SECStatus rv = SECFailure;
1318 SECStatus lrv;
1319 unsigned int bufLen;
1320 int iteration;
1321 int bytesRead;
1322 SECOidTag algtag;
1323 SECItem hmacRes;
1324 SECItem ignore = {0};
1325 CK_MECHANISM_TYPE integrityMech;
1327 if(!p12dcx || p12dcx->error) {
1328 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1329 return SECFailure;
1331 buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE);
1332 if (!buf)
1333 return SECFailure; /* error code has been set. */
1335 #ifdef DEBUG
1336 memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd);
1337 #endif
1339 /* generate hmac key */
1340 if(p12dcx->macData.iter.data) {
1341 iteration = (int)DER_GetInteger(&p12dcx->macData.iter);
1342 } else {
1343 iteration = 1;
1346 params = PK11_CreatePBEParams(&p12dcx->macData.macSalt, p12dcx->pwitem,
1347 iteration);
1349 algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm);
1350 switch (algtag) {
1351 case SEC_OID_SHA1:
1352 integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break;
1353 case SEC_OID_MD5:
1354 integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break;
1355 case SEC_OID_MD2:
1356 integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break;
1357 default:
1358 goto loser;
1361 symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL);
1362 PK11_DestroyPBEParams(params);
1363 params = NULL;
1364 if (!symKey) 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;
1371 lrv = PK11_DigestBegin(pk11cx);
1372 if (lrv == SECFailure ) {
1373 goto loser;
1376 /* try to open the data for readback */
1377 if(p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE)
1378 != SECSuccess)) {
1379 goto loser;
1382 /* read the data back IN_BUF_LEN bytes at a time and recompute
1383 * the hmac. if fewer bytes are read than are requested, it is
1384 * assumed that the end of file has been reached. if bytesRead
1385 * is returned as -1, then an error occured reading from the
1386 * file.
1388 do {
1389 bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN);
1390 if (bytesRead < 0) {
1391 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ);
1392 goto loser;
1394 PORT_Assert(bytesRead <= IN_BUF_LEN);
1395 PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd));
1397 if (bytesRead > IN_BUF_LEN) {
1398 /* dRead callback overflowed buffer. */
1399 PORT_SetError(SEC_ERROR_INPUT_LEN);
1400 goto loser;
1403 if (bytesRead) {
1404 lrv = PK11_DigestOp(pk11cx, buf, bytesRead);
1405 if (lrv == SECFailure) {
1406 goto loser;
1409 } while (bytesRead == IN_BUF_LEN);
1411 /* finish the hmac context */
1412 lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN);
1413 if (lrv == SECFailure ) {
1414 goto loser;
1417 hmacRes.data = buf;
1418 hmacRes.len = bufLen;
1420 /* is the hmac computed the same as the hmac which was decoded? */
1421 rv = SECSuccess;
1422 if(SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest)
1423 != SECEqual) {
1424 PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
1425 rv = SECFailure;
1428 loser:
1429 /* close the file and remove it */
1430 if(p12dcx->dClose) {
1431 (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
1434 if(pk11cx) {
1435 PK11_DestroyContext(pk11cx, PR_TRUE);
1437 if (params) {
1438 PK11_DestroyPBEParams(params);
1440 if (symKey) {
1441 PK11_FreeSymKey(symKey);
1443 PORT_ZFree(buf, IN_BUF_LEN + FUDGE);
1445 return rv;
1448 /* SEC_PKCS12DecoderVerify
1449 * Verify the macData or the signature of the decoded PKCS 12 PDU.
1450 * If the signature or the macData do not match, SECFailure is
1451 * returned.
1453 * p12dcx - the decoder context
1455 SECStatus
1456 SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx)
1458 SECStatus rv = SECSuccess;
1460 /* make sure that no errors have occured... */
1461 if(!p12dcx) {
1462 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1463 return SECFailure;
1465 if(p12dcx->error) {
1466 /* error code is already set! PORT_SetError(p12dcx->errorValue); */
1467 return SECFailure;
1470 rv = SEC_ASN1DecoderFinish(p12dcx->pfxDcx);
1471 p12dcx->pfxDcx = NULL;
1472 if(rv != SECSuccess) {
1473 return rv;
1476 /* check the signature or the mac depending on the type of
1477 * integrity used.
1479 if(p12dcx->pfx.encodedMacData.len) {
1480 rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData,
1481 sec_PKCS12MacDataTemplate,
1482 &p12dcx->pfx.encodedMacData);
1483 if(rv == SECSuccess) {
1484 return sec_pkcs12_decoder_verify_mac(p12dcx);
1486 } else {
1487 if(SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner,
1488 PR_FALSE)) {
1489 return SECSuccess;
1490 } else {
1491 PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
1495 return SECFailure;
1498 /* SEC_PKCS12DecoderFinish
1499 * Free any open ASN1 or PKCS7 decoder contexts and then
1500 * free the arena pool which everything should be allocated
1501 * from. This function should be called upon completion of
1502 * decoding and installing of a pfx pdu. This should be
1503 * called even if an error occurs.
1505 * p12dcx - the decoder context
1507 void
1508 SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
1510 if(!p12dcx) {
1511 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1512 return;
1515 if(p12dcx->pfxDcx) {
1516 SEC_ASN1DecoderFinish(p12dcx->pfxDcx);
1517 p12dcx->pfxDcx = NULL;
1520 if(p12dcx->aSafeDcx) {
1521 SEC_ASN1DecoderFinish(p12dcx->aSafeDcx);
1522 p12dcx->aSafeDcx = NULL;
1525 if(p12dcx->currentASafeP7Dcx) {
1526 SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
1527 p12dcx->currentASafeP7Dcx = NULL;
1530 if(p12dcx->aSafeP7Dcx) {
1531 SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
1534 if(p12dcx->hmacDcx) {
1535 SEC_ASN1DecoderFinish(p12dcx->hmacDcx);
1536 p12dcx->hmacDcx = NULL;
1539 if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
1540 SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
1542 if (p12dcx->decitem.friendlyName != NULL) {
1543 SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
1546 if(p12dcx->slot) {
1547 PK11_FreeSlot(p12dcx->slot);
1548 p12dcx->slot = NULL;
1551 if(p12dcx->arena) {
1552 PORT_FreeArena(p12dcx->arena, PR_TRUE);
1556 static SECStatus
1557 sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag,
1558 SECOidTag attributeType,
1559 SECItem *attrValue)
1561 int i = 0;
1562 SECOidData *oid;
1564 if(!bag || !attrValue) {
1565 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1566 return SECFailure;
1569 oid = SECOID_FindOIDByTag(attributeType);
1570 if(!oid) {
1571 return SECFailure;
1574 if(!bag->attribs) {
1575 bag->attribs = (sec_PKCS12Attribute**)PORT_ArenaZAlloc(bag->arena,
1576 sizeof(sec_PKCS12Attribute *) * 2);
1577 } else {
1578 while(bag->attribs[i]) i++;
1579 bag->attribs = (sec_PKCS12Attribute **)PORT_ArenaGrow(bag->arena,
1580 bag->attribs,
1581 (i + 1) * sizeof(sec_PKCS12Attribute *),
1582 (i + 2) * sizeof(sec_PKCS12Attribute *));
1585 if(!bag->attribs) {
1586 return SECFailure;
1589 bag->attribs[i] = (sec_PKCS12Attribute*)PORT_ArenaZAlloc(bag->arena,
1590 sizeof(sec_PKCS12Attribute));
1591 if(!bag->attribs) {
1592 return SECFailure;
1595 bag->attribs[i]->attrValue = (SECItem**)PORT_ArenaZAlloc(bag->arena,
1596 sizeof(SECItem *) * 2);
1597 if(!bag->attribs[i]->attrValue) {
1598 return SECFailure;
1601 bag->attribs[i+1] = NULL;
1602 bag->attribs[i]->attrValue[0] = attrValue;
1603 bag->attribs[i]->attrValue[1] = NULL;
1605 if(SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid)
1606 != SECSuccess) {
1607 return SECFailure;
1610 return SECSuccess;
1613 static SECItem *
1614 sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag,
1615 SECOidTag attributeType)
1617 int i = 0;
1619 if(!bag->attribs) {
1620 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1621 return NULL;
1624 while(bag->attribs[i] != NULL) {
1625 if(SECOID_FindOIDTag(&bag->attribs[i]->attrType)
1626 == attributeType) {
1627 return bag->attribs[i]->attrValue[0];
1629 i++;
1632 return NULL;
1635 /* For now, this function will merely remove any ":"
1636 * in the nickname which the PK11 functions may have
1637 * placed there. This will keep dual certs from appearing
1638 * twice under "Your" certificates when imported onto smart
1639 * cards. Once with the name "Slot:Cert" and another with
1640 * the nickname "Slot:Slot:Cert"
1642 static void
1643 sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
1645 char *nickname;
1646 char *delimit;
1647 int delimitlen;
1649 nickname = (char*)nick->data; /*Mac breaks without this type cast*/
1650 if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
1651 char *slotName;
1652 int slotNameLen;
1654 slotNameLen = delimit-nickname;
1655 slotName = PORT_NewArray(char, (slotNameLen+1));
1656 PORT_Assert(slotName);
1657 if (slotName == NULL) {
1658 /* What else can we do?*/
1659 return;
1661 PORT_Memcpy(slotName, nickname, slotNameLen);
1662 slotName[slotNameLen] = '\0';
1663 if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
1664 delimitlen = PORT_Strlen(delimit+1);
1665 PORT_Memmove(nickname, delimit+1, delimitlen+1);
1666 nick->len = delimitlen;
1668 PORT_Free(slotName);
1673 static SECItem *
1674 sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag)
1676 SECItem *src, *dest;
1678 if(!bag) {
1679 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1680 return NULL;
1683 src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
1684 if(!src) {
1685 return NULL;
1688 dest = (SECItem*)PORT_ZAlloc(sizeof(SECItem));
1689 if(!dest) {
1690 goto loser;
1692 if(!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE,
1693 PR_FALSE, PR_FALSE)) {
1694 goto loser;
1697 sec_pkcs12_sanitize_nickname(bag->slot, dest);
1699 return dest;
1701 loser:
1702 if(dest) {
1703 SECITEM_ZfreeItem(dest, PR_TRUE);
1706 bag->problem = PR_TRUE;
1707 bag->error = PORT_GetError();
1708 return NULL;
1711 static SECStatus
1712 sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name)
1714 int i = 0;
1715 sec_PKCS12Attribute *attr = NULL;
1716 SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME);
1718 if(!bag || !bag->arena || !name) {
1719 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1720 return SECFailure;
1723 if(!bag->attribs) {
1724 if(!oid) {
1725 goto loser;
1728 bag->attribs = (sec_PKCS12Attribute**)PORT_ArenaZAlloc(bag->arena,
1729 sizeof(sec_PKCS12Attribute *)*2);
1730 if(!bag->attribs) {
1731 goto loser;
1733 bag->attribs[0] = (sec_PKCS12Attribute*)PORT_ArenaZAlloc(bag->arena,
1734 sizeof(sec_PKCS12Attribute));
1735 if(!bag->attribs[0]) {
1736 goto loser;
1738 bag->attribs[1] = NULL;
1740 attr = bag->attribs[0];
1741 if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid)
1742 != SECSuccess) {
1743 goto loser;
1745 } else {
1746 while(bag->attribs[i]) {
1747 if(SECOID_FindOIDTag(&bag->attribs[i]->attrType)
1748 == SEC_OID_PKCS9_FRIENDLY_NAME) {
1749 attr = bag->attribs[i];
1750 break;
1752 i++;
1754 if(!attr) {
1755 if(!oid) {
1756 goto loser;
1758 bag->attribs = (sec_PKCS12Attribute **)PORT_ArenaGrow(bag->arena,
1759 bag->attribs,
1760 (i+1) * sizeof(sec_PKCS12Attribute *),
1761 (i+2) * sizeof(sec_PKCS12Attribute *));
1762 if(!bag->attribs) {
1763 goto loser;
1765 bag->attribs[i] =
1766 (sec_PKCS12Attribute *)PORT_ArenaZAlloc(bag->arena,
1767 sizeof(sec_PKCS12Attribute));
1768 if(!bag->attribs[i]) {
1769 goto loser;
1771 bag->attribs[i+1] = NULL;
1772 attr = bag->attribs[i];
1773 if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid)
1774 != SECSuccess) {
1775 goto loser;
1780 PORT_Assert(attr);
1781 if(!attr->attrValue) {
1782 attr->attrValue = (SECItem **)PORT_ArenaZAlloc(bag->arena,
1783 sizeof(SECItem *) * 2);
1784 if(!attr->attrValue) {
1785 goto loser;
1787 attr->attrValue[0] = (SECItem*)PORT_ArenaZAlloc(bag->arena,
1788 sizeof(SECItem));
1789 if(!attr->attrValue[0]) {
1790 goto loser;
1792 attr->attrValue[1] = NULL;
1795 name->len = PORT_Strlen((char *)name->data);
1796 if(!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0],
1797 name, PR_FALSE, PR_FALSE, PR_TRUE)) {
1798 goto loser;
1801 return SECSuccess;
1803 loser:
1804 bag->problem = PR_TRUE;
1805 bag->error = PORT_GetError();
1806 return SECFailure;
1809 static SECStatus
1810 sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key)
1812 int i = 0;
1813 SECKEYPrivateKeyInfo *pki = NULL;
1815 if(!key) {
1816 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1817 return SECFailure;
1820 /* if the bag does *not* contain an unencrypted PrivateKeyInfo
1821 * then we cannot convert the attributes. We are propagating
1822 * attributes within the PrivateKeyInfo to the SafeBag level.
1824 if(SECOID_FindOIDTag(&(key->safeBagType)) !=
1825 SEC_OID_PKCS12_V1_KEY_BAG_ID) {
1826 return SECSuccess;
1829 pki = key->safeBagContent.pkcs8KeyBag;
1831 if(!pki || !pki->attributes) {
1832 return SECSuccess;
1835 while(pki->attributes[i]) {
1836 SECOidTag tag = SECOID_FindOIDTag(&pki->attributes[i]->attrType);
1838 if (tag == SEC_OID_PKCS9_LOCAL_KEY_ID ||
1839 tag == SEC_OID_PKCS9_FRIENDLY_NAME) {
1840 SECItem *attrValue = sec_pkcs12_get_attribute_value(key, tag);
1841 if(!attrValue) {
1842 if(sec_pkcs12_decoder_set_attribute_value(key, tag,
1843 pki->attributes[i]->attrValue[0])
1844 != SECSuccess) {
1845 key->problem = PR_TRUE;
1846 key->error = PORT_GetError();
1847 return SECFailure;
1851 i++;
1854 return SECSuccess;
1857 /* retrieve the nickname for the certificate bag. first look
1858 * in the cert bag, otherwise get it from the key.
1860 static SECItem *
1861 sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert,
1862 sec_PKCS12SafeBag *key,
1863 void *wincx)
1865 SECItem *nickname;
1867 if(!cert) {
1868 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1869 return NULL;
1872 nickname = sec_pkcs12_get_nickname(cert);
1873 if(nickname) {
1874 return nickname;
1877 if(key) {
1878 nickname = sec_pkcs12_get_nickname(key);
1880 if(nickname && sec_pkcs12_set_nickname(cert, nickname)
1881 != SECSuccess) {
1882 SECITEM_ZfreeItem(nickname, PR_TRUE);
1883 return NULL;
1887 return nickname;
1890 /* set the nickname for the certificate */
1891 static SECStatus
1892 sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert,
1893 sec_PKCS12SafeBag *key,
1894 SECItem *nickname,
1895 void *wincx)
1897 if(!nickname || !cert) {
1898 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1899 return SECFailure;
1902 if(sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
1903 return SECFailure;
1906 if(key) {
1907 if(sec_pkcs12_set_nickname(key, nickname) != SECSuccess) {
1908 cert->problem = PR_TRUE;
1909 cert->error = key->error;
1910 return SECFailure;
1914 return SECSuccess;
1917 /* retrieve the DER cert from the cert bag */
1918 static SECItem *
1919 sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert)
1921 if(!cert) {
1922 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1923 return NULL;
1926 if(SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) {
1927 return NULL;
1930 /* only support X509 certs not SDSI */
1931 if(SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID)
1932 != SEC_OID_PKCS9_X509_CERT) {
1933 return NULL;
1936 return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert));
1939 struct certNickInfo {
1940 PRArenaPool *arena;
1941 unsigned int nNicks;
1942 SECItem **nickList;
1943 unsigned int error;
1946 /* callback for traversing certificates to gather the nicknames
1947 * used in a particular traversal. for instance, when using
1948 * CERT_TraversePermCertsForSubject, gather the nicknames and
1949 * store them in the certNickInfo for a particular DN.
1951 * this handles the case where multiple nicknames are allowed
1952 * for the same dn, which is not currently allowed, but may be
1953 * in the future.
1955 static SECStatus
1956 gatherNicknames(CERTCertificate *cert, void *arg)
1958 struct certNickInfo *nickArg = (struct certNickInfo *)arg;
1959 SECItem tempNick;
1960 unsigned int i;
1962 if(!cert || !nickArg || nickArg->error) {
1963 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1964 return SECFailure;
1967 if(!cert->nickname) {
1968 return SECSuccess;
1971 tempNick.data = (unsigned char *)cert->nickname;
1972 tempNick.len = PORT_Strlen(cert->nickname) + 1;
1974 /* do we already have the nickname in the list? */
1975 if(nickArg->nNicks > 0) {
1977 /* nicknames have been encountered, but there is no list -- bad */
1978 if(!nickArg->nickList) {
1979 nickArg->error = SEC_ERROR_INVALID_ARGS;
1980 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1981 return SECFailure;
1984 for(i = 0; i < nickArg->nNicks; i++) {
1985 if(SECITEM_CompareItem(nickArg->nickList[i], &tempNick)
1986 == SECEqual) {
1987 return SECSuccess;
1992 /* add the nickname to the list */
1993 if(nickArg->nNicks == 0) {
1994 nickArg->nickList = (SECItem **)PORT_ArenaZAlloc(nickArg->arena,
1995 2 * sizeof(SECItem *));
1996 } else {
1997 nickArg->nickList = (SECItem **)PORT_ArenaGrow(nickArg->arena,
1998 nickArg->nickList,
1999 (nickArg->nNicks + 1) * sizeof(SECItem *),
2000 (nickArg->nNicks + 2) * sizeof(SECItem *));
2002 if(!nickArg->nickList) {
2003 nickArg->error = SEC_ERROR_NO_MEMORY;
2004 return SECFailure;
2007 nickArg->nickList[nickArg->nNicks] =
2008 (SECItem *)PORT_ArenaZAlloc(nickArg->arena, sizeof(SECItem));
2009 if(!nickArg->nickList[nickArg->nNicks]) {
2010 nickArg->error = PORT_GetError();
2011 return SECFailure;
2015 if(SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks],
2016 &tempNick) != SECSuccess) {
2017 nickArg->error = PORT_GetError();
2018 return SECFailure;
2021 nickArg->nNicks++;
2023 return SECSuccess;
2026 /* traverses the certs in the data base or in the token for the
2027 * DN to see if any certs currently have a nickname set.
2028 * If so, return it.
2030 static SECItem *
2031 sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert, void *wincx)
2033 struct certNickInfo *nickArg = NULL;
2034 SECItem *derCert, *returnDn = NULL;
2035 PRArenaPool *arena = NULL;
2036 CERTCertificate *tempCert;
2038 if(!cert) {
2039 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2040 return NULL;
2043 derCert = sec_pkcs12_get_der_cert(cert);
2044 if(!derCert) {
2045 return NULL;
2048 tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
2049 if(!tempCert) {
2050 returnDn = NULL;
2051 goto loser;
2054 arena = PORT_NewArena(1024);
2055 if(!arena) {
2056 returnDn = NULL;
2057 goto loser;
2059 nickArg = (struct certNickInfo *)PORT_ArenaZAlloc(arena,
2060 sizeof(struct certNickInfo));
2061 if(!nickArg) {
2062 returnDn = NULL;
2063 goto loser;
2065 nickArg->error = 0;
2066 nickArg->nNicks = 0;
2067 nickArg->nickList = NULL;
2068 nickArg->arena = arena;
2070 /* if the token is local, first traverse the cert database
2071 * then traverse the token.
2073 if(PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames,
2074 (void *)nickArg) != SECSuccess) {
2075 returnDn = NULL;
2076 goto loser;
2079 if(nickArg->error) {
2080 /* XXX do we want to set the error? */
2081 returnDn = NULL;
2082 goto loser;
2085 if(nickArg->nNicks == 0) {
2086 returnDn = NULL;
2087 goto loser;
2090 /* set it to the first name, for now. handle multiple names? */
2091 returnDn = SECITEM_DupItem(nickArg->nickList[0]);
2093 loser:
2094 if(arena) {
2095 PORT_FreeArena(arena, PR_TRUE);
2098 if(tempCert) {
2099 CERT_DestroyCertificate(tempCert);
2102 if(derCert) {
2103 SECITEM_FreeItem(derCert, PR_TRUE);
2106 return (returnDn);
2109 /* counts certificates found for a given traversal function */
2110 static SECStatus
2111 countCertificate(CERTCertificate *cert, void *arg)
2113 unsigned int *nCerts = (unsigned int *)arg;
2115 if(!cert || !arg) {
2116 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2117 return SECFailure;
2120 (*nCerts)++;
2121 return SECSuccess;
2124 static PRBool
2125 sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot)
2127 unsigned int nCerts = 0;
2129 if(!nickname || !slot) {
2130 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2131 return PR_TRUE;
2134 /* we want to check the local database first if we are importing to it */
2135 PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate,
2136 (void *)&nCerts);
2137 return (PRBool)(nCerts != 0);
2140 /* validate cert nickname such that there is a one-to-one relation
2141 * between nicknames and dn's. we want to enforce the case that the
2142 * nickname is non-NULL and that there is only one nickname per DN.
2144 * if there is a problem with a nickname or the nickname is not present,
2145 * the user will be prompted for it.
2147 static void
2148 sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,
2149 sec_PKCS12SafeBag *key,
2150 SEC_PKCS12NicknameCollisionCallback nicknameCb,
2151 void *wincx)
2153 SECItem *certNickname, *existingDNNick;
2154 PRBool setNickname = PR_FALSE, cancel = PR_FALSE;
2155 SECItem *newNickname = NULL;
2157 if(!cert || !cert->hasKey) {
2158 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2159 return;
2162 if(!nicknameCb) {
2163 cert->problem = PR_TRUE;
2164 cert->error = SEC_ERROR_INVALID_ARGS;
2165 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2166 return;
2169 if(cert->hasKey && !key) {
2170 cert->problem = PR_TRUE;
2171 cert->error = SEC_ERROR_INVALID_ARGS;
2172 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2173 return;
2176 certNickname = sec_pkcs12_get_nickname_for_cert(cert, key, wincx);
2177 existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert, wincx);
2179 /* nickname is already used w/ this dn, so it is safe to return */
2180 if(certNickname && existingDNNick &&
2181 SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {
2182 goto loser;
2185 /* nickname not set in pkcs 12 bags, but a nick is already used for
2186 * this dn. set the nicks in the p12 bags and finish.
2188 if(existingDNNick) {
2189 sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick, wincx);
2190 goto loser;
2193 /* at this point, we have a certificate for which the DN is not located
2194 * on the token. the nickname specified may or may not be NULL. if it
2195 * is not null, we need to make sure that there are no other certificates
2196 * with this nickname in the token for it to be valid. this imposes a
2197 * one to one relationship between DN and nickname.
2199 * if the nickname is null, we need the user to enter a nickname for
2200 * the certificate.
2202 * once we have a nickname, we make sure that the nickname is unique
2203 * for the DN. if it is not, the user is reprompted to enter a new
2204 * nickname.
2206 * in order to exit this loop, the nickname entered is either unique
2207 * or the user hits cancel and the certificate is not imported.
2209 setNickname = PR_FALSE;
2210 while(1) {
2211 /* we will use the nickname so long as no other certs have the
2212 * same nickname. and the nickname is not NULL.
2214 if (certNickname && certNickname->data &&
2215 !sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {
2216 if (setNickname) {
2217 sec_pkcs12_set_nickname_for_cert(cert, key, certNickname,
2218 wincx);
2220 break;
2223 setNickname = PR_FALSE;
2224 newNickname = (*nicknameCb)(certNickname, &cancel, wincx);
2225 if(cancel) {
2226 cert->problem = PR_TRUE;
2227 cert->error = SEC_ERROR_USER_CANCELLED;
2228 break;
2231 if(!newNickname) {
2232 cert->problem = PR_TRUE;
2233 cert->error = PORT_GetError();
2234 break;
2237 /* at this point we have a new nickname, if we have an existing
2238 * certNickname, we need to free it and assign the new nickname
2239 * to it to avoid a memory leak. happy?
2241 if(certNickname) {
2242 SECITEM_ZfreeItem(certNickname, PR_TRUE);
2243 certNickname = NULL;
2246 certNickname = newNickname;
2247 setNickname = PR_TRUE;
2248 /* go back and recheck the new nickname */
2251 loser:
2252 if(certNickname) {
2253 SECITEM_ZfreeItem(certNickname, PR_TRUE);
2256 if(existingDNNick) {
2257 SECITEM_ZfreeItem(existingDNNick, PR_TRUE);
2261 static void
2262 sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,
2263 sec_PKCS12SafeBag *key,
2264 SEC_PKCS12NicknameCollisionCallback nicknameCb,
2265 void *wincx)
2267 CERTCertificate *leafCert;
2269 if(!cert) {
2270 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2271 return;
2274 cert->validated = PR_TRUE;
2276 if(!nicknameCb) {
2277 cert->noInstall = PR_TRUE;
2278 cert->problem = PR_TRUE;
2279 cert->error = SEC_ERROR_INVALID_ARGS;
2280 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2281 return;
2284 if(!cert->safeBagContent.certBag) {
2285 cert->noInstall = PR_TRUE;
2286 cert->problem = PR_TRUE;
2287 cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
2288 return;
2291 cert->noInstall = PR_FALSE;
2292 cert->unused = PR_FALSE;
2293 cert->problem = PR_FALSE;
2294 cert->error = 0;
2296 leafCert = CERT_DecodeDERCertificate(
2297 &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
2298 if(!leafCert) {
2299 cert->noInstall = PR_TRUE;
2300 cert->problem = PR_TRUE;
2301 cert->error = PORT_GetError();
2302 return;
2305 sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, (void *)leafCert);
2307 CERT_DestroyCertificate(leafCert);
2310 static void
2311 sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,
2312 void *wincx)
2314 CERTCertificate *leafCert;
2315 SECKEYPrivateKey *privk;
2317 if(!key) {
2318 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2319 return;
2322 key->validated = PR_TRUE;
2324 if(!cert) {
2325 key->problem = PR_TRUE;
2326 key->noInstall = PR_TRUE;
2327 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2328 return;
2331 leafCert = CERT_DecodeDERCertificate(
2332 &(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL);
2333 if(!leafCert) {
2334 key->problem = PR_TRUE;
2335 key->noInstall = PR_TRUE;
2336 key->error = PORT_GetError();
2337 return;
2340 privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);
2341 if(!privk) {
2342 privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);
2345 if(privk) {
2346 SECKEY_DestroyPrivateKey(privk);
2347 key->noInstall = PR_TRUE;
2350 CERT_DestroyCertificate(leafCert);
2353 static SECStatus
2354 sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx)
2356 SECItem *derCert, *nickName;
2357 char *nickData = NULL;
2358 PRBool isIntermediateCA;
2359 SECStatus rv;
2361 if(!cert) {
2362 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2363 return SECFailure;
2366 if(cert->problem || cert->noInstall || cert->installed) {
2367 return SECSuccess;
2370 derCert = &cert->safeBagContent.certBag->value.x509Cert;
2372 PORT_Assert(!cert->problem && !cert->noInstall);
2374 nickName = sec_pkcs12_get_nickname(cert);
2375 if(nickName) {
2376 nickData = (char *)nickName->data;
2379 isIntermediateCA = CERT_IsCADERCert(derCert, NULL) &&
2380 !CERT_IsRootDERCert(derCert);
2382 if(keyExists) {
2383 CERTCertificate *newCert;
2385 newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2386 derCert, NULL, PR_FALSE, PR_FALSE);
2387 if(!newCert) {
2388 if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);
2389 cert->error = PORT_GetError();
2390 cert->problem = PR_TRUE;
2391 return SECFailure;
2394 rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData,
2395 PR_TRUE, wincx);
2396 CERT_DestroyCertificate(newCert);
2397 } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) ||
2398 ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) &&
2399 !isIntermediateCA)) {
2400 SECItem *certList[2];
2401 certList[0] = derCert;
2402 certList[1] = NULL;
2404 rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,
2405 1, certList, NULL, PR_TRUE, PR_FALSE, nickData);
2406 } else {
2407 rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE,
2408 nickData, PR_FALSE);
2411 cert->installed = PR_TRUE;
2412 if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);
2413 return rv;
2416 static SECStatus
2417 sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECItem *publicValue,
2418 KeyType keyType, unsigned int keyUsage,
2419 SECItem *nickName, void *wincx)
2421 SECStatus rv;
2423 /* We should always have values for "key" and "publicValue"
2424 so they can be dereferenced later. */
2425 if(!key || !publicValue) {
2426 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2427 return SECFailure;
2430 if(key->problem || key->noInstall) {
2431 return SECSuccess;
2434 switch(SECOID_FindOIDTag(&key->safeBagType))
2436 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2437 rv = PK11_ImportPrivateKeyInfo(key->slot,
2438 key->safeBagContent.pkcs8KeyBag,
2439 nickName, publicValue, PR_TRUE, PR_TRUE,
2440 keyUsage, wincx);
2441 break;
2442 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2443 rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
2444 key->safeBagContent.pkcs8ShroudedKeyBag,
2445 key->pwitem, nickName, publicValue,
2446 PR_TRUE, PR_TRUE, keyType, keyUsage,
2447 wincx);
2448 break;
2449 default:
2450 key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
2451 key->problem = PR_TRUE;
2452 if(nickName) {
2453 SECITEM_ZfreeItem(nickName, PR_TRUE);
2455 return SECFailure;
2458 if(rv != SECSuccess) {
2459 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2460 key->problem = PR_TRUE;
2461 } else {
2462 key->installed = PR_TRUE;
2465 return rv;
2469 * The correctness of the code in this file ABSOLUTELY REQUIRES
2470 * that ALL BAGs share a single common arena.
2472 * This function allocates the bag list from the arena of whatever bag
2473 * happens to be passed to it. Each time a new bag is handed to it,
2474 * it grows (resizes) the arena of the bag that was handed to it.
2475 * If the bags have different arenas, it will grow the wrong arena.
2477 * Worse, if the bags had separate arenas, then while destroying the bags
2478 * in a bag list, when the bag whose arena contained the bag list was
2479 * destroyed, the baglist itself would be destroyed, making it difficult
2480 * or impossible to continue to destroy the bags in the destroyed list.
2482 static SECStatus
2483 sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList,
2484 sec_PKCS12SafeBag *bag)
2486 sec_PKCS12SafeBag **newBagList = NULL;
2487 int i = 0;
2489 if(!bagList || !bag) {
2490 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2491 return SECFailure;
2494 if(!(*bagList)) {
2495 newBagList = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(bag->arena,
2496 sizeof(sec_PKCS12SafeBag *) * 2);
2497 } else {
2498 while((*bagList)[i])
2499 i++;
2500 newBagList = (sec_PKCS12SafeBag **)PORT_ArenaGrow(bag->arena,
2501 *bagList,
2502 sizeof(sec_PKCS12SafeBag *) * (i + 1),
2503 sizeof(sec_PKCS12SafeBag *) * (i + 2));
2506 if(!newBagList) {
2507 PORT_SetError(SEC_ERROR_NO_MEMORY);
2508 return SECFailure;
2511 newBagList[i] = bag;
2512 newBagList[i+1] = NULL;
2513 *bagList = newBagList;
2515 return SECSuccess;
2518 static sec_PKCS12SafeBag **
2519 sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags,
2520 sec_PKCS12SafeBag *key )
2522 sec_PKCS12SafeBag **certList = NULL;
2523 SECItem *keyId;
2524 int i;
2526 if(!safeBags || !safeBags[0]) {
2527 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2528 return NULL;
2531 keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);
2532 if(!keyId) {
2533 return NULL;
2536 for (i = 0; safeBags[i]; i++) {
2537 if(SECOID_FindOIDTag(&(safeBags[i]->safeBagType))
2538 == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2539 SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],
2540 SEC_OID_PKCS9_LOCAL_KEY_ID);
2542 if(certKeyId && (SECITEM_CompareItem(certKeyId, keyId)
2543 == SECEqual)) {
2544 if(sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i])
2545 != SECSuccess) {
2546 /* This would leak the partial list of safeBags,
2547 * but that list is allocated from the arena of
2548 * one of the safebags, and will be destroyed when
2549 * that arena is destroyed. So this is not a real leak.
2551 return NULL;
2557 return certList;
2560 CERTCertList *
2561 SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx)
2563 CERTCertList *certList = NULL;
2564 sec_PKCS12SafeBag **safeBags;
2565 int i;
2567 if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) {
2568 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2569 return NULL;
2572 safeBags = p12dcx->safeBags;
2573 certList = CERT_NewCertList();
2575 if (certList == NULL) {
2576 return NULL;
2579 for (i = 0; safeBags[i]; i++) {
2580 if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType))
2581 == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
2582 SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]) ;
2583 CERTCertificate *tempCert = NULL;
2585 if (derCert == NULL)
2586 continue;
2587 tempCert=CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2588 derCert, NULL,
2589 PR_FALSE, PR_TRUE);
2591 if (tempCert) {
2592 CERT_AddCertToListTail(certList,tempCert);
2594 SECITEM_FreeItem(derCert,PR_TRUE);
2596 /* fixed an infinite loop here, by ensuring that i gets incremented
2597 * if derCert is NULL above.
2601 return certList;
2603 static sec_PKCS12SafeBag **
2604 sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags)
2606 int i;
2607 sec_PKCS12SafeBag **keyList = NULL;
2608 SECOidTag bagType;
2610 if(!safeBags || !safeBags[0]) {
2611 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2612 return NULL;
2615 for (i = 0; safeBags[i]; i++) {
2616 bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
2617 switch(bagType) {
2618 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2619 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2620 if(sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i])
2621 != SECSuccess) {
2622 /* This would leak, except that keyList is allocated
2623 * from the arena shared by all the safeBags.
2625 return NULL;
2627 break;
2628 default:
2629 break;
2633 return keyList;
2636 /* This function takes two passes over the bags, validating them
2637 * The two passes are intended to mirror exactly the two passes in
2638 * sec_pkcs12_install_bags. But they don't. :(
2640 static SECStatus
2641 sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags,
2642 SEC_PKCS12NicknameCollisionCallback nicknameCb,
2643 void *wincx)
2645 sec_PKCS12SafeBag **keyList;
2646 int i;
2648 if(!safeBags || !nicknameCb) {
2649 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2650 return SECFailure;
2653 if(!safeBags[0]) {
2654 return SECSuccess;
2657 /* First pass. Find all the key bags.
2658 * Find the matching cert(s) for each key.
2660 keyList = sec_pkcs12_get_key_bags(safeBags);
2661 if(keyList) {
2662 for (i = 0; keyList[i]; ++i) {
2663 sec_PKCS12SafeBag *key = keyList[i];
2664 sec_PKCS12SafeBag **certList =
2665 sec_pkcs12_find_certs_for_key(safeBags, key);
2667 if(certList) {
2668 int j;
2670 if(SECOID_FindOIDTag(&(key->safeBagType)) ==
2671 SEC_OID_PKCS12_V1_KEY_BAG_ID) {
2672 /* if it is an unencrypted private key then make sure
2673 * the attributes are propageted to the appropriate
2674 * level
2676 if(sec_pkcs12_get_key_info(key) != SECSuccess) {
2677 return SECFailure;
2681 sec_pkcs12_validate_key_by_cert(certList[0], key, wincx);
2682 for (j = 0; certList[j]; ++j) {
2683 sec_PKCS12SafeBag *cert = certList[j];
2684 cert->hasKey = PR_TRUE;
2685 if(key->problem) {
2686 cert->problem = PR_TRUE;
2687 cert->error = key->error;
2688 continue;
2690 sec_pkcs12_validate_cert(cert, key, nicknameCb, wincx);
2691 if(cert->problem) {
2692 key->problem = cert->problem;
2693 key->error = cert->error;
2700 /* Now take a second pass over the safebags and mark for installation any
2701 * certs that were neither installed nor disqualified by the first pass.
2703 for (i = 0; safeBags[i]; ++i) {
2704 sec_PKCS12SafeBag *bag = safeBags[i];
2706 if(!bag->validated) {
2707 SECOidTag bagType = SECOID_FindOIDTag(&bag->safeBagType);
2709 switch(bagType) {
2710 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
2711 sec_pkcs12_validate_cert(bag, NULL, nicknameCb, wincx);
2712 break;
2713 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2714 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2715 bag->noInstall = PR_TRUE;
2716 bag->problem = PR_TRUE;
2717 bag->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2718 break;
2719 default:
2720 bag->noInstall = PR_TRUE;
2725 return SECSuccess;
2728 SECStatus
2729 SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx,
2730 SEC_PKCS12NicknameCollisionCallback nicknameCb)
2732 SECStatus rv;
2733 int i, noInstallCnt, probCnt, bagCnt, errorVal = 0;
2734 if(!p12dcx || p12dcx->error || !p12dcx->safeBags) {
2735 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2736 return SECFailure;
2739 rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx);
2740 if(rv == SECSuccess) {
2741 p12dcx->bagsVerified = PR_TRUE;
2744 noInstallCnt = probCnt = bagCnt = 0;
2745 i = 0;
2746 while(p12dcx->safeBags[i]) {
2747 bagCnt++;
2748 if(p12dcx->safeBags[i]->noInstall)
2749 noInstallCnt++;
2750 if(p12dcx->safeBags[i]->problem) {
2751 probCnt++;
2752 errorVal = p12dcx->safeBags[i]->error;
2754 i++;
2757 /* formerly was erroneous code here that assumed that if all bags
2758 * failed to import, then the problem was duplicated data;
2759 * that is, it assume that the problem must be that the file had
2760 * previously been successfully imported. But importing a
2761 * previously imported file causes NO ERRORS at all, and this
2762 * false assumption caused real errors to be hidden behind false
2763 * errors about duplicated data.
2766 if(probCnt) {
2767 PORT_SetError(errorVal);
2768 return SECFailure;
2771 return rv;
2774 static SECItem *
2775 sec_pkcs12_get_public_value_and_type(sec_PKCS12SafeBag *certBag,
2776 KeyType *type, unsigned int *usage)
2778 SECKEYPublicKey *pubKey = NULL;
2779 CERTCertificate *cert = NULL;
2780 SECItem *pubValue;
2782 if(!certBag || !type || !usage) {
2783 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2784 return NULL;
2787 *type = nullKey;
2788 *usage = 0;
2790 cert = CERT_DecodeDERCertificate(
2791 &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
2792 if(!cert) {
2793 return NULL;
2796 *usage = cert->keyUsage;
2797 pubKey = CERT_ExtractPublicKey(cert);
2798 CERT_DestroyCertificate(cert);
2799 if(!pubKey) {
2800 return NULL;
2803 *type = pubKey->keyType;
2804 switch(pubKey->keyType) {
2805 case dsaKey:
2806 pubValue = SECITEM_DupItem(&pubKey->u.dsa.publicValue);
2807 break;
2808 case dhKey:
2809 pubValue = SECITEM_DupItem(&pubKey->u.dh.publicValue);
2810 break;
2811 case rsaKey:
2812 pubValue = SECITEM_DupItem(&pubKey->u.rsa.modulus);
2813 break;
2814 case ecKey:
2815 pubValue = SECITEM_DupItem(&pubKey->u.ec.publicValue);
2816 break;
2817 default:
2818 pubValue = NULL;
2821 SECKEY_DestroyPublicKey(pubKey);
2823 return pubValue;
2826 /* This function takes two passes over the bags, installing them in the
2827 * desired slot. The two passes are intended to mirror exactly the
2828 * two passes in sec_pkcs12_validate_bags.
2830 static SECStatus
2831 sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, void *wincx)
2833 sec_PKCS12SafeBag **keyList;
2834 int i;
2835 int failedKeys = 0;
2837 if(!safeBags) {
2838 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2839 return SECFailure;
2842 if(!safeBags[0]) {
2843 return SECSuccess;
2846 /* First pass. Find all the key bags.
2847 * Try to install them, and any certs associated with them.
2849 keyList = sec_pkcs12_get_key_bags(safeBags);
2850 if(keyList) {
2851 for (i = 0; keyList[i]; i++) {
2852 SECStatus rv;
2853 SECItem *publicValue = NULL;
2854 SECItem *nickName = NULL;
2855 sec_PKCS12SafeBag *key = keyList[i];
2856 sec_PKCS12SafeBag **certList;
2857 KeyType keyType;
2858 unsigned int keyUsage;
2860 if(key->problem) {
2861 ++failedKeys;
2862 continue;
2865 certList = sec_pkcs12_find_certs_for_key(safeBags, key);
2866 if(certList && certList[0]) {
2867 publicValue = sec_pkcs12_get_public_value_and_type(certList[0],
2868 &keyType, &keyUsage);
2869 /* use the cert's nickname, if it has one, else use the
2870 * key's nickname, else fail.
2872 nickName = sec_pkcs12_get_nickname_for_cert(certList[0],
2873 key, wincx);
2874 } else {
2875 nickName = sec_pkcs12_get_nickname(key);
2877 if (!nickName) {
2878 key->error = SEC_ERROR_BAD_NICKNAME;
2879 key->problem = PR_TRUE;
2880 rv = SECFailure;
2881 } else if (!publicValue) {
2882 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
2883 key->problem = PR_TRUE;
2884 rv = SECFailure;
2885 } else {
2886 rv = sec_pkcs12_add_key(key, publicValue, keyType,
2887 keyUsage, nickName, wincx);
2889 if (publicValue) {
2890 SECITEM_FreeItem(publicValue, PR_TRUE);
2891 publicValue = NULL;
2893 if (nickName) {
2894 SECITEM_FreeItem(nickName, PR_TRUE);
2895 nickName = NULL;
2897 if(rv != SECSuccess) {
2898 PORT_SetError(key->error);
2899 ++failedKeys;
2902 if(certList) {
2903 int j;
2905 for (j = 0; certList[j]; j++) {
2906 sec_PKCS12SafeBag *cert = certList[j];
2907 SECStatus certRv;
2909 if (!cert)
2910 continue;
2911 if(rv != SECSuccess) {
2912 cert->problem = key->problem;
2913 cert->error = key->error;
2914 cert->noInstall = PR_TRUE;
2915 continue;
2918 certRv = sec_pkcs12_add_cert(cert, cert->hasKey, wincx);
2919 if(certRv != SECSuccess) {
2920 key->problem = cert->problem;
2921 key->error = cert->error;
2922 PORT_SetError(cert->error);
2923 return SECFailure;
2929 if (failedKeys)
2930 return SECFailure;
2932 /* Now take a second pass over the safebags and install any certs
2933 * that were neither installed nor disqualified by the first pass.
2935 for (i = 0; safeBags[i]; i++) {
2936 sec_PKCS12SafeBag *bag = safeBags[i];
2938 if (!bag->installed && !bag->problem && !bag->noInstall) {
2939 SECStatus rv;
2940 SECOidTag bagType = SECOID_FindOIDTag(&(bag->safeBagType));
2942 switch(bagType) {
2943 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
2944 rv = sec_pkcs12_add_cert(bag, bag->hasKey, wincx);
2945 if(rv != SECSuccess) {
2946 PORT_SetError(bag->error);
2947 return SECFailure;
2949 break;
2950 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
2951 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
2952 default:
2953 break;
2958 return SECSuccess;
2961 SECStatus
2962 SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
2964 if(!p12dcx || p12dcx->error) {
2965 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2966 return SECFailure;
2969 if(!p12dcx->bagsVerified) {
2970 return SECFailure;
2973 return sec_pkcs12_install_bags(p12dcx->safeBags, p12dcx->wincx);
2976 PRBool
2977 sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
2979 int i;
2980 SECItem *keyId;
2981 SECItem *certKeyId;
2983 certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
2984 if (certKeyId == NULL) {
2985 return PR_FALSE;
2988 for (i=0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
2989 keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
2990 SEC_OID_PKCS9_LOCAL_KEY_ID);
2991 if(!keyId) {
2992 continue;
2994 if(SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
2995 return PR_TRUE;
2998 return PR_FALSE;
3001 SECItem *
3002 sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
3004 SECItem *friendlyName;
3005 SECItem *tempnm;
3007 tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
3008 friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
3009 if (friendlyName) {
3010 if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
3011 tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
3012 SECITEM_FreeItem(friendlyName, PR_TRUE);
3013 friendlyName = NULL;
3016 return friendlyName;
3019 /* Following two functions provide access to selected portions of the safe bags.
3020 * Iteration is implemented per decoder context and may be accessed after
3021 * SEC_PKCS12DecoderVerify() returns success.
3022 * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
3023 * where item.type is always set; item.friendlyName is set if it is non-null;
3024 * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
3025 * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
3026 * arguments are invalid; PORT_GetError() is 0 at end-of-list.
3027 * Caller has read-only access to decoder items. Any SECItems generated are
3028 * owned by the decoder context and are freed by ...DecoderFinish().
3030 SECStatus
3031 SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
3033 if(!p12dcx || p12dcx->error) {
3034 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3035 return SECFailure;
3038 p12dcx->iteration = 0;
3039 return SECSuccess;
3042 SECStatus
3043 SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
3044 const SEC_PKCS12DecoderItem **ipp)
3046 sec_PKCS12SafeBag *bag;
3048 if(!p12dcx || p12dcx->error) {
3049 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3050 return SECFailure;
3053 if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
3054 SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
3056 if (p12dcx->decitem.friendlyName != NULL) {
3057 SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
3059 p12dcx->decitem.type = 0;
3060 p12dcx->decitem.der = NULL;
3061 p12dcx->decitem.friendlyName = NULL;
3062 p12dcx->decitem.hasKey = PR_FALSE;
3063 *ipp = NULL;
3064 if (p12dcx->keyList == NULL) {
3065 p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
3069 for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
3070 bag = p12dcx->safeBags[p12dcx->iteration];
3071 if(bag == NULL || bag->problem) {
3072 continue;
3074 p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
3075 switch(p12dcx->decitem.type) {
3076 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
3077 p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
3078 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
3079 p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
3080 break;
3081 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
3082 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
3083 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
3084 break;
3085 default:
3086 /* return these even though we don't expect them */
3087 break;
3088 case SEC_OID_UNKNOWN:
3089 /* ignore these */
3090 continue;
3092 *ipp = &p12dcx->decitem;
3093 p12dcx->iteration++;
3094 break; /* end for() */
3097 PORT_SetError(0); /* end-of-list is SECFailure with no PORT error */
3098 return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
3101 static SECStatus
3102 sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
3103 sec_PKCS12SafeBag *bag)
3105 if(!p12dcx || p12dcx->error) {
3106 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3107 return SECFailure;
3110 if(!p12dcx->safeBagCount) {
3111 p12dcx->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(p12dcx->arena,
3112 sizeof(sec_PKCS12SafeBag *) * 2);
3113 } else {
3114 p12dcx->safeBags =
3115 (sec_PKCS12SafeBag **)PORT_ArenaGrow(p12dcx->arena, p12dcx->safeBags,
3116 (p12dcx->safeBagCount + 1) * sizeof(sec_PKCS12SafeBag *),
3117 (p12dcx->safeBagCount + 2) * sizeof(sec_PKCS12SafeBag *));
3120 if(!p12dcx->safeBags) {
3121 PORT_SetError(SEC_ERROR_NO_MEMORY);
3122 return SECFailure;
3125 p12dcx->safeBags[p12dcx->safeBagCount] = bag;
3126 p12dcx->safeBags[p12dcx->safeBagCount+1] = NULL;
3127 p12dcx->safeBagCount++;
3129 return SECSuccess;
3132 static sec_PKCS12SafeBag *
3133 sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx,
3134 void *key, PRBool isEspvk)
3136 sec_PKCS12SafeBag *keyBag;
3137 SECOidData *oid;
3138 SECOidTag keyTag;
3139 SECItem *keyID, *nickName, *newNickName;
3141 if(!p12dcx || p12dcx->error || !key) {
3142 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3143 return NULL;
3146 newNickName =(SECItem *)PORT_ArenaZAlloc(p12dcx->arena, sizeof(SECItem));
3147 keyBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12dcx->arena,
3148 sizeof(sec_PKCS12SafeBag));
3149 if(!keyBag || !newNickName) {
3150 return NULL;
3153 keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
3154 keyBag->slot = p12dcx->slot;
3155 keyBag->arena = p12dcx->arena;
3156 keyBag->pwitem = p12dcx->pwitem;
3157 keyBag->tokenCAs = p12dcx->tokenCAs;
3158 keyBag->oldBagType = PR_TRUE;
3160 keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID :
3161 SEC_OID_PKCS12_V1_KEY_BAG_ID;
3162 oid = SECOID_FindOIDByTag(keyTag);
3163 if(!oid) {
3164 return NULL;
3167 if(SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid)
3168 != SECSuccess) {
3169 return NULL;
3172 if(isEspvk) {
3173 SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key;
3174 keyBag->safeBagContent.pkcs8ShroudedKeyBag =
3175 espvk->espvkCipherText.pkcs8KeyShroud;
3176 nickName = &(espvk->espvkData.uniNickName);
3177 if(!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) {
3178 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3179 return NULL;
3181 keyID = &espvk->espvkData.assocCerts[0]->digest;
3182 } else {
3183 SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key;
3184 keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data;
3185 nickName= &(pk->pvkData.uniNickName);
3186 if(!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) {
3187 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3188 return NULL;
3190 keyID = &pk->pvkData.assocCerts[0]->digest;
3193 if(nickName->len) {
3194 if(nickName->len >= 2) {
3195 if(nickName->data[0] && nickName->data[1]) {
3196 if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
3197 nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
3198 return NULL;
3200 nickName = newNickName;
3201 } else if(nickName->data[0] && !nickName->data[1]) {
3202 unsigned int j = 0;
3203 unsigned char t;
3204 for(j = 0; j < nickName->len; j+=2) {
3205 t = nickName->data[j+1];
3206 nickName->data[j+1] = nickName->data[j];
3207 nickName->data[j] = t;
3210 } else {
3211 if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
3212 nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
3213 return NULL;
3215 nickName = newNickName;
3219 if(sec_pkcs12_decoder_set_attribute_value(keyBag,
3220 SEC_OID_PKCS9_FRIENDLY_NAME,
3221 nickName) != SECSuccess) {
3222 return NULL;
3225 if(sec_pkcs12_decoder_set_attribute_value(keyBag,SEC_OID_PKCS9_LOCAL_KEY_ID,
3226 keyID) != SECSuccess) {
3227 return NULL;
3230 return keyBag;
3233 static sec_PKCS12SafeBag *
3234 sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx,
3235 SECItem *derCert)
3237 sec_PKCS12SafeBag *certBag;
3238 SECOidData *oid;
3239 SGNDigestInfo *digest;
3240 SECItem *keyId;
3241 SECStatus rv;
3243 if(!p12dcx || p12dcx->error || !derCert) {
3244 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3245 return NULL;
3248 keyId = (SECItem *)PORT_ArenaZAlloc(p12dcx->arena, sizeof(SECItem));
3249 if(!keyId) {
3250 return NULL;
3253 digest = sec_pkcs12_compute_thumbprint(derCert);
3254 if(!digest) {
3255 return NULL;
3258 rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest);
3259 SGN_DestroyDigestInfo(digest);
3260 if(rv != SECSuccess) {
3261 PORT_SetError(SEC_ERROR_NO_MEMORY);
3262 return NULL;
3265 oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID);
3266 certBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12dcx->arena,
3267 sizeof(sec_PKCS12SafeBag));
3268 if(!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena,
3269 &certBag->safeBagType, &oid->oid) != SECSuccess)) {
3270 return NULL;
3273 certBag->slot = p12dcx->slot;
3274 certBag->pwitem = p12dcx->pwitem;
3275 certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
3276 certBag->arena = p12dcx->arena;
3277 certBag->tokenCAs = p12dcx->tokenCAs;
3279 oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT);
3280 certBag->safeBagContent.certBag =
3281 (sec_PKCS12CertBag *)PORT_ArenaZAlloc(p12dcx->arena,
3282 sizeof(sec_PKCS12CertBag));
3283 if(!certBag->safeBagContent.certBag || !oid ||
3284 (SECITEM_CopyItem(p12dcx->arena,
3285 &certBag->safeBagContent.certBag->bagID,
3286 &oid->oid) != SECSuccess)) {
3287 return NULL;
3290 if(SECITEM_CopyItem(p12dcx->arena,
3291 &(certBag->safeBagContent.certBag->value.x509Cert),
3292 derCert) != SECSuccess) {
3293 return NULL;
3296 if(sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
3297 keyId) != SECSuccess) {
3298 return NULL;
3301 return certBag;
3304 static sec_PKCS12SafeBag **
3305 sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx,
3306 SEC_PKCS12CertAndCRL *oldCert)
3308 sec_PKCS12SafeBag **certList;
3309 SECItem **derCertList;
3310 int i, j;
3312 if(!p12dcx || p12dcx->error || !oldCert) {
3313 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3314 return NULL;
3317 derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL);
3318 if(!derCertList) {
3319 return NULL;
3322 i = 0;
3323 while(derCertList[i]) i++;
3325 certList = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(p12dcx->arena,
3326 (i + 1) * sizeof(sec_PKCS12SafeBag *));
3327 if(!certList) {
3328 return NULL;
3331 for(j = 0; j < i; j++) {
3332 certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]);
3333 if(!certList[j]) {
3334 return NULL;
3338 return certList;
3341 static SECStatus
3342 sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx,
3343 void *oldKey, PRBool isEspvk,
3344 SEC_PKCS12SafeContents *safe,
3345 SEC_PKCS12Baggage *baggage)
3347 sec_PKCS12SafeBag *key, **certList;
3348 SEC_PKCS12CertAndCRL *oldCert;
3349 SEC_PKCS12PVKSupportingData *pvkData;
3350 int i;
3351 SECItem *keyName;
3353 if(!p12dcx || !oldKey) {
3354 return SECFailure;
3357 if(isEspvk) {
3358 pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData;
3359 } else {
3360 pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData;
3363 if(!pvkData->assocCerts || !pvkData->assocCerts[0]) {
3364 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3365 return SECFailure;
3368 oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
3369 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL,
3370 pvkData->assocCerts[0]);
3371 if(!oldCert) {
3372 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
3373 return SECFailure;
3376 key = sec_pkcs12_decoder_convert_old_key(p12dcx,oldKey, isEspvk);
3377 certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert);
3378 if(!key || !certList) {
3379 return SECFailure;
3382 if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) {
3383 return SECFailure;
3386 keyName = sec_pkcs12_get_nickname(key);
3387 if(!keyName) {
3388 return SECFailure;
3391 i = 0;
3392 while(certList[i]) {
3393 if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i])
3394 != SECSuccess) {
3395 return SECFailure;
3397 i++;
3400 certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key);
3401 if(!certList) {
3402 return SECFailure;
3405 i = 0;
3406 while(certList[i] != 0) {
3407 if(sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) {
3408 return SECFailure;
3410 i++;
3413 return SECSuccess;
3416 static SECStatus
3417 sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx,
3418 SEC_PKCS12SafeContents *safe,
3419 SEC_PKCS12Baggage *baggage)
3421 SECStatus rv;
3423 if(!p12dcx || p12dcx->error) {
3424 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3425 return SECFailure;
3428 if(safe && safe->contents) {
3429 int i = 0;
3430 while(safe->contents[i] != NULL) {
3431 if(SECOID_FindOIDTag(&safe->contents[i]->safeBagType)
3432 == SEC_OID_PKCS12_KEY_BAG_ID) {
3433 int j = 0;
3434 SEC_PKCS12PrivateKeyBag *privBag =
3435 safe->contents[i]->safeContent.keyBag;
3437 while(privBag->privateKeys[j] != NULL) {
3438 SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j];
3439 rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx,pk,
3440 PR_FALSE, safe, baggage);
3441 if(rv != SECSuccess) {
3442 goto loser;
3444 j++;
3447 i++;
3451 if(baggage && baggage->bags) {
3452 int i = 0;
3453 while(baggage->bags[i] != NULL) {
3454 SEC_PKCS12BaggageItem *bag = baggage->bags[i];
3455 int j = 0;
3457 if(!bag->espvks) {
3458 i++;
3459 continue;
3462 while(bag->espvks[j] != NULL) {
3463 SEC_PKCS12ESPVKItem *espvk = bag->espvks[j];
3464 rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk,
3465 PR_TRUE, safe, baggage);
3466 if(rv != SECSuccess) {
3467 goto loser;
3469 j++;
3471 i++;
3475 return SECSuccess;
3477 loser:
3478 return SECFailure;
3481 SEC_PKCS12DecoderContext *
3482 sec_PKCS12ConvertOldSafeToNew(PRArenaPool *arena, PK11SlotInfo *slot,
3483 PRBool swapUnicode, SECItem *pwitem,
3484 void *wincx, SEC_PKCS12SafeContents *safe,
3485 SEC_PKCS12Baggage *baggage)
3487 SEC_PKCS12DecoderContext *p12dcx;
3489 if(!arena || !slot || !pwitem) {
3490 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3491 return NULL;
3494 if(!safe && !baggage) {
3495 PORT_SetError(SEC_ERROR_INVALID_ARGS);
3496 return NULL;
3499 p12dcx = (SEC_PKCS12DecoderContext *)PORT_ArenaZAlloc(arena,
3500 sizeof(SEC_PKCS12DecoderContext));
3501 if(!p12dcx) {
3502 return NULL;
3505 p12dcx->arena = arena;
3506 p12dcx->slot = PK11_ReferenceSlot(slot);
3507 p12dcx->wincx = wincx;
3508 p12dcx->error = PR_FALSE;
3509 p12dcx->swapUnicodeBytes = swapUnicode;
3510 p12dcx->pwitem = pwitem;
3511 p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
3513 if(sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage)
3514 != SECSuccess) {
3515 p12dcx->error = PR_TRUE;
3516 return NULL;
3519 return p12dcx;