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
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.
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 ***** */
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 */
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.
93 struct SEC_PKCS12DecoderContextStr
{
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
;
124 sec_PKCS12MacData macData
;
125 SEC_ASN1DecoderContext
*hmacDcx
;
127 /* routines for reading back the data to be hmac'd */
129 digestCloseFn dClose
;
130 digestIOFn dRead
, dWrite
;
133 /* helper functions */
134 SECKEYGetPasswordKey pwfn
;
136 PRBool swapUnicodeBytes
;
138 /* import information */
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
157 sec_pkcs12_proper_version(sec_PKCS12PFXItem
*pfx
)
159 /* if no version, assume it is not supported */
160 if(pfx
->version
.len
== 0) {
164 if(DER_GetInteger(&pfx
->version
) > SEC_PKCS12_VERSION
) {
171 /* retrieve the key for decrypting the safe contents */
173 sec_pkcs12_decoder_get_decrypt_key(void *arg
, SECAlgorithmID
*algid
)
175 SEC_PKCS12DecoderContext
*p12dcx
=
176 (SEC_PKCS12DecoderContext
*) arg
;
184 /* if no slot specified, use the internal key slot */
186 slot
= PK11_ReferenceSlot(p12dcx
->slot
);
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
)) {
199 slot
= PK11_GetInternalKeySlot();
200 bulkKey
= PK11_PBEKeyGen(slot
, algid
, p12dcx
->pwitem
,
201 PR_FALSE
, p12dcx
->wincx
);
205 /* set the password data on the key */
207 PK11_SetSymKeyUserData(bulkKey
,p12dcx
->pwitem
, NULL
);
214 /* XXX this needs to be modified to handle enveloped data. most
215 * likely, it should mirror the routines for SMIME in that regard.
218 sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID
*algid
,
221 PRBool decryptionAllowed
= SEC_PKCS12DecryptionAllowed(algid
);
223 if(!decryptionAllowed
) {
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.
238 sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext
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
) {
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
259 if(p12dcx
->safeBagCount
) {
261 (sec_PKCS12SafeBag
**)PORT_ArenaGrow(p12dcx
->arena
,p12dcx
->safeBags
,
262 (p12dcx
->safeBagCount
+ 1) * sizeof(sec_PKCS12SafeBag
*),
263 (p12dcx
->safeBagCount
+ 2) * sizeof(sec_PKCS12SafeBag
*));
265 p12dcx
->safeBags
= (sec_PKCS12SafeBag
**)PORT_ArenaZAlloc(p12dcx
->arena
,
266 2 * sizeof(sec_PKCS12SafeBag
*));
268 if(!p12dcx
->safeBags
) {
269 p12dcx
->errorValue
= PORT_GetError();
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();
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
);
299 /* if an error occurred, release the memory and set the error flag
300 * the only possible errors triggered by this function are memory
304 PORT_ArenaRelease(p12dcx
->arena
, mark
);
307 p12dcx
->error
= PR_TRUE
;
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.
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
;
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
) {
334 p12dcx
= safeContentsCtx
->p12dcx
;
336 rv
= SEC_ASN1DecoderUpdate(safeContentsCtx
->currentSafeBagDcx
, data
, len
);
337 if(rv
!= SECSuccess
) {
338 p12dcx
->errorValue
= PORT_GetError();
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
;
356 /* forward declarations of functions that are used when decoding
357 * safeContents bags which are nested and when decoding the
358 * authenticatedSafes.
361 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
364 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
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.
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
;
387 /* if an error is encountered, return */
388 if(!safeContentsCtx
|| !safeContentsCtx
->p12dcx
||
389 safeContentsCtx
->p12dcx
->error
) {
392 p12dcx
= safeContentsCtx
->p12dcx
;
394 /* to make things more readable */
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
;
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
:
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
);
433 case SEC_OID_PKCS12_V1_CRL_BAG_ID
:
434 case SEC_OID_PKCS12_V1_SECRET_BAG_ID
:
436 /* skip any safe bag types we don't understand or handle */
437 safeContentsCtx
->skipCurrentSafeBag
= PR_TRUE
;
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
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
;
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
) {
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.
474 SEC_ASN1DecoderClearFilterProc(safeContentsCtx
->safeContentsDcx
);
475 SEC_ASN1DecoderFinish(safeContentsCtx
->currentSafeBagDcx
);
476 safeContentsCtx
->currentSafeBagDcx
= NULL
;
477 safeContentsCtx
->skipCurrentSafeBag
= PR_FALSE
;
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
) {
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();
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
,
502 SEC_ASN1DecoderSetFilterProc(safeContentsCtx
->safeContentsDcx
,
503 sec_pkcs12_decoder_safe_bag_update
,
504 safeContentsCtx
, PR_TRUE
);
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
);
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
,
533 sec_PKCS12SafeContentsContext
*safeContentsCtx
= NULL
;
534 const SEC_ASN1Template
*theTemplate
;
536 if(!p12dcx
|| p12dcx
->error
) {
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
*));
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();
561 p12dcx
->safeContentsList
[p12dcx
->safeContentsCnt
] = safeContentsCtx
=
562 (sec_PKCS12SafeContentsContext
*)PORT_ArenaZAlloc(
564 sizeof(sec_PKCS12SafeContentsContext
));
565 if(!p12dcx
->safeContentsList
[p12dcx
->safeContentsCnt
]) {
566 p12dcx
->errorValue
= PORT_GetError();
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
;
581 theTemplate
= sec_PKCS12SafeContentsDecodeTemplate
;
584 /* start the decoder context */
585 safeContentsCtx
->safeContentsDcx
= SEC_ASN1DecoderStart(p12dcx
->arena
,
586 &safeContentsCtx
->safeContents
,
589 if(!safeContentsCtx
->safeContentsDcx
) {
590 p12dcx
->errorValue
= PORT_GetError();
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
,
601 return safeContentsCtx
;
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
;
617 /* wrapper for updating safeContents. this is set as the filter of
618 * safeBag when there is a nested safeContents.
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
;
630 /* check for an error */
631 if(!safeContentsCtx
|| !safeContentsCtx
->p12dcx
632 || safeContentsCtx
->p12dcx
->error
633 || !safeContentsCtx
->safeContentsDcx
) {
637 /* no need to update if no data sent in */
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();
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.
665 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
668 /* check for an error */
669 if(!safeContentsCtx
|| !safeContentsCtx
->p12dcx
||
670 safeContentsCtx
->p12dcx
->error
) {
674 safeContentsCtx
->nestedCtx
= sec_pkcs12_decoder_safe_contents_init_decode(
675 safeContentsCtx
->p12dcx
,
677 if(!safeContentsCtx
->nestedCtx
) {
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
);
692 /* when the safeContents is done decoding, we need to reset the
693 * proper filter and notify procs and close the decoding context
696 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
699 /* check for error */
700 if(!safeContentsCtx
|| !safeContentsCtx
->p12dcx
||
701 safeContentsCtx
->p12dcx
->error
) {
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
;
715 /* wrapper for updating safeContents. This is used when decoding
716 * the nested safeContents and any authenticatedSafes.
719 sec_pkcs12_decoder_safe_contents_callback(void *arg
, const char *buf
,
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
) {
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
);
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
;
759 /* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate
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
777 sec_pkcs12_decoder_asafes_notify(void *arg
, PRBool before
, void *dest
,
780 SEC_PKCS12DecoderContext
*p12dcx
;
781 sec_PKCS12SafeContentsContext
*safeContentsCtx
;
783 /* make sure no error occurred. */
784 p12dcx
= (SEC_PKCS12DecoderContext
*)arg
;
785 if(!p12dcx
|| p12dcx
->error
) {
791 /* init a new safeContentsContext */
792 safeContentsCtx
= sec_pkcs12_decoder_safe_contents_init_decode(p12dcx
,
794 if(!safeContentsCtx
) {
798 /* initiate the PKCS7ContentInfo decode */
799 p12dcx
->currentASafeP7Dcx
= SEC_PKCS7DecoderStart(
800 sec_pkcs12_decoder_safe_contents_callback
,
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();
809 SEC_ASN1DecoderSetFilterProc(p12dcx
->aSafeDcx
,
810 sec_pkcs12_decoder_wrap_p7_update
,
811 p12dcx
->currentASafeP7Dcx
, PR_TRUE
);
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();
822 p12dcx
->currentASafeP7Dcx
= NULL
;
830 /* set the error flag */
831 p12dcx
->error
= PR_TRUE
;
835 /* wrapper for updating asafes decoding context. this function
836 * writes data being decoded to disk, so that a mac can be computed
840 sec_pkcs12_decoder_asafes_callback(void *arg
, const char *buf
,
843 SEC_PKCS12DecoderContext
*p12dcx
= (SEC_PKCS12DecoderContext
*)arg
;
846 if(!p12dcx
|| p12dcx
->error
) {
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
;
858 /* if we are writing to a file, write out the new information */
860 unsigned long writeLen
= (*p12dcx
->dWrite
)(p12dcx
->dArg
,
861 (unsigned char *)buf
, len
);
862 if(writeLen
!= len
) {
863 p12dcx
->errorValue
= PORT_GetError();
871 /* set the error flag */
872 p12dcx
->error
= PR_TRUE
;
873 SEC_ASN1DecoderFinish(p12dcx
->aSafeDcx
);
874 p12dcx
->aSafeDcx
= NULL
;
879 /* start the decode of an authenticatedSafe contentInfo.
882 sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext
*p12dcx
)
884 if(!p12dcx
|| p12dcx
->error
) {
888 /* start the decode context */
889 p12dcx
->aSafeDcx
= SEC_ASN1DecoderStart(p12dcx
->arena
,
891 sec_PKCS12AuthenticatedSafeTemplate
);
892 if(!p12dcx
->aSafeDcx
) {
893 p12dcx
->errorValue
= PORT_GetError();
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();
910 /* open the temp file for writing, if the filter functions were set */
911 if(p12dcx
->dOpen
&& (*p12dcx
->dOpen
)(p12dcx
->dArg
, PR_FALSE
)
913 p12dcx
->errorValue
= PORT_GetError();
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
;
935 /* wrapper for updating the safeContents. this function is used as
936 * a filter for the pfx when decoding the authenticated safes
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
;
946 p12dcx
= (SEC_PKCS12DecoderContext
*)arg
;
947 if(!p12dcx
|| p12dcx
->error
) {
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
;
962 /* did we find an error? if so, close the context and set the
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.
977 sec_pkcs12_decoder_pfx_notify_proc(void *arg
, PRBool before
, void *dest
,
981 SEC_PKCS12DecoderContext
*p12dcx
= (SEC_PKCS12DecoderContext
*)arg
;
983 /* if an error occurrs, clear the notifyProc and the filterProc
987 SEC_ASN1DecoderClearNotifyProc(p12dcx
->pfxDcx
);
988 SEC_ASN1DecoderClearFilterProc(p12dcx
->pfxDcx
);
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
;
1000 /* start the decode of the aSafes cinfo... */
1001 rv
= sec_pkcs12_decode_start_asafes_cinfo(p12dcx
);
1002 if(rv
!= SECSuccess
) {
1006 /* set the filter proc to update the authenticated safes. */
1007 SEC_ASN1DecoderSetFilterProc(p12dcx
->pfxDcx
,
1008 sec_pkcs12_decode_asafes_cinfo_update
,
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();
1024 SEC_ASN1DecoderClearFilterProc(p12dcx
->pfxDcx
);
1025 if(p12dcx
->dClose
&& ((*p12dcx
->dClose
)(p12dcx
->dArg
, PR_FALSE
)
1027 p12dcx
->errorValue
= PORT_GetError();
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
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
);
1061 PR_ASSERT(p12cxt
->buffer
);
1062 if (!p12cxt
->buffer
) {
1063 return SECFailure
; /* no data to read */
1071 p12u_DigestClose(void *arg
, PRBool removeFile
)
1073 SEC_PKCS12DecoderContext
* p12cxt
= arg
;
1079 p12cxt
->currentpos
= 0;
1081 if (PR_TRUE
== removeFile
) {
1082 PR_ASSERT(p12cxt
->buffer
);
1083 if (!p12cxt
->buffer
) {
1086 if (p12cxt
->buffer
) {
1087 PORT_Free(p12cxt
->buffer
);
1088 p12cxt
->buffer
= NULL
;
1089 p12cxt
->allocated
= 0;
1090 p12cxt
->filesize
= 0;
1098 p12u_DigestRead(void *arg
, unsigned char *buf
, unsigned long len
)
1101 SEC_PKCS12DecoderContext
* p12cxt
= arg
;
1103 if(!buf
|| len
== 0 || !p12cxt
->buffer
) {
1104 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
;
1118 p12u_DigestWrite(void *arg
, unsigned char *buf
, unsigned long len
)
1120 SEC_PKCS12DecoderContext
* p12cxt
= arg
;
1122 if(!buf
|| len
== 0) {
1126 if (p12cxt
->currentpos
+(long)len
> p12cxt
->filesize
) {
1127 p12cxt
->filesize
= p12cxt
->currentpos
+ len
;
1130 p12cxt
->filesize
+= len
;
1132 if (p12cxt
->filesize
> p12cxt
->allocated
) {
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
;
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
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
;
1182 arena
= PORT_NewArena(2048); /* different size? */
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
));
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
;
1211 p12dcx
->swapUnicodeBytes
= PR_FALSE
;
1213 p12dcx
->errorValue
= 0;
1214 p12dcx
->error
= PR_FALSE
;
1216 /* start the decoding of the PFX and set the notify proc
1219 p12dcx
->pfxDcx
= SEC_ASN1DecoderStart(p12dcx
->arena
, &p12dcx
->pfx
,
1220 sec_PKCS12PFXItemTemplate
);
1221 if(!p12dcx
->pfxDcx
) {
1222 PK11_FreeSlot(p12dcx
->slot
);
1226 SEC_ASN1DecoderSetNotifyProc(p12dcx
->pfxDcx
,
1227 sec_pkcs12_decoder_pfx_notify_proc
,
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;
1247 PORT_FreeArena(arena
, PR_TRUE
);
1252 SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext
*p12dcx
,
1253 SECPKCS12TargetTokenCAs tokenCAs
)
1255 if (!p12dcx
|| p12dcx
->error
) {
1258 p12dcx
->tokenCAs
= tokenCAs
;
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.
1272 SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext
*p12dcx
,
1273 unsigned char *data
, unsigned long len
)
1277 if(!p12dcx
|| p12dcx
->error
) {
1278 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
;
1293 p12dcx
->error
= PR_TRUE
;
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
1302 static const char bufferEnd
[] = { "BufferEnd" } ;
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.
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
;
1319 unsigned int bufLen
;
1324 SECItem ignore
= {0};
1325 CK_MECHANISM_TYPE integrityMech
;
1327 if(!p12dcx
|| p12dcx
->error
) {
1328 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1331 buf
= (unsigned char *)PORT_Alloc(IN_BUF_LEN
+ FUDGE
);
1333 return SECFailure
; /* error code has been set. */
1336 memcpy(buf
+ IN_BUF_LEN
, bufferEnd
, sizeof bufferEnd
);
1339 /* generate hmac key */
1340 if(p12dcx
->macData
.iter
.data
) {
1341 iteration
= (int)DER_GetInteger(&p12dcx
->macData
.iter
);
1346 params
= PK11_CreatePBEParams(&p12dcx
->macData
.macSalt
, p12dcx
->pwitem
,
1349 algtag
= SECOID_GetAlgorithmTag(&p12dcx
->macData
.safeMac
.digestAlgorithm
);
1352 integrityMech
= CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN
; break;
1354 integrityMech
= CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN
; break;
1356 integrityMech
= CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN
; break;
1361 symKey
= PK11_KeyGen(NULL
, integrityMech
, params
, 20, NULL
);
1362 PK11_DestroyPBEParams(params
);
1364 if (!symKey
) goto loser
;
1366 pk11cx
= PK11_CreateContextBySymKey(sec_pkcs12_algtag_to_mech(algtag
),
1367 CKA_SIGN
, symKey
, &ignore
);
1371 lrv
= PK11_DigestBegin(pk11cx
);
1372 if (lrv
== SECFailure
) {
1376 /* try to open the data for readback */
1377 if(p12dcx
->dOpen
&& ((*p12dcx
->dOpen
)(p12dcx
->dArg
, PR_TRUE
)
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
1389 bytesRead
= (*p12dcx
->dRead
)(p12dcx
->dArg
, buf
, IN_BUF_LEN
);
1390 if (bytesRead
< 0) {
1391 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ
);
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
);
1404 lrv
= PK11_DigestOp(pk11cx
, buf
, bytesRead
);
1405 if (lrv
== SECFailure
) {
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
) {
1418 hmacRes
.len
= bufLen
;
1420 /* is the hmac computed the same as the hmac which was decoded? */
1422 if(SECITEM_CompareItem(&hmacRes
, &p12dcx
->macData
.safeMac
.digest
)
1424 PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC
);
1429 /* close the file and remove it */
1430 if(p12dcx
->dClose
) {
1431 (*p12dcx
->dClose
)(p12dcx
->dArg
, PR_TRUE
);
1435 PK11_DestroyContext(pk11cx
, PR_TRUE
);
1438 PK11_DestroyPBEParams(params
);
1441 PK11_FreeSymKey(symKey
);
1443 PORT_ZFree(buf
, IN_BUF_LEN
+ FUDGE
);
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
1453 * p12dcx - the decoder context
1456 SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext
*p12dcx
)
1458 SECStatus rv
= SECSuccess
;
1460 /* make sure that no errors have occured... */
1462 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1466 /* error code is already set! PORT_SetError(p12dcx->errorValue); */
1470 rv
= SEC_ASN1DecoderFinish(p12dcx
->pfxDcx
);
1471 p12dcx
->pfxDcx
= NULL
;
1472 if(rv
!= SECSuccess
) {
1476 /* check the signature or the mac depending on the type of
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
);
1487 if(SEC_PKCS7VerifySignature(p12dcx
->aSafeCinfo
, certUsageEmailSigner
,
1491 PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC
);
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
1508 SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext
*p12dcx
)
1511 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
);
1547 PK11_FreeSlot(p12dcx
->slot
);
1548 p12dcx
->slot
= NULL
;
1552 PORT_FreeArena(p12dcx
->arena
, PR_TRUE
);
1557 sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag
*bag
,
1558 SECOidTag attributeType
,
1564 if(!bag
|| !attrValue
) {
1565 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1569 oid
= SECOID_FindOIDByTag(attributeType
);
1575 bag
->attribs
= (sec_PKCS12Attribute
**)PORT_ArenaZAlloc(bag
->arena
,
1576 sizeof(sec_PKCS12Attribute
*) * 2);
1578 while(bag
->attribs
[i
]) i
++;
1579 bag
->attribs
= (sec_PKCS12Attribute
**)PORT_ArenaGrow(bag
->arena
,
1581 (i
+ 1) * sizeof(sec_PKCS12Attribute
*),
1582 (i
+ 2) * sizeof(sec_PKCS12Attribute
*));
1589 bag
->attribs
[i
] = (sec_PKCS12Attribute
*)PORT_ArenaZAlloc(bag
->arena
,
1590 sizeof(sec_PKCS12Attribute
));
1595 bag
->attribs
[i
]->attrValue
= (SECItem
**)PORT_ArenaZAlloc(bag
->arena
,
1596 sizeof(SECItem
*) * 2);
1597 if(!bag
->attribs
[i
]->attrValue
) {
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
)
1614 sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag
*bag
,
1615 SECOidTag attributeType
)
1620 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1624 while(bag
->attribs
[i
] != NULL
) {
1625 if(SECOID_FindOIDTag(&bag
->attribs
[i
]->attrType
)
1627 return bag
->attribs
[i
]->attrValue
[0];
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"
1643 sec_pkcs12_sanitize_nickname(PK11SlotInfo
*slot
, SECItem
*nick
)
1649 nickname
= (char*)nick
->data
; /*Mac breaks without this type cast*/
1650 if ((delimit
= PORT_Strchr(nickname
, ':')) != NULL
) {
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?*/
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
);
1674 sec_pkcs12_get_nickname(sec_PKCS12SafeBag
*bag
)
1676 SECItem
*src
, *dest
;
1679 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1683 src
= sec_pkcs12_get_attribute_value(bag
, SEC_OID_PKCS9_FRIENDLY_NAME
);
1688 dest
= (SECItem
*)PORT_ZAlloc(sizeof(SECItem
));
1692 if(!sec_pkcs12_convert_item_to_unicode(NULL
, dest
, src
, PR_FALSE
,
1693 PR_FALSE
, PR_FALSE
)) {
1697 sec_pkcs12_sanitize_nickname(bag
->slot
, dest
);
1703 SECITEM_ZfreeItem(dest
, PR_TRUE
);
1706 bag
->problem
= PR_TRUE
;
1707 bag
->error
= PORT_GetError();
1712 sec_pkcs12_set_nickname(sec_PKCS12SafeBag
*bag
, SECItem
*name
)
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
);
1728 bag
->attribs
= (sec_PKCS12Attribute
**)PORT_ArenaZAlloc(bag
->arena
,
1729 sizeof(sec_PKCS12Attribute
*)*2);
1733 bag
->attribs
[0] = (sec_PKCS12Attribute
*)PORT_ArenaZAlloc(bag
->arena
,
1734 sizeof(sec_PKCS12Attribute
));
1735 if(!bag
->attribs
[0]) {
1738 bag
->attribs
[1] = NULL
;
1740 attr
= bag
->attribs
[0];
1741 if(SECITEM_CopyItem(bag
->arena
, &attr
->attrType
, &oid
->oid
)
1746 while(bag
->attribs
[i
]) {
1747 if(SECOID_FindOIDTag(&bag
->attribs
[i
]->attrType
)
1748 == SEC_OID_PKCS9_FRIENDLY_NAME
) {
1749 attr
= bag
->attribs
[i
];
1758 bag
->attribs
= (sec_PKCS12Attribute
**)PORT_ArenaGrow(bag
->arena
,
1760 (i
+1) * sizeof(sec_PKCS12Attribute
*),
1761 (i
+2) * sizeof(sec_PKCS12Attribute
*));
1766 (sec_PKCS12Attribute
*)PORT_ArenaZAlloc(bag
->arena
,
1767 sizeof(sec_PKCS12Attribute
));
1768 if(!bag
->attribs
[i
]) {
1771 bag
->attribs
[i
+1] = NULL
;
1772 attr
= bag
->attribs
[i
];
1773 if(SECITEM_CopyItem(bag
->arena
, &attr
->attrType
, &oid
->oid
)
1781 if(!attr
->attrValue
) {
1782 attr
->attrValue
= (SECItem
**)PORT_ArenaZAlloc(bag
->arena
,
1783 sizeof(SECItem
*) * 2);
1784 if(!attr
->attrValue
) {
1787 attr
->attrValue
[0] = (SECItem
*)PORT_ArenaZAlloc(bag
->arena
,
1789 if(!attr
->attrValue
[0]) {
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
)) {
1804 bag
->problem
= PR_TRUE
;
1805 bag
->error
= PORT_GetError();
1810 sec_pkcs12_get_key_info(sec_PKCS12SafeBag
*key
)
1813 SECKEYPrivateKeyInfo
*pki
= NULL
;
1816 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
) {
1829 pki
= key
->safeBagContent
.pkcs8KeyBag
;
1831 if(!pki
|| !pki
->attributes
) {
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
);
1842 if(sec_pkcs12_decoder_set_attribute_value(key
, tag
,
1843 pki
->attributes
[i
]->attrValue
[0])
1845 key
->problem
= PR_TRUE
;
1846 key
->error
= PORT_GetError();
1857 /* retrieve the nickname for the certificate bag. first look
1858 * in the cert bag, otherwise get it from the key.
1861 sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag
*cert
,
1862 sec_PKCS12SafeBag
*key
,
1868 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1872 nickname
= sec_pkcs12_get_nickname(cert
);
1878 nickname
= sec_pkcs12_get_nickname(key
);
1880 if(nickname
&& sec_pkcs12_set_nickname(cert
, nickname
)
1882 SECITEM_ZfreeItem(nickname
, PR_TRUE
);
1890 /* set the nickname for the certificate */
1892 sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag
*cert
,
1893 sec_PKCS12SafeBag
*key
,
1897 if(!nickname
|| !cert
) {
1898 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1902 if(sec_pkcs12_set_nickname(cert
, nickname
) != SECSuccess
) {
1907 if(sec_pkcs12_set_nickname(key
, nickname
) != SECSuccess
) {
1908 cert
->problem
= PR_TRUE
;
1909 cert
->error
= key
->error
;
1917 /* retrieve the DER cert from the cert bag */
1919 sec_pkcs12_get_der_cert(sec_PKCS12SafeBag
*cert
)
1922 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1926 if(SECOID_FindOIDTag(&cert
->safeBagType
) != SEC_OID_PKCS12_V1_CERT_BAG_ID
) {
1930 /* only support X509 certs not SDSI */
1931 if(SECOID_FindOIDTag(&cert
->safeBagContent
.certBag
->bagID
)
1932 != SEC_OID_PKCS9_X509_CERT
) {
1936 return SECITEM_DupItem(&(cert
->safeBagContent
.certBag
->value
.x509Cert
));
1939 struct certNickInfo
{
1941 unsigned int nNicks
;
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
1956 gatherNicknames(CERTCertificate
*cert
, void *arg
)
1958 struct certNickInfo
*nickArg
= (struct certNickInfo
*)arg
;
1962 if(!cert
|| !nickArg
|| nickArg
->error
) {
1963 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
1967 if(!cert
->nickname
) {
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
);
1984 for(i
= 0; i
< nickArg
->nNicks
; i
++) {
1985 if(SECITEM_CompareItem(nickArg
->nickList
[i
], &tempNick
)
1992 /* add the nickname to the list */
1993 if(nickArg
->nNicks
== 0) {
1994 nickArg
->nickList
= (SECItem
**)PORT_ArenaZAlloc(nickArg
->arena
,
1995 2 * sizeof(SECItem
*));
1997 nickArg
->nickList
= (SECItem
**)PORT_ArenaGrow(nickArg
->arena
,
1999 (nickArg
->nNicks
+ 1) * sizeof(SECItem
*),
2000 (nickArg
->nNicks
+ 2) * sizeof(SECItem
*));
2002 if(!nickArg
->nickList
) {
2003 nickArg
->error
= SEC_ERROR_NO_MEMORY
;
2007 nickArg
->nickList
[nickArg
->nNicks
] =
2008 (SECItem
*)PORT_ArenaZAlloc(nickArg
->arena
, sizeof(SECItem
));
2009 if(!nickArg
->nickList
[nickArg
->nNicks
]) {
2010 nickArg
->error
= PORT_GetError();
2015 if(SECITEM_CopyItem(nickArg
->arena
, nickArg
->nickList
[nickArg
->nNicks
],
2016 &tempNick
) != SECSuccess
) {
2017 nickArg
->error
= PORT_GetError();
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.
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
;
2039 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2043 derCert
= sec_pkcs12_get_der_cert(cert
);
2048 tempCert
= CERT_DecodeDERCertificate(derCert
, PR_FALSE
, NULL
);
2054 arena
= PORT_NewArena(1024);
2059 nickArg
= (struct certNickInfo
*)PORT_ArenaZAlloc(arena
,
2060 sizeof(struct certNickInfo
));
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
) {
2079 if(nickArg
->error
) {
2080 /* XXX do we want to set the error? */
2085 if(nickArg
->nNicks
== 0) {
2090 /* set it to the first name, for now. handle multiple names? */
2091 returnDn
= SECITEM_DupItem(nickArg
->nickList
[0]);
2095 PORT_FreeArena(arena
, PR_TRUE
);
2099 CERT_DestroyCertificate(tempCert
);
2103 SECITEM_FreeItem(derCert
, PR_TRUE
);
2109 /* counts certificates found for a given traversal function */
2111 countCertificate(CERTCertificate
*cert
, void *arg
)
2113 unsigned int *nCerts
= (unsigned int *)arg
;
2116 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
);
2134 /* we want to check the local database first if we are importing to it */
2135 PK11_TraverseCertsForNicknameInSlot(nickname
, slot
, countCertificate
,
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.
2148 sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag
*cert
,
2149 sec_PKCS12SafeBag
*key
,
2150 SEC_PKCS12NicknameCollisionCallback nicknameCb
,
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
);
2163 cert
->problem
= PR_TRUE
;
2164 cert
->error
= SEC_ERROR_INVALID_ARGS
;
2165 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2169 if(cert
->hasKey
&& !key
) {
2170 cert
->problem
= PR_TRUE
;
2171 cert
->error
= SEC_ERROR_INVALID_ARGS
;
2172 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
) {
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
);
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
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
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
;
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
)) {
2217 sec_pkcs12_set_nickname_for_cert(cert
, key
, certNickname
,
2223 setNickname
= PR_FALSE
;
2224 newNickname
= (*nicknameCb
)(certNickname
, &cancel
, wincx
);
2226 cert
->problem
= PR_TRUE
;
2227 cert
->error
= SEC_ERROR_USER_CANCELLED
;
2232 cert
->problem
= PR_TRUE
;
2233 cert
->error
= PORT_GetError();
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?
2242 SECITEM_ZfreeItem(certNickname
, PR_TRUE
);
2243 certNickname
= NULL
;
2246 certNickname
= newNickname
;
2247 setNickname
= PR_TRUE
;
2248 /* go back and recheck the new nickname */
2253 SECITEM_ZfreeItem(certNickname
, PR_TRUE
);
2256 if(existingDNNick
) {
2257 SECITEM_ZfreeItem(existingDNNick
, PR_TRUE
);
2262 sec_pkcs12_validate_cert(sec_PKCS12SafeBag
*cert
,
2263 sec_PKCS12SafeBag
*key
,
2264 SEC_PKCS12NicknameCollisionCallback nicknameCb
,
2267 CERTCertificate
*leafCert
;
2270 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2274 cert
->validated
= PR_TRUE
;
2277 cert
->noInstall
= PR_TRUE
;
2278 cert
->problem
= PR_TRUE
;
2279 cert
->error
= SEC_ERROR_INVALID_ARGS
;
2280 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2284 if(!cert
->safeBagContent
.certBag
) {
2285 cert
->noInstall
= PR_TRUE
;
2286 cert
->problem
= PR_TRUE
;
2287 cert
->error
= SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE
;
2291 cert
->noInstall
= PR_FALSE
;
2292 cert
->unused
= PR_FALSE
;
2293 cert
->problem
= PR_FALSE
;
2296 leafCert
= CERT_DecodeDERCertificate(
2297 &cert
->safeBagContent
.certBag
->value
.x509Cert
, PR_FALSE
, NULL
);
2299 cert
->noInstall
= PR_TRUE
;
2300 cert
->problem
= PR_TRUE
;
2301 cert
->error
= PORT_GetError();
2305 sec_pkcs12_validate_cert_nickname(cert
, key
, nicknameCb
, (void *)leafCert
);
2307 CERT_DestroyCertificate(leafCert
);
2311 sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag
*cert
, sec_PKCS12SafeBag
*key
,
2314 CERTCertificate
*leafCert
;
2315 SECKEYPrivateKey
*privk
;
2318 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2322 key
->validated
= PR_TRUE
;
2325 key
->problem
= PR_TRUE
;
2326 key
->noInstall
= PR_TRUE
;
2327 key
->error
= SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY
;
2331 leafCert
= CERT_DecodeDERCertificate(
2332 &(cert
->safeBagContent
.certBag
->value
.x509Cert
), PR_FALSE
, NULL
);
2334 key
->problem
= PR_TRUE
;
2335 key
->noInstall
= PR_TRUE
;
2336 key
->error
= PORT_GetError();
2340 privk
= PK11_FindPrivateKeyFromCert(key
->slot
, leafCert
, wincx
);
2342 privk
= PK11_FindKeyByDERCert(key
->slot
, leafCert
, wincx
);
2346 SECKEY_DestroyPrivateKey(privk
);
2347 key
->noInstall
= PR_TRUE
;
2350 CERT_DestroyCertificate(leafCert
);
2354 sec_pkcs12_add_cert(sec_PKCS12SafeBag
*cert
, PRBool keyExists
, void *wincx
)
2356 SECItem
*derCert
, *nickName
;
2357 char *nickData
= NULL
;
2358 PRBool isIntermediateCA
;
2362 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2366 if(cert
->problem
|| cert
->noInstall
|| cert
->installed
) {
2370 derCert
= &cert
->safeBagContent
.certBag
->value
.x509Cert
;
2372 PORT_Assert(!cert
->problem
&& !cert
->noInstall
);
2374 nickName
= sec_pkcs12_get_nickname(cert
);
2376 nickData
= (char *)nickName
->data
;
2379 isIntermediateCA
= CERT_IsCADERCert(derCert
, NULL
) &&
2380 !CERT_IsRootDERCert(derCert
);
2383 CERTCertificate
*newCert
;
2385 newCert
= CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
2386 derCert
, NULL
, PR_FALSE
, PR_FALSE
);
2388 if(nickName
) SECITEM_ZfreeItem(nickName
, PR_TRUE
);
2389 cert
->error
= PORT_GetError();
2390 cert
->problem
= PR_TRUE
;
2394 rv
= PK11_ImportCertForKeyToSlot(cert
->slot
, newCert
, nickData
,
2396 CERT_DestroyCertificate(newCert
);
2397 } else if ((cert
->tokenCAs
== SECPKCS12TargetTokenNoCAs
) ||
2398 ((cert
->tokenCAs
== SECPKCS12TargetTokenIntermediateCAs
) &&
2399 !isIntermediateCA
)) {
2400 SECItem
*certList
[2];
2401 certList
[0] = derCert
;
2404 rv
= CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport
,
2405 1, certList
, NULL
, PR_TRUE
, PR_FALSE
, nickData
);
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
);
2417 sec_pkcs12_add_key(sec_PKCS12SafeBag
*key
, SECItem
*publicValue
,
2418 KeyType keyType
, unsigned int keyUsage
,
2419 SECItem
*nickName
, void *wincx
)
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
);
2430 if(key
->problem
|| key
->noInstall
) {
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
,
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
,
2450 key
->error
= SEC_ERROR_PKCS12_UNSUPPORTED_VERSION
;
2451 key
->problem
= PR_TRUE
;
2453 SECITEM_ZfreeItem(nickName
, PR_TRUE
);
2458 if(rv
!= SECSuccess
) {
2459 key
->error
= SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY
;
2460 key
->problem
= PR_TRUE
;
2462 key
->installed
= PR_TRUE
;
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.
2483 sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag
***bagList
,
2484 sec_PKCS12SafeBag
*bag
)
2486 sec_PKCS12SafeBag
**newBagList
= NULL
;
2489 if(!bagList
|| !bag
) {
2490 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2495 newBagList
= (sec_PKCS12SafeBag
**)PORT_ArenaZAlloc(bag
->arena
,
2496 sizeof(sec_PKCS12SafeBag
*) * 2);
2498 while((*bagList
)[i
])
2500 newBagList
= (sec_PKCS12SafeBag
**)PORT_ArenaGrow(bag
->arena
,
2502 sizeof(sec_PKCS12SafeBag
*) * (i
+ 1),
2503 sizeof(sec_PKCS12SafeBag
*) * (i
+ 2));
2507 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2511 newBagList
[i
] = bag
;
2512 newBagList
[i
+1] = NULL
;
2513 *bagList
= newBagList
;
2518 static sec_PKCS12SafeBag
**
2519 sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag
**safeBags
,
2520 sec_PKCS12SafeBag
*key
)
2522 sec_PKCS12SafeBag
**certList
= NULL
;
2526 if(!safeBags
|| !safeBags
[0]) {
2527 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2531 keyId
= sec_pkcs12_get_attribute_value(key
, SEC_OID_PKCS9_LOCAL_KEY_ID
);
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
)
2544 if(sec_pkcs12_add_item_to_bag_list(&certList
, safeBags
[i
])
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.
2561 SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext
*p12dcx
)
2563 CERTCertList
*certList
= NULL
;
2564 sec_PKCS12SafeBag
**safeBags
;
2567 if (!p12dcx
|| !p12dcx
->safeBags
|| !p12dcx
->safeBags
[0]) {
2568 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2572 safeBags
= p12dcx
->safeBags
;
2573 certList
= CERT_NewCertList();
2575 if (certList
== 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
)
2587 tempCert
=CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
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.
2603 static sec_PKCS12SafeBag
**
2604 sec_pkcs12_get_key_bags(sec_PKCS12SafeBag
**safeBags
)
2607 sec_PKCS12SafeBag
**keyList
= NULL
;
2610 if(!safeBags
|| !safeBags
[0]) {
2611 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2615 for (i
= 0; safeBags
[i
]; i
++) {
2616 bagType
= SECOID_FindOIDTag(&(safeBags
[i
]->safeBagType
));
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
])
2622 /* This would leak, except that keyList is allocated
2623 * from the arena shared by all the safeBags.
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. :(
2641 sec_pkcs12_validate_bags(sec_PKCS12SafeBag
**safeBags
,
2642 SEC_PKCS12NicknameCollisionCallback nicknameCb
,
2645 sec_PKCS12SafeBag
**keyList
;
2648 if(!safeBags
|| !nicknameCb
) {
2649 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
);
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
);
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
2676 if(sec_pkcs12_get_key_info(key
) != SECSuccess
) {
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
;
2686 cert
->problem
= PR_TRUE
;
2687 cert
->error
= key
->error
;
2690 sec_pkcs12_validate_cert(cert
, key
, nicknameCb
, wincx
);
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
);
2710 case SEC_OID_PKCS12_V1_CERT_BAG_ID
:
2711 sec_pkcs12_validate_cert(bag
, NULL
, nicknameCb
, wincx
);
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
;
2720 bag
->noInstall
= PR_TRUE
;
2729 SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext
*p12dcx
,
2730 SEC_PKCS12NicknameCollisionCallback nicknameCb
)
2733 int i
, noInstallCnt
, probCnt
, bagCnt
, errorVal
= 0;
2734 if(!p12dcx
|| p12dcx
->error
|| !p12dcx
->safeBags
) {
2735 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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;
2746 while(p12dcx
->safeBags
[i
]) {
2748 if(p12dcx
->safeBags
[i
]->noInstall
)
2750 if(p12dcx
->safeBags
[i
]->problem
) {
2752 errorVal
= p12dcx
->safeBags
[i
]->error
;
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.
2767 PORT_SetError(errorVal
);
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
;
2782 if(!certBag
|| !type
|| !usage
) {
2783 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2790 cert
= CERT_DecodeDERCertificate(
2791 &certBag
->safeBagContent
.certBag
->value
.x509Cert
, PR_FALSE
, NULL
);
2796 *usage
= cert
->keyUsage
;
2797 pubKey
= CERT_ExtractPublicKey(cert
);
2798 CERT_DestroyCertificate(cert
);
2803 *type
= pubKey
->keyType
;
2804 switch(pubKey
->keyType
) {
2806 pubValue
= SECITEM_DupItem(&pubKey
->u
.dsa
.publicValue
);
2809 pubValue
= SECITEM_DupItem(&pubKey
->u
.dh
.publicValue
);
2812 pubValue
= SECITEM_DupItem(&pubKey
->u
.rsa
.modulus
);
2815 pubValue
= SECITEM_DupItem(&pubKey
->u
.ec
.publicValue
);
2821 SECKEY_DestroyPublicKey(pubKey
);
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.
2831 sec_pkcs12_install_bags(sec_PKCS12SafeBag
**safeBags
, void *wincx
)
2833 sec_PKCS12SafeBag
**keyList
;
2838 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
);
2851 for (i
= 0; keyList
[i
]; i
++) {
2853 SECItem
*publicValue
= NULL
;
2854 SECItem
*nickName
= NULL
;
2855 sec_PKCS12SafeBag
*key
= keyList
[i
];
2856 sec_PKCS12SafeBag
**certList
;
2858 unsigned int keyUsage
;
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],
2875 nickName
= sec_pkcs12_get_nickname(key
);
2878 key
->error
= SEC_ERROR_BAD_NICKNAME
;
2879 key
->problem
= PR_TRUE
;
2881 } else if (!publicValue
) {
2882 key
->error
= SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY
;
2883 key
->problem
= PR_TRUE
;
2886 rv
= sec_pkcs12_add_key(key
, publicValue
, keyType
,
2887 keyUsage
, nickName
, wincx
);
2890 SECITEM_FreeItem(publicValue
, PR_TRUE
);
2894 SECITEM_FreeItem(nickName
, PR_TRUE
);
2897 if(rv
!= SECSuccess
) {
2898 PORT_SetError(key
->error
);
2905 for (j
= 0; certList
[j
]; j
++) {
2906 sec_PKCS12SafeBag
*cert
= certList
[j
];
2911 if(rv
!= SECSuccess
) {
2912 cert
->problem
= key
->problem
;
2913 cert
->error
= key
->error
;
2914 cert
->noInstall
= PR_TRUE
;
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
);
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
) {
2940 SECOidTag bagType
= SECOID_FindOIDTag(&(bag
->safeBagType
));
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
);
2950 case SEC_OID_PKCS12_V1_KEY_BAG_ID
:
2951 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
:
2962 SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext
*p12dcx
)
2964 if(!p12dcx
|| p12dcx
->error
) {
2965 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
2969 if(!p12dcx
->bagsVerified
) {
2973 return sec_pkcs12_install_bags(p12dcx
->safeBags
, p12dcx
->wincx
);
2977 sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext
*p12dcx
, sec_PKCS12SafeBag
*bag
)
2983 certKeyId
= sec_pkcs12_get_attribute_value(bag
, SEC_OID_PKCS9_LOCAL_KEY_ID
);
2984 if (certKeyId
== NULL
) {
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
);
2994 if(SECITEM_CompareItem(certKeyId
, keyId
) == SECEqual
) {
3002 sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag
*bag
)
3004 SECItem
*friendlyName
;
3007 tempnm
= sec_pkcs12_get_attribute_value(bag
, SEC_OID_PKCS9_FRIENDLY_NAME
);
3008 friendlyName
= (SECItem
*)PORT_ZAlloc(sizeof(SECItem
));
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().
3031 SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext
*p12dcx
)
3033 if(!p12dcx
|| p12dcx
->error
) {
3034 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
3038 p12dcx
->iteration
= 0;
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
);
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
;
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
) {
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
);
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
);
3086 /* return these even though we don't expect them */
3088 case SEC_OID_UNKNOWN
:
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
);
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
);
3110 if(!p12dcx
->safeBagCount
) {
3111 p12dcx
->safeBags
= (sec_PKCS12SafeBag
**)PORT_ArenaZAlloc(p12dcx
->arena
,
3112 sizeof(sec_PKCS12SafeBag
*) * 2);
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
);
3125 p12dcx
->safeBags
[p12dcx
->safeBagCount
] = bag
;
3126 p12dcx
->safeBags
[p12dcx
->safeBagCount
+1] = NULL
;
3127 p12dcx
->safeBagCount
++;
3132 static sec_PKCS12SafeBag
*
3133 sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext
*p12dcx
,
3134 void *key
, PRBool isEspvk
)
3136 sec_PKCS12SafeBag
*keyBag
;
3139 SECItem
*keyID
, *nickName
, *newNickName
;
3141 if(!p12dcx
|| p12dcx
->error
|| !key
) {
3142 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
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
) {
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
);
3167 if(SECITEM_CopyItem(p12dcx
->arena
, &keyBag
->safeBagType
, &oid
->oid
)
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
);
3181 keyID
= &espvk
->espvkData
.assocCerts
[0]->digest
;
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
);
3190 keyID
= &pk
->pvkData
.assocCerts
[0]->digest
;
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
)) {
3200 nickName
= newNickName
;
3201 } else if(nickName
->data
[0] && !nickName
->data
[1]) {
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
;
3211 if(!sec_pkcs12_convert_item_to_unicode(p12dcx
->arena
, newNickName
,
3212 nickName
, PR_FALSE
, PR_FALSE
, PR_TRUE
)) {
3215 nickName
= newNickName
;
3219 if(sec_pkcs12_decoder_set_attribute_value(keyBag
,
3220 SEC_OID_PKCS9_FRIENDLY_NAME
,
3221 nickName
) != SECSuccess
) {
3225 if(sec_pkcs12_decoder_set_attribute_value(keyBag
,SEC_OID_PKCS9_LOCAL_KEY_ID
,
3226 keyID
) != SECSuccess
) {
3233 static sec_PKCS12SafeBag
*
3234 sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext
*p12dcx
,
3237 sec_PKCS12SafeBag
*certBag
;
3239 SGNDigestInfo
*digest
;
3243 if(!p12dcx
|| p12dcx
->error
|| !derCert
) {
3244 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
3248 keyId
= (SECItem
*)PORT_ArenaZAlloc(p12dcx
->arena
, sizeof(SECItem
));
3253 digest
= sec_pkcs12_compute_thumbprint(derCert
);
3258 rv
= SECITEM_CopyItem(p12dcx
->arena
, keyId
, &digest
->digest
);
3259 SGN_DestroyDigestInfo(digest
);
3260 if(rv
!= SECSuccess
) {
3261 PORT_SetError(SEC_ERROR_NO_MEMORY
);
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
)) {
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
)) {
3290 if(SECITEM_CopyItem(p12dcx
->arena
,
3291 &(certBag
->safeBagContent
.certBag
->value
.x509Cert
),
3292 derCert
) != SECSuccess
) {
3296 if(sec_pkcs12_decoder_set_attribute_value(certBag
, SEC_OID_PKCS9_LOCAL_KEY_ID
,
3297 keyId
) != SECSuccess
) {
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
;
3312 if(!p12dcx
|| p12dcx
->error
|| !oldCert
) {
3313 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
3317 derCertList
= SEC_PKCS7GetCertificateList(&oldCert
->value
.x509
->certOrCRL
);
3323 while(derCertList
[i
]) i
++;
3325 certList
= (sec_PKCS12SafeBag
**)PORT_ArenaZAlloc(p12dcx
->arena
,
3326 (i
+ 1) * sizeof(sec_PKCS12SafeBag
*));
3331 for(j
= 0; j
< i
; j
++) {
3332 certList
[j
] = sec_pkcs12_decoder_create_cert(p12dcx
, derCertList
[j
]);
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
;
3353 if(!p12dcx
|| !oldKey
) {
3358 pvkData
= &((SEC_PKCS12ESPVKItem
*)(oldKey
))->espvkData
;
3360 pvkData
= &((SEC_PKCS12PrivateKey
*)(oldKey
))->pvkData
;
3363 if(!pvkData
->assocCerts
|| !pvkData
->assocCerts
[0]) {
3364 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE
);
3368 oldCert
= (SEC_PKCS12CertAndCRL
*)sec_pkcs12_find_object(safe
, baggage
,
3369 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID
, NULL
,
3370 pvkData
->assocCerts
[0]);
3372 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE
);
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
) {
3382 if(sec_pkcs12_decoder_append_bag_to_context(p12dcx
, key
) != SECSuccess
) {
3386 keyName
= sec_pkcs12_get_nickname(key
);
3392 while(certList
[i
]) {
3393 if(sec_pkcs12_decoder_append_bag_to_context(p12dcx
, certList
[i
])
3400 certList
= sec_pkcs12_find_certs_for_key(p12dcx
->safeBags
, key
);
3406 while(certList
[i
] != 0) {
3407 if(sec_pkcs12_set_nickname(certList
[i
], keyName
) != SECSuccess
) {
3417 sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext
*p12dcx
,
3418 SEC_PKCS12SafeContents
*safe
,
3419 SEC_PKCS12Baggage
*baggage
)
3423 if(!p12dcx
|| p12dcx
->error
) {
3424 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
3428 if(safe
&& safe
->contents
) {
3430 while(safe
->contents
[i
] != NULL
) {
3431 if(SECOID_FindOIDTag(&safe
->contents
[i
]->safeBagType
)
3432 == SEC_OID_PKCS12_KEY_BAG_ID
) {
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
) {
3451 if(baggage
&& baggage
->bags
) {
3453 while(baggage
->bags
[i
] != NULL
) {
3454 SEC_PKCS12BaggageItem
*bag
= baggage
->bags
[i
];
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
) {
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
);
3494 if(!safe
&& !baggage
) {
3495 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
3499 p12dcx
= (SEC_PKCS12DecoderContext
*)PORT_ArenaZAlloc(arena
,
3500 sizeof(SEC_PKCS12DecoderContext
));
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
)
3515 p12dcx
->error
= PR_TRUE
;