security/nss/lib/pkcs12/p12d.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nssrenam.h"
     7 #include "p12t.h"
     8 #include "p12.h"
     9 #include "plarena.h"
    10 #include "secitem.h"
    11 #include "secoid.h"
    12 #include "seccomon.h"
    13 #include "secport.h"
    14 #include "cert.h"
    15 #include "secpkcs7.h"
    16 #include "secasn1.h"
    17 #include "secerr.h"
    18 #include "pk11func.h"
    19 #include "p12plcy.h"
    20 #include "p12local.h"
    21 #include "secder.h"
    22 #include "secport.h"
    24 #include "certdb.h"
    26 #include "prcpucfg.h"
    28 /* This belongs in secport.h */
    29 #define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \
    30     (type *)PORT_ArenaGrow((poolp), (oldptr), \
    31 			   (oldnum) * sizeof(type), (newnum) * sizeof(type))
    34 typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext;
    36 /* Opaque structure for decoding SafeContents.  These are used
    37  * for each authenticated safe as well as any nested safe contents.
    38  */
    39 struct sec_PKCS12SafeContentsContextStr {
    40     /* the parent decoder context */
    41     SEC_PKCS12DecoderContext *p12dcx;
    43     /* memory arena to allocate space from */
    44     PLArenaPool *arena;
    46     /* decoder context and destination for decoding safe contents */
    47     SEC_ASN1DecoderContext *safeContentsA1Dcx;
    48     sec_PKCS12SafeContents safeContents;
    50     /* information for decoding safe bags within the safe contents.
    51      * these variables are updated for each safe bag decoded.
    52      */
    53     SEC_ASN1DecoderContext *currentSafeBagA1Dcx;
    54     sec_PKCS12SafeBag *currentSafeBag;
    55     PRBool skipCurrentSafeBag;
    57     /* if the safe contents is nested, the parent is pointed to here. */
    58     sec_PKCS12SafeContentsContext *nestedSafeContentsCtx;
    59 };
    61 /* opaque decoder context structure.  information for decoding a pkcs 12
    62  * PDU are stored here as well as decoding pointers for intermediary 
    63  * structures which are part of the PKCS 12 PDU.  Upon a successful
    64  * decode, the safe bags containing certificates and keys encountered.
    65  */  
    66 struct SEC_PKCS12DecoderContextStr {
    67     PLArenaPool *arena;
    68     PK11SlotInfo *slot;
    69     void *wincx;
    70     PRBool error;
    71     int errorValue;
    73     /* password */
    74     SECItem *pwitem;
    76     /* used for decoding the PFX structure */
    77     SEC_ASN1DecoderContext 	*pfxA1Dcx;
    78     sec_PKCS12PFXItem 		pfx;
    80     /* safe bags found during decoding */  
    81     sec_PKCS12SafeBag 		**safeBags;
    82     unsigned int 		safeBagCount;
    84     /* state variables for decoding authenticated safes. */
    85     SEC_PKCS7DecoderContext 	*currentASafeP7Dcx;
    86     SEC_ASN1DecoderContext 	*aSafeA1Dcx;
    87     SEC_PKCS7DecoderContext 	*aSafeP7Dcx;
    88     SEC_PKCS7ContentInfo 	*aSafeCinfo;
    89     sec_PKCS12AuthenticatedSafe authSafe;
    90     sec_PKCS12SafeContents 	safeContents;
    92     /* safe contents info */
    93     unsigned int 		safeContentsCnt;
    94     sec_PKCS12SafeContentsContext **safeContentsList;
    96     /* HMAC info */
    97     sec_PKCS12MacData		macData;
    99     /* routines for reading back the data to be hmac'd */
   100     /* They are called as follows.
   101      *
   102      * Stage 1: decode the aSafes cinfo into a buffer in dArg,
   103      * which p12d.c sometimes refers to as the "temp file".
   104      * This occurs during SEC_PKCS12DecoderUpdate calls.
   105      *
   106      * dOpen(dArg, PR_FALSE)
   107      * dWrite(dArg, buf, len)
   108      * ...
   109      * dWrite(dArg, buf, len)
   110      * dClose(dArg, PR_FALSE)
   111      *
   112      * Stage 2: verify MAC
   113      * This occurs SEC_PKCS12DecoderVerify.
   114      *
   115      * dOpen(dArg, PR_TRUE)
   116      * dRead(dArg, buf, IN_BUF_LEN)
   117      * ...
   118      * dRead(dArg, buf, IN_BUF_LEN)
   119      * dClose(dArg, PR_TRUE)
   120      */
   121     digestOpenFn 		dOpen;
   122     digestCloseFn 		dClose;
   123     digestIOFn 			dRead, dWrite;
   124     void 			*dArg;
   125     PRBool			dIsOpen;  /* is the temp file created? */
   127     /* helper functions */
   128     SECKEYGetPasswordKey 	pwfn;
   129     void 			*pwfnarg;
   130     PRBool 			swapUnicodeBytes;
   132     /* import information */
   133     PRBool 			bagsVerified;
   135     /* buffer management for the default callbacks implementation */
   136     void        *buffer;      /* storage area */
   137     PRInt32     filesize;     /* actual data size */
   138     PRInt32     allocated;    /* total buffer size allocated */
   139     PRInt32     currentpos;   /* position counter */
   140     SECPKCS12TargetTokenCAs tokenCAs;
   141     sec_PKCS12SafeBag **keyList;/* used by ...IterateNext() */
   142     unsigned int iteration;
   143     SEC_PKCS12DecoderItem decitem;
   144 };
   146 /* forward declarations of functions that are used when decoding
   147  * safeContents bags which are nested and when decoding the 
   148  * authenticatedSafes.
   149  */
   150 static SECStatus
   151 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext 
   152 							*safeContentsCtx);
   153 static SECStatus
   154 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
   155 							*safeContentsCtx);
   158 /* make sure that the PFX version being decoded is a version
   159  * which we support.
   160  */
   161 static PRBool
   162 sec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx)
   163 {
   164     /* if no version, assume it is not supported */
   165     if(pfx->version.len == 0) {
   166 	return PR_FALSE;
   167     }
   169     if(DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) {
   170 	return PR_FALSE;
   171     }
   173     return PR_TRUE;
   174 }
   176 /* retrieve the key for decrypting the safe contents */ 
   177 static PK11SymKey *
   178 sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid)
   179 {
   180     SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *) arg;
   181     PK11SlotInfo *slot;
   182     PK11SymKey *bulkKey;
   184     if(!p12dcx) {
   185 	return NULL;
   186     }
   188     /* if no slot specified, use the internal key slot */
   189     if(p12dcx->slot) {
   190 	slot = PK11_ReferenceSlot(p12dcx->slot);
   191     } else {
   192 	slot = PK11_GetInternalKeySlot();
   193     }
   195     bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, 
   196 						PR_FALSE, p12dcx->wincx);
   197     /* some tokens can't generate PBE keys on their own, generate the
   198      * key in the internal slot, and let the Import code deal with it,
   199      * (if the slot can't generate PBEs, then we need to use the internal
   200      * slot anyway to unwrap). */
   201     if (!bulkKey && !PK11_IsInternal(slot)) {
   202 	PK11_FreeSlot(slot);
   203 	slot = PK11_GetInternalKeySlot();
   204 	bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, 
   205 						PR_FALSE, p12dcx->wincx);
   206     }
   207     PK11_FreeSlot(slot);
   209     /* set the password data on the key */
   210     if (bulkKey) {
   211         PK11_SetSymKeyUserData(bulkKey,p12dcx->pwitem, NULL);
   212     }
   215     return bulkKey;
   216 }
   218 /* XXX this needs to be modified to handle enveloped data.  most
   219  * likely, it should mirror the routines for SMIME in that regard.
   220  */
   221 static PRBool
   222 sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid, 
   223 				      PK11SymKey *bulkkey)
   224 {
   225     PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid);
   227     if(!decryptionAllowed) {
   228 	return PR_FALSE;
   229     }
   231     return PR_TRUE;
   232 }
   234 /* when we encounter a new safe bag during the decoding, we need
   235  * to allocate space for the bag to be decoded to and set the 
   236  * state variables appropriately.  all of the safe bags are allocated
   237  * in a buffer in the outer SEC_PKCS12DecoderContext, however,
   238  * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext
   239  * for the current bag.
   240  */
   241 static SECStatus
   242 sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext 
   243 						*safeContentsCtx)
   244 {
   245     void *mark = NULL;
   246     SEC_PKCS12DecoderContext *p12dcx;
   248     /* make sure that the structures are defined, and there has
   249      * not been an error in the decoding 
   250      */
   251     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   252 		|| safeContentsCtx->p12dcx->error) {
   253 	return SECFailure;
   254     }
   256     p12dcx = safeContentsCtx->p12dcx;
   257     mark = PORT_ArenaMark(p12dcx->arena);
   259     /* allocate a new safe bag, if bags already exist, grow the 
   260      * list of bags, otherwise allocate a new list.  the list is
   261      * NULL terminated.
   262      */
   263     p12dcx->safeBags = (!p12dcx->safeBagCount)
   264 	? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
   265         : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
   266 				sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
   267 				p12dcx->safeBagCount + 2);
   269     if(!p12dcx->safeBags) {
   270 	p12dcx->errorValue = PORT_GetError();
   271 	goto loser;
   272     }
   274     /* append the bag to the end of the list and update the reference
   275      * in the safeContentsCtx.
   276      */
   277     p12dcx->safeBags[p12dcx->safeBagCount] = 
   278     safeContentsCtx->currentSafeBag = 
   279 			    PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
   280     if(!safeContentsCtx->currentSafeBag) {
   281 	p12dcx->errorValue = PORT_GetError();
   282 	goto loser;
   283     }
   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.
   302      */
   303     if(mark) {
   304 	PORT_ArenaRelease(p12dcx->arena, mark);
   305     }
   307     p12dcx->error = PR_TRUE;
   308     return SECFailure;
   309 }
   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.
   314  */
   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)
   319 {
   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.
   328      */
   329     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   330 		|| safeContentsCtx->p12dcx->error 
   331 		|| safeContentsCtx->skipCurrentSafeBag) {
   332 	return;
   333     }
   334     p12dcx = safeContentsCtx->p12dcx;
   336     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagA1Dcx, data, len);
   337     if(rv != SECSuccess) {
   338 	p12dcx->errorValue = PORT_GetError();
   339 	goto loser;
   340     }
   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.
   349      */
   350     p12dcx->error = PR_TRUE;
   351     SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
   352     safeContentsCtx->currentSafeBagA1Dcx = NULL;
   353     return;
   354 }
   356 /* notify function for decoding safeBags.  This function is
   357  * used to filter safeBag types which are not supported,
   358  * initiate the decoding of nested safe contents, and decode
   359  * safeBags in general.  this function is set when the decoder
   360  * context for the safeBag is first created.
   361  */
   362 static void
   363 sec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before,
   364 				   void *dest, int real_depth)
   365 {
   366     sec_PKCS12SafeContentsContext *safeContentsCtx = 
   367         (sec_PKCS12SafeContentsContext *)arg;
   368     SEC_PKCS12DecoderContext *p12dcx;
   369     sec_PKCS12SafeBag *bag;
   370     PRBool after;
   372     /* if an error is encountered, return */
   373     if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
   374 		safeContentsCtx->p12dcx->error) {
   375 	return;
   376     }
   377     p12dcx = safeContentsCtx->p12dcx;
   379     /* to make things more readable */
   380     if(before)
   381 	after = PR_FALSE;
   382     else 
   383 	after = PR_TRUE;
   385     /* have we determined the safeBagType yet? */
   386     bag = safeContentsCtx->currentSafeBag;
   387     if(bag->bagTypeTag == NULL) {
   388 	if(after && (dest == &(bag->safeBagType))) {
   389 	    bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType));
   390 	    if(bag->bagTypeTag == NULL) {
   391 		p12dcx->error = PR_TRUE;
   392 		p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
   393 	    }
   394 	}
   395 	return;
   396     }
   398     /* process the safeBag depending on it's type.  those
   399      * which we do not support, are ignored.  we start a decoding
   400      * context for a nested safeContents.
   401      */
   402     switch(bag->bagTypeTag->offset) {
   403 	case SEC_OID_PKCS12_V1_KEY_BAG_ID:
   404 	case SEC_OID_PKCS12_V1_CERT_BAG_ID:
   405 	case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
   406 	    break;
   407 	case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
   408 	    /* if we are just starting to decode the safeContents, initialize
   409 	     * a new safeContentsCtx to process it.
   410 	     */
   411 	    if(before && (dest == &(bag->safeBagContent))) {
   412 		sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx);
   413 	    } else if(after && (dest == &(bag->safeBagContent))) {
   414 		/* clean up the nested decoding */
   415 		sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx);
   416 	    }
   417 	    break;
   418 	case SEC_OID_PKCS12_V1_CRL_BAG_ID:
   419 	case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
   420 	default:
   421 	    /* skip any safe bag types we don't understand or handle */
   422 	    safeContentsCtx->skipCurrentSafeBag = PR_TRUE;
   423 	    break;
   424     }
   426     return;
   427 }
   429 /* notify function for decoding safe contents.  each entry in the
   430  * safe contents is a safeBag which needs to be allocated and
   431  * the decoding context initialized at the beginning and then
   432  * the context needs to be closed and finished at the end.
   433  *
   434  * this function is set when the safeContents decode context is
   435  * initialized.
   436  */
   437 static void
   438 sec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before,
   439 					void *dest, int real_depth)
   440 {
   441     sec_PKCS12SafeContentsContext *safeContentsCtx = 
   442         (sec_PKCS12SafeContentsContext*)arg;
   443     SEC_PKCS12DecoderContext *p12dcx;
   444     SECStatus rv;
   446     /* if there is an error we don't want to continue processing,
   447      * just return and keep going.
   448      */
   449     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   450 		|| safeContentsCtx->p12dcx->error) {
   451 	return;
   452     }
   453     p12dcx = safeContentsCtx->p12dcx;
   455     /* if we are done with the current safeBag, then we need to
   456      * finish the context and set the state variables appropriately.
   457      */
   458     if(!before) {
   459 	SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
   460 	SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
   461 	safeContentsCtx->currentSafeBagA1Dcx = NULL;
   462 	safeContentsCtx->skipCurrentSafeBag = PR_FALSE;
   463     } else {
   464 	/* we are starting a new safe bag.  we need to allocate space
   465 	 * for the bag and initialize the decoding context.
   466 	 */
   467 	rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx);
   468 	if(rv != SECSuccess) {
   469 	    goto loser;
   470 	}
   472 	/* set up the decoder context */
   473 	safeContentsCtx->currentSafeBagA1Dcx = 
   474 		SEC_ASN1DecoderStart(p12dcx->arena,
   475 				     safeContentsCtx->currentSafeBag,
   476 				     sec_PKCS12SafeBagTemplate);
   477 	if(!safeContentsCtx->currentSafeBagA1Dcx) {
   478 	    p12dcx->errorValue = PORT_GetError();
   479 	    goto loser;
   480 	}
   482 	/* set the notify and filter procs so that the safe bag
   483 	 * data gets sent to the proper location when decoding.
   484 	 */
   485 	SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagA1Dcx, 
   486 				 sec_pkcs12_decoder_safe_bag_notify, 
   487 				 safeContentsCtx);
   488 	SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsA1Dcx, 
   489 				 sec_pkcs12_decoder_safe_bag_update, 
   490 				 safeContentsCtx, PR_TRUE);
   491     }
   493     return;
   495 loser:
   496     /* in the event of an error, we want to close the decoding
   497      * context and clear the filter and notify procedures.
   498      */
   499     p12dcx->error = PR_TRUE;
   501     if(safeContentsCtx->currentSafeBagA1Dcx) {
   502 	SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
   503 	safeContentsCtx->currentSafeBagA1Dcx = NULL;
   504     }
   506     SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsA1Dcx);
   507     SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
   509     return;
   510 }
   512 /* initialize the safeContents for decoding.  this routine
   513  * is used for authenticatedSafes as well as nested safeContents.
   514  */
   515 static sec_PKCS12SafeContentsContext *
   516 sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx,
   517 					     PRBool nestedSafe)
   518 {
   519     sec_PKCS12SafeContentsContext *safeContentsCtx = NULL;
   520     const SEC_ASN1Template *theTemplate;
   522     if(!p12dcx || p12dcx->error) {
   523 	return NULL;
   524     }
   526     /* allocate a new safeContents list or grow the existing list and
   527      * append the new safeContents onto the end.
   528      */
   529     p12dcx->safeContentsList = (!p12dcx->safeContentsCnt) 
   530 	? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeContentsContext *, 2)
   531 	: PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeContentsList,
   532 			        sec_PKCS12SafeContentsContext *,
   533 			        1 + p12dcx->safeContentsCnt,
   534 			        2 + p12dcx->safeContentsCnt);
   536     if(!p12dcx->safeContentsList) {
   537 	p12dcx->errorValue = PORT_GetError();
   538 	goto loser;
   539     }
   541     p12dcx->safeContentsList[p12dcx->safeContentsCnt] = safeContentsCtx = 
   542         PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeContentsContext);
   543     if(!p12dcx->safeContentsList[p12dcx->safeContentsCnt]) {
   544 	p12dcx->errorValue = PORT_GetError();
   545 	goto loser;
   546     }
   547     p12dcx->safeContentsList[++p12dcx->safeContentsCnt] = NULL;
   549     /* set up the state variables */
   550     safeContentsCtx->p12dcx = p12dcx;
   551     safeContentsCtx->arena = p12dcx->arena;
   553     /* begin the decoding -- the template is based on whether we are
   554      * decoding a nested safeContents or not.
   555      */
   556     if(nestedSafe == PR_TRUE) {
   557 	theTemplate = sec_PKCS12NestedSafeContentsDecodeTemplate;
   558     } else {
   559 	theTemplate = sec_PKCS12SafeContentsDecodeTemplate;
   560     }
   562     /* start the decoder context */
   563     safeContentsCtx->safeContentsA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, 
   564 					&safeContentsCtx->safeContents,
   565 					theTemplate);
   567     if(!safeContentsCtx->safeContentsA1Dcx) {
   568 	p12dcx->errorValue = PORT_GetError();
   569 	goto loser;
   570     }
   572     /* set the safeContents notify procedure to look for
   573      * and start the decode of safeBags.
   574      */
   575     SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->safeContentsA1Dcx, 
   576 				sec_pkcs12_decoder_safe_contents_notify,
   577 				safeContentsCtx);
   579     return safeContentsCtx;
   581 loser:
   582     /* in the case of an error, we want to finish the decoder
   583      * context and set the error flag.
   584      */
   585     if(safeContentsCtx && safeContentsCtx->safeContentsA1Dcx) {
   586 	SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   587 	safeContentsCtx->safeContentsA1Dcx = NULL;
   588     }
   590     p12dcx->error = PR_TRUE;
   592     return NULL;
   593 }
   595 /* wrapper for updating safeContents.  this is set as the filter of
   596  * safeBag when there is a nested safeContents.
   597  */
   598 static void
   599 sec_pkcs12_decoder_nested_safe_contents_update(void *arg, const char *buf,
   600 					  unsigned long len, int depth,
   601 					  SEC_ASN1EncodingPart data_kind)
   602 {
   603     sec_PKCS12SafeContentsContext *safeContentsCtx = 
   604         (sec_PKCS12SafeContentsContext *)arg;
   605     SEC_PKCS12DecoderContext *p12dcx;
   606     SECStatus rv;
   608     /* check for an error */
   609     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   610 			|| safeContentsCtx->p12dcx->error
   611 			|| !safeContentsCtx->safeContentsA1Dcx) {
   612 	return;
   613     }
   615     /* no need to update if no data sent in */
   616     if(!len || !buf) {
   617 	return;
   618     }
   620     /* update the decoding context */
   621     p12dcx = safeContentsCtx->p12dcx;
   622     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
   623     if(rv != SECSuccess) {
   624 	p12dcx->errorValue = PORT_GetError();
   625 	goto loser;
   626     }
   628     return;
   630 loser:
   631     /* handle any errors.  If a decoding context is open, close it. */
   632     p12dcx->error = PR_TRUE;
   633     if(safeContentsCtx->safeContentsA1Dcx) {
   634 	SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   635 	safeContentsCtx->safeContentsA1Dcx = NULL;
   636     }
   637 }
   639 /* whenever a new safeContentsSafeBag is encountered, we need
   640  * to init a safeContentsContext.  
   641  */
   642 static SECStatus  
   643 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext 
   644 							*safeContentsCtx)
   645 {
   646     /* check for an error */
   647     if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
   648 		safeContentsCtx->p12dcx->error) {
   649 	return SECFailure;
   650     }
   652     safeContentsCtx->nestedSafeContentsCtx = 
   653     	sec_pkcs12_decoder_safe_contents_init_decode(safeContentsCtx->p12dcx,
   654 						     PR_TRUE);
   655     if(!safeContentsCtx->nestedSafeContentsCtx) {
   656 	return SECFailure;
   657     }
   659     /* set up new filter proc */
   660     SEC_ASN1DecoderSetNotifyProc(
   661                      safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx,
   662 				 sec_pkcs12_decoder_safe_contents_notify,
   663 				 safeContentsCtx->nestedSafeContentsCtx);
   665     SEC_ASN1DecoderSetFilterProc(safeContentsCtx->currentSafeBagA1Dcx,
   666 				 sec_pkcs12_decoder_nested_safe_contents_update,
   667 				 safeContentsCtx->nestedSafeContentsCtx, 
   668 				 PR_TRUE);
   670     return SECSuccess;
   671 }
   673 /* when the safeContents is done decoding, we need to reset the
   674  * proper filter and notify procs and close the decoding context 
   675  */
   676 static SECStatus
   677 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
   678 							*safeContentsCtx)
   679 {
   680     /* check for error */
   681     if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
   682 		safeContentsCtx->p12dcx->error) {
   683 	return SECFailure;
   684     }
   686     /* clean up */	
   687     SEC_ASN1DecoderClearFilterProc(safeContentsCtx->currentSafeBagA1Dcx);
   688     SEC_ASN1DecoderClearNotifyProc(
   689                     safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
   690     SEC_ASN1DecoderFinish(
   691                     safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
   692     safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx = NULL;
   693     safeContentsCtx->nestedSafeContentsCtx = NULL;
   695     return SECSuccess;
   696 }
   698 /* wrapper for updating safeContents.  This is used when decoding
   699  * the nested safeContents and any authenticatedSafes.
   700  */
   701 static void
   702 sec_pkcs12_decoder_safe_contents_callback(void *arg, const char *buf,
   703 					  unsigned long len)
   704 {
   705     SECStatus rv;
   706     sec_PKCS12SafeContentsContext *safeContentsCtx = 
   707         (sec_PKCS12SafeContentsContext *)arg;
   708     SEC_PKCS12DecoderContext *p12dcx;
   710     /* check for error */  
   711     if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   712 		|| safeContentsCtx->p12dcx->error
   713 		|| !safeContentsCtx->safeContentsA1Dcx) {
   714 	return;
   715     }
   716     p12dcx = safeContentsCtx->p12dcx;
   718     /* update the decoder */
   719     rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
   720     if(rv != SECSuccess) {
   721 	/* if we fail while trying to decode a 'safe', it's probably because
   722 	 * we didn't have the correct password. */
   723 	PORT_SetError(SEC_ERROR_BAD_PASSWORD);
   724 	p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
   725 	SEC_PKCS7DecoderAbort(p12dcx->currentASafeP7Dcx,SEC_ERROR_BAD_PASSWORD);
   726 	goto loser;
   727     }
   729     return;
   731 loser:
   732     /* set the error and finish the context */
   733     p12dcx->error = PR_TRUE;
   734     if(safeContentsCtx->safeContentsA1Dcx) {
   735 	SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   736 	safeContentsCtx->safeContentsA1Dcx = NULL;
   737     }
   739     return;
   740 }
   742 /* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate
   743  */
   744 static void
   745 sec_pkcs12_decoder_wrap_p7_update(void *arg, const char *data,
   746 				  unsigned long len, int depth,
   747 				  SEC_ASN1EncodingPart data_kind)
   748 {
   749     SEC_PKCS7DecoderContext *p7dcx = (SEC_PKCS7DecoderContext *)arg;
   751     SEC_PKCS7DecoderUpdate(p7dcx, data, len);
   752 }
   754 /* notify function for decoding aSafes.  at the beginning,
   755  * of an authenticatedSafe, we start a decode of a safeContents.
   756  * at the end, we clean up the safeContents decoder context and
   757  * reset state variables 
   758  */
   759 static void
   760 sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest, 
   761 			       int real_depth)
   762 {
   763     SEC_PKCS12DecoderContext *p12dcx;
   764     sec_PKCS12SafeContentsContext *safeContentsCtx;
   766     /* make sure no error occurred. */
   767     p12dcx = (SEC_PKCS12DecoderContext *)arg;
   768     if(!p12dcx || p12dcx->error) {
   769 	return;
   770     }
   772     if(before) {
   774 	/* init a new safeContentsContext */
   775 	safeContentsCtx = sec_pkcs12_decoder_safe_contents_init_decode(p12dcx, 
   776 								PR_FALSE);
   777 	if(!safeContentsCtx) {
   778 	    goto loser;
   779 	}
   781 	/* initiate the PKCS7ContentInfo decode */
   782 	p12dcx->currentASafeP7Dcx = SEC_PKCS7DecoderStart(
   783 				sec_pkcs12_decoder_safe_contents_callback,
   784 				safeContentsCtx, 
   785 				p12dcx->pwfn, p12dcx->pwfnarg,
   786 				sec_pkcs12_decoder_get_decrypt_key, p12dcx,
   787 				sec_pkcs12_decoder_decryption_allowed);
   788 	if(!p12dcx->currentASafeP7Dcx) {
   789 	    p12dcx->errorValue = PORT_GetError();
   790 	    goto loser;
   791 	}
   792 	SEC_ASN1DecoderSetFilterProc(p12dcx->aSafeA1Dcx, 
   793 				     sec_pkcs12_decoder_wrap_p7_update,
   794 				     p12dcx->currentASafeP7Dcx, PR_TRUE);
   795     }
   797     if(!before) {
   798 	/* if one is being decoded, finish the decode */
   799 	if(p12dcx->currentASafeP7Dcx != NULL) {
   800 	    SEC_PKCS7ContentInfo * cinfo;
   801 	    unsigned int cnt = p12dcx->safeContentsCnt - 1;
   802 	    safeContentsCtx = p12dcx->safeContentsList[cnt];
   803 	    if (safeContentsCtx->safeContentsA1Dcx) {
   804 		SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   805 		safeContentsCtx->safeContentsA1Dcx = NULL;
   806 	    }
   807 	    cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
   808 	    p12dcx->currentASafeP7Dcx = NULL;
   809 	    if(!cinfo) {
   810 		p12dcx->errorValue = PORT_GetError();
   811 		goto loser;
   812 	    }
   813 	    SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
   814 	}
   815     }
   818     return;
   820 loser:
   821     /* set the error flag */
   822     p12dcx->error = PR_TRUE;
   823     return;
   824 }
   826 /* wrapper for updating asafes decoding context.  this function
   827  * writes data being decoded to disk, so that a mac can be computed
   828  * later.  
   829  */
   830 static void
   831 sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf, 
   832 				  unsigned long len)
   833 {
   834     SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
   835     SECStatus rv;
   837     if(!p12dcx || p12dcx->error) {
   838 	return;
   839     }
   841     /* update the context */
   842     rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeA1Dcx, buf, len);
   843     if(rv != SECSuccess) {
   844 	p12dcx->errorValue = PORT_GetError();
   845 	p12dcx->error = PR_TRUE;
   846 	goto loser;
   847     }
   849     /* if we are writing to a file, write out the new information */
   850     if(p12dcx->dWrite) {
   851 	unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg, 	
   852 						   (unsigned char *)buf, len);
   853 	if(writeLen != len) {
   854 	    p12dcx->errorValue = PORT_GetError();
   855 	    goto loser;
   856 	}
   857     }
   859     return;
   861 loser:
   862     /* set the error flag */
   863     p12dcx->error = PR_TRUE;
   864     SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
   865     p12dcx->aSafeA1Dcx = NULL;
   867     return;
   868 }
   870 /* start the decode of an authenticatedSafe contentInfo.
   871  */ 
   872 static SECStatus
   873 sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx)
   874 {
   875     if(!p12dcx || p12dcx->error) {
   876 	return SECFailure;
   877     }
   879     /* start the decode context */
   880     p12dcx->aSafeA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, 
   881     					&p12dcx->authSafe,
   882     					sec_PKCS12AuthenticatedSafeTemplate);
   883     if(!p12dcx->aSafeA1Dcx) {
   884 	p12dcx->errorValue = PORT_GetError();
   885    	goto loser;
   886     }
   888     /* set the notify function */
   889     SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeA1Dcx,
   890     				 sec_pkcs12_decoder_asafes_notify, p12dcx);
   892     /* begin the authSafe decoder context */
   893     p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart(
   894     				sec_pkcs12_decoder_asafes_callback, p12dcx,
   895     				p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL);
   896     if(!p12dcx->aSafeP7Dcx) {
   897 	p12dcx->errorValue = PORT_GetError();
   898 	goto loser;
   899     }
   901     /* open the temp file for writing, if the digest functions were set */ 
   902     if(p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE) 
   903 				!= SECSuccess) {
   904 	p12dcx->errorValue = PORT_GetError();
   905 	goto loser;
   906     }
   907     /* dOpen(dArg, PR_FALSE) creates the temp file */
   908     p12dcx->dIsOpen = PR_TRUE;
   910     return SECSuccess;
   912 loser:
   913     p12dcx->error = PR_TRUE;
   915     if(p12dcx->aSafeA1Dcx) {
   916 	SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
   917 	p12dcx->aSafeA1Dcx = NULL;
   918     } 
   920     if(p12dcx->aSafeP7Dcx) {
   921 	SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
   922 	p12dcx->aSafeP7Dcx = NULL;
   923     }
   925     return SECFailure;
   926 }
   928 /* wrapper for updating the safeContents.  this function is used as
   929  * a filter for the pfx when decoding the authenticated safes 
   930  */
   931 static void 
   932 sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf,
   933 				      unsigned long len, int depth,
   934 				      SEC_ASN1EncodingPart data_kind)
   935 {
   936     SEC_PKCS12DecoderContext *p12dcx;
   937     SECStatus rv;
   939     p12dcx = (SEC_PKCS12DecoderContext*)arg;
   940     if(!p12dcx || p12dcx->error) {
   941 	return;
   942     }
   944     /* update the safeContents decoder */
   945     rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len);
   946     if(rv != SECSuccess) {
   947 	p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
   948 	goto loser;
   949     }
   951     return;
   953 loser:
   955     /* did we find an error?  if so, close the context and set the 
   956      * error flag.
   957      */
   958     SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
   959     p12dcx->aSafeP7Dcx = NULL;
   960     p12dcx->error = PR_TRUE;
   961 }
   963 /* notify procedure used while decoding the pfx.  When we encounter
   964  * the authSafes, we want to trigger the decoding of authSafes as well
   965  * as when we encounter the macData, trigger the decoding of it.  we do
   966  * this because we we are streaming the decoder and not decoding in place.
   967  * the pfx which is the destination, only has the version decoded into it.
   968  */
   969 static void 
   970 sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest,
   971 				   int real_depth)
   972 {
   973     SECStatus rv;
   974     SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext*)arg;
   976     /* if an error occurs, clear the notifyProc and the filterProc 
   977      * and continue. 
   978      */
   979     if(p12dcx->error) {
   980 	SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxA1Dcx);
   981 	SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
   982 	return;
   983     }
   985     if(before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
   987 	/* we want to make sure this is a version we support */
   988 	if(!sec_pkcs12_proper_version(&p12dcx->pfx)) {
   989 	    p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
   990 	    goto loser;
   991 	}
   993 	/* start the decode of the aSafes cinfo... */
   994 	rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx);
   995 	if(rv != SECSuccess) {
   996 	    goto loser;
   997 	}
   999 	/* set the filter proc to update the authenticated safes. */
  1000 	SEC_ASN1DecoderSetFilterProc(p12dcx->pfxA1Dcx,
  1001 				     sec_pkcs12_decode_asafes_cinfo_update,
  1002 				     p12dcx, PR_TRUE);
  1005     if(!before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
  1007 	/* we are done decoding the authenticatedSafes, so we need to 
  1008 	 * finish the decoderContext and clear the filter proc
  1009 	 * and close the hmac callback, if present
  1010 	 */
  1011 	p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
  1012 	p12dcx->aSafeP7Dcx = NULL;
  1013 	if(!p12dcx->aSafeCinfo) {
  1014 	    p12dcx->errorValue = PORT_GetError();
  1015 	    goto loser;
  1017 	SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
  1018 	if(p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) 
  1019 				!= SECSuccess)) {
  1020 	    p12dcx->errorValue = PORT_GetError();
  1021 	    goto loser;
  1026     return;
  1028 loser:
  1029     p12dcx->error = PR_TRUE;
  1032 /*  default implementations of the open/close/read/write functions for
  1033     SEC_PKCS12DecoderStart 
  1034 */
  1036 #define DEFAULT_TEMP_SIZE 4096
  1038 static SECStatus
  1039 p12u_DigestOpen(void *arg, PRBool readData)
  1041     SEC_PKCS12DecoderContext* p12cxt = arg;
  1043     p12cxt->currentpos = 0;
  1045     if (PR_FALSE == readData) {
  1046         /* allocate an initial buffer */
  1047         p12cxt->filesize = 0;
  1048         p12cxt->allocated = DEFAULT_TEMP_SIZE;
  1049         p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE);
  1050         PR_ASSERT(p12cxt->buffer);
  1052     else
  1054         PR_ASSERT(p12cxt->buffer);
  1055         if (!p12cxt->buffer) {
  1056             return SECFailure; /* no data to read */
  1060     return SECSuccess;
  1063 static SECStatus
  1064 p12u_DigestClose(void *arg, PRBool removeFile)
  1066     SEC_PKCS12DecoderContext* p12cxt = arg;
  1068     PR_ASSERT(p12cxt);
  1069     if (!p12cxt) {
  1070         return SECFailure;
  1072     p12cxt->currentpos = 0;
  1074     if (PR_TRUE == removeFile) {
  1075         PR_ASSERT(p12cxt->buffer);
  1076         if (!p12cxt->buffer) {
  1077             return SECFailure;
  1079         if (p12cxt->buffer) {
  1080             PORT_Free(p12cxt->buffer);
  1081             p12cxt->buffer = NULL;
  1082             p12cxt->allocated = 0;
  1083             p12cxt->filesize = 0;
  1087     return SECSuccess;
  1090 static int
  1091 p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
  1093     int toread = len;
  1094     SEC_PKCS12DecoderContext* p12cxt = arg;
  1096     if(!buf || len == 0 || !p12cxt->buffer) {
  1097 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1098 	return -1;
  1101     if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
  1102         /* trying to read past the end of the buffer */
  1103         toread = p12cxt->filesize - p12cxt->currentpos;
  1105     memcpy(buf, (char*)p12cxt->buffer + p12cxt->currentpos, toread);
  1106     p12cxt->currentpos += toread;
  1107     return toread;
  1110 static int
  1111 p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
  1113     SEC_PKCS12DecoderContext* p12cxt = arg;
  1115     if(!buf || len == 0) {
  1116         return -1;
  1119     if (p12cxt->currentpos+(long)len > p12cxt->filesize) {
  1120         p12cxt->filesize = p12cxt->currentpos + len;
  1122     else {
  1123         p12cxt->filesize += len;
  1125     if (p12cxt->filesize > p12cxt->allocated) {
  1126         void* newbuffer;
  1127         size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE;
  1128         newbuffer  = PORT_Realloc(p12cxt->buffer, newsize);
  1129         if (NULL == newbuffer) {
  1130             return -1; /* can't extend the buffer */
  1132         p12cxt->buffer = newbuffer;
  1133         p12cxt->allocated = newsize;
  1135     PR_ASSERT(p12cxt->buffer);
  1136     memcpy((char*)p12cxt->buffer + p12cxt->currentpos, buf, len);
  1137     p12cxt->currentpos += len;
  1138     return len;
  1141 /* SEC_PKCS12DecoderStart
  1142  *	Creates a decoder context for decoding a PKCS 12 PDU objct.
  1143  *	This function sets up the initial decoding context for the
  1144  *	PFX and sets the needed state variables.
  1146  *	pwitem - the password for the hMac and any encoded safes.
  1147  *		 this should be changed to take a callback which retrieves
  1148  *		 the password.  it may be possible for different safes to
  1149  *		 have different passwords.  also, the password is already
  1150  *		 in unicode.  it should probably be converted down below via
  1151  *		 a unicode conversion callback.
  1152  *	slot - the slot to import the dataa into should multiple slots 
  1153  *		 be supported based on key type and cert type?
  1154  *	dOpen, dClose, dRead, dWrite - digest routines for writing data
  1155  *		 to a file so it could be read back and the hmac recomputed
  1156  *		 and verified.  doesn't seem to be a way for both encoding
  1157  *		 and decoding to be single pass, thus the need for these
  1158  *		 routines.
  1159  *	dArg - the argument for dOpen, etc.
  1161  *      if NULL == dOpen == dClose == dRead == dWrite == dArg, then default
  1162  *      implementations using a memory buffer are used
  1164  *	This function returns the decoder context, if it was successful.
  1165  *	Otherwise, null is returned.
  1166  */
  1167 SEC_PKCS12DecoderContext *
  1168 SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
  1169 		       digestOpenFn dOpen, digestCloseFn dClose, 
  1170 		       digestIOFn dRead, digestIOFn dWrite, void *dArg)
  1172     SEC_PKCS12DecoderContext *p12dcx;
  1173     PLArenaPool *arena;
  1175     arena = PORT_NewArena(2048); /* different size? */
  1176     if(!arena) {
  1177 	return NULL;	/* error is already set */
  1180     /* allocate the decoder context and set the state variables */
  1181     p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
  1182     if(!p12dcx) {
  1183 	goto loser;	/* error is already set */
  1186     if (!dOpen && !dClose && !dRead && !dWrite && !dArg) {
  1187         /* use default implementations */
  1188         dOpen = p12u_DigestOpen;
  1189         dClose = p12u_DigestClose;
  1190         dRead = p12u_DigestRead;
  1191         dWrite = p12u_DigestWrite;
  1192         dArg = (void*)p12dcx;
  1195     p12dcx->arena = arena;
  1196     p12dcx->pwitem = pwitem;
  1197     p12dcx->slot = (slot ? PK11_ReferenceSlot(slot) 
  1198 						: PK11_GetInternalKeySlot());
  1199     p12dcx->wincx = wincx;
  1200     p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
  1201 #ifdef IS_LITTLE_ENDIAN
  1202     p12dcx->swapUnicodeBytes = PR_TRUE;
  1203 #else
  1204     p12dcx->swapUnicodeBytes = PR_FALSE;
  1205 #endif
  1206     p12dcx->errorValue = 0;
  1207     p12dcx->error = PR_FALSE;
  1209     /* start the decoding of the PFX and set the notify proc
  1210      * for the PFX item.
  1211      */
  1212     p12dcx->pfxA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx,
  1213     					  sec_PKCS12PFXItemTemplate);
  1214     if(!p12dcx->pfxA1Dcx) {
  1215 	PK11_FreeSlot(p12dcx->slot);
  1216 	goto loser;
  1219     SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxA1Dcx, 
  1220 				 sec_pkcs12_decoder_pfx_notify_proc,
  1221     				 p12dcx); 
  1223     /* set up digest functions */
  1224     p12dcx->dOpen = dOpen;
  1225     p12dcx->dWrite = dWrite;
  1226     p12dcx->dClose = dClose;
  1227     p12dcx->dRead = dRead;
  1228     p12dcx->dArg = dArg;
  1229     p12dcx->dIsOpen = PR_FALSE;
  1231     p12dcx->keyList = NULL;
  1232     p12dcx->decitem.type = 0;
  1233     p12dcx->decitem.der = NULL;
  1234     p12dcx->decitem.hasKey = PR_FALSE;
  1235     p12dcx->decitem.friendlyName = NULL;
  1236     p12dcx->iteration = 0;
  1238     return p12dcx;
  1240 loser:
  1241     PORT_FreeArena(arena, PR_TRUE);
  1242     return NULL;
  1245 SECStatus
  1246 SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx,
  1247 		SECPKCS12TargetTokenCAs tokenCAs)
  1249     if (!p12dcx || p12dcx->error) {
  1250 	return SECFailure;
  1252     p12dcx->tokenCAs = tokenCAs;
  1253     return SECSuccess;
  1257 /* SEC_PKCS12DecoderUpdate 
  1258  *	Streaming update sending more data to the decoder.  If 
  1259  *	an error occurs, SECFailure is returned.
  1261  *	p12dcx - the decoder context 
  1262  *	data, len - the data buffer and length of data to send to 
  1263  *		the update functions.
  1264  */
  1265 SECStatus
  1266 SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx,
  1267 			unsigned char *data, unsigned long len)
  1269     SECStatus rv;
  1271     if(!p12dcx || p12dcx->error) {
  1272 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1273 	return SECFailure;
  1276     /* update the PFX decoder context */
  1277     rv = SEC_ASN1DecoderUpdate(p12dcx->pfxA1Dcx, (const char *)data, len);
  1278     if(rv != SECSuccess) {
  1279 	p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
  1280 	goto loser;
  1283     return SECSuccess;
  1285 loser:
  1287     p12dcx->error = PR_TRUE;
  1288     return SECFailure;
  1291 /* This should be a nice sized buffer for reading in data (potentially large 
  1292 ** amounts) to be MACed.  It should be MUCH larger than HASH_LENGTH_MAX.
  1293 */
  1294 #define IN_BUF_LEN	1024
  1295 #ifdef DEBUG
  1296 static const char bufferEnd[] = { "BufferEnd" } ;
  1297 #endif
  1298 #define FUDGE 128 /* must be as large as bufferEnd or more. */
  1300 /* verify the hmac by reading the data from the temporary file
  1301  * using the routines specified when the decodingContext was 
  1302  * created and return SECSuccess if the hmac matches.
  1303  */
  1304 static SECStatus
  1305 sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
  1307     PK11Context *     pk11cx = NULL;
  1308     PK11SymKey *      symKey = NULL;
  1309     SECItem *         params = NULL;
  1310     unsigned char *   buf;
  1311     SECStatus         rv     = SECFailure;
  1312     SECStatus         lrv;
  1313     unsigned int      bufLen;
  1314     int               iteration;
  1315     int               bytesRead;
  1316     SECOidTag         algtag;
  1317     SECItem           hmacRes;
  1318     SECItem           ignore = {0};
  1319     CK_MECHANISM_TYPE integrityMech;
  1321     if(!p12dcx || p12dcx->error) {
  1322 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1323 	return SECFailure;
  1325     buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE);
  1326     if (!buf)
  1327     	return SECFailure;  /* error code has been set. */
  1329 #ifdef DEBUG
  1330     memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd);
  1331 #endif
  1333     /* generate hmac key */
  1334     if(p12dcx->macData.iter.data) {
  1335 	iteration = (int)DER_GetInteger(&p12dcx->macData.iter);
  1336     } else {
  1337 	iteration = 1;
  1340     params = PK11_CreatePBEParams(&p12dcx->macData.macSalt, p12dcx->pwitem,
  1341                                   iteration);
  1343     algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm);
  1344     switch (algtag) {
  1345     case SEC_OID_SHA1:
  1346 	integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break;
  1347     case SEC_OID_MD5:
  1348 	integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN;  break;
  1349     case SEC_OID_MD2:
  1350 	integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN;  break;
  1351     default:
  1352 	goto loser;
  1355     symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL);
  1356     PK11_DestroyPBEParams(params);
  1357     params = NULL;
  1358     if (!symKey) goto loser;
  1359     /* init hmac */
  1360     pk11cx = PK11_CreateContextBySymKey(sec_pkcs12_algtag_to_mech(algtag),
  1361                                         CKA_SIGN, symKey, &ignore);
  1362     if(!pk11cx) {
  1363 	goto loser;
  1365     lrv = PK11_DigestBegin(pk11cx);
  1366     if (lrv == SECFailure ) {
  1367 	goto loser;
  1370     /* try to open the data for readback */
  1371     if(p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) 
  1372 			!= SECSuccess)) {
  1373 	goto loser;
  1376     /* read the data back IN_BUF_LEN bytes at a time and recompute
  1377      * the hmac.  if fewer bytes are read than are requested, it is
  1378      * assumed that the end of file has been reached. if bytesRead
  1379      * is returned as -1, then an error occurred reading from the 
  1380      * file.
  1381      */
  1382     do {
  1383 	bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN);
  1384 	if (bytesRead < 0) {
  1385 	    PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ);
  1386 	    goto loser;
  1388 	PORT_Assert(bytesRead <= IN_BUF_LEN);
  1389 	PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd));
  1391 	if (bytesRead > IN_BUF_LEN) {
  1392 	    /* dRead callback overflowed buffer. */
  1393 	    PORT_SetError(SEC_ERROR_INPUT_LEN);
  1394 	    goto loser;
  1397 	if (bytesRead) {
  1398 	    lrv = PK11_DigestOp(pk11cx, buf, bytesRead);
  1399 	    if (lrv == SECFailure) {
  1400 		goto loser;
  1403     } while (bytesRead == IN_BUF_LEN);
  1405     /* finish the hmac context */
  1406     lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN);
  1407     if (lrv == SECFailure ) {
  1408 	goto loser;
  1411     hmacRes.data = buf;
  1412     hmacRes.len = bufLen;
  1414     /* is the hmac computed the same as the hmac which was decoded? */
  1415     rv = SECSuccess;
  1416     if(SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) 
  1417 			!= SECEqual) {
  1418 	PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
  1419 	rv = SECFailure;
  1422 loser:
  1423     /* close the file and remove it */
  1424     if(p12dcx->dClose) {
  1425 	(*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
  1426 	p12dcx->dIsOpen = PR_FALSE;
  1429     if(pk11cx) {
  1430 	PK11_DestroyContext(pk11cx, PR_TRUE);
  1432     if (params) {
  1433 	PK11_DestroyPBEParams(params);
  1435     if (symKey) {
  1436 	PK11_FreeSymKey(symKey);
  1438     PORT_ZFree(buf, IN_BUF_LEN + FUDGE);
  1440     return rv;
  1443 /* SEC_PKCS12DecoderVerify
  1444  * 	Verify the macData or the signature of the decoded PKCS 12 PDU.
  1445  *	If the signature or the macData do not match, SECFailure is
  1446  *	returned.
  1448  * 	p12dcx - the decoder context 
  1449  */
  1450 SECStatus
  1451 SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx)
  1453     SECStatus rv = SECSuccess;
  1455     /* make sure that no errors have occurred... */
  1456     if(!p12dcx) {
  1457 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1458 	return SECFailure;
  1460     if(p12dcx->error) {
  1461 	/* error code is already set! PORT_SetError(p12dcx->errorValue); */
  1462 	return SECFailure;
  1465     rv = SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
  1466     p12dcx->pfxA1Dcx = NULL;
  1467     if(rv != SECSuccess) {
  1468 	return rv;
  1471     /* check the signature or the mac depending on the type of
  1472      * integrity used.
  1473      */
  1474     if(p12dcx->pfx.encodedMacData.len) {
  1475 	rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData,
  1476 				sec_PKCS12MacDataTemplate,
  1477 				&p12dcx->pfx.encodedMacData);
  1478 	if(rv == SECSuccess) {
  1479 	    return sec_pkcs12_decoder_verify_mac(p12dcx);
  1481 	return rv;
  1483     if (SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner, 
  1484                                  PR_FALSE)) {
  1485 	return SECSuccess;
  1487     PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
  1488     return SECFailure;
  1491 /* SEC_PKCS12DecoderFinish
  1492  *	Free any open ASN1 or PKCS7 decoder contexts and then
  1493  *	free the arena pool which everything should be allocated
  1494  *	from.  This function should be called upon completion of
  1495  *	decoding and installing of a pfx pdu.  This should be
  1496  *	called even if an error occurs.
  1498  *	p12dcx - the decoder context
  1499  */
  1500 void
  1501 SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
  1503     unsigned int i;
  1505     if(!p12dcx) {
  1506 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1507 	return;
  1510     if(p12dcx->pfxA1Dcx) {
  1511 	SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
  1512 	p12dcx->pfxA1Dcx = NULL;
  1515     if(p12dcx->aSafeA1Dcx) {
  1516 	SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
  1517 	p12dcx->aSafeA1Dcx = NULL;
  1520     /* cleanup any old ASN1 decoder contexts */
  1521     for (i = 0; i < p12dcx->safeContentsCnt; ++i) {
  1522 	sec_PKCS12SafeContentsContext *safeContentsCtx, *nested;
  1523 	safeContentsCtx = p12dcx->safeContentsList[i];
  1524 	if (safeContentsCtx) {
  1525 	    nested = safeContentsCtx->nestedSafeContentsCtx;
  1526 	    while (nested) {
  1527 		if (nested->safeContentsA1Dcx) {
  1528 		    SEC_ASN1DecoderFinish(nested->safeContentsA1Dcx);
  1529 		    nested->safeContentsA1Dcx = NULL;
  1531 		nested = nested->nestedSafeContentsCtx;
  1533 	    if (safeContentsCtx->safeContentsA1Dcx) {
  1534 		SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
  1535 		safeContentsCtx->safeContentsA1Dcx = NULL;
  1540     if (p12dcx->currentASafeP7Dcx &&
  1541 	p12dcx->currentASafeP7Dcx != p12dcx->aSafeP7Dcx) {
  1542 	SEC_PKCS7ContentInfo * cinfo;
  1543 	cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
  1544 	if (cinfo) {
  1545 	    SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
  1548     p12dcx->currentASafeP7Dcx = NULL;
  1550     if(p12dcx->aSafeP7Dcx) {
  1551 	SEC_PKCS7ContentInfo * cinfo;
  1552 	cinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
  1553 	if (cinfo) {
  1554 	    SEC_PKCS7DestroyContentInfo(cinfo);
  1556 	p12dcx->aSafeP7Dcx = NULL;
  1559     if(p12dcx->aSafeCinfo) {
  1560 	SEC_PKCS7DestroyContentInfo(p12dcx->aSafeCinfo);
  1561 	p12dcx->aSafeCinfo = NULL;
  1564     if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
  1565         SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
  1567     if (p12dcx->decitem.friendlyName != NULL) {
  1568         SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
  1571     if(p12dcx->slot) {
  1572 	PK11_FreeSlot(p12dcx->slot);
  1573 	p12dcx->slot = NULL;
  1576     if(p12dcx->dIsOpen && p12dcx->dClose) {
  1577 	(*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
  1578 	p12dcx->dIsOpen = PR_FALSE;
  1581     if(p12dcx->arena) {
  1582 	PORT_FreeArena(p12dcx->arena, PR_TRUE);
  1586 static SECStatus
  1587 sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag,
  1588 			       SECOidTag attributeType,
  1589 			       SECItem *attrValue)
  1591     int i = 0;
  1592     SECOidData *oid;
  1594     if(!bag || !attrValue) {
  1595 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1596 	return SECFailure;
  1599     oid = SECOID_FindOIDByTag(attributeType);
  1600     if(!oid) {
  1601 	return SECFailure;
  1604     if(!bag->attribs) {
  1605 	bag->attribs = 
  1606 		PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
  1607     } else {
  1608 	while(bag->attribs[i]) 
  1609 	    i++;
  1610 	bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs, 
  1611 				           sec_PKCS12Attribute *, i + 1, i + 2);
  1614     if(!bag->attribs) {
  1615 	return SECFailure;
  1618     bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
  1619     if(!bag->attribs) {
  1620 	return SECFailure;
  1623     bag->attribs[i]->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
  1624     if(!bag->attribs[i]->attrValue) {
  1625 	return SECFailure;
  1628     bag->attribs[i+1] = NULL;
  1629     bag->attribs[i]->attrValue[0] = attrValue;
  1630     bag->attribs[i]->attrValue[1] = NULL;
  1632     return SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid);
  1635 static SECItem *
  1636 sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag,
  1637 			       SECOidTag attributeType)
  1639     int i;
  1641     if(!bag->attribs) {
  1642 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1643 	return NULL;
  1646     for (i = 0; bag->attribs[i] != NULL; i++) {
  1647 	if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == attributeType) {
  1648 	    return bag->attribs[i]->attrValue[0];
  1651     return NULL;
  1654 /* For now, this function will merely remove any ":"
  1655  * in the nickname which the PK11 functions may have
  1656  * placed there.  This will keep dual certs from appearing
  1657  * twice under "Your" certificates when imported onto smart
  1658  * cards.  Once with the name "Slot:Cert" and another with
  1659  * the nickname "Slot:Slot:Cert"
  1660  */
  1661 static void
  1662 sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
  1664     char *nickname;
  1665     char *delimit;
  1666     int delimitlen;
  1668     nickname = (char*)nick->data;
  1669     if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
  1670         char *slotName;
  1671 	int slotNameLen;
  1673 	slotNameLen = delimit-nickname;
  1674 	slotName = PORT_NewArray(char, (slotNameLen+1));
  1675 	PORT_Assert(slotName);
  1676 	if (slotName == NULL) {
  1677 	  /* What else can we do?*/
  1678 	  return;
  1680 	PORT_Memcpy(slotName, nickname, slotNameLen);
  1681 	slotName[slotNameLen] = '\0';
  1682 	if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
  1683 	  delimitlen = PORT_Strlen(delimit+1);
  1684 	  PORT_Memmove(nickname, delimit+1, delimitlen+1);
  1685 	  nick->len = delimitlen;
  1687 	PORT_Free(slotName);
  1692 static SECItem *
  1693 sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag)
  1695     SECItem *src, *dest;
  1697     if(!bag) {
  1698 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1699 	return NULL;
  1702     src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
  1704     /* The return value src is 16-bit Unicode characters, in big-endian format.
  1705      * Check if it is NULL or empty name.
  1706      */
  1707     if(!src || !src->data || src->len < 2 || (!src->data[0] && !src->data[1])) {
  1708 	return NULL;
  1711     dest = (SECItem*)PORT_ZAlloc(sizeof(SECItem));
  1712     if(!dest) { 
  1713 	goto loser;
  1715     if(!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE, 
  1716 				PR_FALSE, PR_FALSE)) {
  1717 	goto loser;
  1720     sec_pkcs12_sanitize_nickname(bag->slot, dest);
  1722     return dest;
  1724 loser:
  1725     if(dest) {
  1726 	SECITEM_ZfreeItem(dest, PR_TRUE);
  1729     bag->problem = PR_TRUE;
  1730     bag->error = PORT_GetError();
  1731     return NULL;
  1734 static SECStatus
  1735 sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name)
  1737     sec_PKCS12Attribute *attr = NULL;
  1738     SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME);
  1740     if(!bag || !bag->arena || !name) {
  1741 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1742 	return SECFailure;
  1745     if(!bag->attribs) {
  1746 	if(!oid) {
  1747 	    goto loser;
  1750 	bag->attribs = 
  1751 	    PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
  1752 	if(!bag->attribs) {
  1753 	    goto loser;
  1755 	bag->attribs[0] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
  1756 	if(!bag->attribs[0]) {
  1757 	    goto loser;
  1759 	bag->attribs[1] = NULL;
  1761 	attr = bag->attribs[0];
  1762 	if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) 
  1763 			!= SECSuccess) {
  1764 	    goto loser;
  1766     } else {
  1767 	int i;
  1768 	for (i = 0; bag->attribs[i]; i++) {
  1769 	    if(SECOID_FindOIDTag(&bag->attribs[i]->attrType)
  1770 			== SEC_OID_PKCS9_FRIENDLY_NAME) {
  1771 		attr = bag->attribs[i];
  1772 		break;
  1775 	if(!attr) {
  1776 	    if(!oid) {
  1777 		goto loser;
  1779 	    bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
  1780 					       sec_PKCS12Attribute *, i+1, i+2);
  1781 	    if(!bag->attribs) {
  1782 		goto loser;
  1784 	    bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
  1785 	    if(!bag->attribs[i]) {
  1786 		goto loser;
  1788 	    bag->attribs[i+1] = NULL;
  1789 	    attr = bag->attribs[i];
  1790 	    if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) 
  1791 				!= SECSuccess) {
  1792 		goto loser;
  1797     PORT_Assert(attr);
  1798     if(!attr->attrValue) {
  1799 	attr->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
  1800 	if(!attr->attrValue) {
  1801 	    goto loser;
  1803 	attr->attrValue[0] = PORT_ArenaZNew(bag->arena, SECItem);
  1804 	if(!attr->attrValue[0]) {
  1805 	    goto loser;
  1807 	attr->attrValue[1] = NULL;
  1810     name->len = PORT_Strlen((char *)name->data);
  1811     if(!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0],
  1812 				name, PR_FALSE, PR_FALSE, PR_TRUE)) {
  1813 	goto loser;
  1816     return SECSuccess;
  1818 loser:
  1819     bag->problem = PR_TRUE;
  1820     bag->error = PORT_GetError();
  1821     return SECFailure;
  1824 static SECStatus
  1825 sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key) 
  1827     int i = 0;
  1828     SECKEYPrivateKeyInfo *pki = NULL;
  1830     if(!key) {
  1831 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1832 	return SECFailure;
  1835     /* if the bag does *not* contain an unencrypted PrivateKeyInfo 
  1836      * then we cannot convert the attributes.  We are propagating
  1837      * attributes within the PrivateKeyInfo to the SafeBag level.
  1838      */
  1839     if(SECOID_FindOIDTag(&(key->safeBagType)) != 
  1840 			SEC_OID_PKCS12_V1_KEY_BAG_ID) {
  1841 	return SECSuccess;
  1844     pki = key->safeBagContent.pkcs8KeyBag;
  1846     if(!pki || !pki->attributes) {
  1847 	return SECSuccess;
  1850     while(pki->attributes[i]) {
  1851 	SECOidTag tag = SECOID_FindOIDTag(&pki->attributes[i]->attrType);
  1853 	if (tag == SEC_OID_PKCS9_LOCAL_KEY_ID ||
  1854 	    tag == SEC_OID_PKCS9_FRIENDLY_NAME) {
  1855 	    SECItem *attrValue = sec_pkcs12_get_attribute_value(key, tag);
  1856 	    if(!attrValue) {
  1857 		if(sec_pkcs12_decoder_set_attribute_value(key, tag,
  1858 					pki->attributes[i]->attrValue[0])
  1859 					!= SECSuccess) {
  1860 		    key->problem = PR_TRUE;
  1861 		    key->error = PORT_GetError();
  1862 		    return SECFailure;
  1866 	i++;
  1869     return SECSuccess;
  1872 /* retrieve the nickname for the certificate bag.  first look
  1873  * in the cert bag, otherwise get it from the key.
  1874  */
  1875 static SECItem *
  1876 sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert,
  1877 				 sec_PKCS12SafeBag *key)
  1879     SECItem *nickname;
  1881     if(!cert) {
  1882 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1883 	return NULL;
  1886     nickname = sec_pkcs12_get_nickname(cert);
  1887     if(nickname) {
  1888 	return nickname;
  1891     if(key) {
  1892 	nickname = sec_pkcs12_get_nickname(key);
  1894         if(nickname && sec_pkcs12_set_nickname(cert, nickname)
  1895 			!= SECSuccess) {
  1896 	    SECITEM_ZfreeItem(nickname, PR_TRUE);
  1897 	    return NULL;
  1901     return nickname;
  1904 /* set the nickname for the certificate */
  1905 static SECStatus
  1906 sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert, 
  1907 				 sec_PKCS12SafeBag *key, 
  1908 				 SECItem *nickname)
  1910     if(!nickname || !cert) {
  1911 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1912 	return SECFailure;
  1915     if(sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
  1916 	return SECFailure;
  1919     if(key) {
  1920 	if(sec_pkcs12_set_nickname(key, nickname) != SECSuccess) {
  1921 	    cert->problem = PR_TRUE;
  1922 	    cert->error   = key->error;
  1923 	    return SECFailure;
  1927     return SECSuccess;
  1930 /* retrieve the DER cert from the cert bag */
  1931 static SECItem *
  1932 sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert) 
  1934     if(!cert) {
  1935 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1936 	return NULL;
  1939     if(SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) {
  1940 	return NULL;
  1943     /* only support X509 certs not SDSI */
  1944     if(SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID) 
  1945 			!= SEC_OID_PKCS9_X509_CERT) {
  1946 	return NULL;
  1949     return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert));
  1952 struct certNickInfo {
  1953     PLArenaPool *arena;
  1954     unsigned int nNicks;
  1955     SECItem **nickList;
  1956     unsigned int error;
  1957 };
  1959 /* callback for traversing certificates to gather the nicknames 
  1960  * used in a particular traversal.  for instance, when using
  1961  * CERT_TraversePermCertsForSubject, gather the nicknames and
  1962  * store them in the certNickInfo for a particular DN.
  1964  * this handles the case where multiple nicknames are allowed
  1965  * for the same dn, which is not currently allowed, but may be
  1966  * in the future.
  1967  */ 
  1968 static SECStatus
  1969 gatherNicknames(CERTCertificate *cert, void *arg)
  1971     struct certNickInfo *nickArg = (struct certNickInfo *)arg;
  1972     SECItem tempNick;
  1973     unsigned int i;
  1975     if(!cert || !nickArg || nickArg->error) {
  1976 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1977 	return SECFailure;
  1980     if(!cert->nickname) {
  1981 	return SECSuccess;
  1984     tempNick.data = (unsigned char *)cert->nickname;
  1985     tempNick.len = PORT_Strlen(cert->nickname) + 1;
  1987     /* do we already have the nickname in the list? */
  1988     if(nickArg->nNicks > 0) {
  1990 	/* nicknames have been encountered, but there is no list -- bad */
  1991 	if(!nickArg->nickList) {
  1992 	    nickArg->error = SEC_ERROR_INVALID_ARGS;
  1993 	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1994 	    return SECFailure;
  1997 	for(i = 0; i < nickArg->nNicks; i++) {
  1998 	    if(SECITEM_CompareItem(nickArg->nickList[i], &tempNick) 
  1999 				== SECEqual) {
  2000 		return SECSuccess;
  2005     /* add the nickname to the list */
  2006     nickArg->nickList = (nickArg->nNicks == 0) 
  2007 	? PORT_ArenaZNewArray(nickArg->arena, SECItem *, 2)
  2008 	: PORT_ArenaGrowArray(nickArg->arena, nickArg->nickList, SECItem *, 
  2009 	                      nickArg->nNicks + 1, nickArg->nNicks + 2);
  2011     if(!nickArg->nickList) {
  2012 	nickArg->error = SEC_ERROR_NO_MEMORY;
  2013 	return SECFailure;
  2016     nickArg->nickList[nickArg->nNicks] = 
  2017 				    PORT_ArenaZNew(nickArg->arena, SECItem);
  2018     if(!nickArg->nickList[nickArg->nNicks]) {
  2019 	nickArg->error = PORT_GetError();
  2020 	return SECFailure;
  2024     if(SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks],
  2025 			&tempNick) != SECSuccess) {
  2026 	nickArg->error = PORT_GetError();
  2027 	return SECFailure;
  2030     nickArg->nNicks++;
  2032     return SECSuccess;
  2035 /* traverses the certs in the data base or in the token for the
  2036  * DN to see if any certs currently have a nickname set.
  2037  * If so, return it. 
  2038  */
  2039 static SECItem *
  2040 sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert)
  2042     struct certNickInfo *nickArg = NULL;
  2043     SECItem *derCert, *returnDn = NULL;
  2044     PLArenaPool *arena = NULL;
  2045     CERTCertificate *tempCert;
  2047     if(!cert) {
  2048 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2049 	return NULL;
  2052     derCert = sec_pkcs12_get_der_cert(cert);
  2053     if(!derCert) {
  2054 	return NULL;
  2057     tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
  2058     if(!tempCert) {
  2059 	returnDn = NULL;
  2060 	goto loser;
  2063     arena = PORT_NewArena(1024);
  2064     if(!arena) {
  2065 	returnDn = NULL;
  2066 	goto loser;
  2068     nickArg = PORT_ArenaZNew(arena, struct certNickInfo);
  2069     if(!nickArg) {
  2070 	returnDn = NULL;
  2071 	goto loser;
  2073     nickArg->error = 0;
  2074     nickArg->nNicks = 0;
  2075     nickArg->nickList = NULL;
  2076     nickArg->arena = arena;
  2078     /* if the token is local, first traverse the cert database 
  2079      * then traverse the token.
  2080      */
  2081     if(PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames,
  2082 			(void *)nickArg) != SECSuccess) {
  2083 	returnDn = NULL;
  2084 	goto loser;
  2087     if(nickArg->error) {
  2088 	/* XXX do we want to set the error? */
  2089 	returnDn = NULL;
  2090 	goto loser;
  2093     if(nickArg->nNicks == 0) {
  2094 	returnDn = NULL;
  2095 	goto loser;
  2098     /* set it to the first name, for now.  handle multiple names? */
  2099     returnDn = SECITEM_DupItem(nickArg->nickList[0]);
  2101 loser:
  2102     if(arena) {
  2103 	PORT_FreeArena(arena, PR_TRUE);
  2106     if(tempCert) {
  2107 	CERT_DestroyCertificate(tempCert);
  2110     if(derCert) {
  2111 	SECITEM_FreeItem(derCert, PR_TRUE);
  2114     return (returnDn);
  2117 /* counts certificates found for a given traversal function */
  2118 static SECStatus
  2119 countCertificate(CERTCertificate *cert, void *arg)
  2121     unsigned int *nCerts = (unsigned int *)arg;
  2123     if(!cert || !arg) {
  2124 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2125 	return SECFailure;
  2128     (*nCerts)++;
  2129     return SECSuccess;
  2132 static PRBool
  2133 sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot)
  2135     unsigned int nCerts = 0;
  2137     if(!nickname || !slot) {
  2138 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2139 	return PR_TRUE;
  2142     /* we want to check the local database first if we are importing to it */
  2143     PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate, 
  2144 					(void *)&nCerts);
  2145     return (PRBool)(nCerts != 0);
  2148 /* validate cert nickname such that there is a one-to-one relation
  2149  * between nicknames and dn's.  we want to enforce the case that the
  2150  * nickname is non-NULL and that there is only one nickname per DN.
  2152  * if there is a problem with a nickname or the nickname is not present, 
  2153  * the user will be prompted for it.
  2154  */
  2155 static void
  2156 sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,
  2157 				sec_PKCS12SafeBag *key,
  2158 				SEC_PKCS12NicknameCollisionCallback nicknameCb,
  2159 				CERTCertificate *leafCert)
  2161     SECItem *certNickname, *existingDNNick;
  2162     PRBool setNickname = PR_FALSE, cancel = PR_FALSE;
  2163     SECItem *newNickname = NULL;
  2165     if(!cert || !cert->hasKey) {
  2166 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2167 	return;
  2170     if(!nicknameCb) {
  2171 	cert->problem = PR_TRUE;
  2172 	cert->error = SEC_ERROR_INVALID_ARGS;
  2173 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2174 	return;
  2177     if(cert->hasKey && !key) {
  2178 	cert->problem = PR_TRUE;
  2179 	cert->error = SEC_ERROR_INVALID_ARGS;
  2180 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2181 	return;
  2184     certNickname = sec_pkcs12_get_nickname_for_cert(cert, key);
  2185     existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert);
  2187     /* nickname is already used w/ this dn, so it is safe to return */
  2188     if(certNickname && existingDNNick &&
  2189 		SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {
  2190 	goto loser;
  2193     /* nickname not set in pkcs 12 bags, but a nick is already used for
  2194      * this dn.  set the nicks in the p12 bags and finish.
  2195      */
  2196     if(existingDNNick) {
  2197 	sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick);
  2198 	goto loser;
  2201     /* at this point, we have a certificate for which the DN is not located
  2202      * on the token.  the nickname specified may or may not be NULL.  if it
  2203      * is not null, we need to make sure that there are no other certificates
  2204      * with this nickname in the token for it to be valid.  this imposes a 
  2205      * one to one relationship between DN and nickname.  
  2207      * if the nickname is null, we need the user to enter a nickname for
  2208      * the certificate.
  2210      * once we have a nickname, we make sure that the nickname is unique
  2211      * for the DN.  if it is not, the user is reprompted to enter a new 
  2212      * nickname.  
  2214      * in order to exit this loop, the nickname entered is either unique
  2215      * or the user hits cancel and the certificate is not imported.
  2216      */
  2217     setNickname = PR_FALSE;
  2218     while(1) {
  2219 	/* we will use the nickname so long as no other certs have the
  2220 	 * same nickname.  and the nickname is not NULL.
  2221 	 */		
  2222 	if (certNickname && certNickname->data &&
  2223 	    !sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {
  2224 	    if (setNickname) {
  2225 		sec_pkcs12_set_nickname_for_cert(cert, key, certNickname);
  2227 	    break;
  2230 	setNickname = PR_FALSE;
  2231 	newNickname = (*nicknameCb)(certNickname, &cancel, leafCert);
  2232 	if(cancel) {
  2233 	    cert->problem = PR_TRUE;
  2234 	    cert->error = SEC_ERROR_USER_CANCELLED;
  2235 	    break;
  2238 	if(!newNickname) {
  2239 	    cert->problem = PR_TRUE;
  2240 	    cert->error = PORT_GetError();
  2241 	    break;
  2244 	/* at this point we have a new nickname, if we have an existing
  2245 	 * certNickname, we need to free it and assign the new nickname
  2246 	 * to it to avoid a memory leak.  happy?
  2247 	 */
  2248 	if(certNickname) {
  2249 	    SECITEM_ZfreeItem(certNickname, PR_TRUE);
  2250 	    certNickname = NULL;
  2253 	certNickname = newNickname;
  2254 	setNickname = PR_TRUE;
  2255 	/* go back and recheck the new nickname */
  2258 loser:
  2259     if(certNickname) {
  2260 	SECITEM_ZfreeItem(certNickname, PR_TRUE);
  2263     if(existingDNNick) {
  2264 	SECITEM_ZfreeItem(existingDNNick, PR_TRUE);
  2268 static void 
  2269 sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,
  2270 			 sec_PKCS12SafeBag *key,
  2271 			 SEC_PKCS12NicknameCollisionCallback nicknameCb)
  2273     CERTCertificate *leafCert;
  2275     if(!cert) {
  2276 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2277 	return;
  2280     cert->validated = PR_TRUE;
  2282     if(!nicknameCb) {
  2283 	cert->noInstall = PR_TRUE;
  2284 	cert->problem = PR_TRUE;
  2285 	cert->error   = SEC_ERROR_INVALID_ARGS;
  2286 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2287 	return;
  2290     if(!cert->safeBagContent.certBag) {
  2291 	cert->noInstall = PR_TRUE;
  2292 	cert->problem = PR_TRUE;
  2293 	cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
  2294 	return;
  2297     cert->noInstall = PR_FALSE;
  2298     cert->unused = PR_FALSE;
  2299     cert->problem = PR_FALSE;
  2300     cert->error = 0;
  2302     leafCert = CERT_DecodeDERCertificate(
  2303 	 &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
  2304     if(!leafCert) {
  2305 	cert->noInstall = PR_TRUE;
  2306 	cert->problem = PR_TRUE;
  2307 	cert->error = PORT_GetError();
  2308 	return;
  2311     sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, leafCert);
  2313     CERT_DestroyCertificate(leafCert);
  2316 static void
  2317 sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,
  2318 				void *wincx)
  2320     CERTCertificate *leafCert;
  2321     SECKEYPrivateKey *privk;
  2323     if(!key) {
  2324 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2325 	return;
  2328     key->validated = PR_TRUE;
  2330     if(!cert) {
  2331 	key->problem = PR_TRUE;
  2332 	key->noInstall = PR_TRUE;
  2333 	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  2334 	return;
  2337     leafCert = CERT_DecodeDERCertificate(
  2338 	&(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL);
  2339     if(!leafCert) {
  2340 	key->problem = PR_TRUE;
  2341 	key->noInstall = PR_TRUE;
  2342 	key->error = PORT_GetError();
  2343 	return;
  2346     privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);
  2347     if(!privk) {
  2348 	privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);
  2351     if(privk) {
  2352 	SECKEY_DestroyPrivateKey(privk);
  2353 	key->noInstall = PR_TRUE;
  2356     CERT_DestroyCertificate(leafCert);
  2359 static SECStatus
  2360 sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx)
  2362     SECItem *derCert, *nickName;
  2363     char *nickData = NULL;
  2364     PRBool isIntermediateCA;
  2365     SECStatus rv;
  2367     if(!cert) {
  2368 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2369 	return SECFailure;
  2372     if(cert->problem || cert->noInstall || cert->installed) {
  2373 	return SECSuccess;
  2376     derCert = &cert->safeBagContent.certBag->value.x509Cert;
  2378     PORT_Assert(!cert->problem && !cert->noInstall);
  2380     nickName = sec_pkcs12_get_nickname(cert);
  2381     if(nickName) {
  2382 	nickData = (char *)nickName->data;
  2385     isIntermediateCA = CERT_IsCADERCert(derCert, NULL) && 
  2386 						!CERT_IsRootDERCert(derCert);
  2388     if(keyExists) {
  2389 	CERTCertificate *newCert;
  2391 	newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  2392 	                                  derCert, NULL, PR_FALSE, PR_FALSE);
  2393 	if(!newCert) {
  2394 	     if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);
  2395 	     cert->error = PORT_GetError();
  2396 	     cert->problem = PR_TRUE;
  2397 	     return SECFailure;
  2400 	rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData, 
  2401 					 PR_TRUE, wincx);
  2402 	CERT_DestroyCertificate(newCert);
  2403     } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) || 
  2404      ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) && 
  2405 							!isIntermediateCA)) {
  2406 	SECItem *certList[2];
  2407 	certList[0] = derCert;
  2408 	certList[1] = NULL;
  2410 	rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,
  2411 			     1, certList, NULL, PR_TRUE, PR_FALSE, nickData);
  2412     } else {
  2413 	rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE,
  2414 							nickData, PR_FALSE);
  2416     if (rv) {
  2417 	cert->problem = 1;
  2418 	cert->error = PORT_GetError();
  2420     cert->installed = PR_TRUE;
  2421     if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);
  2422     return rv;
  2425 static SECItem *
  2426 sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey, KeyType *type);
  2428 static SECStatus
  2429 sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECKEYPublicKey *pubKey, 
  2430 		   unsigned int keyUsage, 
  2431 		   SECItem *nickName, void *wincx)
  2433     SECStatus rv;
  2434     SECItem *publicValue = NULL;
  2435     KeyType keyType;
  2437     /* We should always have values for "key" and "pubKey"
  2438        so they can be dereferenced later. */
  2439     if(!key || !pubKey) {
  2440 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2441 	return SECFailure;
  2444     if(key->problem || key->noInstall) {
  2445 	return SECSuccess;
  2448     /* get the value and type from the public key */
  2449     publicValue = sec_pkcs12_get_public_value_and_type(pubKey, &keyType);
  2450     if (!publicValue) {
  2451 	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  2452 	key->problem = PR_TRUE;
  2453 	return SECFailure;
  2456     switch(SECOID_FindOIDTag(&key->safeBagType))
  2458 	case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  2459 	    rv = PK11_ImportPrivateKeyInfo(key->slot, 
  2460 			  key->safeBagContent.pkcs8KeyBag, 
  2461 			  nickName, publicValue, PR_TRUE, PR_TRUE,
  2462 			  keyUsage,  wincx);
  2463 	    break;
  2464 	case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  2465 	    rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
  2466 					key->safeBagContent.pkcs8ShroudedKeyBag,
  2467 					key->pwitem, nickName, publicValue, 
  2468 					PR_TRUE, PR_TRUE, keyType, keyUsage,
  2469 					wincx);
  2470 	    break;
  2471 	default:
  2472 	    key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
  2473 	    key->problem = PR_TRUE;
  2474 	    if(nickName) {
  2475 		SECITEM_ZfreeItem(nickName, PR_TRUE);
  2477 	    return SECFailure;
  2480     if(rv != SECSuccess) {
  2481 	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  2482 	key->problem = PR_TRUE;
  2483     } else {
  2484 	/* try to import the public key. Failure to do so is not fatal,
  2485 	 * not all tokens can store the public key */
  2486 	if (pubKey) {
  2487 	    PK11_ImportPublicKey(key->slot, pubKey, PR_TRUE);
  2489 	key->installed = PR_TRUE;
  2492     return rv;
  2495 /* 
  2496  * The correctness of the code in this file ABSOLUTELY REQUIRES 
  2497  * that ALL BAGs share a single common arena.  
  2499  * This function allocates the bag list from the arena of whatever bag 
  2500  * happens to be passed to it.  Each time a new bag is handed to it,
  2501  * it grows (resizes) the arena of the bag that was handed to it.  
  2502  * If the bags have different arenas, it will grow the wrong arena.
  2504  * Worse, if the bags had separate arenas, then while destroying the bags 
  2505  * in a bag list, when the bag whose arena contained the bag list was 
  2506  * destroyed, the baglist itself would be destroyed, making it difficult 
  2507  * or impossible to continue to destroy the bags in the destroyed list.
  2508  */
  2509 static SECStatus
  2510 sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList, 
  2511 				sec_PKCS12SafeBag *bag)
  2513     sec_PKCS12SafeBag **newBagList = NULL;
  2514     int i = 0;
  2516     if(!bagList || !bag) {
  2517 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2518 	return SECFailure;
  2521     if(!(*bagList)) {
  2522 	newBagList = PORT_ArenaZNewArray(bag->arena, sec_PKCS12SafeBag *, 2);
  2523     } else {
  2524 	while((*bagList)[i]) 
  2525 	    i++;
  2526 	newBagList = PORT_ArenaGrowArray(bag->arena, *bagList,
  2527 				         sec_PKCS12SafeBag *, i + 1, i + 2);
  2530     if(!newBagList) {
  2531 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  2532 	return SECFailure;
  2535     newBagList[i]   = bag;
  2536     newBagList[i+1] = NULL;
  2537     *bagList = newBagList;
  2539     return SECSuccess;
  2542 static sec_PKCS12SafeBag **
  2543 sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags, 
  2544                               sec_PKCS12SafeBag *key ) 
  2546     sec_PKCS12SafeBag **certList = NULL;
  2547     SECItem *keyId;
  2548     int i;
  2550     if(!safeBags || !safeBags[0]) {
  2551 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2552 	return NULL;
  2555     keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);
  2556     if(!keyId) {
  2557 	return NULL;
  2560     for (i = 0; safeBags[i]; i++) {
  2561 	if(SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) 
  2562 				== SEC_OID_PKCS12_V1_CERT_BAG_ID) {
  2563 	    SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],
  2564 						SEC_OID_PKCS9_LOCAL_KEY_ID);
  2566 	    if(certKeyId && (SECITEM_CompareItem(certKeyId, keyId) 
  2567 				== SECEqual)) {
  2568 		if(sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i])
  2569 				!= SECSuccess) {
  2570 		    /* This would leak the partial list of safeBags,
  2571 		     * but that list is allocated from the arena of 
  2572 		     * one of the safebags, and will be destroyed when 
  2573 		     * that arena is destroyed.  So this is not a real leak.
  2574 		     */
  2575 		    return NULL;
  2581     return certList;
  2584 CERTCertList *
  2585 SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx)
  2587     CERTCertList *certList = NULL;
  2588     sec_PKCS12SafeBag **safeBags;
  2589     int i;
  2591     if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) {
  2592 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2593 	return NULL;
  2596     safeBags = p12dcx->safeBags;
  2597     certList = CERT_NewCertList();
  2599     if (certList == NULL) {
  2600 	 return NULL;
  2603     for (i = 0; safeBags[i]; i++) {
  2604 	if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) 
  2605 				== SEC_OID_PKCS12_V1_CERT_BAG_ID) {
  2606 		SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]) ;
  2607 		CERTCertificate *tempCert = NULL;
  2609 		if (derCert == NULL) 
  2610 		    continue;
  2611     		tempCert=CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  2612 		                                 derCert, NULL, 
  2613 		                                 PR_FALSE, PR_TRUE);
  2615 		if (tempCert) {
  2616 		    CERT_AddCertToListTail(certList,tempCert);
  2618 		SECITEM_FreeItem(derCert,PR_TRUE);
  2620 	/* fixed an infinite loop here, by ensuring that i gets incremented
  2621 	 * if derCert is NULL above.
  2622 	 */
  2625     return certList;
  2627 static sec_PKCS12SafeBag **
  2628 sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags)
  2630     int i;
  2631     sec_PKCS12SafeBag **keyList = NULL;
  2632     SECOidTag bagType;
  2634     if(!safeBags || !safeBags[0]) {
  2635 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2636 	return NULL;
  2639     for (i = 0; safeBags[i]; i++) {
  2640 	bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
  2641 	switch(bagType) {
  2642 	    case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  2643 	    case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  2644 		if(sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i])
  2645 				!= SECSuccess) {
  2646 		    /* This would leak, except that keyList is allocated
  2647 		     * from the arena shared by all the safeBags.
  2648 		     */
  2649 		    return NULL;
  2651 		break;
  2652 	    default:
  2653 		break;
  2657     return keyList;
  2660 /* This function takes two passes over the bags, validating them 
  2661  * The two passes are intended to mirror exactly the two passes in 
  2662  * sec_pkcs12_install_bags.  But they don't. :(
  2663  */
  2664 static SECStatus 
  2665 sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags, 
  2666 			 SEC_PKCS12NicknameCollisionCallback nicknameCb,
  2667 			 void *wincx)
  2669     sec_PKCS12SafeBag **keyList;
  2670     int i;
  2672     if(!safeBags || !nicknameCb) {
  2673 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2674 	return SECFailure;
  2677     if(!safeBags[0]) {
  2678 	return SECSuccess;
  2681     /* First pass.  Find all the key bags.  
  2682      * Find the matching cert(s) for each key.  
  2683      */
  2684     keyList = sec_pkcs12_get_key_bags(safeBags);
  2685     if(keyList) {
  2686 	for (i = 0; keyList[i]; ++i) {
  2687 	    sec_PKCS12SafeBag *key = keyList[i];
  2688 	    sec_PKCS12SafeBag **certList = 
  2689 			    sec_pkcs12_find_certs_for_key(safeBags, key);
  2691 	    if(certList) {
  2692 		int j;
  2694 		if(SECOID_FindOIDTag(&(key->safeBagType)) == 
  2695 					SEC_OID_PKCS12_V1_KEY_BAG_ID) {
  2696 		    /* if it is an unencrypted private key then make sure
  2697 		     * the attributes are propageted to the appropriate 
  2698 		     * level 
  2699 		     */
  2700 		    if(sec_pkcs12_get_key_info(key) != SECSuccess) {
  2701 			return SECFailure;
  2705 		sec_pkcs12_validate_key_by_cert(certList[0], key, wincx);
  2706 		for (j = 0; certList[j]; ++j) {
  2707 		    sec_PKCS12SafeBag *cert = certList[j];
  2708 		    cert->hasKey = PR_TRUE;
  2709 		    if(key->problem) {
  2710 			cert->problem = PR_TRUE;
  2711 			cert->error   = key->error;
  2712 			continue;
  2714 		    sec_pkcs12_validate_cert(cert, key, nicknameCb);
  2715 		    if(cert->problem) {
  2716 			key->problem = cert->problem;
  2717 			key->error   = cert->error;
  2724     /* Now take a second pass over the safebags and mark for installation any 
  2725      * certs that were neither installed nor disqualified by the first pass.
  2726      */
  2727     for (i = 0; safeBags[i]; ++i) {
  2728 	sec_PKCS12SafeBag *bag = safeBags[i];
  2730 	if(!bag->validated) {
  2731 	    SECOidTag bagType = SECOID_FindOIDTag(&bag->safeBagType);
  2733 	    switch(bagType) {
  2734 	    case SEC_OID_PKCS12_V1_CERT_BAG_ID:
  2735 		sec_pkcs12_validate_cert(bag, NULL, nicknameCb);
  2736 		break;
  2737 	    case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  2738 	    case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  2739 		bag->noInstall = PR_TRUE;
  2740 		bag->problem = PR_TRUE;	
  2741 		bag->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  2742 		break;
  2743 	    default:
  2744 		bag->noInstall = PR_TRUE;
  2749     return SECSuccess;
  2752 SECStatus
  2753 SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx,
  2754 			      SEC_PKCS12NicknameCollisionCallback nicknameCb)
  2756     SECStatus rv;
  2757     int i, noInstallCnt, probCnt, bagCnt, errorVal = 0;
  2758     if(!p12dcx || p12dcx->error || !p12dcx->safeBags) {
  2759 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2760 	return SECFailure;
  2763     rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx);
  2764     if(rv == SECSuccess) {
  2765 	p12dcx->bagsVerified = PR_TRUE;
  2768     noInstallCnt = probCnt = bagCnt = 0;
  2769     i = 0;
  2770     while(p12dcx->safeBags[i]) {
  2771 	bagCnt++;
  2772 	if(p12dcx->safeBags[i]->noInstall) 
  2773 	    noInstallCnt++;
  2774 	if(p12dcx->safeBags[i]->problem) {
  2775 	    probCnt++;
  2776 	    errorVal = p12dcx->safeBags[i]->error;
  2778 	i++;
  2781     /* formerly was erroneous code here that assumed that if all bags
  2782      * failed to import, then the problem was duplicated data; 
  2783      * that is, it assume that the problem must be that the file had
  2784      * previously been successfully imported.  But importing a 
  2785      * previously imported file causes NO ERRORS at all, and this 
  2786      * false assumption caused real errors to be hidden behind false
  2787      * errors about duplicated data.
  2788      */
  2790     if(probCnt) {
  2791 	PORT_SetError(errorVal);
  2792 	return SECFailure;
  2795     return rv;
  2799 static SECKEYPublicKey *
  2800 sec_pkcs12_get_public_key_and_usage(sec_PKCS12SafeBag *certBag,
  2801 					 unsigned int *usage)
  2803     SECKEYPublicKey *pubKey = NULL;
  2804     CERTCertificate *cert = NULL;
  2806     if(!certBag || !usage) {
  2807 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2808 	return NULL;
  2811     *usage = 0;
  2813     cert = CERT_DecodeDERCertificate(
  2814 	 &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
  2815     if(!cert) {
  2816 	return NULL;
  2819     *usage = cert->keyUsage;
  2820     pubKey = CERT_ExtractPublicKey(cert);
  2821     CERT_DestroyCertificate(cert);
  2822     return pubKey;
  2825 static SECItem *
  2826 sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey,
  2827 					KeyType *type)
  2829     SECItem *pubValue = NULL;
  2831     if(!type || !pubKey) {
  2832 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2833 	return NULL;
  2836     *type = pubKey->keyType;
  2837     switch(pubKey->keyType) {
  2838 	case dsaKey:
  2839 	    pubValue = &pubKey->u.dsa.publicValue;
  2840 	    break;
  2841 	case dhKey:
  2842 	    pubValue = &pubKey->u.dh.publicValue;
  2843 	    break;
  2844 	case rsaKey:
  2845 	    pubValue = &pubKey->u.rsa.modulus;
  2846 	    break;
  2847         case ecKey:
  2848 	    pubValue = &pubKey->u.ec.publicValue;
  2849 	    break;
  2850 	default:
  2851 	    pubValue = NULL;
  2854     return pubValue;
  2857 /* This function takes two passes over the bags, installing them in the
  2858  * desired slot.  The two passes are intended to mirror exactly the 
  2859  * two passes in sec_pkcs12_validate_bags.
  2860  */
  2861 static SECStatus 
  2862 sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, void *wincx)
  2864     sec_PKCS12SafeBag **keyList;
  2865     int i;
  2866     int failedKeys = 0;
  2868     if(!safeBags) {
  2869 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2870 	return SECFailure;
  2873     if(!safeBags[0]) {
  2874 	return SECSuccess;
  2877     /* First pass.  Find all the key bags. 
  2878      * Try to install them, and any certs associated with them.  
  2879      */
  2880     keyList = sec_pkcs12_get_key_bags(safeBags);
  2881     if(keyList) {
  2882 	for (i = 0; keyList[i]; i++) {
  2883 	    SECStatus rv;
  2884 	    SECKEYPublicKey *pubKey = NULL;
  2885 	    SECItem *nickName    = NULL;
  2886 	    sec_PKCS12SafeBag *key = keyList[i];
  2887 	    sec_PKCS12SafeBag **certList;
  2888 	    unsigned int keyUsage;
  2890 	    if(key->problem) {
  2891 		++failedKeys;
  2892 		continue;
  2895 	    certList = sec_pkcs12_find_certs_for_key(safeBags, key);
  2896 	    if(certList && certList[0]) {
  2897 		pubKey = sec_pkcs12_get_public_key_and_usage(certList[0],
  2898 					&keyUsage);
  2899 		/* use the cert's nickname, if it has one, else use the 
  2900 		 * key's nickname, else fail.
  2901 		 */
  2902 		nickName = sec_pkcs12_get_nickname_for_cert(certList[0], key);
  2903 	    } else {
  2904 		nickName = sec_pkcs12_get_nickname(key);
  2906 	    if (!nickName) {
  2907 		key->error = SEC_ERROR_BAD_NICKNAME;
  2908 		key->problem = PR_TRUE;
  2909 		rv = SECFailure;
  2910 	    } else if (!pubKey) {
  2911                 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  2912 		key->problem = PR_TRUE;
  2913                 rv = SECFailure;
  2914 	    } else {
  2915 		rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName, wincx);
  2917 	    if (pubKey) {
  2918 		SECKEY_DestroyPublicKey(pubKey);
  2919 		pubKey = NULL;
  2921 	    if (nickName) {
  2922 		SECITEM_FreeItem(nickName, PR_TRUE);
  2923 		nickName = NULL;
  2925 	    if(rv != SECSuccess) {
  2926 		PORT_SetError(key->error);
  2927 		++failedKeys;
  2930 	    if(certList) {
  2931 		int j;
  2933 		for (j = 0; certList[j]; j++) {
  2934 		    sec_PKCS12SafeBag *cert = certList[j];
  2935 		    SECStatus certRv;
  2937 		    if (!cert)
  2938 		    	continue;
  2939 		    if(rv != SECSuccess) {
  2940 			cert->problem = key->problem;
  2941 			cert->error   = key->error;	
  2942 			cert->noInstall = PR_TRUE;
  2943 			continue;
  2946 		    certRv = sec_pkcs12_add_cert(cert, cert->hasKey, wincx);
  2947 		    if(certRv != SECSuccess) {
  2948 			key->problem = cert->problem;
  2949 			key->error   = cert->error;
  2950 			PORT_SetError(cert->error);
  2951 			return SECFailure;
  2957     if (failedKeys)
  2958     	return SECFailure;
  2960     /* Now take a second pass over the safebags and install any certs 
  2961      * that were neither installed nor disqualified by the first pass.
  2962      */
  2963     for (i = 0; safeBags[i]; i++) {
  2964 	sec_PKCS12SafeBag *bag = safeBags[i];
  2966 	if (!bag->installed && !bag->problem && !bag->noInstall) {
  2967 	    SECStatus rv;
  2968 	    SECOidTag bagType = SECOID_FindOIDTag(&(bag->safeBagType));
  2970 	    switch(bagType) {
  2971 	    case SEC_OID_PKCS12_V1_CERT_BAG_ID:
  2972 		rv = sec_pkcs12_add_cert(bag, bag->hasKey, wincx);
  2973 		if(rv != SECSuccess) {
  2974 		    PORT_SetError(bag->error);
  2975 		    return SECFailure;
  2977 		break;
  2978 	    case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  2979 	    case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  2980 	    default:
  2981 		break;
  2986     return SECSuccess;
  2989 SECStatus
  2990 SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
  2992     if(!p12dcx || p12dcx->error) {
  2993 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2994 	return SECFailure;
  2997     if(!p12dcx->bagsVerified) {
  2998 	return SECFailure;
  3001     return sec_pkcs12_install_bags(p12dcx->safeBags, p12dcx->wincx);
  3004 PRBool
  3005 sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
  3007     int i;
  3008     SECItem *keyId;
  3009     SECItem *certKeyId;
  3011     certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
  3012     if (certKeyId == NULL) {
  3013         return PR_FALSE;
  3016     for (i=0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
  3017         keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
  3018                                                 SEC_OID_PKCS9_LOCAL_KEY_ID);
  3019         if(!keyId) {
  3020             continue;
  3022         if(SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
  3023             return PR_TRUE;
  3026     return PR_FALSE;
  3029 SECItem *
  3030 sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
  3032     SECItem *friendlyName;
  3033     SECItem *tempnm;
  3035     tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
  3036     friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
  3037     if (friendlyName) {
  3038         if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
  3039                                    tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
  3040             SECITEM_FreeItem(friendlyName, PR_TRUE);
  3041             friendlyName = NULL;
  3044     return friendlyName;
  3047 /* Following two functions provide access to selected portions of the safe bags.
  3048  * Iteration is implemented per decoder context and may be accessed after
  3049  * SEC_PKCS12DecoderVerify() returns success.
  3050  * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
  3051  * where item.type is always set; item.friendlyName is set if it is non-null;
  3052  * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
  3053  * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
  3054  * arguments are invalid; PORT_GetError() is 0 at end-of-list.
  3055  * Caller has read-only access to decoder items. Any SECItems generated are
  3056  * owned by the decoder context and are freed by ...DecoderFinish().
  3057  */
  3058 SECStatus
  3059 SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
  3061     if(!p12dcx || p12dcx->error) {
  3062         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3063 	return SECFailure;
  3066     p12dcx->iteration = 0;
  3067     return SECSuccess;
  3070 SECStatus
  3071 SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
  3072                              const SEC_PKCS12DecoderItem **ipp)
  3074     sec_PKCS12SafeBag *bag;
  3076     if(!p12dcx || p12dcx->error) {
  3077         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3078 	return SECFailure;
  3081     if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
  3082         SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
  3084     if (p12dcx->decitem.shroudAlg != NULL) {
  3085         SECOID_DestroyAlgorithmID(p12dcx->decitem.shroudAlg, PR_TRUE);
  3087     if (p12dcx->decitem.friendlyName != NULL) {
  3088         SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
  3090     p12dcx->decitem.type = 0;
  3091     p12dcx->decitem.der = NULL;
  3092     p12dcx->decitem.shroudAlg = NULL;
  3093     p12dcx->decitem.friendlyName = NULL;
  3094     p12dcx->decitem.hasKey = PR_FALSE;
  3095     *ipp = NULL;
  3096     if (p12dcx->keyList == NULL) {
  3097         p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
  3101     for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
  3102         bag = p12dcx->safeBags[p12dcx->iteration];
  3103  	if(bag == NULL || bag->problem) {
  3104             continue;
  3106         p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
  3107         switch(p12dcx->decitem.type) {
  3108             case SEC_OID_PKCS12_V1_CERT_BAG_ID:
  3109                 p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
  3110                 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
  3111                 p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
  3112                 break;
  3113             case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  3114                 p12dcx->decitem.shroudAlg = PORT_ZNew(SECAlgorithmID);
  3115 		if (p12dcx->decitem.shroudAlg) {
  3116 		    SECOID_CopyAlgorithmID(NULL, p12dcx->decitem.shroudAlg,
  3117 			&bag->safeBagContent.pkcs8ShroudedKeyBag->algorithm);
  3119                 /* fall through */
  3120             case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  3121                 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
  3122                 break;
  3123             default:
  3124                 /* return these even though we don't expect them */
  3125                 break;
  3126             case SEC_OID_UNKNOWN:
  3127                 /* ignore these */
  3128                 continue;
  3130         *ipp = &p12dcx->decitem;
  3131         p12dcx->iteration++;
  3132         break;  /* end for() */
  3135     PORT_SetError(0);       /* end-of-list is SECFailure with no PORT error */
  3136     return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
  3139 static SECStatus
  3140 sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
  3141 					 sec_PKCS12SafeBag *bag)
  3143     if(!p12dcx || p12dcx->error) {
  3144 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3145 	return SECFailure;
  3148     p12dcx->safeBags = !p12dcx->safeBagCount 
  3149 	? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
  3150 	: PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags, 
  3151 	                      sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1, 
  3152 			      p12dcx->safeBagCount + 2);
  3154     if(!p12dcx->safeBags) {
  3155 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  3156 	return SECFailure;
  3159     p12dcx->safeBags[p12dcx->safeBagCount] = bag;
  3160     p12dcx->safeBags[p12dcx->safeBagCount+1] = NULL;
  3161     p12dcx->safeBagCount++;
  3163     return SECSuccess;
  3166 static sec_PKCS12SafeBag *
  3167 sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx,
  3168 				   void *key, PRBool isEspvk)
  3170     sec_PKCS12SafeBag *keyBag;
  3171     SECOidData *oid;
  3172     SECOidTag keyTag;
  3173     SECItem *keyID, *nickName, *newNickName;
  3175     if(!p12dcx || p12dcx->error || !key) {
  3176 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3177 	return NULL;
  3180     newNickName = PORT_ArenaZNew(p12dcx->arena, SECItem);
  3181     keyBag      = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
  3182     if(!keyBag || !newNickName) {
  3183 	return NULL;
  3186     keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
  3187     keyBag->slot = p12dcx->slot;
  3188     keyBag->arena = p12dcx->arena;
  3189     keyBag->pwitem = p12dcx->pwitem;
  3190     keyBag->tokenCAs = p12dcx->tokenCAs;
  3191     keyBag->oldBagType = PR_TRUE;
  3193     keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID :
  3194 			 SEC_OID_PKCS12_V1_KEY_BAG_ID;
  3195     oid = SECOID_FindOIDByTag(keyTag);
  3196     if(!oid) {
  3197 	return NULL;
  3200     if(SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid) 
  3201 			!= SECSuccess) {
  3202 	return NULL;
  3205     if(isEspvk) {
  3206 	SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key;
  3207 	keyBag->safeBagContent.pkcs8ShroudedKeyBag  = 
  3208 					espvk->espvkCipherText.pkcs8KeyShroud;
  3209 	nickName = &(espvk->espvkData.uniNickName); 
  3210 	if(!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) {
  3211 	    PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  3212 	    return NULL;
  3214 	keyID = &espvk->espvkData.assocCerts[0]->digest;
  3215     } else {
  3216 	SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key;
  3217 	keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data;
  3218 	nickName= &(pk->pvkData.uniNickName);
  3219 	if(!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) {
  3220 	    PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  3221 	    return NULL;
  3223 	keyID = &pk->pvkData.assocCerts[0]->digest;
  3226     if(nickName->len) {
  3227 	if(nickName->len >= 2) {
  3228 	    if(nickName->data[0] && nickName->data[1]) {
  3229 		if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName, 
  3230 					nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
  3231 		    return NULL;
  3233 		nickName = newNickName;
  3234 	    } else if(nickName->data[0] && !nickName->data[1]) {
  3235 		unsigned int j = 0;
  3236 		unsigned char t;
  3237 		for(j = 0; j < nickName->len; j+=2) {
  3238 		    t = nickName->data[j+1];
  3239 		    nickName->data[j+1] = nickName->data[j];
  3240 		    nickName->data[j] = t;
  3243 	} else {
  3244 	    if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName, 
  3245 					nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
  3246 		return NULL;
  3248 	    nickName = newNickName;
  3252     if(sec_pkcs12_decoder_set_attribute_value(keyBag,
  3253 					      SEC_OID_PKCS9_FRIENDLY_NAME,
  3254 					      nickName) != SECSuccess) {
  3255 	return NULL;
  3258     if(sec_pkcs12_decoder_set_attribute_value(keyBag,SEC_OID_PKCS9_LOCAL_KEY_ID,
  3259 					keyID) != SECSuccess) {
  3260 	return NULL;
  3263     return keyBag;
  3266 static sec_PKCS12SafeBag *
  3267 sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx,
  3268 			       SECItem *derCert)
  3270     sec_PKCS12SafeBag *certBag;
  3271     SECOidData *oid;
  3272     SGNDigestInfo *digest;
  3273     SECItem *keyId;
  3274     SECStatus rv;
  3276     if(!p12dcx || p12dcx->error || !derCert) {
  3277 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3278 	return NULL;
  3281     keyId = PORT_ArenaZNew(p12dcx->arena, SECItem);
  3282     if(!keyId) {
  3283 	return NULL;
  3286     digest = sec_pkcs12_compute_thumbprint(derCert);
  3287     if(!digest) {
  3288 	return NULL;
  3291     rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest);
  3292     SGN_DestroyDigestInfo(digest);
  3293     if(rv != SECSuccess) {
  3294 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  3295 	return NULL;
  3298     oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID);
  3299     certBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
  3300     if(!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena, 
  3301 			&certBag->safeBagType, &oid->oid) != SECSuccess)) {
  3302 	return NULL;
  3305     certBag->slot = p12dcx->slot;
  3306     certBag->pwitem = p12dcx->pwitem;
  3307     certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
  3308     certBag->arena = p12dcx->arena;
  3309     certBag->tokenCAs = p12dcx->tokenCAs;
  3311     oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT);
  3312     certBag->safeBagContent.certBag = 
  3313 			PORT_ArenaZNew(p12dcx->arena, sec_PKCS12CertBag);
  3314     if(!certBag->safeBagContent.certBag || !oid ||
  3315 			(SECITEM_CopyItem(p12dcx->arena, 
  3316 				 &certBag->safeBagContent.certBag->bagID,
  3317 				 &oid->oid) != SECSuccess)) {
  3318 	return NULL;
  3321     if(SECITEM_CopyItem(p12dcx->arena, 
  3322 			 &(certBag->safeBagContent.certBag->value.x509Cert),
  3323 			 derCert) != SECSuccess) {
  3324 	return NULL;
  3327     if(sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
  3328 					keyId) != SECSuccess) {
  3329 	return NULL;
  3332     return certBag;
  3335 static sec_PKCS12SafeBag **
  3336 sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx,
  3337 				    SEC_PKCS12CertAndCRL *oldCert)
  3339     sec_PKCS12SafeBag **certList;
  3340     SECItem **derCertList;
  3341     int i, j;
  3343     if(!p12dcx || p12dcx->error || !oldCert) {
  3344 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3345 	return NULL;
  3348     derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL);
  3349     if(!derCertList) {
  3350 	return NULL;
  3353     i = 0;
  3354     while(derCertList[i]) i++;
  3356     certList = PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, (i + 1));
  3357     if(!certList) {
  3358 	return NULL;
  3361     for(j = 0; j < i; j++) {
  3362 	certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]);
  3363 	if(!certList[j]) {
  3364 	    return NULL;
  3368     return certList;
  3371 static SECStatus
  3372 sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx,
  3373 					     void *oldKey, PRBool isEspvk,
  3374 					     SEC_PKCS12SafeContents *safe,
  3375 					     SEC_PKCS12Baggage *baggage)
  3377     sec_PKCS12SafeBag *key, **certList;
  3378     SEC_PKCS12CertAndCRL *oldCert;
  3379     SEC_PKCS12PVKSupportingData *pvkData;
  3380     int i;
  3381     SECItem *keyName;
  3383     if(!p12dcx || !oldKey) {
  3384 	return SECFailure;
  3387     if(isEspvk) {
  3388 	pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData;
  3389     } else {
  3390 	pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData;
  3393     if(!pvkData->assocCerts || !pvkData->assocCerts[0]) {
  3394 	PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  3395 	return SECFailure;
  3398     oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage, 
  3399 				     SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL,
  3400 				     pvkData->assocCerts[0]);
  3401     if(!oldCert) {
  3402 	PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  3403 	return SECFailure;
  3406     key = sec_pkcs12_decoder_convert_old_key(p12dcx,oldKey, isEspvk);
  3407     certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert);
  3408     if(!key || !certList) {
  3409 	return SECFailure;
  3412     if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) {
  3413 	return SECFailure;
  3416     keyName = sec_pkcs12_get_nickname(key);
  3417     if(!keyName) {
  3418 	return SECFailure;
  3421     i = 0;
  3422     while(certList[i]) {
  3423 	if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i]) 
  3424 				!= SECSuccess) {
  3425 	    return SECFailure;
  3427 	i++;
  3430     certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key);
  3431     if(!certList) {
  3432 	return SECFailure;
  3435     i = 0;
  3436     while(certList[i] != 0) {
  3437 	if(sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) {
  3438 	    return SECFailure;
  3440 	i++;
  3443     return SECSuccess;
  3446 static SECStatus
  3447 sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx,
  3448 					    SEC_PKCS12SafeContents *safe,
  3449 					    SEC_PKCS12Baggage *baggage)
  3451     SECStatus rv;
  3453     if(!p12dcx || p12dcx->error) {
  3454 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3455 	return SECFailure;
  3458     if(safe && safe->contents) {
  3459 	int i = 0;
  3460 	while(safe->contents[i] != NULL) {
  3461 	    if(SECOID_FindOIDTag(&safe->contents[i]->safeBagType) 
  3462 				== SEC_OID_PKCS12_KEY_BAG_ID) {
  3463 		int j = 0;
  3464 		SEC_PKCS12PrivateKeyBag *privBag = 
  3465 					safe->contents[i]->safeContent.keyBag;
  3467 		while(privBag->privateKeys[j] != NULL) {
  3468 		    SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j];
  3469 		    rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx,pk,
  3470 						PR_FALSE, safe, baggage);
  3471 		    if(rv != SECSuccess) {
  3472 			goto loser;
  3474 		    j++;
  3477 	    i++;
  3481     if(baggage && baggage->bags) {
  3482 	int i = 0;
  3483 	while(baggage->bags[i] != NULL) {
  3484 	    SEC_PKCS12BaggageItem *bag = baggage->bags[i];
  3485 	    int j = 0;
  3487 	    if(!bag->espvks) {
  3488 		i++;
  3489 		continue;
  3492 	    while(bag->espvks[j] != NULL) {
  3493 		SEC_PKCS12ESPVKItem *espvk = bag->espvks[j];
  3494 		rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk,
  3495 							PR_TRUE, safe, baggage);
  3496 		if(rv != SECSuccess) {
  3497 		    goto loser;
  3499 		j++;
  3501 	    i++;
  3505     return SECSuccess;
  3507 loser:
  3508     return SECFailure;
  3511 SEC_PKCS12DecoderContext *
  3512 sec_PKCS12ConvertOldSafeToNew(PLArenaPool *arena, PK11SlotInfo *slot,
  3513 			      PRBool swapUnicode, SECItem *pwitem,
  3514 			      void *wincx, SEC_PKCS12SafeContents *safe,
  3515 			      SEC_PKCS12Baggage *baggage)
  3517     SEC_PKCS12DecoderContext *p12dcx;
  3519     if(!arena || !slot || !pwitem) {
  3520 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3521 	return NULL;
  3524     if(!safe && !baggage) {
  3525 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  3526 	return NULL;
  3529     p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
  3530     if(!p12dcx) {
  3531 	return NULL;
  3534     p12dcx->arena = arena;
  3535     p12dcx->slot = PK11_ReferenceSlot(slot);
  3536     p12dcx->wincx = wincx;
  3537     p12dcx->error = PR_FALSE;
  3538     p12dcx->swapUnicodeBytes = swapUnicode; 
  3539     p12dcx->pwitem = pwitem;
  3540     p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
  3542     if(sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage) 
  3543 				!= SECSuccess) {
  3544 	p12dcx->error = PR_TRUE;
  3545 	return NULL;
  3548     return p12dcx;

mercurial