security/nss/lib/pkcs12/p12d.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/pkcs12/p12d.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3549 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +
     1.9 +#include "nssrenam.h"
    1.10 +#include "p12t.h"
    1.11 +#include "p12.h"
    1.12 +#include "plarena.h"
    1.13 +#include "secitem.h"
    1.14 +#include "secoid.h"
    1.15 +#include "seccomon.h"
    1.16 +#include "secport.h"
    1.17 +#include "cert.h"
    1.18 +#include "secpkcs7.h"
    1.19 +#include "secasn1.h"
    1.20 +#include "secerr.h"
    1.21 +#include "pk11func.h"
    1.22 +#include "p12plcy.h"
    1.23 +#include "p12local.h"
    1.24 +#include "secder.h"
    1.25 +#include "secport.h"
    1.26 +
    1.27 +#include "certdb.h"
    1.28 +
    1.29 +#include "prcpucfg.h"
    1.30 +
    1.31 +/* This belongs in secport.h */
    1.32 +#define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \
    1.33 +    (type *)PORT_ArenaGrow((poolp), (oldptr), \
    1.34 +			   (oldnum) * sizeof(type), (newnum) * sizeof(type))
    1.35 +
    1.36 +
    1.37 +typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext;
    1.38 +
    1.39 +/* Opaque structure for decoding SafeContents.  These are used
    1.40 + * for each authenticated safe as well as any nested safe contents.
    1.41 + */
    1.42 +struct sec_PKCS12SafeContentsContextStr {
    1.43 +    /* the parent decoder context */
    1.44 +    SEC_PKCS12DecoderContext *p12dcx;
    1.45 +
    1.46 +    /* memory arena to allocate space from */
    1.47 +    PLArenaPool *arena;
    1.48 +
    1.49 +    /* decoder context and destination for decoding safe contents */
    1.50 +    SEC_ASN1DecoderContext *safeContentsA1Dcx;
    1.51 +    sec_PKCS12SafeContents safeContents;
    1.52 +
    1.53 +    /* information for decoding safe bags within the safe contents.
    1.54 +     * these variables are updated for each safe bag decoded.
    1.55 +     */
    1.56 +    SEC_ASN1DecoderContext *currentSafeBagA1Dcx;
    1.57 +    sec_PKCS12SafeBag *currentSafeBag;
    1.58 +    PRBool skipCurrentSafeBag;
    1.59 +
    1.60 +    /* if the safe contents is nested, the parent is pointed to here. */
    1.61 +    sec_PKCS12SafeContentsContext *nestedSafeContentsCtx;
    1.62 +};
    1.63 +
    1.64 +/* opaque decoder context structure.  information for decoding a pkcs 12
    1.65 + * PDU are stored here as well as decoding pointers for intermediary 
    1.66 + * structures which are part of the PKCS 12 PDU.  Upon a successful
    1.67 + * decode, the safe bags containing certificates and keys encountered.
    1.68 + */  
    1.69 +struct SEC_PKCS12DecoderContextStr {
    1.70 +    PLArenaPool *arena;
    1.71 +    PK11SlotInfo *slot;
    1.72 +    void *wincx;
    1.73 +    PRBool error;
    1.74 +    int errorValue;
    1.75 +
    1.76 +    /* password */
    1.77 +    SECItem *pwitem;
    1.78 +
    1.79 +    /* used for decoding the PFX structure */
    1.80 +    SEC_ASN1DecoderContext 	*pfxA1Dcx;
    1.81 +    sec_PKCS12PFXItem 		pfx;
    1.82 +
    1.83 +    /* safe bags found during decoding */  
    1.84 +    sec_PKCS12SafeBag 		**safeBags;
    1.85 +    unsigned int 		safeBagCount;
    1.86 +
    1.87 +    /* state variables for decoding authenticated safes. */
    1.88 +    SEC_PKCS7DecoderContext 	*currentASafeP7Dcx;
    1.89 +    SEC_ASN1DecoderContext 	*aSafeA1Dcx;
    1.90 +    SEC_PKCS7DecoderContext 	*aSafeP7Dcx;
    1.91 +    SEC_PKCS7ContentInfo 	*aSafeCinfo;
    1.92 +    sec_PKCS12AuthenticatedSafe authSafe;
    1.93 +    sec_PKCS12SafeContents 	safeContents;
    1.94 +
    1.95 +    /* safe contents info */
    1.96 +    unsigned int 		safeContentsCnt;
    1.97 +    sec_PKCS12SafeContentsContext **safeContentsList;
    1.98 +
    1.99 +    /* HMAC info */
   1.100 +    sec_PKCS12MacData		macData;
   1.101 +
   1.102 +    /* routines for reading back the data to be hmac'd */
   1.103 +    /* They are called as follows.
   1.104 +     *
   1.105 +     * Stage 1: decode the aSafes cinfo into a buffer in dArg,
   1.106 +     * which p12d.c sometimes refers to as the "temp file".
   1.107 +     * This occurs during SEC_PKCS12DecoderUpdate calls.
   1.108 +     *
   1.109 +     * dOpen(dArg, PR_FALSE)
   1.110 +     * dWrite(dArg, buf, len)
   1.111 +     * ...
   1.112 +     * dWrite(dArg, buf, len)
   1.113 +     * dClose(dArg, PR_FALSE)
   1.114 +     *
   1.115 +     * Stage 2: verify MAC
   1.116 +     * This occurs SEC_PKCS12DecoderVerify.
   1.117 +     *
   1.118 +     * dOpen(dArg, PR_TRUE)
   1.119 +     * dRead(dArg, buf, IN_BUF_LEN)
   1.120 +     * ...
   1.121 +     * dRead(dArg, buf, IN_BUF_LEN)
   1.122 +     * dClose(dArg, PR_TRUE)
   1.123 +     */
   1.124 +    digestOpenFn 		dOpen;
   1.125 +    digestCloseFn 		dClose;
   1.126 +    digestIOFn 			dRead, dWrite;
   1.127 +    void 			*dArg;
   1.128 +    PRBool			dIsOpen;  /* is the temp file created? */
   1.129 +
   1.130 +    /* helper functions */
   1.131 +    SECKEYGetPasswordKey 	pwfn;
   1.132 +    void 			*pwfnarg;
   1.133 +    PRBool 			swapUnicodeBytes;
   1.134 +
   1.135 +    /* import information */
   1.136 +    PRBool 			bagsVerified;
   1.137 +
   1.138 +    /* buffer management for the default callbacks implementation */
   1.139 +    void        *buffer;      /* storage area */
   1.140 +    PRInt32     filesize;     /* actual data size */
   1.141 +    PRInt32     allocated;    /* total buffer size allocated */
   1.142 +    PRInt32     currentpos;   /* position counter */
   1.143 +    SECPKCS12TargetTokenCAs tokenCAs;
   1.144 +    sec_PKCS12SafeBag **keyList;/* used by ...IterateNext() */
   1.145 +    unsigned int iteration;
   1.146 +    SEC_PKCS12DecoderItem decitem;
   1.147 +};
   1.148 +
   1.149 +/* forward declarations of functions that are used when decoding
   1.150 + * safeContents bags which are nested and when decoding the 
   1.151 + * authenticatedSafes.
   1.152 + */
   1.153 +static SECStatus
   1.154 +sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext 
   1.155 +							*safeContentsCtx);
   1.156 +static SECStatus
   1.157 +sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
   1.158 +							*safeContentsCtx);
   1.159 +
   1.160 +
   1.161 +/* make sure that the PFX version being decoded is a version
   1.162 + * which we support.
   1.163 + */
   1.164 +static PRBool
   1.165 +sec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx)
   1.166 +{
   1.167 +    /* if no version, assume it is not supported */
   1.168 +    if(pfx->version.len == 0) {
   1.169 +	return PR_FALSE;
   1.170 +    }
   1.171 +
   1.172 +    if(DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) {
   1.173 +	return PR_FALSE;
   1.174 +    }
   1.175 +
   1.176 +    return PR_TRUE;
   1.177 +}
   1.178 +
   1.179 +/* retrieve the key for decrypting the safe contents */ 
   1.180 +static PK11SymKey *
   1.181 +sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid)
   1.182 +{
   1.183 +    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *) arg;
   1.184 +    PK11SlotInfo *slot;
   1.185 +    PK11SymKey *bulkKey;
   1.186 +
   1.187 +    if(!p12dcx) {
   1.188 +	return NULL;
   1.189 +    }
   1.190 +
   1.191 +    /* if no slot specified, use the internal key slot */
   1.192 +    if(p12dcx->slot) {
   1.193 +	slot = PK11_ReferenceSlot(p12dcx->slot);
   1.194 +    } else {
   1.195 +	slot = PK11_GetInternalKeySlot();
   1.196 +    }
   1.197 +
   1.198 +    bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, 
   1.199 +						PR_FALSE, p12dcx->wincx);
   1.200 +    /* some tokens can't generate PBE keys on their own, generate the
   1.201 +     * key in the internal slot, and let the Import code deal with it,
   1.202 +     * (if the slot can't generate PBEs, then we need to use the internal
   1.203 +     * slot anyway to unwrap). */
   1.204 +    if (!bulkKey && !PK11_IsInternal(slot)) {
   1.205 +	PK11_FreeSlot(slot);
   1.206 +	slot = PK11_GetInternalKeySlot();
   1.207 +	bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, 
   1.208 +						PR_FALSE, p12dcx->wincx);
   1.209 +    }
   1.210 +    PK11_FreeSlot(slot);
   1.211 +
   1.212 +    /* set the password data on the key */
   1.213 +    if (bulkKey) {
   1.214 +        PK11_SetSymKeyUserData(bulkKey,p12dcx->pwitem, NULL);
   1.215 +    }
   1.216 +
   1.217 +
   1.218 +    return bulkKey;
   1.219 +}
   1.220 +
   1.221 +/* XXX this needs to be modified to handle enveloped data.  most
   1.222 + * likely, it should mirror the routines for SMIME in that regard.
   1.223 + */
   1.224 +static PRBool
   1.225 +sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid, 
   1.226 +				      PK11SymKey *bulkkey)
   1.227 +{
   1.228 +    PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid);
   1.229 +
   1.230 +    if(!decryptionAllowed) {
   1.231 +	return PR_FALSE;
   1.232 +    }
   1.233 +
   1.234 +    return PR_TRUE;
   1.235 +}
   1.236 +
   1.237 +/* when we encounter a new safe bag during the decoding, we need
   1.238 + * to allocate space for the bag to be decoded to and set the 
   1.239 + * state variables appropriately.  all of the safe bags are allocated
   1.240 + * in a buffer in the outer SEC_PKCS12DecoderContext, however,
   1.241 + * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext
   1.242 + * for the current bag.
   1.243 + */
   1.244 +static SECStatus
   1.245 +sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext 
   1.246 +						*safeContentsCtx)
   1.247 +{
   1.248 +    void *mark = NULL;
   1.249 +    SEC_PKCS12DecoderContext *p12dcx;
   1.250 +
   1.251 +    /* make sure that the structures are defined, and there has
   1.252 +     * not been an error in the decoding 
   1.253 +     */
   1.254 +    if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   1.255 +		|| safeContentsCtx->p12dcx->error) {
   1.256 +	return SECFailure;
   1.257 +    }
   1.258 +
   1.259 +    p12dcx = safeContentsCtx->p12dcx;
   1.260 +    mark = PORT_ArenaMark(p12dcx->arena);
   1.261 +
   1.262 +    /* allocate a new safe bag, if bags already exist, grow the 
   1.263 +     * list of bags, otherwise allocate a new list.  the list is
   1.264 +     * NULL terminated.
   1.265 +     */
   1.266 +    p12dcx->safeBags = (!p12dcx->safeBagCount)
   1.267 +	? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
   1.268 +        : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
   1.269 +				sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
   1.270 +				p12dcx->safeBagCount + 2);
   1.271 +
   1.272 +    if(!p12dcx->safeBags) {
   1.273 +	p12dcx->errorValue = PORT_GetError();
   1.274 +	goto loser;
   1.275 +    }
   1.276 +
   1.277 +    /* append the bag to the end of the list and update the reference
   1.278 +     * in the safeContentsCtx.
   1.279 +     */
   1.280 +    p12dcx->safeBags[p12dcx->safeBagCount] = 
   1.281 +    safeContentsCtx->currentSafeBag = 
   1.282 +			    PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
   1.283 +    if(!safeContentsCtx->currentSafeBag) {
   1.284 +	p12dcx->errorValue = PORT_GetError();
   1.285 +	goto loser;
   1.286 +    }
   1.287 +    p12dcx->safeBags[++p12dcx->safeBagCount] = NULL;
   1.288 +
   1.289 +    safeContentsCtx->currentSafeBag->slot = safeContentsCtx->p12dcx->slot;
   1.290 +    safeContentsCtx->currentSafeBag->pwitem = safeContentsCtx->p12dcx->pwitem;
   1.291 +    safeContentsCtx->currentSafeBag->swapUnicodeBytes = 
   1.292 +				safeContentsCtx->p12dcx->swapUnicodeBytes;
   1.293 +    safeContentsCtx->currentSafeBag->arena = safeContentsCtx->p12dcx->arena;
   1.294 +    safeContentsCtx->currentSafeBag->tokenCAs = 
   1.295 +				safeContentsCtx->p12dcx->tokenCAs;
   1.296 +
   1.297 +    PORT_ArenaUnmark(p12dcx->arena, mark);
   1.298 +    return SECSuccess;
   1.299 +
   1.300 +loser:
   1.301 +
   1.302 +    /* if an error occurred, release the memory and set the error flag
   1.303 +     * the only possible errors triggered by this function are memory 
   1.304 +     * related.
   1.305 +     */
   1.306 +    if(mark) {
   1.307 +	PORT_ArenaRelease(p12dcx->arena, mark);
   1.308 +    }
   1.309 +
   1.310 +    p12dcx->error = PR_TRUE;
   1.311 +    return SECFailure;
   1.312 +}
   1.313 +
   1.314 +/* A wrapper for updating the ASN1 context in which a safeBag is
   1.315 + * being decoded.  This function is called as a callback from
   1.316 + * secasn1d when decoding SafeContents structures.
   1.317 + */
   1.318 +static void
   1.319 +sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data, 
   1.320 +				   unsigned long len, int depth, 
   1.321 +				   SEC_ASN1EncodingPart data_kind)
   1.322 +{
   1.323 +    sec_PKCS12SafeContentsContext *safeContentsCtx = 
   1.324 +        (sec_PKCS12SafeContentsContext *)arg;
   1.325 +    SEC_PKCS12DecoderContext *p12dcx;
   1.326 +    SECStatus rv;
   1.327 +
   1.328 +    /* make sure that we are not skipping the current safeBag,
   1.329 +     * and that there are no errors.  If so, just return rather
   1.330 +     * than continuing to process.
   1.331 +     */
   1.332 +    if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   1.333 +		|| safeContentsCtx->p12dcx->error 
   1.334 +		|| safeContentsCtx->skipCurrentSafeBag) {
   1.335 +	return;
   1.336 +    }
   1.337 +    p12dcx = safeContentsCtx->p12dcx;
   1.338 +
   1.339 +    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagA1Dcx, data, len);
   1.340 +    if(rv != SECSuccess) {
   1.341 +	p12dcx->errorValue = PORT_GetError();
   1.342 +	goto loser;
   1.343 +    }
   1.344 +
   1.345 +    return;
   1.346 +
   1.347 +loser:
   1.348 +    /* set the error, and finish the decoder context.  because there 
   1.349 +     * is not a way of returning an error message, it may be worth
   1.350 +     * while to do a check higher up and finish any decoding contexts
   1.351 +     * that are still open.
   1.352 +     */
   1.353 +    p12dcx->error = PR_TRUE;
   1.354 +    SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
   1.355 +    safeContentsCtx->currentSafeBagA1Dcx = NULL;
   1.356 +    return;
   1.357 +}
   1.358 +
   1.359 +/* notify function for decoding safeBags.  This function is
   1.360 + * used to filter safeBag types which are not supported,
   1.361 + * initiate the decoding of nested safe contents, and decode
   1.362 + * safeBags in general.  this function is set when the decoder
   1.363 + * context for the safeBag is first created.
   1.364 + */
   1.365 +static void
   1.366 +sec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before,
   1.367 +				   void *dest, int real_depth)
   1.368 +{
   1.369 +    sec_PKCS12SafeContentsContext *safeContentsCtx = 
   1.370 +        (sec_PKCS12SafeContentsContext *)arg;
   1.371 +    SEC_PKCS12DecoderContext *p12dcx;
   1.372 +    sec_PKCS12SafeBag *bag;
   1.373 +    PRBool after;
   1.374 +
   1.375 +    /* if an error is encountered, return */
   1.376 +    if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
   1.377 +		safeContentsCtx->p12dcx->error) {
   1.378 +	return;
   1.379 +    }
   1.380 +    p12dcx = safeContentsCtx->p12dcx;
   1.381 +
   1.382 +    /* to make things more readable */
   1.383 +    if(before)
   1.384 +	after = PR_FALSE;
   1.385 +    else 
   1.386 +	after = PR_TRUE;
   1.387 +
   1.388 +    /* have we determined the safeBagType yet? */
   1.389 +    bag = safeContentsCtx->currentSafeBag;
   1.390 +    if(bag->bagTypeTag == NULL) {
   1.391 +	if(after && (dest == &(bag->safeBagType))) {
   1.392 +	    bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType));
   1.393 +	    if(bag->bagTypeTag == NULL) {
   1.394 +		p12dcx->error = PR_TRUE;
   1.395 +		p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
   1.396 +	    }
   1.397 +	}
   1.398 +	return;
   1.399 +    }
   1.400 +
   1.401 +    /* process the safeBag depending on it's type.  those
   1.402 +     * which we do not support, are ignored.  we start a decoding
   1.403 +     * context for a nested safeContents.
   1.404 +     */
   1.405 +    switch(bag->bagTypeTag->offset) {
   1.406 +	case SEC_OID_PKCS12_V1_KEY_BAG_ID:
   1.407 +	case SEC_OID_PKCS12_V1_CERT_BAG_ID:
   1.408 +	case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
   1.409 +	    break;
   1.410 +	case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
   1.411 +	    /* if we are just starting to decode the safeContents, initialize
   1.412 +	     * a new safeContentsCtx to process it.
   1.413 +	     */
   1.414 +	    if(before && (dest == &(bag->safeBagContent))) {
   1.415 +		sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx);
   1.416 +	    } else if(after && (dest == &(bag->safeBagContent))) {
   1.417 +		/* clean up the nested decoding */
   1.418 +		sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx);
   1.419 +	    }
   1.420 +	    break;
   1.421 +	case SEC_OID_PKCS12_V1_CRL_BAG_ID:
   1.422 +	case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
   1.423 +	default:
   1.424 +	    /* skip any safe bag types we don't understand or handle */
   1.425 +	    safeContentsCtx->skipCurrentSafeBag = PR_TRUE;
   1.426 +	    break;
   1.427 +    }
   1.428 +
   1.429 +    return;
   1.430 +}
   1.431 +
   1.432 +/* notify function for decoding safe contents.  each entry in the
   1.433 + * safe contents is a safeBag which needs to be allocated and
   1.434 + * the decoding context initialized at the beginning and then
   1.435 + * the context needs to be closed and finished at the end.
   1.436 + *
   1.437 + * this function is set when the safeContents decode context is
   1.438 + * initialized.
   1.439 + */
   1.440 +static void
   1.441 +sec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before,
   1.442 +					void *dest, int real_depth)
   1.443 +{
   1.444 +    sec_PKCS12SafeContentsContext *safeContentsCtx = 
   1.445 +        (sec_PKCS12SafeContentsContext*)arg;
   1.446 +    SEC_PKCS12DecoderContext *p12dcx;
   1.447 +    SECStatus rv;
   1.448 +
   1.449 +    /* if there is an error we don't want to continue processing,
   1.450 +     * just return and keep going.
   1.451 +     */
   1.452 +    if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   1.453 +		|| safeContentsCtx->p12dcx->error) {
   1.454 +	return;
   1.455 +    }
   1.456 +    p12dcx = safeContentsCtx->p12dcx;
   1.457 +
   1.458 +    /* if we are done with the current safeBag, then we need to
   1.459 +     * finish the context and set the state variables appropriately.
   1.460 +     */
   1.461 +    if(!before) {
   1.462 +	SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
   1.463 +	SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
   1.464 +	safeContentsCtx->currentSafeBagA1Dcx = NULL;
   1.465 +	safeContentsCtx->skipCurrentSafeBag = PR_FALSE;
   1.466 +    } else {
   1.467 +	/* we are starting a new safe bag.  we need to allocate space
   1.468 +	 * for the bag and initialize the decoding context.
   1.469 +	 */
   1.470 +	rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx);
   1.471 +	if(rv != SECSuccess) {
   1.472 +	    goto loser;
   1.473 +	}
   1.474 +
   1.475 +	/* set up the decoder context */
   1.476 +	safeContentsCtx->currentSafeBagA1Dcx = 
   1.477 +		SEC_ASN1DecoderStart(p12dcx->arena,
   1.478 +				     safeContentsCtx->currentSafeBag,
   1.479 +				     sec_PKCS12SafeBagTemplate);
   1.480 +	if(!safeContentsCtx->currentSafeBagA1Dcx) {
   1.481 +	    p12dcx->errorValue = PORT_GetError();
   1.482 +	    goto loser;
   1.483 +	}
   1.484 +
   1.485 +	/* set the notify and filter procs so that the safe bag
   1.486 +	 * data gets sent to the proper location when decoding.
   1.487 +	 */
   1.488 +	SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagA1Dcx, 
   1.489 +				 sec_pkcs12_decoder_safe_bag_notify, 
   1.490 +				 safeContentsCtx);
   1.491 +	SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsA1Dcx, 
   1.492 +				 sec_pkcs12_decoder_safe_bag_update, 
   1.493 +				 safeContentsCtx, PR_TRUE);
   1.494 +    }
   1.495 +
   1.496 +    return;
   1.497 +
   1.498 +loser:
   1.499 +    /* in the event of an error, we want to close the decoding
   1.500 +     * context and clear the filter and notify procedures.
   1.501 +     */
   1.502 +    p12dcx->error = PR_TRUE;
   1.503 +
   1.504 +    if(safeContentsCtx->currentSafeBagA1Dcx) {
   1.505 +	SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
   1.506 +	safeContentsCtx->currentSafeBagA1Dcx = NULL;
   1.507 +    }
   1.508 +
   1.509 +    SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsA1Dcx);
   1.510 +    SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
   1.511 +
   1.512 +    return;
   1.513 +}
   1.514 +
   1.515 +/* initialize the safeContents for decoding.  this routine
   1.516 + * is used for authenticatedSafes as well as nested safeContents.
   1.517 + */
   1.518 +static sec_PKCS12SafeContentsContext *
   1.519 +sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx,
   1.520 +					     PRBool nestedSafe)
   1.521 +{
   1.522 +    sec_PKCS12SafeContentsContext *safeContentsCtx = NULL;
   1.523 +    const SEC_ASN1Template *theTemplate;
   1.524 +
   1.525 +    if(!p12dcx || p12dcx->error) {
   1.526 +	return NULL;
   1.527 +    }
   1.528 +
   1.529 +    /* allocate a new safeContents list or grow the existing list and
   1.530 +     * append the new safeContents onto the end.
   1.531 +     */
   1.532 +    p12dcx->safeContentsList = (!p12dcx->safeContentsCnt) 
   1.533 +	? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeContentsContext *, 2)
   1.534 +	: PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeContentsList,
   1.535 +			        sec_PKCS12SafeContentsContext *,
   1.536 +			        1 + p12dcx->safeContentsCnt,
   1.537 +			        2 + p12dcx->safeContentsCnt);
   1.538 +
   1.539 +    if(!p12dcx->safeContentsList) {
   1.540 +	p12dcx->errorValue = PORT_GetError();
   1.541 +	goto loser;
   1.542 +    }
   1.543 +
   1.544 +    p12dcx->safeContentsList[p12dcx->safeContentsCnt] = safeContentsCtx = 
   1.545 +        PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeContentsContext);
   1.546 +    if(!p12dcx->safeContentsList[p12dcx->safeContentsCnt]) {
   1.547 +	p12dcx->errorValue = PORT_GetError();
   1.548 +	goto loser;
   1.549 +    }
   1.550 +    p12dcx->safeContentsList[++p12dcx->safeContentsCnt] = NULL;
   1.551 +
   1.552 +    /* set up the state variables */
   1.553 +    safeContentsCtx->p12dcx = p12dcx;
   1.554 +    safeContentsCtx->arena = p12dcx->arena;
   1.555 +
   1.556 +    /* begin the decoding -- the template is based on whether we are
   1.557 +     * decoding a nested safeContents or not.
   1.558 +     */
   1.559 +    if(nestedSafe == PR_TRUE) {
   1.560 +	theTemplate = sec_PKCS12NestedSafeContentsDecodeTemplate;
   1.561 +    } else {
   1.562 +	theTemplate = sec_PKCS12SafeContentsDecodeTemplate;
   1.563 +    }
   1.564 +
   1.565 +    /* start the decoder context */
   1.566 +    safeContentsCtx->safeContentsA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, 
   1.567 +					&safeContentsCtx->safeContents,
   1.568 +					theTemplate);
   1.569 +	
   1.570 +    if(!safeContentsCtx->safeContentsA1Dcx) {
   1.571 +	p12dcx->errorValue = PORT_GetError();
   1.572 +	goto loser;
   1.573 +    }
   1.574 +
   1.575 +    /* set the safeContents notify procedure to look for
   1.576 +     * and start the decode of safeBags.
   1.577 +     */
   1.578 +    SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->safeContentsA1Dcx, 
   1.579 +				sec_pkcs12_decoder_safe_contents_notify,
   1.580 +				safeContentsCtx);
   1.581 +
   1.582 +    return safeContentsCtx;
   1.583 +
   1.584 +loser:
   1.585 +    /* in the case of an error, we want to finish the decoder
   1.586 +     * context and set the error flag.
   1.587 +     */
   1.588 +    if(safeContentsCtx && safeContentsCtx->safeContentsA1Dcx) {
   1.589 +	SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   1.590 +	safeContentsCtx->safeContentsA1Dcx = NULL;
   1.591 +    }
   1.592 +
   1.593 +    p12dcx->error = PR_TRUE;
   1.594 +
   1.595 +    return NULL;
   1.596 +}
   1.597 +
   1.598 +/* wrapper for updating safeContents.  this is set as the filter of
   1.599 + * safeBag when there is a nested safeContents.
   1.600 + */
   1.601 +static void
   1.602 +sec_pkcs12_decoder_nested_safe_contents_update(void *arg, const char *buf,
   1.603 +					  unsigned long len, int depth,
   1.604 +					  SEC_ASN1EncodingPart data_kind)
   1.605 +{
   1.606 +    sec_PKCS12SafeContentsContext *safeContentsCtx = 
   1.607 +        (sec_PKCS12SafeContentsContext *)arg;
   1.608 +    SEC_PKCS12DecoderContext *p12dcx;
   1.609 +    SECStatus rv;
   1.610 +
   1.611 +    /* check for an error */
   1.612 +    if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   1.613 +			|| safeContentsCtx->p12dcx->error
   1.614 +			|| !safeContentsCtx->safeContentsA1Dcx) {
   1.615 +	return;
   1.616 +    }
   1.617 +
   1.618 +    /* no need to update if no data sent in */
   1.619 +    if(!len || !buf) {
   1.620 +	return;
   1.621 +    }
   1.622 +
   1.623 +    /* update the decoding context */
   1.624 +    p12dcx = safeContentsCtx->p12dcx;
   1.625 +    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
   1.626 +    if(rv != SECSuccess) {
   1.627 +	p12dcx->errorValue = PORT_GetError();
   1.628 +	goto loser;
   1.629 +    }
   1.630 +
   1.631 +    return;
   1.632 +
   1.633 +loser:
   1.634 +    /* handle any errors.  If a decoding context is open, close it. */
   1.635 +    p12dcx->error = PR_TRUE;
   1.636 +    if(safeContentsCtx->safeContentsA1Dcx) {
   1.637 +	SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   1.638 +	safeContentsCtx->safeContentsA1Dcx = NULL;
   1.639 +    }
   1.640 +}
   1.641 +
   1.642 +/* whenever a new safeContentsSafeBag is encountered, we need
   1.643 + * to init a safeContentsContext.  
   1.644 + */
   1.645 +static SECStatus  
   1.646 +sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext 
   1.647 +							*safeContentsCtx)
   1.648 +{
   1.649 +    /* check for an error */
   1.650 +    if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
   1.651 +		safeContentsCtx->p12dcx->error) {
   1.652 +	return SECFailure;
   1.653 +    }
   1.654 +
   1.655 +    safeContentsCtx->nestedSafeContentsCtx = 
   1.656 +    	sec_pkcs12_decoder_safe_contents_init_decode(safeContentsCtx->p12dcx,
   1.657 +						     PR_TRUE);
   1.658 +    if(!safeContentsCtx->nestedSafeContentsCtx) {
   1.659 +	return SECFailure;
   1.660 +    }
   1.661 +
   1.662 +    /* set up new filter proc */
   1.663 +    SEC_ASN1DecoderSetNotifyProc(
   1.664 +                     safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx,
   1.665 +				 sec_pkcs12_decoder_safe_contents_notify,
   1.666 +				 safeContentsCtx->nestedSafeContentsCtx);
   1.667 +
   1.668 +    SEC_ASN1DecoderSetFilterProc(safeContentsCtx->currentSafeBagA1Dcx,
   1.669 +				 sec_pkcs12_decoder_nested_safe_contents_update,
   1.670 +				 safeContentsCtx->nestedSafeContentsCtx, 
   1.671 +				 PR_TRUE);
   1.672 +
   1.673 +    return SECSuccess;
   1.674 +}
   1.675 +
   1.676 +/* when the safeContents is done decoding, we need to reset the
   1.677 + * proper filter and notify procs and close the decoding context 
   1.678 + */
   1.679 +static SECStatus
   1.680 +sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
   1.681 +							*safeContentsCtx)
   1.682 +{
   1.683 +    /* check for error */
   1.684 +    if(!safeContentsCtx || !safeContentsCtx->p12dcx || 
   1.685 +		safeContentsCtx->p12dcx->error) {
   1.686 +	return SECFailure;
   1.687 +    }
   1.688 +
   1.689 +    /* clean up */	
   1.690 +    SEC_ASN1DecoderClearFilterProc(safeContentsCtx->currentSafeBagA1Dcx);
   1.691 +    SEC_ASN1DecoderClearNotifyProc(
   1.692 +                    safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
   1.693 +    SEC_ASN1DecoderFinish(
   1.694 +                    safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
   1.695 +    safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx = NULL;
   1.696 +    safeContentsCtx->nestedSafeContentsCtx = NULL;
   1.697 +
   1.698 +    return SECSuccess;
   1.699 +}
   1.700 +
   1.701 +/* wrapper for updating safeContents.  This is used when decoding
   1.702 + * the nested safeContents and any authenticatedSafes.
   1.703 + */
   1.704 +static void
   1.705 +sec_pkcs12_decoder_safe_contents_callback(void *arg, const char *buf,
   1.706 +					  unsigned long len)
   1.707 +{
   1.708 +    SECStatus rv;
   1.709 +    sec_PKCS12SafeContentsContext *safeContentsCtx = 
   1.710 +        (sec_PKCS12SafeContentsContext *)arg;
   1.711 +    SEC_PKCS12DecoderContext *p12dcx;
   1.712 +
   1.713 +    /* check for error */  
   1.714 +    if(!safeContentsCtx || !safeContentsCtx->p12dcx 
   1.715 +		|| safeContentsCtx->p12dcx->error
   1.716 +		|| !safeContentsCtx->safeContentsA1Dcx) {
   1.717 +	return;
   1.718 +    }
   1.719 +    p12dcx = safeContentsCtx->p12dcx;
   1.720 +
   1.721 +    /* update the decoder */
   1.722 +    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
   1.723 +    if(rv != SECSuccess) {
   1.724 +	/* if we fail while trying to decode a 'safe', it's probably because
   1.725 +	 * we didn't have the correct password. */
   1.726 +	PORT_SetError(SEC_ERROR_BAD_PASSWORD);
   1.727 +	p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
   1.728 +	SEC_PKCS7DecoderAbort(p12dcx->currentASafeP7Dcx,SEC_ERROR_BAD_PASSWORD);
   1.729 +	goto loser;
   1.730 +    }
   1.731 +
   1.732 +    return;
   1.733 +
   1.734 +loser:
   1.735 +    /* set the error and finish the context */
   1.736 +    p12dcx->error = PR_TRUE;
   1.737 +    if(safeContentsCtx->safeContentsA1Dcx) {
   1.738 +	SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   1.739 +	safeContentsCtx->safeContentsA1Dcx = NULL;
   1.740 +    }
   1.741 +
   1.742 +    return;
   1.743 +}
   1.744 +
   1.745 +/* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate
   1.746 + */
   1.747 +static void
   1.748 +sec_pkcs12_decoder_wrap_p7_update(void *arg, const char *data,
   1.749 +				  unsigned long len, int depth,
   1.750 +				  SEC_ASN1EncodingPart data_kind)
   1.751 +{
   1.752 +    SEC_PKCS7DecoderContext *p7dcx = (SEC_PKCS7DecoderContext *)arg;
   1.753 +
   1.754 +    SEC_PKCS7DecoderUpdate(p7dcx, data, len);
   1.755 +}
   1.756 +
   1.757 +/* notify function for decoding aSafes.  at the beginning,
   1.758 + * of an authenticatedSafe, we start a decode of a safeContents.
   1.759 + * at the end, we clean up the safeContents decoder context and
   1.760 + * reset state variables 
   1.761 + */
   1.762 +static void
   1.763 +sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest, 
   1.764 +			       int real_depth)
   1.765 +{
   1.766 +    SEC_PKCS12DecoderContext *p12dcx;
   1.767 +    sec_PKCS12SafeContentsContext *safeContentsCtx;
   1.768 +
   1.769 +    /* make sure no error occurred. */
   1.770 +    p12dcx = (SEC_PKCS12DecoderContext *)arg;
   1.771 +    if(!p12dcx || p12dcx->error) {
   1.772 +	return;
   1.773 +    }
   1.774 +
   1.775 +    if(before) {
   1.776 +
   1.777 +	/* init a new safeContentsContext */
   1.778 +	safeContentsCtx = sec_pkcs12_decoder_safe_contents_init_decode(p12dcx, 
   1.779 +								PR_FALSE);
   1.780 +	if(!safeContentsCtx) {
   1.781 +	    goto loser;
   1.782 +	}
   1.783 +
   1.784 +	/* initiate the PKCS7ContentInfo decode */
   1.785 +	p12dcx->currentASafeP7Dcx = SEC_PKCS7DecoderStart(
   1.786 +				sec_pkcs12_decoder_safe_contents_callback,
   1.787 +				safeContentsCtx, 
   1.788 +				p12dcx->pwfn, p12dcx->pwfnarg,
   1.789 +				sec_pkcs12_decoder_get_decrypt_key, p12dcx,
   1.790 +				sec_pkcs12_decoder_decryption_allowed);
   1.791 +	if(!p12dcx->currentASafeP7Dcx) {
   1.792 +	    p12dcx->errorValue = PORT_GetError();
   1.793 +	    goto loser;
   1.794 +	}
   1.795 +	SEC_ASN1DecoderSetFilterProc(p12dcx->aSafeA1Dcx, 
   1.796 +				     sec_pkcs12_decoder_wrap_p7_update,
   1.797 +				     p12dcx->currentASafeP7Dcx, PR_TRUE);
   1.798 +    }
   1.799 +
   1.800 +    if(!before) {
   1.801 +	/* if one is being decoded, finish the decode */
   1.802 +	if(p12dcx->currentASafeP7Dcx != NULL) {
   1.803 +	    SEC_PKCS7ContentInfo * cinfo;
   1.804 +	    unsigned int cnt = p12dcx->safeContentsCnt - 1;
   1.805 +	    safeContentsCtx = p12dcx->safeContentsList[cnt];
   1.806 +	    if (safeContentsCtx->safeContentsA1Dcx) {
   1.807 +		SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   1.808 +		safeContentsCtx->safeContentsA1Dcx = NULL;
   1.809 +	    }
   1.810 +	    cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
   1.811 +	    p12dcx->currentASafeP7Dcx = NULL;
   1.812 +	    if(!cinfo) {
   1.813 +		p12dcx->errorValue = PORT_GetError();
   1.814 +		goto loser;
   1.815 +	    }
   1.816 +	    SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
   1.817 +	}
   1.818 +    }
   1.819 +
   1.820 +
   1.821 +    return;
   1.822 +
   1.823 +loser:
   1.824 +    /* set the error flag */
   1.825 +    p12dcx->error = PR_TRUE;
   1.826 +    return;
   1.827 +}
   1.828 +
   1.829 +/* wrapper for updating asafes decoding context.  this function
   1.830 + * writes data being decoded to disk, so that a mac can be computed
   1.831 + * later.  
   1.832 + */
   1.833 +static void
   1.834 +sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf, 
   1.835 +				  unsigned long len)
   1.836 +{
   1.837 +    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
   1.838 +    SECStatus rv;
   1.839 +
   1.840 +    if(!p12dcx || p12dcx->error) {
   1.841 +	return;
   1.842 +    }
   1.843 +
   1.844 +    /* update the context */
   1.845 +    rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeA1Dcx, buf, len);
   1.846 +    if(rv != SECSuccess) {
   1.847 +	p12dcx->errorValue = PORT_GetError();
   1.848 +	p12dcx->error = PR_TRUE;
   1.849 +	goto loser;
   1.850 +    }
   1.851 +
   1.852 +    /* if we are writing to a file, write out the new information */
   1.853 +    if(p12dcx->dWrite) {
   1.854 +	unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg, 	
   1.855 +						   (unsigned char *)buf, len);
   1.856 +	if(writeLen != len) {
   1.857 +	    p12dcx->errorValue = PORT_GetError();
   1.858 +	    goto loser;
   1.859 +	}
   1.860 +    }
   1.861 +
   1.862 +    return;
   1.863 +
   1.864 +loser:
   1.865 +    /* set the error flag */
   1.866 +    p12dcx->error = PR_TRUE;
   1.867 +    SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
   1.868 +    p12dcx->aSafeA1Dcx = NULL;
   1.869 +
   1.870 +    return;
   1.871 +}
   1.872 +   
   1.873 +/* start the decode of an authenticatedSafe contentInfo.
   1.874 + */ 
   1.875 +static SECStatus
   1.876 +sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx)
   1.877 +{
   1.878 +    if(!p12dcx || p12dcx->error) {
   1.879 +	return SECFailure;
   1.880 +    }
   1.881 +
   1.882 +    /* start the decode context */
   1.883 +    p12dcx->aSafeA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, 
   1.884 +    					&p12dcx->authSafe,
   1.885 +    					sec_PKCS12AuthenticatedSafeTemplate);
   1.886 +    if(!p12dcx->aSafeA1Dcx) {
   1.887 +	p12dcx->errorValue = PORT_GetError();
   1.888 +   	goto loser;
   1.889 +    }
   1.890 +
   1.891 +    /* set the notify function */
   1.892 +    SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeA1Dcx,
   1.893 +    				 sec_pkcs12_decoder_asafes_notify, p12dcx);
   1.894 +
   1.895 +    /* begin the authSafe decoder context */
   1.896 +    p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart(
   1.897 +    				sec_pkcs12_decoder_asafes_callback, p12dcx,
   1.898 +    				p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL);
   1.899 +    if(!p12dcx->aSafeP7Dcx) {
   1.900 +	p12dcx->errorValue = PORT_GetError();
   1.901 +	goto loser;
   1.902 +    }
   1.903 +  
   1.904 +    /* open the temp file for writing, if the digest functions were set */ 
   1.905 +    if(p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE) 
   1.906 +				!= SECSuccess) {
   1.907 +	p12dcx->errorValue = PORT_GetError();
   1.908 +	goto loser;
   1.909 +    }
   1.910 +    /* dOpen(dArg, PR_FALSE) creates the temp file */
   1.911 +    p12dcx->dIsOpen = PR_TRUE;
   1.912 +
   1.913 +    return SECSuccess;
   1.914 +
   1.915 +loser:
   1.916 +    p12dcx->error = PR_TRUE;
   1.917 +
   1.918 +    if(p12dcx->aSafeA1Dcx) {
   1.919 +	SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
   1.920 +	p12dcx->aSafeA1Dcx = NULL;
   1.921 +    } 
   1.922 +
   1.923 +    if(p12dcx->aSafeP7Dcx) {
   1.924 +	SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
   1.925 +	p12dcx->aSafeP7Dcx = NULL;
   1.926 +    }
   1.927 +
   1.928 +    return SECFailure;
   1.929 +}
   1.930 +
   1.931 +/* wrapper for updating the safeContents.  this function is used as
   1.932 + * a filter for the pfx when decoding the authenticated safes 
   1.933 + */
   1.934 +static void 
   1.935 +sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf,
   1.936 +				      unsigned long len, int depth,
   1.937 +				      SEC_ASN1EncodingPart data_kind)
   1.938 +{
   1.939 +    SEC_PKCS12DecoderContext *p12dcx;
   1.940 +    SECStatus rv;
   1.941 +
   1.942 +    p12dcx = (SEC_PKCS12DecoderContext*)arg;
   1.943 +    if(!p12dcx || p12dcx->error) {
   1.944 +	return;
   1.945 +    }
   1.946 +
   1.947 +    /* update the safeContents decoder */
   1.948 +    rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len);
   1.949 +    if(rv != SECSuccess) {
   1.950 +	p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
   1.951 +	goto loser;
   1.952 +    }
   1.953 +
   1.954 +    return;
   1.955 +
   1.956 +loser:
   1.957 +
   1.958 +    /* did we find an error?  if so, close the context and set the 
   1.959 +     * error flag.
   1.960 +     */
   1.961 +    SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
   1.962 +    p12dcx->aSafeP7Dcx = NULL;
   1.963 +    p12dcx->error = PR_TRUE;
   1.964 +}
   1.965 +
   1.966 +/* notify procedure used while decoding the pfx.  When we encounter
   1.967 + * the authSafes, we want to trigger the decoding of authSafes as well
   1.968 + * as when we encounter the macData, trigger the decoding of it.  we do
   1.969 + * this because we we are streaming the decoder and not decoding in place.
   1.970 + * the pfx which is the destination, only has the version decoded into it.
   1.971 + */
   1.972 +static void 
   1.973 +sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest,
   1.974 +				   int real_depth)
   1.975 +{
   1.976 +    SECStatus rv;
   1.977 +    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext*)arg;
   1.978 +
   1.979 +    /* if an error occurs, clear the notifyProc and the filterProc 
   1.980 +     * and continue. 
   1.981 +     */
   1.982 +    if(p12dcx->error) {
   1.983 +	SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxA1Dcx);
   1.984 +	SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
   1.985 +	return;
   1.986 +    }
   1.987 +
   1.988 +    if(before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
   1.989 +
   1.990 +	/* we want to make sure this is a version we support */
   1.991 +	if(!sec_pkcs12_proper_version(&p12dcx->pfx)) {
   1.992 +	    p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
   1.993 +	    goto loser;
   1.994 +	}
   1.995 +
   1.996 +	/* start the decode of the aSafes cinfo... */
   1.997 +	rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx);
   1.998 +	if(rv != SECSuccess) {
   1.999 +	    goto loser;
  1.1000 +	}
  1.1001 +
  1.1002 +	/* set the filter proc to update the authenticated safes. */
  1.1003 +	SEC_ASN1DecoderSetFilterProc(p12dcx->pfxA1Dcx,
  1.1004 +				     sec_pkcs12_decode_asafes_cinfo_update,
  1.1005 +				     p12dcx, PR_TRUE);
  1.1006 +    }
  1.1007 +
  1.1008 +    if(!before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
  1.1009 +
  1.1010 +	/* we are done decoding the authenticatedSafes, so we need to 
  1.1011 +	 * finish the decoderContext and clear the filter proc
  1.1012 +	 * and close the hmac callback, if present
  1.1013 +	 */
  1.1014 +	p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
  1.1015 +	p12dcx->aSafeP7Dcx = NULL;
  1.1016 +	if(!p12dcx->aSafeCinfo) {
  1.1017 +	    p12dcx->errorValue = PORT_GetError();
  1.1018 +	    goto loser;
  1.1019 +	}
  1.1020 +	SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
  1.1021 +	if(p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) 
  1.1022 +				!= SECSuccess)) {
  1.1023 +	    p12dcx->errorValue = PORT_GetError();
  1.1024 +	    goto loser;
  1.1025 +	}
  1.1026 +
  1.1027 +    }
  1.1028 +
  1.1029 +    return;
  1.1030 +
  1.1031 +loser:
  1.1032 +    p12dcx->error = PR_TRUE;
  1.1033 +}
  1.1034 +
  1.1035 +/*  default implementations of the open/close/read/write functions for
  1.1036 +    SEC_PKCS12DecoderStart 
  1.1037 +*/
  1.1038 +
  1.1039 +#define DEFAULT_TEMP_SIZE 4096
  1.1040 +
  1.1041 +static SECStatus
  1.1042 +p12u_DigestOpen(void *arg, PRBool readData)
  1.1043 +{
  1.1044 +    SEC_PKCS12DecoderContext* p12cxt = arg;
  1.1045 +
  1.1046 +    p12cxt->currentpos = 0;
  1.1047 +
  1.1048 +    if (PR_FALSE == readData) {
  1.1049 +        /* allocate an initial buffer */
  1.1050 +        p12cxt->filesize = 0;
  1.1051 +        p12cxt->allocated = DEFAULT_TEMP_SIZE;
  1.1052 +        p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE);
  1.1053 +        PR_ASSERT(p12cxt->buffer);
  1.1054 +    }
  1.1055 +    else
  1.1056 +    {
  1.1057 +        PR_ASSERT(p12cxt->buffer);
  1.1058 +        if (!p12cxt->buffer) {
  1.1059 +            return SECFailure; /* no data to read */
  1.1060 +        }
  1.1061 +    }
  1.1062 +
  1.1063 +    return SECSuccess;
  1.1064 +}
  1.1065 +
  1.1066 +static SECStatus
  1.1067 +p12u_DigestClose(void *arg, PRBool removeFile)
  1.1068 +{
  1.1069 +    SEC_PKCS12DecoderContext* p12cxt = arg;
  1.1070 +
  1.1071 +    PR_ASSERT(p12cxt);
  1.1072 +    if (!p12cxt) {
  1.1073 +        return SECFailure;
  1.1074 +    }
  1.1075 +    p12cxt->currentpos = 0;
  1.1076 +
  1.1077 +    if (PR_TRUE == removeFile) {
  1.1078 +        PR_ASSERT(p12cxt->buffer);
  1.1079 +        if (!p12cxt->buffer) {
  1.1080 +            return SECFailure;
  1.1081 +        }
  1.1082 +        if (p12cxt->buffer) {
  1.1083 +            PORT_Free(p12cxt->buffer);
  1.1084 +            p12cxt->buffer = NULL;
  1.1085 +            p12cxt->allocated = 0;
  1.1086 +            p12cxt->filesize = 0;
  1.1087 +        }
  1.1088 +    }
  1.1089 +
  1.1090 +    return SECSuccess;
  1.1091 +}
  1.1092 +
  1.1093 +static int
  1.1094 +p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
  1.1095 +{
  1.1096 +    int toread = len;
  1.1097 +    SEC_PKCS12DecoderContext* p12cxt = arg;
  1.1098 +
  1.1099 +    if(!buf || len == 0 || !p12cxt->buffer) {
  1.1100 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1101 +	return -1;
  1.1102 +    }
  1.1103 +
  1.1104 +    if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
  1.1105 +        /* trying to read past the end of the buffer */
  1.1106 +        toread = p12cxt->filesize - p12cxt->currentpos;
  1.1107 +    }
  1.1108 +    memcpy(buf, (char*)p12cxt->buffer + p12cxt->currentpos, toread);
  1.1109 +    p12cxt->currentpos += toread;
  1.1110 +    return toread;
  1.1111 +}
  1.1112 +
  1.1113 +static int
  1.1114 +p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
  1.1115 +{
  1.1116 +    SEC_PKCS12DecoderContext* p12cxt = arg;
  1.1117 +
  1.1118 +    if(!buf || len == 0) {
  1.1119 +        return -1;
  1.1120 +    }
  1.1121 +
  1.1122 +    if (p12cxt->currentpos+(long)len > p12cxt->filesize) {
  1.1123 +        p12cxt->filesize = p12cxt->currentpos + len;
  1.1124 +    }
  1.1125 +    else {
  1.1126 +        p12cxt->filesize += len;
  1.1127 +    }
  1.1128 +    if (p12cxt->filesize > p12cxt->allocated) {
  1.1129 +        void* newbuffer;
  1.1130 +        size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE;
  1.1131 +        newbuffer  = PORT_Realloc(p12cxt->buffer, newsize);
  1.1132 +        if (NULL == newbuffer) {
  1.1133 +            return -1; /* can't extend the buffer */
  1.1134 +        }
  1.1135 +        p12cxt->buffer = newbuffer;
  1.1136 +        p12cxt->allocated = newsize;
  1.1137 +    }
  1.1138 +    PR_ASSERT(p12cxt->buffer);
  1.1139 +    memcpy((char*)p12cxt->buffer + p12cxt->currentpos, buf, len);
  1.1140 +    p12cxt->currentpos += len;
  1.1141 +    return len;
  1.1142 +}
  1.1143 +
  1.1144 +/* SEC_PKCS12DecoderStart
  1.1145 + *	Creates a decoder context for decoding a PKCS 12 PDU objct.
  1.1146 + *	This function sets up the initial decoding context for the
  1.1147 + *	PFX and sets the needed state variables.
  1.1148 + *
  1.1149 + *	pwitem - the password for the hMac and any encoded safes.
  1.1150 + *		 this should be changed to take a callback which retrieves
  1.1151 + *		 the password.  it may be possible for different safes to
  1.1152 + *		 have different passwords.  also, the password is already
  1.1153 + *		 in unicode.  it should probably be converted down below via
  1.1154 + *		 a unicode conversion callback.
  1.1155 + *	slot - the slot to import the dataa into should multiple slots 
  1.1156 + *		 be supported based on key type and cert type?
  1.1157 + *	dOpen, dClose, dRead, dWrite - digest routines for writing data
  1.1158 + *		 to a file so it could be read back and the hmac recomputed
  1.1159 + *		 and verified.  doesn't seem to be a way for both encoding
  1.1160 + *		 and decoding to be single pass, thus the need for these
  1.1161 + *		 routines.
  1.1162 + *	dArg - the argument for dOpen, etc.
  1.1163 + *
  1.1164 + *      if NULL == dOpen == dClose == dRead == dWrite == dArg, then default
  1.1165 + *      implementations using a memory buffer are used
  1.1166 + *
  1.1167 + *	This function returns the decoder context, if it was successful.
  1.1168 + *	Otherwise, null is returned.
  1.1169 + */
  1.1170 +SEC_PKCS12DecoderContext *
  1.1171 +SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
  1.1172 +		       digestOpenFn dOpen, digestCloseFn dClose, 
  1.1173 +		       digestIOFn dRead, digestIOFn dWrite, void *dArg)
  1.1174 +{
  1.1175 +    SEC_PKCS12DecoderContext *p12dcx;
  1.1176 +    PLArenaPool *arena;
  1.1177 +
  1.1178 +    arena = PORT_NewArena(2048); /* different size? */
  1.1179 +    if(!arena) {
  1.1180 +	return NULL;	/* error is already set */
  1.1181 +    }
  1.1182 +
  1.1183 +    /* allocate the decoder context and set the state variables */
  1.1184 +    p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
  1.1185 +    if(!p12dcx) {
  1.1186 +	goto loser;	/* error is already set */
  1.1187 +    }
  1.1188 +
  1.1189 +    if (!dOpen && !dClose && !dRead && !dWrite && !dArg) {
  1.1190 +        /* use default implementations */
  1.1191 +        dOpen = p12u_DigestOpen;
  1.1192 +        dClose = p12u_DigestClose;
  1.1193 +        dRead = p12u_DigestRead;
  1.1194 +        dWrite = p12u_DigestWrite;
  1.1195 +        dArg = (void*)p12dcx;
  1.1196 +    }
  1.1197 +
  1.1198 +    p12dcx->arena = arena;
  1.1199 +    p12dcx->pwitem = pwitem;
  1.1200 +    p12dcx->slot = (slot ? PK11_ReferenceSlot(slot) 
  1.1201 +						: PK11_GetInternalKeySlot());
  1.1202 +    p12dcx->wincx = wincx;
  1.1203 +    p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
  1.1204 +#ifdef IS_LITTLE_ENDIAN
  1.1205 +    p12dcx->swapUnicodeBytes = PR_TRUE;
  1.1206 +#else
  1.1207 +    p12dcx->swapUnicodeBytes = PR_FALSE;
  1.1208 +#endif
  1.1209 +    p12dcx->errorValue = 0;
  1.1210 +    p12dcx->error = PR_FALSE;
  1.1211 +
  1.1212 +    /* start the decoding of the PFX and set the notify proc
  1.1213 +     * for the PFX item.
  1.1214 +     */
  1.1215 +    p12dcx->pfxA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx,
  1.1216 +    					  sec_PKCS12PFXItemTemplate);
  1.1217 +    if(!p12dcx->pfxA1Dcx) {
  1.1218 +	PK11_FreeSlot(p12dcx->slot);
  1.1219 +	goto loser;
  1.1220 +    }
  1.1221 +
  1.1222 +    SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxA1Dcx, 
  1.1223 +				 sec_pkcs12_decoder_pfx_notify_proc,
  1.1224 +    				 p12dcx); 
  1.1225 +    
  1.1226 +    /* set up digest functions */
  1.1227 +    p12dcx->dOpen = dOpen;
  1.1228 +    p12dcx->dWrite = dWrite;
  1.1229 +    p12dcx->dClose = dClose;
  1.1230 +    p12dcx->dRead = dRead;
  1.1231 +    p12dcx->dArg = dArg;
  1.1232 +    p12dcx->dIsOpen = PR_FALSE;
  1.1233 +    
  1.1234 +    p12dcx->keyList = NULL;
  1.1235 +    p12dcx->decitem.type = 0;
  1.1236 +    p12dcx->decitem.der = NULL;
  1.1237 +    p12dcx->decitem.hasKey = PR_FALSE;
  1.1238 +    p12dcx->decitem.friendlyName = NULL;
  1.1239 +    p12dcx->iteration = 0;
  1.1240 +
  1.1241 +    return p12dcx;
  1.1242 +
  1.1243 +loser:
  1.1244 +    PORT_FreeArena(arena, PR_TRUE);
  1.1245 +    return NULL;
  1.1246 +}
  1.1247 +
  1.1248 +SECStatus
  1.1249 +SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx,
  1.1250 +		SECPKCS12TargetTokenCAs tokenCAs)
  1.1251 +{
  1.1252 +    if (!p12dcx || p12dcx->error) {
  1.1253 +	return SECFailure;
  1.1254 +    }
  1.1255 +    p12dcx->tokenCAs = tokenCAs;
  1.1256 +    return SECSuccess;
  1.1257 +}
  1.1258 +
  1.1259 +
  1.1260 +/* SEC_PKCS12DecoderUpdate 
  1.1261 + *	Streaming update sending more data to the decoder.  If 
  1.1262 + *	an error occurs, SECFailure is returned.
  1.1263 + *
  1.1264 + *	p12dcx - the decoder context 
  1.1265 + *	data, len - the data buffer and length of data to send to 
  1.1266 + *		the update functions.
  1.1267 + */
  1.1268 +SECStatus
  1.1269 +SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx,
  1.1270 +			unsigned char *data, unsigned long len)
  1.1271 +{
  1.1272 +    SECStatus rv;
  1.1273 +
  1.1274 +    if(!p12dcx || p12dcx->error) {
  1.1275 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1276 +	return SECFailure;
  1.1277 +    }
  1.1278 +
  1.1279 +    /* update the PFX decoder context */
  1.1280 +    rv = SEC_ASN1DecoderUpdate(p12dcx->pfxA1Dcx, (const char *)data, len);
  1.1281 +    if(rv != SECSuccess) {
  1.1282 +	p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
  1.1283 +	goto loser;
  1.1284 +    }
  1.1285 +
  1.1286 +    return SECSuccess;
  1.1287 +
  1.1288 +loser:
  1.1289 +
  1.1290 +    p12dcx->error = PR_TRUE;
  1.1291 +    return SECFailure;
  1.1292 +}
  1.1293 +
  1.1294 +/* This should be a nice sized buffer for reading in data (potentially large 
  1.1295 +** amounts) to be MACed.  It should be MUCH larger than HASH_LENGTH_MAX.
  1.1296 +*/
  1.1297 +#define IN_BUF_LEN	1024
  1.1298 +#ifdef DEBUG
  1.1299 +static const char bufferEnd[] = { "BufferEnd" } ;
  1.1300 +#endif
  1.1301 +#define FUDGE 128 /* must be as large as bufferEnd or more. */
  1.1302 +
  1.1303 +/* verify the hmac by reading the data from the temporary file
  1.1304 + * using the routines specified when the decodingContext was 
  1.1305 + * created and return SECSuccess if the hmac matches.
  1.1306 + */
  1.1307 +static SECStatus
  1.1308 +sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
  1.1309 +{
  1.1310 +    PK11Context *     pk11cx = NULL;
  1.1311 +    PK11SymKey *      symKey = NULL;
  1.1312 +    SECItem *         params = NULL;
  1.1313 +    unsigned char *   buf;
  1.1314 +    SECStatus         rv     = SECFailure;
  1.1315 +    SECStatus         lrv;
  1.1316 +    unsigned int      bufLen;
  1.1317 +    int               iteration;
  1.1318 +    int               bytesRead;
  1.1319 +    SECOidTag         algtag;
  1.1320 +    SECItem           hmacRes;
  1.1321 +    SECItem           ignore = {0};
  1.1322 +    CK_MECHANISM_TYPE integrityMech;
  1.1323 +    
  1.1324 +    if(!p12dcx || p12dcx->error) {
  1.1325 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1326 +	return SECFailure;
  1.1327 +    }
  1.1328 +    buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE);
  1.1329 +    if (!buf)
  1.1330 +    	return SECFailure;  /* error code has been set. */
  1.1331 +
  1.1332 +#ifdef DEBUG
  1.1333 +    memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd);
  1.1334 +#endif
  1.1335 +
  1.1336 +    /* generate hmac key */
  1.1337 +    if(p12dcx->macData.iter.data) {
  1.1338 +	iteration = (int)DER_GetInteger(&p12dcx->macData.iter);
  1.1339 +    } else {
  1.1340 +	iteration = 1;
  1.1341 +    }
  1.1342 +
  1.1343 +    params = PK11_CreatePBEParams(&p12dcx->macData.macSalt, p12dcx->pwitem,
  1.1344 +                                  iteration);
  1.1345 +
  1.1346 +    algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm);
  1.1347 +    switch (algtag) {
  1.1348 +    case SEC_OID_SHA1:
  1.1349 +	integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break;
  1.1350 +    case SEC_OID_MD5:
  1.1351 +	integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN;  break;
  1.1352 +    case SEC_OID_MD2:
  1.1353 +	integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN;  break;
  1.1354 +    default:
  1.1355 +	goto loser;
  1.1356 +    }
  1.1357 +
  1.1358 +    symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL);
  1.1359 +    PK11_DestroyPBEParams(params);
  1.1360 +    params = NULL;
  1.1361 +    if (!symKey) goto loser;
  1.1362 +    /* init hmac */
  1.1363 +    pk11cx = PK11_CreateContextBySymKey(sec_pkcs12_algtag_to_mech(algtag),
  1.1364 +                                        CKA_SIGN, symKey, &ignore);
  1.1365 +    if(!pk11cx) {
  1.1366 +	goto loser;
  1.1367 +    }
  1.1368 +    lrv = PK11_DigestBegin(pk11cx);
  1.1369 +    if (lrv == SECFailure ) {
  1.1370 +	goto loser;
  1.1371 +    }
  1.1372 +
  1.1373 +    /* try to open the data for readback */
  1.1374 +    if(p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) 
  1.1375 +			!= SECSuccess)) {
  1.1376 +	goto loser;
  1.1377 +    }
  1.1378 +
  1.1379 +    /* read the data back IN_BUF_LEN bytes at a time and recompute
  1.1380 +     * the hmac.  if fewer bytes are read than are requested, it is
  1.1381 +     * assumed that the end of file has been reached. if bytesRead
  1.1382 +     * is returned as -1, then an error occurred reading from the 
  1.1383 +     * file.
  1.1384 +     */
  1.1385 +    do {
  1.1386 +	bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN);
  1.1387 +	if (bytesRead < 0) {
  1.1388 +	    PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ);
  1.1389 +	    goto loser;
  1.1390 +	}
  1.1391 +	PORT_Assert(bytesRead <= IN_BUF_LEN);
  1.1392 +	PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd));
  1.1393 +
  1.1394 +	if (bytesRead > IN_BUF_LEN) {
  1.1395 +	    /* dRead callback overflowed buffer. */
  1.1396 +	    PORT_SetError(SEC_ERROR_INPUT_LEN);
  1.1397 +	    goto loser;
  1.1398 +	}
  1.1399 +
  1.1400 +	if (bytesRead) {
  1.1401 +	    lrv = PK11_DigestOp(pk11cx, buf, bytesRead);
  1.1402 +	    if (lrv == SECFailure) {
  1.1403 +		goto loser;
  1.1404 +	    }
  1.1405 +    	}
  1.1406 +    } while (bytesRead == IN_BUF_LEN);
  1.1407 +
  1.1408 +    /* finish the hmac context */
  1.1409 +    lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN);
  1.1410 +    if (lrv == SECFailure ) {
  1.1411 +	goto loser;
  1.1412 +    }
  1.1413 +
  1.1414 +    hmacRes.data = buf;
  1.1415 +    hmacRes.len = bufLen;
  1.1416 +
  1.1417 +    /* is the hmac computed the same as the hmac which was decoded? */
  1.1418 +    rv = SECSuccess;
  1.1419 +    if(SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) 
  1.1420 +			!= SECEqual) {
  1.1421 +	PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
  1.1422 +	rv = SECFailure;
  1.1423 +    }
  1.1424 +
  1.1425 +loser:
  1.1426 +    /* close the file and remove it */
  1.1427 +    if(p12dcx->dClose) {
  1.1428 +	(*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
  1.1429 +	p12dcx->dIsOpen = PR_FALSE;
  1.1430 +    }
  1.1431 +
  1.1432 +    if(pk11cx) {
  1.1433 +	PK11_DestroyContext(pk11cx, PR_TRUE);
  1.1434 +    }
  1.1435 +    if (params) {
  1.1436 +	PK11_DestroyPBEParams(params);
  1.1437 +    }
  1.1438 +    if (symKey) {
  1.1439 +	PK11_FreeSymKey(symKey);
  1.1440 +    }
  1.1441 +    PORT_ZFree(buf, IN_BUF_LEN + FUDGE);
  1.1442 +
  1.1443 +    return rv;
  1.1444 +}
  1.1445 +
  1.1446 +/* SEC_PKCS12DecoderVerify
  1.1447 + * 	Verify the macData or the signature of the decoded PKCS 12 PDU.
  1.1448 + *	If the signature or the macData do not match, SECFailure is
  1.1449 + *	returned.
  1.1450 + *
  1.1451 + * 	p12dcx - the decoder context 
  1.1452 + */
  1.1453 +SECStatus
  1.1454 +SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx)
  1.1455 +{
  1.1456 +    SECStatus rv = SECSuccess;
  1.1457 +
  1.1458 +    /* make sure that no errors have occurred... */
  1.1459 +    if(!p12dcx) {
  1.1460 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1461 +	return SECFailure;
  1.1462 +    }
  1.1463 +    if(p12dcx->error) {
  1.1464 +	/* error code is already set! PORT_SetError(p12dcx->errorValue); */
  1.1465 +	return SECFailure;
  1.1466 +    }
  1.1467 +
  1.1468 +    rv = SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
  1.1469 +    p12dcx->pfxA1Dcx = NULL;
  1.1470 +    if(rv != SECSuccess) {
  1.1471 +	return rv;
  1.1472 +    }
  1.1473 +
  1.1474 +    /* check the signature or the mac depending on the type of
  1.1475 +     * integrity used.
  1.1476 +     */
  1.1477 +    if(p12dcx->pfx.encodedMacData.len) {
  1.1478 +	rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData,
  1.1479 +				sec_PKCS12MacDataTemplate,
  1.1480 +				&p12dcx->pfx.encodedMacData);
  1.1481 +	if(rv == SECSuccess) {
  1.1482 +	    return sec_pkcs12_decoder_verify_mac(p12dcx);
  1.1483 +	}
  1.1484 +	return rv;
  1.1485 +    } 
  1.1486 +    if (SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner, 
  1.1487 +                                 PR_FALSE)) {
  1.1488 +	return SECSuccess;
  1.1489 +    } 
  1.1490 +    PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
  1.1491 +    return SECFailure;
  1.1492 +}
  1.1493 +
  1.1494 +/* SEC_PKCS12DecoderFinish
  1.1495 + *	Free any open ASN1 or PKCS7 decoder contexts and then
  1.1496 + *	free the arena pool which everything should be allocated
  1.1497 + *	from.  This function should be called upon completion of
  1.1498 + *	decoding and installing of a pfx pdu.  This should be
  1.1499 + *	called even if an error occurs.
  1.1500 + *
  1.1501 + *	p12dcx - the decoder context
  1.1502 + */
  1.1503 +void
  1.1504 +SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
  1.1505 +{
  1.1506 +    unsigned int i;
  1.1507 +
  1.1508 +    if(!p12dcx) {
  1.1509 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1510 +	return;
  1.1511 +    }
  1.1512 +
  1.1513 +    if(p12dcx->pfxA1Dcx) {
  1.1514 +	SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
  1.1515 +	p12dcx->pfxA1Dcx = NULL;
  1.1516 +    }
  1.1517 +
  1.1518 +    if(p12dcx->aSafeA1Dcx) {
  1.1519 +	SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
  1.1520 +	p12dcx->aSafeA1Dcx = NULL;
  1.1521 +    }
  1.1522 +
  1.1523 +    /* cleanup any old ASN1 decoder contexts */
  1.1524 +    for (i = 0; i < p12dcx->safeContentsCnt; ++i) {
  1.1525 +	sec_PKCS12SafeContentsContext *safeContentsCtx, *nested;
  1.1526 +	safeContentsCtx = p12dcx->safeContentsList[i];
  1.1527 +	if (safeContentsCtx) {
  1.1528 +	    nested = safeContentsCtx->nestedSafeContentsCtx;
  1.1529 +	    while (nested) {
  1.1530 +		if (nested->safeContentsA1Dcx) {
  1.1531 +		    SEC_ASN1DecoderFinish(nested->safeContentsA1Dcx);
  1.1532 +		    nested->safeContentsA1Dcx = NULL;
  1.1533 +		}
  1.1534 +		nested = nested->nestedSafeContentsCtx;
  1.1535 +	    }
  1.1536 +	    if (safeContentsCtx->safeContentsA1Dcx) {
  1.1537 +		SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
  1.1538 +		safeContentsCtx->safeContentsA1Dcx = NULL;
  1.1539 +	    }
  1.1540 +	}
  1.1541 +    }
  1.1542 +
  1.1543 +    if (p12dcx->currentASafeP7Dcx &&
  1.1544 +	p12dcx->currentASafeP7Dcx != p12dcx->aSafeP7Dcx) {
  1.1545 +	SEC_PKCS7ContentInfo * cinfo;
  1.1546 +	cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
  1.1547 +	if (cinfo) {
  1.1548 +	    SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
  1.1549 +	}
  1.1550 +    }
  1.1551 +    p12dcx->currentASafeP7Dcx = NULL;
  1.1552 +
  1.1553 +    if(p12dcx->aSafeP7Dcx) {
  1.1554 +	SEC_PKCS7ContentInfo * cinfo;
  1.1555 +	cinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
  1.1556 +	if (cinfo) {
  1.1557 +	    SEC_PKCS7DestroyContentInfo(cinfo);
  1.1558 +	}
  1.1559 +	p12dcx->aSafeP7Dcx = NULL;
  1.1560 +    }
  1.1561 +
  1.1562 +    if(p12dcx->aSafeCinfo) {
  1.1563 +	SEC_PKCS7DestroyContentInfo(p12dcx->aSafeCinfo);
  1.1564 +	p12dcx->aSafeCinfo = NULL;
  1.1565 +    }
  1.1566 +
  1.1567 +    if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
  1.1568 +        SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
  1.1569 +    }
  1.1570 +    if (p12dcx->decitem.friendlyName != NULL) {
  1.1571 +        SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
  1.1572 +    }
  1.1573 +
  1.1574 +    if(p12dcx->slot) {
  1.1575 +	PK11_FreeSlot(p12dcx->slot);
  1.1576 +	p12dcx->slot = NULL;
  1.1577 +    }
  1.1578 +
  1.1579 +    if(p12dcx->dIsOpen && p12dcx->dClose) {
  1.1580 +	(*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
  1.1581 +	p12dcx->dIsOpen = PR_FALSE;
  1.1582 +    }
  1.1583 +
  1.1584 +    if(p12dcx->arena) {
  1.1585 +	PORT_FreeArena(p12dcx->arena, PR_TRUE);
  1.1586 +    }
  1.1587 +}
  1.1588 +
  1.1589 +static SECStatus
  1.1590 +sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag,
  1.1591 +			       SECOidTag attributeType,
  1.1592 +			       SECItem *attrValue)
  1.1593 +{
  1.1594 +    int i = 0;
  1.1595 +    SECOidData *oid;
  1.1596 +
  1.1597 +    if(!bag || !attrValue) {
  1.1598 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1599 +	return SECFailure;
  1.1600 +    }
  1.1601 +
  1.1602 +    oid = SECOID_FindOIDByTag(attributeType);
  1.1603 +    if(!oid) {
  1.1604 +	return SECFailure;
  1.1605 +    }
  1.1606 +
  1.1607 +    if(!bag->attribs) {
  1.1608 +	bag->attribs = 
  1.1609 +		PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
  1.1610 +    } else {
  1.1611 +	while(bag->attribs[i]) 
  1.1612 +	    i++;
  1.1613 +	bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs, 
  1.1614 +				           sec_PKCS12Attribute *, i + 1, i + 2);
  1.1615 +    }
  1.1616 +
  1.1617 +    if(!bag->attribs) {
  1.1618 +	return SECFailure;
  1.1619 +    }
  1.1620 +
  1.1621 +    bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
  1.1622 +    if(!bag->attribs) {
  1.1623 +	return SECFailure;
  1.1624 +    }
  1.1625 +
  1.1626 +    bag->attribs[i]->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
  1.1627 +    if(!bag->attribs[i]->attrValue) {
  1.1628 +	return SECFailure;
  1.1629 +    }
  1.1630 +
  1.1631 +    bag->attribs[i+1] = NULL;
  1.1632 +    bag->attribs[i]->attrValue[0] = attrValue;
  1.1633 +    bag->attribs[i]->attrValue[1] = NULL;
  1.1634 +
  1.1635 +    return SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid);
  1.1636 +}
  1.1637 +
  1.1638 +static SECItem *
  1.1639 +sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag,
  1.1640 +			       SECOidTag attributeType)
  1.1641 +{
  1.1642 +    int i;
  1.1643 +
  1.1644 +    if(!bag->attribs) {
  1.1645 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1646 +	return NULL;
  1.1647 +    }
  1.1648 +
  1.1649 +    for (i = 0; bag->attribs[i] != NULL; i++) {
  1.1650 +	if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == attributeType) {
  1.1651 +	    return bag->attribs[i]->attrValue[0];
  1.1652 +	}
  1.1653 +    }
  1.1654 +    return NULL;
  1.1655 +}
  1.1656 +
  1.1657 +/* For now, this function will merely remove any ":"
  1.1658 + * in the nickname which the PK11 functions may have
  1.1659 + * placed there.  This will keep dual certs from appearing
  1.1660 + * twice under "Your" certificates when imported onto smart
  1.1661 + * cards.  Once with the name "Slot:Cert" and another with
  1.1662 + * the nickname "Slot:Slot:Cert"
  1.1663 + */
  1.1664 +static void
  1.1665 +sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
  1.1666 +{
  1.1667 +    char *nickname;
  1.1668 +    char *delimit;
  1.1669 +    int delimitlen;
  1.1670 + 
  1.1671 +    nickname = (char*)nick->data;
  1.1672 +    if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
  1.1673 +        char *slotName;
  1.1674 +	int slotNameLen;
  1.1675 +
  1.1676 +	slotNameLen = delimit-nickname;
  1.1677 +	slotName = PORT_NewArray(char, (slotNameLen+1));
  1.1678 +	PORT_Assert(slotName);
  1.1679 +	if (slotName == NULL) {
  1.1680 +	  /* What else can we do?*/
  1.1681 +	  return;
  1.1682 +	}
  1.1683 +	PORT_Memcpy(slotName, nickname, slotNameLen);
  1.1684 +	slotName[slotNameLen] = '\0';
  1.1685 +	if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
  1.1686 +	  delimitlen = PORT_Strlen(delimit+1);
  1.1687 +	  PORT_Memmove(nickname, delimit+1, delimitlen+1);
  1.1688 +	  nick->len = delimitlen;
  1.1689 +	}
  1.1690 +	PORT_Free(slotName);
  1.1691 +    }
  1.1692 + 
  1.1693 +}
  1.1694 +
  1.1695 +static SECItem *
  1.1696 +sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag)
  1.1697 +{
  1.1698 +    SECItem *src, *dest;
  1.1699 +
  1.1700 +    if(!bag) {
  1.1701 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1702 +	return NULL;
  1.1703 +    }
  1.1704 +
  1.1705 +    src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
  1.1706 +
  1.1707 +    /* The return value src is 16-bit Unicode characters, in big-endian format.
  1.1708 +     * Check if it is NULL or empty name.
  1.1709 +     */
  1.1710 +    if(!src || !src->data || src->len < 2 || (!src->data[0] && !src->data[1])) {
  1.1711 +	return NULL;
  1.1712 +    }
  1.1713 +
  1.1714 +    dest = (SECItem*)PORT_ZAlloc(sizeof(SECItem));
  1.1715 +    if(!dest) { 
  1.1716 +	goto loser;
  1.1717 +    }
  1.1718 +    if(!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE, 
  1.1719 +				PR_FALSE, PR_FALSE)) {
  1.1720 +	goto loser;
  1.1721 +    }
  1.1722 +
  1.1723 +    sec_pkcs12_sanitize_nickname(bag->slot, dest);
  1.1724 +
  1.1725 +    return dest;
  1.1726 +
  1.1727 +loser:
  1.1728 +    if(dest) {
  1.1729 +	SECITEM_ZfreeItem(dest, PR_TRUE);
  1.1730 +    }
  1.1731 +
  1.1732 +    bag->problem = PR_TRUE;
  1.1733 +    bag->error = PORT_GetError();
  1.1734 +    return NULL;
  1.1735 +}
  1.1736 +
  1.1737 +static SECStatus
  1.1738 +sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name)
  1.1739 +{
  1.1740 +    sec_PKCS12Attribute *attr = NULL;
  1.1741 +    SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME);
  1.1742 +
  1.1743 +    if(!bag || !bag->arena || !name) {
  1.1744 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1745 +	return SECFailure;
  1.1746 +    }
  1.1747 +	
  1.1748 +    if(!bag->attribs) {
  1.1749 +	if(!oid) {
  1.1750 +	    goto loser;
  1.1751 +	}
  1.1752 +
  1.1753 +	bag->attribs = 
  1.1754 +	    PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
  1.1755 +	if(!bag->attribs) {
  1.1756 +	    goto loser;
  1.1757 +	}
  1.1758 +	bag->attribs[0] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
  1.1759 +	if(!bag->attribs[0]) {
  1.1760 +	    goto loser;
  1.1761 +	}
  1.1762 +	bag->attribs[1] = NULL;
  1.1763 +
  1.1764 +	attr = bag->attribs[0];
  1.1765 +	if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) 
  1.1766 +			!= SECSuccess) {
  1.1767 +	    goto loser;
  1.1768 +	}
  1.1769 +    } else {
  1.1770 +	int i;
  1.1771 +	for (i = 0; bag->attribs[i]; i++) {
  1.1772 +	    if(SECOID_FindOIDTag(&bag->attribs[i]->attrType)
  1.1773 +			== SEC_OID_PKCS9_FRIENDLY_NAME) {
  1.1774 +		attr = bag->attribs[i];
  1.1775 +		break;
  1.1776 +	    }
  1.1777 +	}
  1.1778 +	if(!attr) {
  1.1779 +	    if(!oid) {
  1.1780 +		goto loser;
  1.1781 +	    }
  1.1782 +	    bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
  1.1783 +					       sec_PKCS12Attribute *, i+1, i+2);
  1.1784 +	    if(!bag->attribs) {
  1.1785 +		goto loser;
  1.1786 +	    }
  1.1787 +	    bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
  1.1788 +	    if(!bag->attribs[i]) {
  1.1789 +		goto loser;
  1.1790 +	    }
  1.1791 +	    bag->attribs[i+1] = NULL;
  1.1792 +	    attr = bag->attribs[i];
  1.1793 +	    if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) 
  1.1794 +				!= SECSuccess) {
  1.1795 +		goto loser;
  1.1796 +	    }
  1.1797 +	}
  1.1798 +    }
  1.1799 +
  1.1800 +    PORT_Assert(attr);
  1.1801 +    if(!attr->attrValue) {
  1.1802 +	attr->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
  1.1803 +	if(!attr->attrValue) {
  1.1804 +	    goto loser;
  1.1805 +	}
  1.1806 +	attr->attrValue[0] = PORT_ArenaZNew(bag->arena, SECItem);
  1.1807 +	if(!attr->attrValue[0]) {
  1.1808 +	    goto loser;
  1.1809 +	}
  1.1810 +	attr->attrValue[1] = NULL;
  1.1811 +    }
  1.1812 +
  1.1813 +    name->len = PORT_Strlen((char *)name->data);
  1.1814 +    if(!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0],
  1.1815 +				name, PR_FALSE, PR_FALSE, PR_TRUE)) {
  1.1816 +	goto loser;
  1.1817 +    }
  1.1818 +
  1.1819 +    return SECSuccess;
  1.1820 +
  1.1821 +loser:
  1.1822 +    bag->problem = PR_TRUE;
  1.1823 +    bag->error = PORT_GetError();
  1.1824 +    return SECFailure;
  1.1825 +}
  1.1826 +	
  1.1827 +static SECStatus
  1.1828 +sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key) 
  1.1829 +{
  1.1830 +    int i = 0;
  1.1831 +    SECKEYPrivateKeyInfo *pki = NULL;
  1.1832 +
  1.1833 +    if(!key) {
  1.1834 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1835 +	return SECFailure;
  1.1836 +    }
  1.1837 +
  1.1838 +    /* if the bag does *not* contain an unencrypted PrivateKeyInfo 
  1.1839 +     * then we cannot convert the attributes.  We are propagating
  1.1840 +     * attributes within the PrivateKeyInfo to the SafeBag level.
  1.1841 +     */
  1.1842 +    if(SECOID_FindOIDTag(&(key->safeBagType)) != 
  1.1843 +			SEC_OID_PKCS12_V1_KEY_BAG_ID) {
  1.1844 +	return SECSuccess;
  1.1845 +    }
  1.1846 +
  1.1847 +    pki = key->safeBagContent.pkcs8KeyBag;
  1.1848 +
  1.1849 +    if(!pki || !pki->attributes) {
  1.1850 +	return SECSuccess;
  1.1851 +    }
  1.1852 +
  1.1853 +    while(pki->attributes[i]) {
  1.1854 +	SECOidTag tag = SECOID_FindOIDTag(&pki->attributes[i]->attrType);
  1.1855 +
  1.1856 +	if (tag == SEC_OID_PKCS9_LOCAL_KEY_ID ||
  1.1857 +	    tag == SEC_OID_PKCS9_FRIENDLY_NAME) {
  1.1858 +	    SECItem *attrValue = sec_pkcs12_get_attribute_value(key, tag);
  1.1859 +	    if(!attrValue) {
  1.1860 +		if(sec_pkcs12_decoder_set_attribute_value(key, tag,
  1.1861 +					pki->attributes[i]->attrValue[0])
  1.1862 +					!= SECSuccess) {
  1.1863 +		    key->problem = PR_TRUE;
  1.1864 +		    key->error = PORT_GetError();
  1.1865 +		    return SECFailure;
  1.1866 +		}
  1.1867 +	    }
  1.1868 +	}
  1.1869 +	i++;
  1.1870 +    }
  1.1871 +
  1.1872 +    return SECSuccess;
  1.1873 +}
  1.1874 +
  1.1875 +/* retrieve the nickname for the certificate bag.  first look
  1.1876 + * in the cert bag, otherwise get it from the key.
  1.1877 + */
  1.1878 +static SECItem *
  1.1879 +sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert,
  1.1880 +				 sec_PKCS12SafeBag *key)
  1.1881 +{
  1.1882 +    SECItem *nickname;
  1.1883 +
  1.1884 +    if(!cert) {
  1.1885 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1886 +	return NULL;
  1.1887 +    }
  1.1888 +
  1.1889 +    nickname = sec_pkcs12_get_nickname(cert);
  1.1890 +    if(nickname) {
  1.1891 +	return nickname;
  1.1892 +    }
  1.1893 +
  1.1894 +    if(key) {
  1.1895 +	nickname = sec_pkcs12_get_nickname(key);
  1.1896 +	
  1.1897 +        if(nickname && sec_pkcs12_set_nickname(cert, nickname)
  1.1898 +			!= SECSuccess) {
  1.1899 +	    SECITEM_ZfreeItem(nickname, PR_TRUE);
  1.1900 +	    return NULL;
  1.1901 +	}
  1.1902 +    }
  1.1903 +
  1.1904 +    return nickname;
  1.1905 +}
  1.1906 +
  1.1907 +/* set the nickname for the certificate */
  1.1908 +static SECStatus
  1.1909 +sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert, 
  1.1910 +				 sec_PKCS12SafeBag *key, 
  1.1911 +				 SECItem *nickname)
  1.1912 +{
  1.1913 +    if(!nickname || !cert) {
  1.1914 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1915 +	return SECFailure;
  1.1916 +    }
  1.1917 +
  1.1918 +    if(sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
  1.1919 +	return SECFailure;
  1.1920 +    }
  1.1921 +
  1.1922 +    if(key) {
  1.1923 +	if(sec_pkcs12_set_nickname(key, nickname) != SECSuccess) {
  1.1924 +	    cert->problem = PR_TRUE;
  1.1925 +	    cert->error   = key->error;
  1.1926 +	    return SECFailure;
  1.1927 +	}
  1.1928 +    }
  1.1929 +
  1.1930 +    return SECSuccess;
  1.1931 +}
  1.1932 +
  1.1933 +/* retrieve the DER cert from the cert bag */
  1.1934 +static SECItem *
  1.1935 +sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert) 
  1.1936 +{
  1.1937 +    if(!cert) {
  1.1938 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1939 +	return NULL;
  1.1940 +    }
  1.1941 +
  1.1942 +    if(SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) {
  1.1943 +	return NULL;
  1.1944 +    }
  1.1945 +
  1.1946 +    /* only support X509 certs not SDSI */
  1.1947 +    if(SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID) 
  1.1948 +			!= SEC_OID_PKCS9_X509_CERT) {
  1.1949 +	return NULL;
  1.1950 +    }
  1.1951 +			
  1.1952 +    return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert));
  1.1953 +}
  1.1954 +
  1.1955 +struct certNickInfo {
  1.1956 +    PLArenaPool *arena;
  1.1957 +    unsigned int nNicks;
  1.1958 +    SECItem **nickList;
  1.1959 +    unsigned int error;
  1.1960 +};
  1.1961 +
  1.1962 +/* callback for traversing certificates to gather the nicknames 
  1.1963 + * used in a particular traversal.  for instance, when using
  1.1964 + * CERT_TraversePermCertsForSubject, gather the nicknames and
  1.1965 + * store them in the certNickInfo for a particular DN.
  1.1966 + * 
  1.1967 + * this handles the case where multiple nicknames are allowed
  1.1968 + * for the same dn, which is not currently allowed, but may be
  1.1969 + * in the future.
  1.1970 + */ 
  1.1971 +static SECStatus
  1.1972 +gatherNicknames(CERTCertificate *cert, void *arg)
  1.1973 +{
  1.1974 +    struct certNickInfo *nickArg = (struct certNickInfo *)arg;
  1.1975 +    SECItem tempNick;
  1.1976 +    unsigned int i;
  1.1977 +
  1.1978 +    if(!cert || !nickArg || nickArg->error) {
  1.1979 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1980 +	return SECFailure;
  1.1981 +    }
  1.1982 +
  1.1983 +    if(!cert->nickname) {
  1.1984 +	return SECSuccess;
  1.1985 +    }
  1.1986 +
  1.1987 +    tempNick.data = (unsigned char *)cert->nickname;
  1.1988 +    tempNick.len = PORT_Strlen(cert->nickname) + 1;
  1.1989 +
  1.1990 +    /* do we already have the nickname in the list? */
  1.1991 +    if(nickArg->nNicks > 0) {
  1.1992 +
  1.1993 +	/* nicknames have been encountered, but there is no list -- bad */
  1.1994 +	if(!nickArg->nickList) {
  1.1995 +	    nickArg->error = SEC_ERROR_INVALID_ARGS;
  1.1996 +	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1997 +	    return SECFailure;
  1.1998 +	}
  1.1999 +
  1.2000 +	for(i = 0; i < nickArg->nNicks; i++) {
  1.2001 +	    if(SECITEM_CompareItem(nickArg->nickList[i], &tempNick) 
  1.2002 +				== SECEqual) {
  1.2003 +		return SECSuccess;
  1.2004 +	    }
  1.2005 +	}
  1.2006 +    }
  1.2007 +
  1.2008 +    /* add the nickname to the list */
  1.2009 +    nickArg->nickList = (nickArg->nNicks == 0) 
  1.2010 +	? PORT_ArenaZNewArray(nickArg->arena, SECItem *, 2)
  1.2011 +	: PORT_ArenaGrowArray(nickArg->arena, nickArg->nickList, SECItem *, 
  1.2012 +	                      nickArg->nNicks + 1, nickArg->nNicks + 2);
  1.2013 +
  1.2014 +    if(!nickArg->nickList) {
  1.2015 +	nickArg->error = SEC_ERROR_NO_MEMORY;
  1.2016 +	return SECFailure;
  1.2017 +    }
  1.2018 +
  1.2019 +    nickArg->nickList[nickArg->nNicks] = 
  1.2020 +				    PORT_ArenaZNew(nickArg->arena, SECItem);
  1.2021 +    if(!nickArg->nickList[nickArg->nNicks]) {
  1.2022 +	nickArg->error = PORT_GetError();
  1.2023 +	return SECFailure;
  1.2024 +    }
  1.2025 +    
  1.2026 +
  1.2027 +    if(SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks],
  1.2028 +			&tempNick) != SECSuccess) {
  1.2029 +	nickArg->error = PORT_GetError();
  1.2030 +	return SECFailure;
  1.2031 +    }
  1.2032 +
  1.2033 +    nickArg->nNicks++;
  1.2034 +
  1.2035 +    return SECSuccess;
  1.2036 +}
  1.2037 +
  1.2038 +/* traverses the certs in the data base or in the token for the
  1.2039 + * DN to see if any certs currently have a nickname set.
  1.2040 + * If so, return it. 
  1.2041 + */
  1.2042 +static SECItem *
  1.2043 +sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert)
  1.2044 +{
  1.2045 +    struct certNickInfo *nickArg = NULL;
  1.2046 +    SECItem *derCert, *returnDn = NULL;
  1.2047 +    PLArenaPool *arena = NULL;
  1.2048 +    CERTCertificate *tempCert;
  1.2049 +
  1.2050 +    if(!cert) {
  1.2051 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2052 +	return NULL;
  1.2053 +    }
  1.2054 +
  1.2055 +    derCert = sec_pkcs12_get_der_cert(cert);
  1.2056 +    if(!derCert) {
  1.2057 +	return NULL;
  1.2058 +    }
  1.2059 +
  1.2060 +    tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
  1.2061 +    if(!tempCert) {
  1.2062 +	returnDn = NULL;
  1.2063 +	goto loser;
  1.2064 +    }
  1.2065 +
  1.2066 +    arena = PORT_NewArena(1024);
  1.2067 +    if(!arena) {
  1.2068 +	returnDn = NULL;
  1.2069 +	goto loser;
  1.2070 +    }
  1.2071 +    nickArg = PORT_ArenaZNew(arena, struct certNickInfo);
  1.2072 +    if(!nickArg) {
  1.2073 +	returnDn = NULL;
  1.2074 +	goto loser;
  1.2075 +    }
  1.2076 +    nickArg->error = 0;
  1.2077 +    nickArg->nNicks = 0;
  1.2078 +    nickArg->nickList = NULL;
  1.2079 +    nickArg->arena = arena;
  1.2080 +
  1.2081 +    /* if the token is local, first traverse the cert database 
  1.2082 +     * then traverse the token.
  1.2083 +     */
  1.2084 +    if(PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames,
  1.2085 +			(void *)nickArg) != SECSuccess) {
  1.2086 +	returnDn = NULL;
  1.2087 +	goto loser;
  1.2088 +    }
  1.2089 +
  1.2090 +    if(nickArg->error) {
  1.2091 +	/* XXX do we want to set the error? */
  1.2092 +	returnDn = NULL;
  1.2093 +	goto loser;
  1.2094 +    }
  1.2095 +		
  1.2096 +    if(nickArg->nNicks == 0) {
  1.2097 +	returnDn = NULL;
  1.2098 +	goto loser;
  1.2099 +    }
  1.2100 +
  1.2101 +    /* set it to the first name, for now.  handle multiple names? */
  1.2102 +    returnDn = SECITEM_DupItem(nickArg->nickList[0]);
  1.2103 +
  1.2104 +loser:
  1.2105 +    if(arena) {
  1.2106 +	PORT_FreeArena(arena, PR_TRUE);
  1.2107 +    }
  1.2108 +
  1.2109 +    if(tempCert) {
  1.2110 +	CERT_DestroyCertificate(tempCert);
  1.2111 +    }
  1.2112 +
  1.2113 +    if(derCert) {
  1.2114 +	SECITEM_FreeItem(derCert, PR_TRUE);
  1.2115 +    }
  1.2116 +
  1.2117 +    return (returnDn);
  1.2118 +}
  1.2119 +
  1.2120 +/* counts certificates found for a given traversal function */
  1.2121 +static SECStatus
  1.2122 +countCertificate(CERTCertificate *cert, void *arg)
  1.2123 +{
  1.2124 +    unsigned int *nCerts = (unsigned int *)arg;
  1.2125 +
  1.2126 +    if(!cert || !arg) {
  1.2127 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2128 +	return SECFailure;
  1.2129 +    }
  1.2130 +
  1.2131 +    (*nCerts)++;
  1.2132 +    return SECSuccess;
  1.2133 +}
  1.2134 +
  1.2135 +static PRBool
  1.2136 +sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot)
  1.2137 +{
  1.2138 +    unsigned int nCerts = 0;
  1.2139 +
  1.2140 +    if(!nickname || !slot) {
  1.2141 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2142 +	return PR_TRUE;
  1.2143 +    }
  1.2144 +
  1.2145 +    /* we want to check the local database first if we are importing to it */
  1.2146 +    PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate, 
  1.2147 +					(void *)&nCerts);
  1.2148 +    return (PRBool)(nCerts != 0);
  1.2149 +}
  1.2150 +
  1.2151 +/* validate cert nickname such that there is a one-to-one relation
  1.2152 + * between nicknames and dn's.  we want to enforce the case that the
  1.2153 + * nickname is non-NULL and that there is only one nickname per DN.
  1.2154 + * 
  1.2155 + * if there is a problem with a nickname or the nickname is not present, 
  1.2156 + * the user will be prompted for it.
  1.2157 + */
  1.2158 +static void
  1.2159 +sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,
  1.2160 +				sec_PKCS12SafeBag *key,
  1.2161 +				SEC_PKCS12NicknameCollisionCallback nicknameCb,
  1.2162 +				CERTCertificate *leafCert)
  1.2163 +{
  1.2164 +    SECItem *certNickname, *existingDNNick;
  1.2165 +    PRBool setNickname = PR_FALSE, cancel = PR_FALSE;
  1.2166 +    SECItem *newNickname = NULL;
  1.2167 +
  1.2168 +    if(!cert || !cert->hasKey) {
  1.2169 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2170 +	return;
  1.2171 +    }
  1.2172 +
  1.2173 +    if(!nicknameCb) {
  1.2174 +	cert->problem = PR_TRUE;
  1.2175 +	cert->error = SEC_ERROR_INVALID_ARGS;
  1.2176 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2177 +	return;
  1.2178 +    }
  1.2179 +
  1.2180 +    if(cert->hasKey && !key) {
  1.2181 +	cert->problem = PR_TRUE;
  1.2182 +	cert->error = SEC_ERROR_INVALID_ARGS;
  1.2183 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2184 +	return;
  1.2185 +    }
  1.2186 +
  1.2187 +    certNickname = sec_pkcs12_get_nickname_for_cert(cert, key);
  1.2188 +    existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert);
  1.2189 +
  1.2190 +    /* nickname is already used w/ this dn, so it is safe to return */
  1.2191 +    if(certNickname && existingDNNick &&
  1.2192 +		SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {
  1.2193 +	goto loser;
  1.2194 +    }
  1.2195 +
  1.2196 +    /* nickname not set in pkcs 12 bags, but a nick is already used for
  1.2197 +     * this dn.  set the nicks in the p12 bags and finish.
  1.2198 +     */
  1.2199 +    if(existingDNNick) {
  1.2200 +	sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick);
  1.2201 +	goto loser;
  1.2202 +    }
  1.2203 +
  1.2204 +    /* at this point, we have a certificate for which the DN is not located
  1.2205 +     * on the token.  the nickname specified may or may not be NULL.  if it
  1.2206 +     * is not null, we need to make sure that there are no other certificates
  1.2207 +     * with this nickname in the token for it to be valid.  this imposes a 
  1.2208 +     * one to one relationship between DN and nickname.  
  1.2209 +     *
  1.2210 +     * if the nickname is null, we need the user to enter a nickname for
  1.2211 +     * the certificate.
  1.2212 +     *
  1.2213 +     * once we have a nickname, we make sure that the nickname is unique
  1.2214 +     * for the DN.  if it is not, the user is reprompted to enter a new 
  1.2215 +     * nickname.  
  1.2216 +     *
  1.2217 +     * in order to exit this loop, the nickname entered is either unique
  1.2218 +     * or the user hits cancel and the certificate is not imported.
  1.2219 +     */
  1.2220 +    setNickname = PR_FALSE;
  1.2221 +    while(1) {
  1.2222 +	/* we will use the nickname so long as no other certs have the
  1.2223 +	 * same nickname.  and the nickname is not NULL.
  1.2224 +	 */		
  1.2225 +	if (certNickname && certNickname->data &&
  1.2226 +	    !sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {
  1.2227 +	    if (setNickname) {
  1.2228 +		sec_pkcs12_set_nickname_for_cert(cert, key, certNickname);
  1.2229 +	    }
  1.2230 +	    break;
  1.2231 +	}
  1.2232 +
  1.2233 +	setNickname = PR_FALSE;
  1.2234 +	newNickname = (*nicknameCb)(certNickname, &cancel, leafCert);
  1.2235 +	if(cancel) {
  1.2236 +	    cert->problem = PR_TRUE;
  1.2237 +	    cert->error = SEC_ERROR_USER_CANCELLED;
  1.2238 +	    break;
  1.2239 +	}
  1.2240 +
  1.2241 +	if(!newNickname) {
  1.2242 +	    cert->problem = PR_TRUE;
  1.2243 +	    cert->error = PORT_GetError();
  1.2244 +	    break;
  1.2245 +	}
  1.2246 +
  1.2247 +	/* at this point we have a new nickname, if we have an existing
  1.2248 +	 * certNickname, we need to free it and assign the new nickname
  1.2249 +	 * to it to avoid a memory leak.  happy?
  1.2250 +	 */
  1.2251 +	if(certNickname) {
  1.2252 +	    SECITEM_ZfreeItem(certNickname, PR_TRUE);
  1.2253 +	    certNickname = NULL;
  1.2254 +	}
  1.2255 +
  1.2256 +	certNickname = newNickname;
  1.2257 +	setNickname = PR_TRUE;
  1.2258 +	/* go back and recheck the new nickname */
  1.2259 +    }
  1.2260 +
  1.2261 +loser:
  1.2262 +    if(certNickname) {
  1.2263 +	SECITEM_ZfreeItem(certNickname, PR_TRUE);
  1.2264 +    }
  1.2265 +
  1.2266 +    if(existingDNNick) {
  1.2267 +	SECITEM_ZfreeItem(existingDNNick, PR_TRUE);
  1.2268 +    }
  1.2269 +}
  1.2270 +
  1.2271 +static void 
  1.2272 +sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,
  1.2273 +			 sec_PKCS12SafeBag *key,
  1.2274 +			 SEC_PKCS12NicknameCollisionCallback nicknameCb)
  1.2275 +{
  1.2276 +    CERTCertificate *leafCert;
  1.2277 +
  1.2278 +    if(!cert) {
  1.2279 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2280 +	return;
  1.2281 +    }
  1.2282 +    
  1.2283 +    cert->validated = PR_TRUE;
  1.2284 +
  1.2285 +    if(!nicknameCb) {
  1.2286 +	cert->noInstall = PR_TRUE;
  1.2287 +	cert->problem = PR_TRUE;
  1.2288 +	cert->error   = SEC_ERROR_INVALID_ARGS;
  1.2289 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2290 +	return;
  1.2291 +    }
  1.2292 +
  1.2293 +    if(!cert->safeBagContent.certBag) {
  1.2294 +	cert->noInstall = PR_TRUE;
  1.2295 +	cert->problem = PR_TRUE;
  1.2296 +	cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
  1.2297 +	return;
  1.2298 +    }
  1.2299 +
  1.2300 +    cert->noInstall = PR_FALSE;
  1.2301 +    cert->unused = PR_FALSE;
  1.2302 +    cert->problem = PR_FALSE;
  1.2303 +    cert->error = 0;
  1.2304 +
  1.2305 +    leafCert = CERT_DecodeDERCertificate(
  1.2306 +	 &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
  1.2307 +    if(!leafCert) {
  1.2308 +	cert->noInstall = PR_TRUE;
  1.2309 +	cert->problem = PR_TRUE;
  1.2310 +	cert->error = PORT_GetError();
  1.2311 +	return;
  1.2312 +    }
  1.2313 +
  1.2314 +    sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, leafCert);
  1.2315 +
  1.2316 +    CERT_DestroyCertificate(leafCert);
  1.2317 +}
  1.2318 +
  1.2319 +static void
  1.2320 +sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,
  1.2321 +				void *wincx)
  1.2322 +{
  1.2323 +    CERTCertificate *leafCert;
  1.2324 +    SECKEYPrivateKey *privk;
  1.2325 +
  1.2326 +    if(!key) {
  1.2327 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2328 +	return;
  1.2329 +    }
  1.2330 +
  1.2331 +    key->validated = PR_TRUE;
  1.2332 +
  1.2333 +    if(!cert) {
  1.2334 +	key->problem = PR_TRUE;
  1.2335 +	key->noInstall = PR_TRUE;
  1.2336 +	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  1.2337 +	return;
  1.2338 +    }
  1.2339 +
  1.2340 +    leafCert = CERT_DecodeDERCertificate(
  1.2341 +	&(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL);
  1.2342 +    if(!leafCert) {
  1.2343 +	key->problem = PR_TRUE;
  1.2344 +	key->noInstall = PR_TRUE;
  1.2345 +	key->error = PORT_GetError();
  1.2346 +	return;
  1.2347 +    }
  1.2348 +
  1.2349 +    privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);
  1.2350 +    if(!privk) {
  1.2351 +	privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);
  1.2352 +    }
  1.2353 + 
  1.2354 +    if(privk) {
  1.2355 +	SECKEY_DestroyPrivateKey(privk);
  1.2356 +	key->noInstall = PR_TRUE;
  1.2357 +    } 
  1.2358 +
  1.2359 +    CERT_DestroyCertificate(leafCert);
  1.2360 +}
  1.2361 +
  1.2362 +static SECStatus
  1.2363 +sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx)
  1.2364 +{
  1.2365 +    SECItem *derCert, *nickName;
  1.2366 +    char *nickData = NULL;
  1.2367 +    PRBool isIntermediateCA;
  1.2368 +    SECStatus rv;
  1.2369 +
  1.2370 +    if(!cert) {
  1.2371 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2372 +	return SECFailure;
  1.2373 +    }
  1.2374 +
  1.2375 +    if(cert->problem || cert->noInstall || cert->installed) {
  1.2376 +	return SECSuccess;
  1.2377 +    }
  1.2378 +
  1.2379 +    derCert = &cert->safeBagContent.certBag->value.x509Cert;
  1.2380 +
  1.2381 +    PORT_Assert(!cert->problem && !cert->noInstall);
  1.2382 +
  1.2383 +    nickName = sec_pkcs12_get_nickname(cert);
  1.2384 +    if(nickName) {
  1.2385 +	nickData = (char *)nickName->data;
  1.2386 +    }
  1.2387 +
  1.2388 +    isIntermediateCA = CERT_IsCADERCert(derCert, NULL) && 
  1.2389 +						!CERT_IsRootDERCert(derCert);
  1.2390 +
  1.2391 +    if(keyExists) {
  1.2392 +	CERTCertificate *newCert;
  1.2393 +
  1.2394 +	newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  1.2395 +	                                  derCert, NULL, PR_FALSE, PR_FALSE);
  1.2396 +	if(!newCert) {
  1.2397 +	     if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);
  1.2398 +	     cert->error = PORT_GetError();
  1.2399 +	     cert->problem = PR_TRUE;
  1.2400 +	     return SECFailure;
  1.2401 +	}
  1.2402 +
  1.2403 +	rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData, 
  1.2404 +					 PR_TRUE, wincx);
  1.2405 +	CERT_DestroyCertificate(newCert);
  1.2406 +    } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) || 
  1.2407 +     ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) && 
  1.2408 +							!isIntermediateCA)) {
  1.2409 +	SECItem *certList[2];
  1.2410 +	certList[0] = derCert;
  1.2411 +	certList[1] = NULL;
  1.2412 +	
  1.2413 +	rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,
  1.2414 +			     1, certList, NULL, PR_TRUE, PR_FALSE, nickData);
  1.2415 +    } else {
  1.2416 +	rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE,
  1.2417 +							nickData, PR_FALSE);
  1.2418 +    }
  1.2419 +    if (rv) {
  1.2420 +	cert->problem = 1;
  1.2421 +	cert->error = PORT_GetError();
  1.2422 +    }
  1.2423 +    cert->installed = PR_TRUE;
  1.2424 +    if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);
  1.2425 +    return rv;
  1.2426 +}
  1.2427 +
  1.2428 +static SECItem *
  1.2429 +sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey, KeyType *type);
  1.2430 +
  1.2431 +static SECStatus
  1.2432 +sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECKEYPublicKey *pubKey, 
  1.2433 +		   unsigned int keyUsage, 
  1.2434 +		   SECItem *nickName, void *wincx)
  1.2435 +{
  1.2436 +    SECStatus rv;
  1.2437 +    SECItem *publicValue = NULL;
  1.2438 +    KeyType keyType;
  1.2439 +
  1.2440 +    /* We should always have values for "key" and "pubKey"
  1.2441 +       so they can be dereferenced later. */
  1.2442 +    if(!key || !pubKey) {
  1.2443 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2444 +	return SECFailure;
  1.2445 +    }
  1.2446 +
  1.2447 +    if(key->problem || key->noInstall) {
  1.2448 +	return SECSuccess;
  1.2449 +    }
  1.2450 +
  1.2451 +    /* get the value and type from the public key */
  1.2452 +    publicValue = sec_pkcs12_get_public_value_and_type(pubKey, &keyType);
  1.2453 +    if (!publicValue) {
  1.2454 +	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  1.2455 +	key->problem = PR_TRUE;
  1.2456 +	return SECFailure;
  1.2457 +    }
  1.2458 +
  1.2459 +    switch(SECOID_FindOIDTag(&key->safeBagType))
  1.2460 +    {
  1.2461 +	case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  1.2462 +	    rv = PK11_ImportPrivateKeyInfo(key->slot, 
  1.2463 +			  key->safeBagContent.pkcs8KeyBag, 
  1.2464 +			  nickName, publicValue, PR_TRUE, PR_TRUE,
  1.2465 +			  keyUsage,  wincx);
  1.2466 +	    break;
  1.2467 +	case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  1.2468 +	    rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
  1.2469 +					key->safeBagContent.pkcs8ShroudedKeyBag,
  1.2470 +					key->pwitem, nickName, publicValue, 
  1.2471 +					PR_TRUE, PR_TRUE, keyType, keyUsage,
  1.2472 +					wincx);
  1.2473 +	    break;
  1.2474 +	default:
  1.2475 +	    key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
  1.2476 +	    key->problem = PR_TRUE;
  1.2477 +	    if(nickName) {
  1.2478 +		SECITEM_ZfreeItem(nickName, PR_TRUE);
  1.2479 +	    }
  1.2480 +	    return SECFailure;
  1.2481 +    }
  1.2482 +
  1.2483 +    if(rv != SECSuccess) {
  1.2484 +	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  1.2485 +	key->problem = PR_TRUE;
  1.2486 +    } else {
  1.2487 +	/* try to import the public key. Failure to do so is not fatal,
  1.2488 +	 * not all tokens can store the public key */
  1.2489 +	if (pubKey) {
  1.2490 +	    PK11_ImportPublicKey(key->slot, pubKey, PR_TRUE);
  1.2491 +	}
  1.2492 +	key->installed = PR_TRUE;
  1.2493 +    }
  1.2494 +
  1.2495 +    return rv;
  1.2496 +}
  1.2497 +
  1.2498 +/* 
  1.2499 + * The correctness of the code in this file ABSOLUTELY REQUIRES 
  1.2500 + * that ALL BAGs share a single common arena.  
  1.2501 + *
  1.2502 + * This function allocates the bag list from the arena of whatever bag 
  1.2503 + * happens to be passed to it.  Each time a new bag is handed to it,
  1.2504 + * it grows (resizes) the arena of the bag that was handed to it.  
  1.2505 + * If the bags have different arenas, it will grow the wrong arena.
  1.2506 + *
  1.2507 + * Worse, if the bags had separate arenas, then while destroying the bags 
  1.2508 + * in a bag list, when the bag whose arena contained the bag list was 
  1.2509 + * destroyed, the baglist itself would be destroyed, making it difficult 
  1.2510 + * or impossible to continue to destroy the bags in the destroyed list.
  1.2511 + */
  1.2512 +static SECStatus
  1.2513 +sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList, 
  1.2514 +				sec_PKCS12SafeBag *bag)
  1.2515 +{
  1.2516 +    sec_PKCS12SafeBag **newBagList = NULL;
  1.2517 +    int i = 0;
  1.2518 +
  1.2519 +    if(!bagList || !bag) {
  1.2520 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2521 +	return SECFailure;
  1.2522 +    }
  1.2523 +
  1.2524 +    if(!(*bagList)) {
  1.2525 +	newBagList = PORT_ArenaZNewArray(bag->arena, sec_PKCS12SafeBag *, 2);
  1.2526 +    } else {
  1.2527 +	while((*bagList)[i]) 
  1.2528 +	    i++;
  1.2529 +	newBagList = PORT_ArenaGrowArray(bag->arena, *bagList,
  1.2530 +				         sec_PKCS12SafeBag *, i + 1, i + 2);
  1.2531 +    }
  1.2532 +
  1.2533 +    if(!newBagList) {
  1.2534 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1.2535 +	return SECFailure;
  1.2536 +    }
  1.2537 +
  1.2538 +    newBagList[i]   = bag;
  1.2539 +    newBagList[i+1] = NULL;
  1.2540 +    *bagList = newBagList;
  1.2541 +
  1.2542 +    return SECSuccess;
  1.2543 +}
  1.2544 +
  1.2545 +static sec_PKCS12SafeBag **
  1.2546 +sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags, 
  1.2547 +                              sec_PKCS12SafeBag *key ) 
  1.2548 +{
  1.2549 +    sec_PKCS12SafeBag **certList = NULL;
  1.2550 +    SECItem *keyId;
  1.2551 +    int i;
  1.2552 +
  1.2553 +    if(!safeBags || !safeBags[0]) {
  1.2554 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2555 +	return NULL;
  1.2556 +    }
  1.2557 +
  1.2558 +    keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);
  1.2559 +    if(!keyId) {
  1.2560 +	return NULL;
  1.2561 +    }
  1.2562 +
  1.2563 +    for (i = 0; safeBags[i]; i++) {
  1.2564 +	if(SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) 
  1.2565 +				== SEC_OID_PKCS12_V1_CERT_BAG_ID) {
  1.2566 +	    SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],
  1.2567 +						SEC_OID_PKCS9_LOCAL_KEY_ID);
  1.2568 +
  1.2569 +	    if(certKeyId && (SECITEM_CompareItem(certKeyId, keyId) 
  1.2570 +				== SECEqual)) {
  1.2571 +		if(sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i])
  1.2572 +				!= SECSuccess) {
  1.2573 +		    /* This would leak the partial list of safeBags,
  1.2574 +		     * but that list is allocated from the arena of 
  1.2575 +		     * one of the safebags, and will be destroyed when 
  1.2576 +		     * that arena is destroyed.  So this is not a real leak.
  1.2577 +		     */
  1.2578 +		    return NULL;
  1.2579 +		}
  1.2580 +	    }
  1.2581 +	}
  1.2582 +    }
  1.2583 +
  1.2584 +    return certList;
  1.2585 +}
  1.2586 +
  1.2587 +CERTCertList *
  1.2588 +SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx)
  1.2589 +{
  1.2590 +    CERTCertList *certList = NULL;
  1.2591 +    sec_PKCS12SafeBag **safeBags;
  1.2592 +    int i;
  1.2593 +
  1.2594 +    if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) {
  1.2595 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2596 +	return NULL;
  1.2597 +    }
  1.2598 +
  1.2599 +    safeBags = p12dcx->safeBags;
  1.2600 +    certList = CERT_NewCertList();
  1.2601 +
  1.2602 +    if (certList == NULL) {
  1.2603 +	 return NULL;
  1.2604 +    }
  1.2605 +
  1.2606 +    for (i = 0; safeBags[i]; i++) {
  1.2607 +	if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) 
  1.2608 +				== SEC_OID_PKCS12_V1_CERT_BAG_ID) {
  1.2609 +		SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]) ;
  1.2610 +		CERTCertificate *tempCert = NULL;
  1.2611 +
  1.2612 +		if (derCert == NULL) 
  1.2613 +		    continue;
  1.2614 +    		tempCert=CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
  1.2615 +		                                 derCert, NULL, 
  1.2616 +		                                 PR_FALSE, PR_TRUE);
  1.2617 +
  1.2618 +		if (tempCert) {
  1.2619 +		    CERT_AddCertToListTail(certList,tempCert);
  1.2620 +		}
  1.2621 +		SECITEM_FreeItem(derCert,PR_TRUE);
  1.2622 +	}
  1.2623 +	/* fixed an infinite loop here, by ensuring that i gets incremented
  1.2624 +	 * if derCert is NULL above.
  1.2625 +	 */
  1.2626 +    }
  1.2627 +
  1.2628 +    return certList;
  1.2629 +}
  1.2630 +static sec_PKCS12SafeBag **
  1.2631 +sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags)
  1.2632 +{
  1.2633 +    int i;
  1.2634 +    sec_PKCS12SafeBag **keyList = NULL;
  1.2635 +    SECOidTag bagType;
  1.2636 +
  1.2637 +    if(!safeBags || !safeBags[0]) {
  1.2638 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2639 +	return NULL;
  1.2640 +    }
  1.2641 +
  1.2642 +    for (i = 0; safeBags[i]; i++) {
  1.2643 +	bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
  1.2644 +	switch(bagType) {
  1.2645 +	    case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  1.2646 +	    case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  1.2647 +		if(sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i])
  1.2648 +				!= SECSuccess) {
  1.2649 +		    /* This would leak, except that keyList is allocated
  1.2650 +		     * from the arena shared by all the safeBags.
  1.2651 +		     */
  1.2652 +		    return NULL;
  1.2653 +		}
  1.2654 +		break;
  1.2655 +	    default:
  1.2656 +		break;
  1.2657 +	}
  1.2658 +    }
  1.2659 +
  1.2660 +    return keyList;
  1.2661 +}
  1.2662 +
  1.2663 +/* This function takes two passes over the bags, validating them 
  1.2664 + * The two passes are intended to mirror exactly the two passes in 
  1.2665 + * sec_pkcs12_install_bags.  But they don't. :(
  1.2666 + */
  1.2667 +static SECStatus 
  1.2668 +sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags, 
  1.2669 +			 SEC_PKCS12NicknameCollisionCallback nicknameCb,
  1.2670 +			 void *wincx)
  1.2671 +{
  1.2672 +    sec_PKCS12SafeBag **keyList;
  1.2673 +    int i;
  1.2674 +
  1.2675 +    if(!safeBags || !nicknameCb) {
  1.2676 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2677 +	return SECFailure;
  1.2678 +    }
  1.2679 +
  1.2680 +    if(!safeBags[0]) {
  1.2681 +	return SECSuccess;
  1.2682 +    }
  1.2683 +
  1.2684 +    /* First pass.  Find all the key bags.  
  1.2685 +     * Find the matching cert(s) for each key.  
  1.2686 +     */
  1.2687 +    keyList = sec_pkcs12_get_key_bags(safeBags);
  1.2688 +    if(keyList) {
  1.2689 +	for (i = 0; keyList[i]; ++i) {
  1.2690 +	    sec_PKCS12SafeBag *key = keyList[i];
  1.2691 +	    sec_PKCS12SafeBag **certList = 
  1.2692 +			    sec_pkcs12_find_certs_for_key(safeBags, key);
  1.2693 +
  1.2694 +	    if(certList) {
  1.2695 +		int j;
  1.2696 +
  1.2697 +		if(SECOID_FindOIDTag(&(key->safeBagType)) == 
  1.2698 +					SEC_OID_PKCS12_V1_KEY_BAG_ID) {
  1.2699 +		    /* if it is an unencrypted private key then make sure
  1.2700 +		     * the attributes are propageted to the appropriate 
  1.2701 +		     * level 
  1.2702 +		     */
  1.2703 +		    if(sec_pkcs12_get_key_info(key) != SECSuccess) {
  1.2704 +			return SECFailure;
  1.2705 +		    }
  1.2706 +		}
  1.2707 +	
  1.2708 +		sec_pkcs12_validate_key_by_cert(certList[0], key, wincx);
  1.2709 +		for (j = 0; certList[j]; ++j) {
  1.2710 +		    sec_PKCS12SafeBag *cert = certList[j];
  1.2711 +		    cert->hasKey = PR_TRUE;
  1.2712 +		    if(key->problem) {
  1.2713 +			cert->problem = PR_TRUE;
  1.2714 +			cert->error   = key->error;
  1.2715 +			continue;
  1.2716 +		    } 
  1.2717 +		    sec_pkcs12_validate_cert(cert, key, nicknameCb);
  1.2718 +		    if(cert->problem) {
  1.2719 +			key->problem = cert->problem;
  1.2720 +			key->error   = cert->error;
  1.2721 +		    }
  1.2722 +		}
  1.2723 +	    }
  1.2724 +	}
  1.2725 +    }
  1.2726 +
  1.2727 +    /* Now take a second pass over the safebags and mark for installation any 
  1.2728 +     * certs that were neither installed nor disqualified by the first pass.
  1.2729 +     */
  1.2730 +    for (i = 0; safeBags[i]; ++i) {
  1.2731 +	sec_PKCS12SafeBag *bag = safeBags[i];
  1.2732 +
  1.2733 +	if(!bag->validated) {
  1.2734 +	    SECOidTag bagType = SECOID_FindOIDTag(&bag->safeBagType);
  1.2735 +
  1.2736 +	    switch(bagType) {
  1.2737 +	    case SEC_OID_PKCS12_V1_CERT_BAG_ID:
  1.2738 +		sec_pkcs12_validate_cert(bag, NULL, nicknameCb);
  1.2739 +		break;
  1.2740 +	    case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  1.2741 +	    case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  1.2742 +		bag->noInstall = PR_TRUE;
  1.2743 +		bag->problem = PR_TRUE;	
  1.2744 +		bag->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  1.2745 +		break;
  1.2746 +	    default:
  1.2747 +		bag->noInstall = PR_TRUE;
  1.2748 +	    }
  1.2749 +	}
  1.2750 +    }
  1.2751 +
  1.2752 +    return SECSuccess;
  1.2753 +}
  1.2754 +
  1.2755 +SECStatus
  1.2756 +SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx,
  1.2757 +			      SEC_PKCS12NicknameCollisionCallback nicknameCb)
  1.2758 +{
  1.2759 +    SECStatus rv;
  1.2760 +    int i, noInstallCnt, probCnt, bagCnt, errorVal = 0;
  1.2761 +    if(!p12dcx || p12dcx->error || !p12dcx->safeBags) {
  1.2762 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2763 +	return SECFailure;
  1.2764 +    }
  1.2765 +
  1.2766 +    rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx);
  1.2767 +    if(rv == SECSuccess) {
  1.2768 +	p12dcx->bagsVerified = PR_TRUE;
  1.2769 +    }
  1.2770 +
  1.2771 +    noInstallCnt = probCnt = bagCnt = 0;
  1.2772 +    i = 0;
  1.2773 +    while(p12dcx->safeBags[i]) {
  1.2774 +	bagCnt++;
  1.2775 +	if(p12dcx->safeBags[i]->noInstall) 
  1.2776 +	    noInstallCnt++;
  1.2777 +	if(p12dcx->safeBags[i]->problem) {
  1.2778 +	    probCnt++;
  1.2779 +	    errorVal = p12dcx->safeBags[i]->error;
  1.2780 +	}
  1.2781 +	i++;
  1.2782 +    }
  1.2783 +
  1.2784 +    /* formerly was erroneous code here that assumed that if all bags
  1.2785 +     * failed to import, then the problem was duplicated data; 
  1.2786 +     * that is, it assume that the problem must be that the file had
  1.2787 +     * previously been successfully imported.  But importing a 
  1.2788 +     * previously imported file causes NO ERRORS at all, and this 
  1.2789 +     * false assumption caused real errors to be hidden behind false
  1.2790 +     * errors about duplicated data.
  1.2791 +     */
  1.2792 +
  1.2793 +    if(probCnt) {
  1.2794 +	PORT_SetError(errorVal);
  1.2795 +	return SECFailure;
  1.2796 +    }
  1.2797 +
  1.2798 +    return rv;
  1.2799 +}
  1.2800 +
  1.2801 +
  1.2802 +static SECKEYPublicKey *
  1.2803 +sec_pkcs12_get_public_key_and_usage(sec_PKCS12SafeBag *certBag,
  1.2804 +					 unsigned int *usage)
  1.2805 +{
  1.2806 +    SECKEYPublicKey *pubKey = NULL;
  1.2807 +    CERTCertificate *cert = NULL;
  1.2808 +
  1.2809 +    if(!certBag || !usage) {
  1.2810 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2811 +	return NULL;
  1.2812 +    }
  1.2813 +
  1.2814 +    *usage = 0;
  1.2815 +
  1.2816 +    cert = CERT_DecodeDERCertificate(
  1.2817 +	 &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
  1.2818 +    if(!cert) {
  1.2819 +	return NULL;
  1.2820 +    }
  1.2821 +
  1.2822 +    *usage = cert->keyUsage;
  1.2823 +    pubKey = CERT_ExtractPublicKey(cert);
  1.2824 +    CERT_DestroyCertificate(cert);
  1.2825 +    return pubKey;
  1.2826 +}
  1.2827 +
  1.2828 +static SECItem *
  1.2829 +sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey,
  1.2830 +					KeyType *type)
  1.2831 +{
  1.2832 +    SECItem *pubValue = NULL;
  1.2833 +
  1.2834 +    if(!type || !pubKey) {
  1.2835 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2836 +	return NULL;
  1.2837 +    }
  1.2838 +
  1.2839 +    *type = pubKey->keyType;
  1.2840 +    switch(pubKey->keyType) {
  1.2841 +	case dsaKey:
  1.2842 +	    pubValue = &pubKey->u.dsa.publicValue;
  1.2843 +	    break;
  1.2844 +	case dhKey:
  1.2845 +	    pubValue = &pubKey->u.dh.publicValue;
  1.2846 +	    break;
  1.2847 +	case rsaKey:
  1.2848 +	    pubValue = &pubKey->u.rsa.modulus;
  1.2849 +	    break;
  1.2850 +        case ecKey:
  1.2851 +	    pubValue = &pubKey->u.ec.publicValue;
  1.2852 +	    break;
  1.2853 +	default:
  1.2854 +	    pubValue = NULL;
  1.2855 +    }
  1.2856 +
  1.2857 +    return pubValue;
  1.2858 +}
  1.2859 +
  1.2860 +/* This function takes two passes over the bags, installing them in the
  1.2861 + * desired slot.  The two passes are intended to mirror exactly the 
  1.2862 + * two passes in sec_pkcs12_validate_bags.
  1.2863 + */
  1.2864 +static SECStatus 
  1.2865 +sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, void *wincx)
  1.2866 +{
  1.2867 +    sec_PKCS12SafeBag **keyList;
  1.2868 +    int i;
  1.2869 +    int failedKeys = 0;
  1.2870 +
  1.2871 +    if(!safeBags) {
  1.2872 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2873 +	return SECFailure;
  1.2874 +    }
  1.2875 +
  1.2876 +    if(!safeBags[0]) {
  1.2877 +	return SECSuccess;
  1.2878 +    }
  1.2879 +
  1.2880 +    /* First pass.  Find all the key bags. 
  1.2881 +     * Try to install them, and any certs associated with them.  
  1.2882 +     */
  1.2883 +    keyList = sec_pkcs12_get_key_bags(safeBags);
  1.2884 +    if(keyList) {
  1.2885 +	for (i = 0; keyList[i]; i++) {
  1.2886 +	    SECStatus rv;
  1.2887 +	    SECKEYPublicKey *pubKey = NULL;
  1.2888 +	    SECItem *nickName    = NULL;
  1.2889 +	    sec_PKCS12SafeBag *key = keyList[i];
  1.2890 +	    sec_PKCS12SafeBag **certList;
  1.2891 +	    unsigned int keyUsage;
  1.2892 +
  1.2893 +	    if(key->problem) {
  1.2894 +		++failedKeys;
  1.2895 +		continue;
  1.2896 +	    }
  1.2897 +
  1.2898 +	    certList = sec_pkcs12_find_certs_for_key(safeBags, key);
  1.2899 +	    if(certList && certList[0]) {
  1.2900 +		pubKey = sec_pkcs12_get_public_key_and_usage(certList[0],
  1.2901 +					&keyUsage);
  1.2902 +		/* use the cert's nickname, if it has one, else use the 
  1.2903 +		 * key's nickname, else fail.
  1.2904 +		 */
  1.2905 +		nickName = sec_pkcs12_get_nickname_for_cert(certList[0], key);
  1.2906 +	    } else {
  1.2907 +		nickName = sec_pkcs12_get_nickname(key);
  1.2908 +	    }
  1.2909 +	    if (!nickName) {
  1.2910 +		key->error = SEC_ERROR_BAD_NICKNAME;
  1.2911 +		key->problem = PR_TRUE;
  1.2912 +		rv = SECFailure;
  1.2913 +	    } else if (!pubKey) {
  1.2914 +                key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
  1.2915 +		key->problem = PR_TRUE;
  1.2916 +                rv = SECFailure;
  1.2917 +	    } else {
  1.2918 +		rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName, wincx);
  1.2919 +            }
  1.2920 +	    if (pubKey) {
  1.2921 +		SECKEY_DestroyPublicKey(pubKey);
  1.2922 +		pubKey = NULL;
  1.2923 +	    }
  1.2924 +	    if (nickName) {
  1.2925 +		SECITEM_FreeItem(nickName, PR_TRUE);
  1.2926 +		nickName = NULL;
  1.2927 +	    }
  1.2928 +	    if(rv != SECSuccess) {
  1.2929 +		PORT_SetError(key->error);
  1.2930 +		++failedKeys;
  1.2931 +	    }
  1.2932 +
  1.2933 +	    if(certList) {
  1.2934 +		int j;
  1.2935 +
  1.2936 +		for (j = 0; certList[j]; j++) {
  1.2937 +		    sec_PKCS12SafeBag *cert = certList[j];
  1.2938 +		    SECStatus certRv;
  1.2939 +
  1.2940 +		    if (!cert)
  1.2941 +		    	continue;
  1.2942 +		    if(rv != SECSuccess) {
  1.2943 +			cert->problem = key->problem;
  1.2944 +			cert->error   = key->error;	
  1.2945 +			cert->noInstall = PR_TRUE;
  1.2946 +			continue;
  1.2947 +		    }
  1.2948 +
  1.2949 +		    certRv = sec_pkcs12_add_cert(cert, cert->hasKey, wincx);
  1.2950 +		    if(certRv != SECSuccess) {
  1.2951 +			key->problem = cert->problem;
  1.2952 +			key->error   = cert->error;
  1.2953 +			PORT_SetError(cert->error);
  1.2954 +			return SECFailure;
  1.2955 +		    }
  1.2956 +		}
  1.2957 +	    }
  1.2958 +	}
  1.2959 +    }
  1.2960 +    if (failedKeys)
  1.2961 +    	return SECFailure;
  1.2962 +
  1.2963 +    /* Now take a second pass over the safebags and install any certs 
  1.2964 +     * that were neither installed nor disqualified by the first pass.
  1.2965 +     */
  1.2966 +    for (i = 0; safeBags[i]; i++) {
  1.2967 +	sec_PKCS12SafeBag *bag = safeBags[i];
  1.2968 +
  1.2969 +	if (!bag->installed && !bag->problem && !bag->noInstall) {
  1.2970 +	    SECStatus rv;
  1.2971 +	    SECOidTag bagType = SECOID_FindOIDTag(&(bag->safeBagType));
  1.2972 +
  1.2973 +	    switch(bagType) {
  1.2974 +	    case SEC_OID_PKCS12_V1_CERT_BAG_ID:
  1.2975 +		rv = sec_pkcs12_add_cert(bag, bag->hasKey, wincx);
  1.2976 +		if(rv != SECSuccess) {
  1.2977 +		    PORT_SetError(bag->error);
  1.2978 +		    return SECFailure;
  1.2979 +		}
  1.2980 +		break;
  1.2981 +	    case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  1.2982 +	    case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  1.2983 +	    default:
  1.2984 +		break;
  1.2985 +	    }
  1.2986 +	}
  1.2987 +    }
  1.2988 +
  1.2989 +    return SECSuccess;
  1.2990 +}
  1.2991 +
  1.2992 +SECStatus
  1.2993 +SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
  1.2994 +{
  1.2995 +    if(!p12dcx || p12dcx->error) {
  1.2996 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2997 +	return SECFailure;
  1.2998 +    }
  1.2999 +
  1.3000 +    if(!p12dcx->bagsVerified) {
  1.3001 +	return SECFailure;
  1.3002 +    }
  1.3003 +
  1.3004 +    return sec_pkcs12_install_bags(p12dcx->safeBags, p12dcx->wincx);
  1.3005 +}
  1.3006 +
  1.3007 +PRBool
  1.3008 +sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
  1.3009 +{
  1.3010 +    int i;
  1.3011 +    SECItem *keyId;
  1.3012 +    SECItem *certKeyId;
  1.3013 +
  1.3014 +    certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
  1.3015 +    if (certKeyId == NULL) {
  1.3016 +        return PR_FALSE;
  1.3017 +    }
  1.3018 +            
  1.3019 +    for (i=0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
  1.3020 +        keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
  1.3021 +                                                SEC_OID_PKCS9_LOCAL_KEY_ID);
  1.3022 +        if(!keyId) {
  1.3023 +            continue;
  1.3024 +        }
  1.3025 +        if(SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
  1.3026 +            return PR_TRUE;
  1.3027 +        }
  1.3028 +    }
  1.3029 +    return PR_FALSE;
  1.3030 +}
  1.3031 +
  1.3032 +SECItem *
  1.3033 +sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
  1.3034 +{
  1.3035 +    SECItem *friendlyName;
  1.3036 +    SECItem *tempnm;
  1.3037 +    
  1.3038 +    tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
  1.3039 +    friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
  1.3040 +    if (friendlyName) {
  1.3041 +        if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
  1.3042 +                                   tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
  1.3043 +            SECITEM_FreeItem(friendlyName, PR_TRUE);
  1.3044 +            friendlyName = NULL;
  1.3045 +        }
  1.3046 +    }
  1.3047 +    return friendlyName;
  1.3048 +}
  1.3049 +
  1.3050 +/* Following two functions provide access to selected portions of the safe bags.
  1.3051 + * Iteration is implemented per decoder context and may be accessed after
  1.3052 + * SEC_PKCS12DecoderVerify() returns success.
  1.3053 + * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
  1.3054 + * where item.type is always set; item.friendlyName is set if it is non-null;
  1.3055 + * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
  1.3056 + * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
  1.3057 + * arguments are invalid; PORT_GetError() is 0 at end-of-list.
  1.3058 + * Caller has read-only access to decoder items. Any SECItems generated are
  1.3059 + * owned by the decoder context and are freed by ...DecoderFinish().
  1.3060 + */
  1.3061 +SECStatus
  1.3062 +SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
  1.3063 +{
  1.3064 +    if(!p12dcx || p12dcx->error) {
  1.3065 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3066 +	return SECFailure;
  1.3067 +    }
  1.3068 +
  1.3069 +    p12dcx->iteration = 0;
  1.3070 +    return SECSuccess;
  1.3071 +}
  1.3072 +
  1.3073 +SECStatus
  1.3074 +SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
  1.3075 +                             const SEC_PKCS12DecoderItem **ipp)
  1.3076 +{
  1.3077 +    sec_PKCS12SafeBag *bag;
  1.3078 +    
  1.3079 +    if(!p12dcx || p12dcx->error) {
  1.3080 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3081 +	return SECFailure;
  1.3082 +    }
  1.3083 +
  1.3084 +    if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
  1.3085 +        SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
  1.3086 +    }
  1.3087 +    if (p12dcx->decitem.shroudAlg != NULL) {
  1.3088 +        SECOID_DestroyAlgorithmID(p12dcx->decitem.shroudAlg, PR_TRUE);
  1.3089 +    }
  1.3090 +    if (p12dcx->decitem.friendlyName != NULL) {
  1.3091 +        SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
  1.3092 +    }
  1.3093 +    p12dcx->decitem.type = 0;
  1.3094 +    p12dcx->decitem.der = NULL;
  1.3095 +    p12dcx->decitem.shroudAlg = NULL;
  1.3096 +    p12dcx->decitem.friendlyName = NULL;
  1.3097 +    p12dcx->decitem.hasKey = PR_FALSE;
  1.3098 +    *ipp = NULL;
  1.3099 +    if (p12dcx->keyList == NULL) {
  1.3100 +        p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
  1.3101 +    }
  1.3102 +
  1.3103 +    
  1.3104 +    for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
  1.3105 +        bag = p12dcx->safeBags[p12dcx->iteration];
  1.3106 + 	if(bag == NULL || bag->problem) {
  1.3107 +            continue;
  1.3108 +        }
  1.3109 +        p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
  1.3110 +        switch(p12dcx->decitem.type) {
  1.3111 +            case SEC_OID_PKCS12_V1_CERT_BAG_ID:
  1.3112 +                p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
  1.3113 +                p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
  1.3114 +                p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
  1.3115 +                break;
  1.3116 +            case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
  1.3117 +                p12dcx->decitem.shroudAlg = PORT_ZNew(SECAlgorithmID);
  1.3118 +		if (p12dcx->decitem.shroudAlg) {
  1.3119 +		    SECOID_CopyAlgorithmID(NULL, p12dcx->decitem.shroudAlg,
  1.3120 +			&bag->safeBagContent.pkcs8ShroudedKeyBag->algorithm);
  1.3121 +		}
  1.3122 +                /* fall through */
  1.3123 +            case SEC_OID_PKCS12_V1_KEY_BAG_ID:
  1.3124 +                p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
  1.3125 +                break;
  1.3126 +            default:
  1.3127 +                /* return these even though we don't expect them */
  1.3128 +                break;
  1.3129 +            case SEC_OID_UNKNOWN:
  1.3130 +                /* ignore these */
  1.3131 +                continue;
  1.3132 +        }
  1.3133 +        *ipp = &p12dcx->decitem;
  1.3134 +        p12dcx->iteration++;
  1.3135 +        break;  /* end for() */
  1.3136 +    }
  1.3137 +    
  1.3138 +    PORT_SetError(0);       /* end-of-list is SECFailure with no PORT error */
  1.3139 +    return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
  1.3140 +}
  1.3141 +
  1.3142 +static SECStatus
  1.3143 +sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
  1.3144 +					 sec_PKCS12SafeBag *bag)
  1.3145 +{
  1.3146 +    if(!p12dcx || p12dcx->error) {
  1.3147 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3148 +	return SECFailure;
  1.3149 +    }
  1.3150 +
  1.3151 +    p12dcx->safeBags = !p12dcx->safeBagCount 
  1.3152 +	? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
  1.3153 +	: PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags, 
  1.3154 +	                      sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1, 
  1.3155 +			      p12dcx->safeBagCount + 2);
  1.3156 +
  1.3157 +    if(!p12dcx->safeBags) {
  1.3158 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1.3159 +	return SECFailure;
  1.3160 +    }
  1.3161 +
  1.3162 +    p12dcx->safeBags[p12dcx->safeBagCount] = bag;
  1.3163 +    p12dcx->safeBags[p12dcx->safeBagCount+1] = NULL;
  1.3164 +    p12dcx->safeBagCount++;
  1.3165 +
  1.3166 +    return SECSuccess;
  1.3167 +}
  1.3168 +
  1.3169 +static sec_PKCS12SafeBag *
  1.3170 +sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx,
  1.3171 +				   void *key, PRBool isEspvk)
  1.3172 +{
  1.3173 +    sec_PKCS12SafeBag *keyBag;
  1.3174 +    SECOidData *oid;
  1.3175 +    SECOidTag keyTag;
  1.3176 +    SECItem *keyID, *nickName, *newNickName;
  1.3177 +
  1.3178 +    if(!p12dcx || p12dcx->error || !key) {
  1.3179 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3180 +	return NULL;
  1.3181 +    }
  1.3182 +
  1.3183 +    newNickName = PORT_ArenaZNew(p12dcx->arena, SECItem);
  1.3184 +    keyBag      = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
  1.3185 +    if(!keyBag || !newNickName) {
  1.3186 +	return NULL;
  1.3187 +    }
  1.3188 +
  1.3189 +    keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
  1.3190 +    keyBag->slot = p12dcx->slot;
  1.3191 +    keyBag->arena = p12dcx->arena;
  1.3192 +    keyBag->pwitem = p12dcx->pwitem;
  1.3193 +    keyBag->tokenCAs = p12dcx->tokenCAs;
  1.3194 +    keyBag->oldBagType = PR_TRUE;
  1.3195 +
  1.3196 +    keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID :
  1.3197 +			 SEC_OID_PKCS12_V1_KEY_BAG_ID;
  1.3198 +    oid = SECOID_FindOIDByTag(keyTag);
  1.3199 +    if(!oid) {
  1.3200 +	return NULL;
  1.3201 +    }
  1.3202 +
  1.3203 +    if(SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid) 
  1.3204 +			!= SECSuccess) {
  1.3205 +	return NULL;
  1.3206 +    }
  1.3207 +
  1.3208 +    if(isEspvk) {
  1.3209 +	SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key;
  1.3210 +	keyBag->safeBagContent.pkcs8ShroudedKeyBag  = 
  1.3211 +					espvk->espvkCipherText.pkcs8KeyShroud;
  1.3212 +	nickName = &(espvk->espvkData.uniNickName); 
  1.3213 +	if(!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) {
  1.3214 +	    PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  1.3215 +	    return NULL;
  1.3216 +	}
  1.3217 +	keyID = &espvk->espvkData.assocCerts[0]->digest;
  1.3218 +    } else {
  1.3219 +	SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key;
  1.3220 +	keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data;
  1.3221 +	nickName= &(pk->pvkData.uniNickName);
  1.3222 +	if(!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) {
  1.3223 +	    PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  1.3224 +	    return NULL;
  1.3225 +	}
  1.3226 +	keyID = &pk->pvkData.assocCerts[0]->digest;
  1.3227 +    }
  1.3228 +
  1.3229 +    if(nickName->len) {
  1.3230 +	if(nickName->len >= 2) {
  1.3231 +	    if(nickName->data[0] && nickName->data[1]) {
  1.3232 +		if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName, 
  1.3233 +					nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
  1.3234 +		    return NULL;
  1.3235 +		}
  1.3236 +		nickName = newNickName;
  1.3237 +	    } else if(nickName->data[0] && !nickName->data[1]) {
  1.3238 +		unsigned int j = 0;
  1.3239 +		unsigned char t;
  1.3240 +		for(j = 0; j < nickName->len; j+=2) {
  1.3241 +		    t = nickName->data[j+1];
  1.3242 +		    nickName->data[j+1] = nickName->data[j];
  1.3243 +		    nickName->data[j] = t;
  1.3244 +		}
  1.3245 +	    }
  1.3246 +	} else {
  1.3247 +	    if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName, 
  1.3248 +					nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
  1.3249 +		return NULL;
  1.3250 +	    }
  1.3251 +	    nickName = newNickName;
  1.3252 +	}
  1.3253 +    }
  1.3254 +
  1.3255 +    if(sec_pkcs12_decoder_set_attribute_value(keyBag,
  1.3256 +					      SEC_OID_PKCS9_FRIENDLY_NAME,
  1.3257 +					      nickName) != SECSuccess) {
  1.3258 +	return NULL;
  1.3259 +    }
  1.3260 +	
  1.3261 +    if(sec_pkcs12_decoder_set_attribute_value(keyBag,SEC_OID_PKCS9_LOCAL_KEY_ID,
  1.3262 +					keyID) != SECSuccess) {
  1.3263 +	return NULL;
  1.3264 +    }
  1.3265 +
  1.3266 +    return keyBag;
  1.3267 +}
  1.3268 +
  1.3269 +static sec_PKCS12SafeBag *
  1.3270 +sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx,
  1.3271 +			       SECItem *derCert)
  1.3272 +{
  1.3273 +    sec_PKCS12SafeBag *certBag;
  1.3274 +    SECOidData *oid;
  1.3275 +    SGNDigestInfo *digest;
  1.3276 +    SECItem *keyId;
  1.3277 +    SECStatus rv;
  1.3278 +
  1.3279 +    if(!p12dcx || p12dcx->error || !derCert) {
  1.3280 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3281 +	return NULL;
  1.3282 +    }
  1.3283 +
  1.3284 +    keyId = PORT_ArenaZNew(p12dcx->arena, SECItem);
  1.3285 +    if(!keyId) {
  1.3286 +	return NULL;
  1.3287 +    }
  1.3288 +
  1.3289 +    digest = sec_pkcs12_compute_thumbprint(derCert);
  1.3290 +    if(!digest) {
  1.3291 +	return NULL;
  1.3292 +    }
  1.3293 +
  1.3294 +    rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest);
  1.3295 +    SGN_DestroyDigestInfo(digest);
  1.3296 +    if(rv != SECSuccess) {
  1.3297 +	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1.3298 +	return NULL;
  1.3299 +    }
  1.3300 +
  1.3301 +    oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID);
  1.3302 +    certBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
  1.3303 +    if(!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena, 
  1.3304 +			&certBag->safeBagType, &oid->oid) != SECSuccess)) {
  1.3305 +	return NULL;
  1.3306 +    }
  1.3307 +
  1.3308 +    certBag->slot = p12dcx->slot;
  1.3309 +    certBag->pwitem = p12dcx->pwitem;
  1.3310 +    certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
  1.3311 +    certBag->arena = p12dcx->arena;
  1.3312 +    certBag->tokenCAs = p12dcx->tokenCAs;
  1.3313 +
  1.3314 +    oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT);
  1.3315 +    certBag->safeBagContent.certBag = 
  1.3316 +			PORT_ArenaZNew(p12dcx->arena, sec_PKCS12CertBag);
  1.3317 +    if(!certBag->safeBagContent.certBag || !oid ||
  1.3318 +			(SECITEM_CopyItem(p12dcx->arena, 
  1.3319 +				 &certBag->safeBagContent.certBag->bagID,
  1.3320 +				 &oid->oid) != SECSuccess)) {
  1.3321 +	return NULL;
  1.3322 +    }
  1.3323 +      
  1.3324 +    if(SECITEM_CopyItem(p12dcx->arena, 
  1.3325 +			 &(certBag->safeBagContent.certBag->value.x509Cert),
  1.3326 +			 derCert) != SECSuccess) {
  1.3327 +	return NULL;
  1.3328 +    }
  1.3329 +
  1.3330 +    if(sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
  1.3331 +					keyId) != SECSuccess) {
  1.3332 +	return NULL;
  1.3333 +    }
  1.3334 +
  1.3335 +    return certBag;
  1.3336 +}
  1.3337 +
  1.3338 +static sec_PKCS12SafeBag **
  1.3339 +sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx,
  1.3340 +				    SEC_PKCS12CertAndCRL *oldCert)
  1.3341 +{
  1.3342 +    sec_PKCS12SafeBag **certList;
  1.3343 +    SECItem **derCertList;
  1.3344 +    int i, j;
  1.3345 +
  1.3346 +    if(!p12dcx || p12dcx->error || !oldCert) {
  1.3347 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3348 +	return NULL;
  1.3349 +    }
  1.3350 +
  1.3351 +    derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL);
  1.3352 +    if(!derCertList) {
  1.3353 +	return NULL;
  1.3354 +    }
  1.3355 +
  1.3356 +    i = 0;
  1.3357 +    while(derCertList[i]) i++;
  1.3358 +
  1.3359 +    certList = PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, (i + 1));
  1.3360 +    if(!certList) {
  1.3361 +	return NULL;
  1.3362 +    }
  1.3363 +
  1.3364 +    for(j = 0; j < i; j++) {
  1.3365 +	certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]);
  1.3366 +	if(!certList[j]) {
  1.3367 +	    return NULL;
  1.3368 +	}
  1.3369 +    }
  1.3370 +
  1.3371 +    return certList;
  1.3372 +}   
  1.3373 +
  1.3374 +static SECStatus
  1.3375 +sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx,
  1.3376 +					     void *oldKey, PRBool isEspvk,
  1.3377 +					     SEC_PKCS12SafeContents *safe,
  1.3378 +					     SEC_PKCS12Baggage *baggage)
  1.3379 +{
  1.3380 +    sec_PKCS12SafeBag *key, **certList;
  1.3381 +    SEC_PKCS12CertAndCRL *oldCert;
  1.3382 +    SEC_PKCS12PVKSupportingData *pvkData;
  1.3383 +    int i;
  1.3384 +    SECItem *keyName;
  1.3385 +
  1.3386 +    if(!p12dcx || !oldKey) {
  1.3387 +	return SECFailure;
  1.3388 +    }
  1.3389 +
  1.3390 +    if(isEspvk) {
  1.3391 +	pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData;
  1.3392 +    } else {
  1.3393 +	pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData;
  1.3394 +    }
  1.3395 +
  1.3396 +    if(!pvkData->assocCerts || !pvkData->assocCerts[0]) {
  1.3397 +	PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  1.3398 +	return SECFailure;
  1.3399 +    }
  1.3400 +
  1.3401 +    oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage, 
  1.3402 +				     SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL,
  1.3403 +				     pvkData->assocCerts[0]);
  1.3404 +    if(!oldCert) {
  1.3405 +	PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  1.3406 +	return SECFailure;
  1.3407 +    }
  1.3408 +	
  1.3409 +    key = sec_pkcs12_decoder_convert_old_key(p12dcx,oldKey, isEspvk);
  1.3410 +    certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert);
  1.3411 +    if(!key || !certList) {
  1.3412 +	return SECFailure;
  1.3413 +    }
  1.3414 +
  1.3415 +    if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) {
  1.3416 +	return SECFailure;
  1.3417 +    }
  1.3418 +
  1.3419 +    keyName = sec_pkcs12_get_nickname(key);
  1.3420 +    if(!keyName) {
  1.3421 +	return SECFailure;
  1.3422 +    }
  1.3423 +
  1.3424 +    i = 0;
  1.3425 +    while(certList[i]) {
  1.3426 +	if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i]) 
  1.3427 +				!= SECSuccess) {
  1.3428 +	    return SECFailure;
  1.3429 +	}
  1.3430 +	i++;
  1.3431 +    }
  1.3432 +
  1.3433 +    certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key);
  1.3434 +    if(!certList) {
  1.3435 +	return SECFailure;
  1.3436 +    }
  1.3437 +
  1.3438 +    i = 0;
  1.3439 +    while(certList[i] != 0) {
  1.3440 +	if(sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) {
  1.3441 +	    return SECFailure;
  1.3442 +	}
  1.3443 +	i++;
  1.3444 +    }
  1.3445 +				
  1.3446 +    return SECSuccess;
  1.3447 +}
  1.3448 +	
  1.3449 +static SECStatus
  1.3450 +sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx,
  1.3451 +					    SEC_PKCS12SafeContents *safe,
  1.3452 +					    SEC_PKCS12Baggage *baggage)
  1.3453 +{
  1.3454 +    SECStatus rv;
  1.3455 +
  1.3456 +    if(!p12dcx || p12dcx->error) {
  1.3457 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3458 +	return SECFailure;
  1.3459 +    }
  1.3460 +
  1.3461 +    if(safe && safe->contents) {
  1.3462 +	int i = 0;
  1.3463 +	while(safe->contents[i] != NULL) {
  1.3464 +	    if(SECOID_FindOIDTag(&safe->contents[i]->safeBagType) 
  1.3465 +				== SEC_OID_PKCS12_KEY_BAG_ID) {
  1.3466 +		int j = 0;
  1.3467 +		SEC_PKCS12PrivateKeyBag *privBag = 
  1.3468 +					safe->contents[i]->safeContent.keyBag;
  1.3469 +		
  1.3470 +		while(privBag->privateKeys[j] != NULL) {
  1.3471 +		    SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j];
  1.3472 +		    rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx,pk,
  1.3473 +						PR_FALSE, safe, baggage);
  1.3474 +		    if(rv != SECSuccess) {
  1.3475 +			goto loser;
  1.3476 +		    }
  1.3477 +		    j++;
  1.3478 +		}
  1.3479 +	    }
  1.3480 +	    i++;
  1.3481 +	}
  1.3482 +    }
  1.3483 +
  1.3484 +    if(baggage && baggage->bags) {
  1.3485 +	int i = 0;
  1.3486 +	while(baggage->bags[i] != NULL) {
  1.3487 +	    SEC_PKCS12BaggageItem *bag = baggage->bags[i];
  1.3488 +	    int j = 0;
  1.3489 +
  1.3490 +	    if(!bag->espvks) {
  1.3491 +		i++;
  1.3492 +		continue;
  1.3493 +	    }
  1.3494 +
  1.3495 +	    while(bag->espvks[j] != NULL) {
  1.3496 +		SEC_PKCS12ESPVKItem *espvk = bag->espvks[j];
  1.3497 +		rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk,
  1.3498 +							PR_TRUE, safe, baggage);
  1.3499 +		if(rv != SECSuccess) {
  1.3500 +		    goto loser;
  1.3501 +		}
  1.3502 +		j++;
  1.3503 +	    }
  1.3504 +	    i++;
  1.3505 +	}
  1.3506 +    }
  1.3507 +
  1.3508 +    return SECSuccess;
  1.3509 +
  1.3510 +loser:
  1.3511 +    return SECFailure;
  1.3512 +}
  1.3513 +
  1.3514 +SEC_PKCS12DecoderContext *
  1.3515 +sec_PKCS12ConvertOldSafeToNew(PLArenaPool *arena, PK11SlotInfo *slot,
  1.3516 +			      PRBool swapUnicode, SECItem *pwitem,
  1.3517 +			      void *wincx, SEC_PKCS12SafeContents *safe,
  1.3518 +			      SEC_PKCS12Baggage *baggage)
  1.3519 +{
  1.3520 +    SEC_PKCS12DecoderContext *p12dcx;
  1.3521 +
  1.3522 +    if(!arena || !slot || !pwitem) {
  1.3523 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3524 +	return NULL;
  1.3525 +    }
  1.3526 +
  1.3527 +    if(!safe && !baggage) {
  1.3528 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3529 +	return NULL;
  1.3530 +    }
  1.3531 +
  1.3532 +    p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
  1.3533 +    if(!p12dcx) {
  1.3534 +	return NULL;
  1.3535 +    }
  1.3536 +
  1.3537 +    p12dcx->arena = arena;
  1.3538 +    p12dcx->slot = PK11_ReferenceSlot(slot);
  1.3539 +    p12dcx->wincx = wincx;
  1.3540 +    p12dcx->error = PR_FALSE;
  1.3541 +    p12dcx->swapUnicodeBytes = swapUnicode; 
  1.3542 +    p12dcx->pwitem = pwitem;
  1.3543 +    p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
  1.3544 +    
  1.3545 +    if(sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage) 
  1.3546 +				!= SECSuccess) {
  1.3547 +	p12dcx->error = PR_TRUE;
  1.3548 +	return NULL;
  1.3549 +    }
  1.3550 +
  1.3551 +    return p12dcx;
  1.3552 +}

mercurial