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 +}