| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 | |
| 5 | |
| 6 #include "nssrenam.h" | |
| 7 #include "p12t.h" | |
| 8 #include "p12.h" | |
| 9 #include "plarena.h" | |
| 10 #include "secitem.h" | |
| 11 #include "secoid.h" | |
| 12 #include "seccomon.h" | |
| 13 #include "secport.h" | |
| 14 #include "cert.h" | |
| 15 #include "secpkcs7.h" | |
| 16 #include "secasn1.h" | |
| 17 #include "secerr.h" | |
| 18 #include "pk11func.h" | |
| 19 #include "p12plcy.h" | |
| 20 #include "p12local.h" | |
| 21 #include "secder.h" | |
| 22 #include "secport.h" | |
| 23 | |
| 24 #include "certdb.h" | |
| 25 | |
| 26 #include "prcpucfg.h" | |
| 27 | |
| 28 /* This belongs in secport.h */ | |
| 29 #define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \ | |
| 30 (type *)PORT_ArenaGrow((poolp), (oldptr), \ | |
| 31 (oldnum) * sizeof(type), (newnum) * sizeof(type)) | |
| 32 | |
| 33 | |
| 34 typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext; | |
| 35 | |
| 36 /* Opaque structure for decoding SafeContents. These are used | |
| 37 * for each authenticated safe as well as any nested safe contents. | |
| 38 */ | |
| 39 struct sec_PKCS12SafeContentsContextStr { | |
| 40 /* the parent decoder context */ | |
| 41 SEC_PKCS12DecoderContext *p12dcx; | |
| 42 | |
| 43 /* memory arena to allocate space from */ | |
| 44 PLArenaPool *arena; | |
| 45 | |
| 46 /* decoder context and destination for decoding safe contents */ | |
| 47 SEC_ASN1DecoderContext *safeContentsA1Dcx; | |
| 48 sec_PKCS12SafeContents safeContents; | |
| 49 | |
| 50 /* information for decoding safe bags within the safe contents. | |
| 51 * these variables are updated for each safe bag decoded. | |
| 52 */ | |
| 53 SEC_ASN1DecoderContext *currentSafeBagA1Dcx; | |
| 54 sec_PKCS12SafeBag *currentSafeBag; | |
| 55 PRBool skipCurrentSafeBag; | |
| 56 | |
| 57 /* if the safe contents is nested, the parent is pointed to here. */ | |
| 58 sec_PKCS12SafeContentsContext *nestedSafeContentsCtx; | |
| 59 }; | |
| 60 | |
| 61 /* opaque decoder context structure. information for decoding a pkcs 12 | |
| 62 * PDU are stored here as well as decoding pointers for intermediary | |
| 63 * structures which are part of the PKCS 12 PDU. Upon a successful | |
| 64 * decode, the safe bags containing certificates and keys encountered. | |
| 65 */ | |
| 66 struct SEC_PKCS12DecoderContextStr { | |
| 67 PLArenaPool *arena; | |
| 68 PK11SlotInfo *slot; | |
| 69 void *wincx; | |
| 70 PRBool error; | |
| 71 int errorValue; | |
| 72 | |
| 73 /* password */ | |
| 74 SECItem *pwitem; | |
| 75 | |
| 76 /* used for decoding the PFX structure */ | |
| 77 SEC_ASN1DecoderContext *pfxA1Dcx; | |
| 78 sec_PKCS12PFXItem pfx; | |
| 79 | |
| 80 /* safe bags found during decoding */ | |
| 81 sec_PKCS12SafeBag **safeBags; | |
| 82 unsigned int safeBagCount; | |
| 83 | |
| 84 /* state variables for decoding authenticated safes. */ | |
| 85 SEC_PKCS7DecoderContext *currentASafeP7Dcx; | |
| 86 SEC_ASN1DecoderContext *aSafeA1Dcx; | |
| 87 SEC_PKCS7DecoderContext *aSafeP7Dcx; | |
| 88 SEC_PKCS7ContentInfo *aSafeCinfo; | |
| 89 sec_PKCS12AuthenticatedSafe authSafe; | |
| 90 sec_PKCS12SafeContents safeContents; | |
| 91 | |
| 92 /* safe contents info */ | |
| 93 unsigned int safeContentsCnt; | |
| 94 sec_PKCS12SafeContentsContext **safeContentsList; | |
| 95 | |
| 96 /* HMAC info */ | |
| 97 sec_PKCS12MacData macData; | |
| 98 | |
| 99 /* routines for reading back the data to be hmac'd */ | |
| 100 /* They are called as follows. | |
| 101 * | |
| 102 * Stage 1: decode the aSafes cinfo into a buffer in dArg, | |
| 103 * which p12d.c sometimes refers to as the "temp file". | |
| 104 * This occurs during SEC_PKCS12DecoderUpdate calls. | |
| 105 * | |
| 106 * dOpen(dArg, PR_FALSE) | |
| 107 * dWrite(dArg, buf, len) | |
| 108 * ... | |
| 109 * dWrite(dArg, buf, len) | |
| 110 * dClose(dArg, PR_FALSE) | |
| 111 * | |
| 112 * Stage 2: verify MAC | |
| 113 * This occurs SEC_PKCS12DecoderVerify. | |
| 114 * | |
| 115 * dOpen(dArg, PR_TRUE) | |
| 116 * dRead(dArg, buf, IN_BUF_LEN) | |
| 117 * ... | |
| 118 * dRead(dArg, buf, IN_BUF_LEN) | |
| 119 * dClose(dArg, PR_TRUE) | |
| 120 */ | |
| 121 digestOpenFn dOpen; | |
| 122 digestCloseFn dClose; | |
| 123 digestIOFn dRead, dWrite; | |
| 124 void *dArg; | |
| 125 PRBool dIsOpen; /* is the temp file created? */ | |
| 126 | |
| 127 /* helper functions */ | |
| 128 SECKEYGetPasswordKey pwfn; | |
| 129 void *pwfnarg; | |
| 130 PRBool swapUnicodeBytes; | |
| 131 | |
| 132 /* import information */ | |
| 133 PRBool bagsVerified; | |
| 134 | |
| 135 /* buffer management for the default callbacks implementation */ | |
| 136 void *buffer; /* storage area */ | |
| 137 PRInt32 filesize; /* actual data size */ | |
| 138 PRInt32 allocated; /* total buffer size allocated */ | |
| 139 PRInt32 currentpos; /* position counter */ | |
| 140 SECPKCS12TargetTokenCAs tokenCAs; | |
| 141 sec_PKCS12SafeBag **keyList;/* used by ...IterateNext() */ | |
| 142 unsigned int iteration; | |
| 143 SEC_PKCS12DecoderItem decitem; | |
| 144 }; | |
| 145 | |
| 146 /* forward declarations of functions that are used when decoding | |
| 147 * safeContents bags which are nested and when decoding the | |
| 148 * authenticatedSafes. | |
| 149 */ | |
| 150 static SECStatus | |
| 151 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext | |
| 152 *safeContentsCtx); | |
| 153 static SECStatus | |
| 154 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext | |
| 155 *safeContentsCtx); | |
| 156 | |
| 157 | |
| 158 /* make sure that the PFX version being decoded is a version | |
| 159 * which we support. | |
| 160 */ | |
| 161 static PRBool | |
| 162 sec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx) | |
| 163 { | |
| 164 /* if no version, assume it is not supported */ | |
| 165 if(pfx->version.len == 0) { | |
| 166 return PR_FALSE; | |
| 167 } | |
| 168 | |
| 169 if(DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) { | |
| 170 return PR_FALSE; | |
| 171 } | |
| 172 | |
| 173 return PR_TRUE; | |
| 174 } | |
| 175 | |
| 176 /* retrieve the key for decrypting the safe contents */ | |
| 177 static PK11SymKey * | |
| 178 sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid) | |
| 179 { | |
| 180 SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *) arg; | |
| 181 PK11SlotInfo *slot; | |
| 182 PK11SymKey *bulkKey; | |
| 183 | |
| 184 if(!p12dcx) { | |
| 185 return NULL; | |
| 186 } | |
| 187 | |
| 188 /* if no slot specified, use the internal key slot */ | |
| 189 if(p12dcx->slot) { | |
| 190 slot = PK11_ReferenceSlot(p12dcx->slot); | |
| 191 } else { | |
| 192 slot = PK11_GetInternalKeySlot(); | |
| 193 } | |
| 194 | |
| 195 bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, | |
| 196 PR_FALSE, p12dcx->wincx); | |
| 197 /* some tokens can't generate PBE keys on their own, generate the | |
| 198 * key in the internal slot, and let the Import code deal with it, | |
| 199 * (if the slot can't generate PBEs, then we need to use the internal | |
| 200 * slot anyway to unwrap). */ | |
| 201 if (!bulkKey && !PK11_IsInternal(slot)) { | |
| 202 PK11_FreeSlot(slot); | |
| 203 slot = PK11_GetInternalKeySlot(); | |
| 204 bulkKey = PK11_PBEKeyGen(slot, algid, p12dcx->pwitem, | |
| 205 PR_FALSE, p12dcx->wincx); | |
| 206 } | |
| 207 PK11_FreeSlot(slot); | |
| 208 | |
| 209 /* set the password data on the key */ | |
| 210 if (bulkKey) { | |
| 211 PK11_SetSymKeyUserData(bulkKey,p12dcx->pwitem, NULL); | |
| 212 } | |
| 213 | |
| 214 | |
| 215 return bulkKey; | |
| 216 } | |
| 217 | |
| 218 /* XXX this needs to be modified to handle enveloped data. most | |
| 219 * likely, it should mirror the routines for SMIME in that regard. | |
| 220 */ | |
| 221 static PRBool | |
| 222 sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid, | |
| 223 PK11SymKey *bulkkey) | |
| 224 { | |
| 225 PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid); | |
| 226 | |
| 227 if(!decryptionAllowed) { | |
| 228 return PR_FALSE; | |
| 229 } | |
| 230 | |
| 231 return PR_TRUE; | |
| 232 } | |
| 233 | |
| 234 /* when we encounter a new safe bag during the decoding, we need | |
| 235 * to allocate space for the bag to be decoded to and set the | |
| 236 * state variables appropriately. all of the safe bags are allocated | |
| 237 * in a buffer in the outer SEC_PKCS12DecoderContext, however, | |
| 238 * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext | |
| 239 * for the current bag. | |
| 240 */ | |
| 241 static SECStatus | |
| 242 sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext | |
| 243 *safeContentsCtx) | |
| 244 { | |
| 245 void *mark = NULL; | |
| 246 SEC_PKCS12DecoderContext *p12dcx; | |
| 247 | |
| 248 /* make sure that the structures are defined, and there has | |
| 249 * not been an error in the decoding | |
| 250 */ | |
| 251 if(!safeContentsCtx || !safeContentsCtx->p12dcx | |
| 252 || safeContentsCtx->p12dcx->error) { | |
| 253 return SECFailure; | |
| 254 } | |
| 255 | |
| 256 p12dcx = safeContentsCtx->p12dcx; | |
| 257 mark = PORT_ArenaMark(p12dcx->arena); | |
| 258 | |
| 259 /* allocate a new safe bag, if bags already exist, grow the | |
| 260 * list of bags, otherwise allocate a new list. the list is | |
| 261 * NULL terminated. | |
| 262 */ | |
| 263 p12dcx->safeBags = (!p12dcx->safeBagCount) | |
| 264 ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2) | |
| 265 : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags, | |
| 266 sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1, | |
| 267 p12dcx->safeBagCount + 2); | |
| 268 | |
| 269 if(!p12dcx->safeBags) { | |
| 270 p12dcx->errorValue = PORT_GetError(); | |
| 271 goto loser; | |
| 272 } | |
| 273 | |
| 274 /* append the bag to the end of the list and update the reference | |
| 275 * in the safeContentsCtx. | |
| 276 */ | |
| 277 p12dcx->safeBags[p12dcx->safeBagCount] = | |
| 278 safeContentsCtx->currentSafeBag = | |
| 279 PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag); | |
| 280 if(!safeContentsCtx->currentSafeBag) { | |
| 281 p12dcx->errorValue = PORT_GetError(); | |
| 282 goto loser; | |
| 283 } | |
| 284 p12dcx->safeBags[++p12dcx->safeBagCount] = NULL; | |
| 285 | |
| 286 safeContentsCtx->currentSafeBag->slot = safeContentsCtx->p12dcx->slot; | |
| 287 safeContentsCtx->currentSafeBag->pwitem = safeContentsCtx->p12dcx->pwitem; | |
| 288 safeContentsCtx->currentSafeBag->swapUnicodeBytes = | |
| 289 safeContentsCtx->p12dcx->swapUnicodeBytes; | |
| 290 safeContentsCtx->currentSafeBag->arena = safeContentsCtx->p12dcx->arena; | |
| 291 safeContentsCtx->currentSafeBag->tokenCAs = | |
| 292 safeContentsCtx->p12dcx->tokenCAs; | |
| 293 | |
| 294 PORT_ArenaUnmark(p12dcx->arena, mark); | |
| 295 return SECSuccess; | |
| 296 | |
| 297 loser: | |
| 298 | |
| 299 /* if an error occurred, release the memory and set the error flag | |
| 300 * the only possible errors triggered by this function are memory | |
| 301 * related. | |
| 302 */ | |
| 303 if(mark) { | |
| 304 PORT_ArenaRelease(p12dcx->arena, mark); | |
| 305 } | |
| 306 | |
| 307 p12dcx->error = PR_TRUE; | |
| 308 return SECFailure; | |
| 309 } | |
| 310 | |
| 311 /* A wrapper for updating the ASN1 context in which a safeBag is | |
| 312 * being decoded. This function is called as a callback from | |
| 313 * secasn1d when decoding SafeContents structures. | |
| 314 */ | |
| 315 static void | |
| 316 sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data, | |
| 317 unsigned long len, int depth, | |
| 318 SEC_ASN1EncodingPart data_kind) | |
| 319 { | |
| 320 sec_PKCS12SafeContentsContext *safeContentsCtx = | |
| 321 (sec_PKCS12SafeContentsContext *)arg; | |
| 322 SEC_PKCS12DecoderContext *p12dcx; | |
| 323 SECStatus rv; | |
| 324 | |
| 325 /* make sure that we are not skipping the current safeBag, | |
| 326 * and that there are no errors. If so, just return rather | |
| 327 * than continuing to process. | |
| 328 */ | |
| 329 if(!safeContentsCtx || !safeContentsCtx->p12dcx | |
| 330 || safeContentsCtx->p12dcx->error | |
| 331 || safeContentsCtx->skipCurrentSafeBag) { | |
| 332 return; | |
| 333 } | |
| 334 p12dcx = safeContentsCtx->p12dcx; | |
| 335 | |
| 336 rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagA1Dcx, data, len); | |
| 337 if(rv != SECSuccess) { | |
| 338 p12dcx->errorValue = PORT_GetError(); | |
| 339 goto loser; | |
| 340 } | |
| 341 | |
| 342 return; | |
| 343 | |
| 344 loser: | |
| 345 /* set the error, and finish the decoder context. because there | |
| 346 * is not a way of returning an error message, it may be worth | |
| 347 * while to do a check higher up and finish any decoding contexts | |
| 348 * that are still open. | |
| 349 */ | |
| 350 p12dcx->error = PR_TRUE; | |
| 351 SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx); | |
| 352 safeContentsCtx->currentSafeBagA1Dcx = NULL; | |
| 353 return; | |
| 354 } | |
| 355 | |
| 356 /* notify function for decoding safeBags. This function is | |
| 357 * used to filter safeBag types which are not supported, | |
| 358 * initiate the decoding of nested safe contents, and decode | |
| 359 * safeBags in general. this function is set when the decoder | |
| 360 * context for the safeBag is first created. | |
| 361 */ | |
| 362 static void | |
| 363 sec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before, | |
| 364 void *dest, int real_depth) | |
| 365 { | |
| 366 sec_PKCS12SafeContentsContext *safeContentsCtx = | |
| 367 (sec_PKCS12SafeContentsContext *)arg; | |
| 368 SEC_PKCS12DecoderContext *p12dcx; | |
| 369 sec_PKCS12SafeBag *bag; | |
| 370 PRBool after; | |
| 371 | |
| 372 /* if an error is encountered, return */ | |
| 373 if(!safeContentsCtx || !safeContentsCtx->p12dcx || | |
| 374 safeContentsCtx->p12dcx->error) { | |
| 375 return; | |
| 376 } | |
| 377 p12dcx = safeContentsCtx->p12dcx; | |
| 378 | |
| 379 /* to make things more readable */ | |
| 380 if(before) | |
| 381 after = PR_FALSE; | |
| 382 else | |
| 383 after = PR_TRUE; | |
| 384 | |
| 385 /* have we determined the safeBagType yet? */ | |
| 386 bag = safeContentsCtx->currentSafeBag; | |
| 387 if(bag->bagTypeTag == NULL) { | |
| 388 if(after && (dest == &(bag->safeBagType))) { | |
| 389 bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType)); | |
| 390 if(bag->bagTypeTag == NULL) { | |
| 391 p12dcx->error = PR_TRUE; | |
| 392 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE; | |
| 393 } | |
| 394 } | |
| 395 return; | |
| 396 } | |
| 397 | |
| 398 /* process the safeBag depending on it's type. those | |
| 399 * which we do not support, are ignored. we start a decoding | |
| 400 * context for a nested safeContents. | |
| 401 */ | |
| 402 switch(bag->bagTypeTag->offset) { | |
| 403 case SEC_OID_PKCS12_V1_KEY_BAG_ID: | |
| 404 case SEC_OID_PKCS12_V1_CERT_BAG_ID: | |
| 405 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: | |
| 406 break; | |
| 407 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID: | |
| 408 /* if we are just starting to decode the safeContents, initialize | |
| 409 * a new safeContentsCtx to process it. | |
| 410 */ | |
| 411 if(before && (dest == &(bag->safeBagContent))) { | |
| 412 sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx); | |
| 413 } else if(after && (dest == &(bag->safeBagContent))) { | |
| 414 /* clean up the nested decoding */ | |
| 415 sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx); | |
| 416 } | |
| 417 break; | |
| 418 case SEC_OID_PKCS12_V1_CRL_BAG_ID: | |
| 419 case SEC_OID_PKCS12_V1_SECRET_BAG_ID: | |
| 420 default: | |
| 421 /* skip any safe bag types we don't understand or handle */ | |
| 422 safeContentsCtx->skipCurrentSafeBag = PR_TRUE; | |
| 423 break; | |
| 424 } | |
| 425 | |
| 426 return; | |
| 427 } | |
| 428 | |
| 429 /* notify function for decoding safe contents. each entry in the | |
| 430 * safe contents is a safeBag which needs to be allocated and | |
| 431 * the decoding context initialized at the beginning and then | |
| 432 * the context needs to be closed and finished at the end. | |
| 433 * | |
| 434 * this function is set when the safeContents decode context is | |
| 435 * initialized. | |
| 436 */ | |
| 437 static void | |
| 438 sec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before, | |
| 439 void *dest, int real_depth) | |
| 440 { | |
| 441 sec_PKCS12SafeContentsContext *safeContentsCtx = | |
| 442 (sec_PKCS12SafeContentsContext*)arg; | |
| 443 SEC_PKCS12DecoderContext *p12dcx; | |
| 444 SECStatus rv; | |
| 445 | |
| 446 /* if there is an error we don't want to continue processing, | |
| 447 * just return and keep going. | |
| 448 */ | |
| 449 if(!safeContentsCtx || !safeContentsCtx->p12dcx | |
| 450 || safeContentsCtx->p12dcx->error) { | |
| 451 return; | |
| 452 } | |
| 453 p12dcx = safeContentsCtx->p12dcx; | |
| 454 | |
| 455 /* if we are done with the current safeBag, then we need to | |
| 456 * finish the context and set the state variables appropriately. | |
| 457 */ | |
| 458 if(!before) { | |
| 459 SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx); | |
| 460 SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx); | |
| 461 safeContentsCtx->currentSafeBagA1Dcx = NULL; | |
| 462 safeContentsCtx->skipCurrentSafeBag = PR_FALSE; | |
| 463 } else { | |
| 464 /* we are starting a new safe bag. we need to allocate space | |
| 465 * for the bag and initialize the decoding context. | |
| 466 */ | |
| 467 rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx); | |
| 468 if(rv != SECSuccess) { | |
| 469 goto loser; | |
| 470 } | |
| 471 | |
| 472 /* set up the decoder context */ | |
| 473 safeContentsCtx->currentSafeBagA1Dcx = | |
| 474 SEC_ASN1DecoderStart(p12dcx->arena, | |
| 475 safeContentsCtx->currentSafeBag, | |
| 476 sec_PKCS12SafeBagTemplate); | |
| 477 if(!safeContentsCtx->currentSafeBagA1Dcx) { | |
| 478 p12dcx->errorValue = PORT_GetError(); | |
| 479 goto loser; | |
| 480 } | |
| 481 | |
| 482 /* set the notify and filter procs so that the safe bag | |
| 483 * data gets sent to the proper location when decoding. | |
| 484 */ | |
| 485 SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagA1Dcx, | |
| 486 sec_pkcs12_decoder_safe_bag_notify, | |
| 487 safeContentsCtx); | |
| 488 SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsA1Dcx, | |
| 489 sec_pkcs12_decoder_safe_bag_update, | |
| 490 safeContentsCtx, PR_TRUE); | |
| 491 } | |
| 492 | |
| 493 return; | |
| 494 | |
| 495 loser: | |
| 496 /* in the event of an error, we want to close the decoding | |
| 497 * context and clear the filter and notify procedures. | |
| 498 */ | |
| 499 p12dcx->error = PR_TRUE; | |
| 500 | |
| 501 if(safeContentsCtx->currentSafeBagA1Dcx) { | |
| 502 SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx); | |
| 503 safeContentsCtx->currentSafeBagA1Dcx = NULL; | |
| 504 } | |
| 505 | |
| 506 SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsA1Dcx); | |
| 507 SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx); | |
| 508 | |
| 509 return; | |
| 510 } | |
| 511 | |
| 512 /* initialize the safeContents for decoding. this routine | |
| 513 * is used for authenticatedSafes as well as nested safeContents. | |
| 514 */ | |
| 515 static sec_PKCS12SafeContentsContext * | |
| 516 sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx, | |
| 517 PRBool nestedSafe) | |
| 518 { | |
| 519 sec_PKCS12SafeContentsContext *safeContentsCtx = NULL; | |
| 520 const SEC_ASN1Template *theTemplate; | |
| 521 | |
| 522 if(!p12dcx || p12dcx->error) { | |
| 523 return NULL; | |
| 524 } | |
| 525 | |
| 526 /* allocate a new safeContents list or grow the existing list and | |
| 527 * append the new safeContents onto the end. | |
| 528 */ | |
| 529 p12dcx->safeContentsList = (!p12dcx->safeContentsCnt) | |
| 530 ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeContentsContext *, 2) | |
| 531 : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeContentsList, | |
| 532 sec_PKCS12SafeContentsContext *, | |
| 533 1 + p12dcx->safeContentsCnt, | |
| 534 2 + p12dcx->safeContentsCnt); | |
| 535 | |
| 536 if(!p12dcx->safeContentsList) { | |
| 537 p12dcx->errorValue = PORT_GetError(); | |
| 538 goto loser; | |
| 539 } | |
| 540 | |
| 541 p12dcx->safeContentsList[p12dcx->safeContentsCnt] = safeContentsCtx = | |
| 542 PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeContentsContext); | |
| 543 if(!p12dcx->safeContentsList[p12dcx->safeContentsCnt]) { | |
| 544 p12dcx->errorValue = PORT_GetError(); | |
| 545 goto loser; | |
| 546 } | |
| 547 p12dcx->safeContentsList[++p12dcx->safeContentsCnt] = NULL; | |
| 548 | |
| 549 /* set up the state variables */ | |
| 550 safeContentsCtx->p12dcx = p12dcx; | |
| 551 safeContentsCtx->arena = p12dcx->arena; | |
| 552 | |
| 553 /* begin the decoding -- the template is based on whether we are | |
| 554 * decoding a nested safeContents or not. | |
| 555 */ | |
| 556 if(nestedSafe == PR_TRUE) { | |
| 557 theTemplate = sec_PKCS12NestedSafeContentsDecodeTemplate; | |
| 558 } else { | |
| 559 theTemplate = sec_PKCS12SafeContentsDecodeTemplate; | |
| 560 } | |
| 561 | |
| 562 /* start the decoder context */ | |
| 563 safeContentsCtx->safeContentsA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, | |
| 564 &safeContentsCtx->safeContents, | |
| 565 theTemplate); | |
| 566 | |
| 567 if(!safeContentsCtx->safeContentsA1Dcx) { | |
| 568 p12dcx->errorValue = PORT_GetError(); | |
| 569 goto loser; | |
| 570 } | |
| 571 | |
| 572 /* set the safeContents notify procedure to look for | |
| 573 * and start the decode of safeBags. | |
| 574 */ | |
| 575 SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->safeContentsA1Dcx, | |
| 576 sec_pkcs12_decoder_safe_contents_notify, | |
| 577 safeContentsCtx); | |
| 578 | |
| 579 return safeContentsCtx; | |
| 580 | |
| 581 loser: | |
| 582 /* in the case of an error, we want to finish the decoder | |
| 583 * context and set the error flag. | |
| 584 */ | |
| 585 if(safeContentsCtx && safeContentsCtx->safeContentsA1Dcx) { | |
| 586 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx); | |
| 587 safeContentsCtx->safeContentsA1Dcx = NULL; | |
| 588 } | |
| 589 | |
| 590 p12dcx->error = PR_TRUE; | |
| 591 | |
| 592 return NULL; | |
| 593 } | |
| 594 | |
| 595 /* wrapper for updating safeContents. this is set as the filter of | |
| 596 * safeBag when there is a nested safeContents. | |
| 597 */ | |
| 598 static void | |
| 599 sec_pkcs12_decoder_nested_safe_contents_update(void *arg, const char *buf, | |
| 600 unsigned long len, int depth, | |
| 601 SEC_ASN1EncodingPart data_kind) | |
| 602 { | |
| 603 sec_PKCS12SafeContentsContext *safeContentsCtx = | |
| 604 (sec_PKCS12SafeContentsContext *)arg; | |
| 605 SEC_PKCS12DecoderContext *p12dcx; | |
| 606 SECStatus rv; | |
| 607 | |
| 608 /* check for an error */ | |
| 609 if(!safeContentsCtx || !safeContentsCtx->p12dcx | |
| 610 || safeContentsCtx->p12dcx->error | |
| 611 || !safeContentsCtx->safeContentsA1Dcx) { | |
| 612 return; | |
| 613 } | |
| 614 | |
| 615 /* no need to update if no data sent in */ | |
| 616 if(!len || !buf) { | |
| 617 return; | |
| 618 } | |
| 619 | |
| 620 /* update the decoding context */ | |
| 621 p12dcx = safeContentsCtx->p12dcx; | |
| 622 rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len); | |
| 623 if(rv != SECSuccess) { | |
| 624 p12dcx->errorValue = PORT_GetError(); | |
| 625 goto loser; | |
| 626 } | |
| 627 | |
| 628 return; | |
| 629 | |
| 630 loser: | |
| 631 /* handle any errors. If a decoding context is open, close it. */ | |
| 632 p12dcx->error = PR_TRUE; | |
| 633 if(safeContentsCtx->safeContentsA1Dcx) { | |
| 634 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx); | |
| 635 safeContentsCtx->safeContentsA1Dcx = NULL; | |
| 636 } | |
| 637 } | |
| 638 | |
| 639 /* whenever a new safeContentsSafeBag is encountered, we need | |
| 640 * to init a safeContentsContext. | |
| 641 */ | |
| 642 static SECStatus | |
| 643 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext | |
| 644 *safeContentsCtx) | |
| 645 { | |
| 646 /* check for an error */ | |
| 647 if(!safeContentsCtx || !safeContentsCtx->p12dcx || | |
| 648 safeContentsCtx->p12dcx->error) { | |
| 649 return SECFailure; | |
| 650 } | |
| 651 | |
| 652 safeContentsCtx->nestedSafeContentsCtx = | |
| 653 sec_pkcs12_decoder_safe_contents_init_decode(safeContentsCtx->p12dcx, | |
| 654 PR_TRUE); | |
| 655 if(!safeContentsCtx->nestedSafeContentsCtx) { | |
| 656 return SECFailure; | |
| 657 } | |
| 658 | |
| 659 /* set up new filter proc */ | |
| 660 SEC_ASN1DecoderSetNotifyProc( | |
| 661 safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx, | |
| 662 sec_pkcs12_decoder_safe_contents_notify, | |
| 663 safeContentsCtx->nestedSafeContentsCtx); | |
| 664 | |
| 665 SEC_ASN1DecoderSetFilterProc(safeContentsCtx->currentSafeBagA1Dcx, | |
| 666 sec_pkcs12_decoder_nested_safe_contents_update, | |
| 667 safeContentsCtx->nestedSafeContentsCtx, | |
| 668 PR_TRUE); | |
| 669 | |
| 670 return SECSuccess; | |
| 671 } | |
| 672 | |
| 673 /* when the safeContents is done decoding, we need to reset the | |
| 674 * proper filter and notify procs and close the decoding context | |
| 675 */ | |
| 676 static SECStatus | |
| 677 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext | |
| 678 *safeContentsCtx) | |
| 679 { | |
| 680 /* check for error */ | |
| 681 if(!safeContentsCtx || !safeContentsCtx->p12dcx || | |
| 682 safeContentsCtx->p12dcx->error) { | |
| 683 return SECFailure; | |
| 684 } | |
| 685 | |
| 686 /* clean up */ | |
| 687 SEC_ASN1DecoderClearFilterProc(safeContentsCtx->currentSafeBagA1Dcx); | |
| 688 SEC_ASN1DecoderClearNotifyProc( | |
| 689 safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx); | |
| 690 SEC_ASN1DecoderFinish( | |
| 691 safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx); | |
| 692 safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx = NULL; | |
| 693 safeContentsCtx->nestedSafeContentsCtx = NULL; | |
| 694 | |
| 695 return SECSuccess; | |
| 696 } | |
| 697 | |
| 698 /* wrapper for updating safeContents. This is used when decoding | |
| 699 * the nested safeContents and any authenticatedSafes. | |
| 700 */ | |
| 701 static void | |
| 702 sec_pkcs12_decoder_safe_contents_callback(void *arg, const char *buf, | |
| 703 unsigned long len) | |
| 704 { | |
| 705 SECStatus rv; | |
| 706 sec_PKCS12SafeContentsContext *safeContentsCtx = | |
| 707 (sec_PKCS12SafeContentsContext *)arg; | |
| 708 SEC_PKCS12DecoderContext *p12dcx; | |
| 709 | |
| 710 /* check for error */ | |
| 711 if(!safeContentsCtx || !safeContentsCtx->p12dcx | |
| 712 || safeContentsCtx->p12dcx->error | |
| 713 || !safeContentsCtx->safeContentsA1Dcx) { | |
| 714 return; | |
| 715 } | |
| 716 p12dcx = safeContentsCtx->p12dcx; | |
| 717 | |
| 718 /* update the decoder */ | |
| 719 rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len); | |
| 720 if(rv != SECSuccess) { | |
| 721 /* if we fail while trying to decode a 'safe', it's probably because | |
| 722 * we didn't have the correct password. */ | |
| 723 PORT_SetError(SEC_ERROR_BAD_PASSWORD); | |
| 724 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE; | |
| 725 SEC_PKCS7DecoderAbort(p12dcx->currentASafeP7Dcx,SEC_ERROR_BAD_PASSWORD); | |
| 726 goto loser; | |
| 727 } | |
| 728 | |
| 729 return; | |
| 730 | |
| 731 loser: | |
| 732 /* set the error and finish the context */ | |
| 733 p12dcx->error = PR_TRUE; | |
| 734 if(safeContentsCtx->safeContentsA1Dcx) { | |
| 735 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx); | |
| 736 safeContentsCtx->safeContentsA1Dcx = NULL; | |
| 737 } | |
| 738 | |
| 739 return; | |
| 740 } | |
| 741 | |
| 742 /* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate | |
| 743 */ | |
| 744 static void | |
| 745 sec_pkcs12_decoder_wrap_p7_update(void *arg, const char *data, | |
| 746 unsigned long len, int depth, | |
| 747 SEC_ASN1EncodingPart data_kind) | |
| 748 { | |
| 749 SEC_PKCS7DecoderContext *p7dcx = (SEC_PKCS7DecoderContext *)arg; | |
| 750 | |
| 751 SEC_PKCS7DecoderUpdate(p7dcx, data, len); | |
| 752 } | |
| 753 | |
| 754 /* notify function for decoding aSafes. at the beginning, | |
| 755 * of an authenticatedSafe, we start a decode of a safeContents. | |
| 756 * at the end, we clean up the safeContents decoder context and | |
| 757 * reset state variables | |
| 758 */ | |
| 759 static void | |
| 760 sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest, | |
| 761 int real_depth) | |
| 762 { | |
| 763 SEC_PKCS12DecoderContext *p12dcx; | |
| 764 sec_PKCS12SafeContentsContext *safeContentsCtx; | |
| 765 | |
| 766 /* make sure no error occurred. */ | |
| 767 p12dcx = (SEC_PKCS12DecoderContext *)arg; | |
| 768 if(!p12dcx || p12dcx->error) { | |
| 769 return; | |
| 770 } | |
| 771 | |
| 772 if(before) { | |
| 773 | |
| 774 /* init a new safeContentsContext */ | |
| 775 safeContentsCtx = sec_pkcs12_decoder_safe_contents_init_decode(p12dcx, | |
| 776 PR_FALSE); | |
| 777 if(!safeContentsCtx) { | |
| 778 goto loser; | |
| 779 } | |
| 780 | |
| 781 /* initiate the PKCS7ContentInfo decode */ | |
| 782 p12dcx->currentASafeP7Dcx = SEC_PKCS7DecoderStart( | |
| 783 sec_pkcs12_decoder_safe_contents_callback, | |
| 784 safeContentsCtx, | |
| 785 p12dcx->pwfn, p12dcx->pwfnarg, | |
| 786 sec_pkcs12_decoder_get_decrypt_key, p12dcx, | |
| 787 sec_pkcs12_decoder_decryption_allowed); | |
| 788 if(!p12dcx->currentASafeP7Dcx) { | |
| 789 p12dcx->errorValue = PORT_GetError(); | |
| 790 goto loser; | |
| 791 } | |
| 792 SEC_ASN1DecoderSetFilterProc(p12dcx->aSafeA1Dcx, | |
| 793 sec_pkcs12_decoder_wrap_p7_update, | |
| 794 p12dcx->currentASafeP7Dcx, PR_TRUE); | |
| 795 } | |
| 796 | |
| 797 if(!before) { | |
| 798 /* if one is being decoded, finish the decode */ | |
| 799 if(p12dcx->currentASafeP7Dcx != NULL) { | |
| 800 SEC_PKCS7ContentInfo * cinfo; | |
| 801 unsigned int cnt = p12dcx->safeContentsCnt - 1; | |
| 802 safeContentsCtx = p12dcx->safeContentsList[cnt]; | |
| 803 if (safeContentsCtx->safeContentsA1Dcx) { | |
| 804 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx); | |
| 805 safeContentsCtx->safeContentsA1Dcx = NULL; | |
| 806 } | |
| 807 cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx); | |
| 808 p12dcx->currentASafeP7Dcx = NULL; | |
| 809 if(!cinfo) { | |
| 810 p12dcx->errorValue = PORT_GetError(); | |
| 811 goto loser; | |
| 812 } | |
| 813 SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */ | |
| 814 } | |
| 815 } | |
| 816 | |
| 817 | |
| 818 return; | |
| 819 | |
| 820 loser: | |
| 821 /* set the error flag */ | |
| 822 p12dcx->error = PR_TRUE; | |
| 823 return; | |
| 824 } | |
| 825 | |
| 826 /* wrapper for updating asafes decoding context. this function | |
| 827 * writes data being decoded to disk, so that a mac can be computed | |
| 828 * later. | |
| 829 */ | |
| 830 static void | |
| 831 sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf, | |
| 832 unsigned long len) | |
| 833 { | |
| 834 SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg; | |
| 835 SECStatus rv; | |
| 836 | |
| 837 if(!p12dcx || p12dcx->error) { | |
| 838 return; | |
| 839 } | |
| 840 | |
| 841 /* update the context */ | |
| 842 rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeA1Dcx, buf, len); | |
| 843 if(rv != SECSuccess) { | |
| 844 p12dcx->errorValue = PORT_GetError(); | |
| 845 p12dcx->error = PR_TRUE; | |
| 846 goto loser; | |
| 847 } | |
| 848 | |
| 849 /* if we are writing to a file, write out the new information */ | |
| 850 if(p12dcx->dWrite) { | |
| 851 unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg, | |
| 852 (unsigned char *)buf, len); | |
| 853 if(writeLen != len) { | |
| 854 p12dcx->errorValue = PORT_GetError(); | |
| 855 goto loser; | |
| 856 } | |
| 857 } | |
| 858 | |
| 859 return; | |
| 860 | |
| 861 loser: | |
| 862 /* set the error flag */ | |
| 863 p12dcx->error = PR_TRUE; | |
| 864 SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx); | |
| 865 p12dcx->aSafeA1Dcx = NULL; | |
| 866 | |
| 867 return; | |
| 868 } | |
| 869 | |
| 870 /* start the decode of an authenticatedSafe contentInfo. | |
| 871 */ | |
| 872 static SECStatus | |
| 873 sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx) | |
| 874 { | |
| 875 if(!p12dcx || p12dcx->error) { | |
| 876 return SECFailure; | |
| 877 } | |
| 878 | |
| 879 /* start the decode context */ | |
| 880 p12dcx->aSafeA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, | |
| 881 &p12dcx->authSafe, | |
| 882 sec_PKCS12AuthenticatedSafeTemplate); | |
| 883 if(!p12dcx->aSafeA1Dcx) { | |
| 884 p12dcx->errorValue = PORT_GetError(); | |
| 885 goto loser; | |
| 886 } | |
| 887 | |
| 888 /* set the notify function */ | |
| 889 SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeA1Dcx, | |
| 890 sec_pkcs12_decoder_asafes_notify, p12dcx); | |
| 891 | |
| 892 /* begin the authSafe decoder context */ | |
| 893 p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart( | |
| 894 sec_pkcs12_decoder_asafes_callback, p12dcx, | |
| 895 p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL)
; | |
| 896 if(!p12dcx->aSafeP7Dcx) { | |
| 897 p12dcx->errorValue = PORT_GetError(); | |
| 898 goto loser; | |
| 899 } | |
| 900 | |
| 901 /* open the temp file for writing, if the digest functions were set */ | |
| 902 if(p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE) | |
| 903 != SECSuccess) { | |
| 904 p12dcx->errorValue = PORT_GetError(); | |
| 905 goto loser; | |
| 906 } | |
| 907 /* dOpen(dArg, PR_FALSE) creates the temp file */ | |
| 908 p12dcx->dIsOpen = PR_TRUE; | |
| 909 | |
| 910 return SECSuccess; | |
| 911 | |
| 912 loser: | |
| 913 p12dcx->error = PR_TRUE; | |
| 914 | |
| 915 if(p12dcx->aSafeA1Dcx) { | |
| 916 SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx); | |
| 917 p12dcx->aSafeA1Dcx = NULL; | |
| 918 } | |
| 919 | |
| 920 if(p12dcx->aSafeP7Dcx) { | |
| 921 SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx); | |
| 922 p12dcx->aSafeP7Dcx = NULL; | |
| 923 } | |
| 924 | |
| 925 return SECFailure; | |
| 926 } | |
| 927 | |
| 928 /* wrapper for updating the safeContents. this function is used as | |
| 929 * a filter for the pfx when decoding the authenticated safes | |
| 930 */ | |
| 931 static void | |
| 932 sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf, | |
| 933 unsigned long len, int depth, | |
| 934 SEC_ASN1EncodingPart data_kind) | |
| 935 { | |
| 936 SEC_PKCS12DecoderContext *p12dcx; | |
| 937 SECStatus rv; | |
| 938 | |
| 939 p12dcx = (SEC_PKCS12DecoderContext*)arg; | |
| 940 if(!p12dcx || p12dcx->error) { | |
| 941 return; | |
| 942 } | |
| 943 | |
| 944 /* update the safeContents decoder */ | |
| 945 rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len); | |
| 946 if(rv != SECSuccess) { | |
| 947 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE; | |
| 948 goto loser; | |
| 949 } | |
| 950 | |
| 951 return; | |
| 952 | |
| 953 loser: | |
| 954 | |
| 955 /* did we find an error? if so, close the context and set the | |
| 956 * error flag. | |
| 957 */ | |
| 958 SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx); | |
| 959 p12dcx->aSafeP7Dcx = NULL; | |
| 960 p12dcx->error = PR_TRUE; | |
| 961 } | |
| 962 | |
| 963 /* notify procedure used while decoding the pfx. When we encounter | |
| 964 * the authSafes, we want to trigger the decoding of authSafes as well | |
| 965 * as when we encounter the macData, trigger the decoding of it. we do | |
| 966 * this because we we are streaming the decoder and not decoding in place. | |
| 967 * the pfx which is the destination, only has the version decoded into it. | |
| 968 */ | |
| 969 static void | |
| 970 sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest, | |
| 971 int real_depth) | |
| 972 { | |
| 973 SECStatus rv; | |
| 974 SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext*)arg; | |
| 975 | |
| 976 /* if an error occurs, clear the notifyProc and the filterProc | |
| 977 * and continue. | |
| 978 */ | |
| 979 if(p12dcx->error) { | |
| 980 SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxA1Dcx); | |
| 981 SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx); | |
| 982 return; | |
| 983 } | |
| 984 | |
| 985 if(before && (dest == &p12dcx->pfx.encodedAuthSafe)) { | |
| 986 | |
| 987 /* we want to make sure this is a version we support */ | |
| 988 if(!sec_pkcs12_proper_version(&p12dcx->pfx)) { | |
| 989 p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION; | |
| 990 goto loser; | |
| 991 } | |
| 992 | |
| 993 /* start the decode of the aSafes cinfo... */ | |
| 994 rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx); | |
| 995 if(rv != SECSuccess) { | |
| 996 goto loser; | |
| 997 } | |
| 998 | |
| 999 /* set the filter proc to update the authenticated safes. */ | |
| 1000 SEC_ASN1DecoderSetFilterProc(p12dcx->pfxA1Dcx, | |
| 1001 sec_pkcs12_decode_asafes_cinfo_update, | |
| 1002 p12dcx, PR_TRUE); | |
| 1003 } | |
| 1004 | |
| 1005 if(!before && (dest == &p12dcx->pfx.encodedAuthSafe)) { | |
| 1006 | |
| 1007 /* we are done decoding the authenticatedSafes, so we need to | |
| 1008 * finish the decoderContext and clear the filter proc | |
| 1009 * and close the hmac callback, if present | |
| 1010 */ | |
| 1011 p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx); | |
| 1012 p12dcx->aSafeP7Dcx = NULL; | |
| 1013 if(!p12dcx->aSafeCinfo) { | |
| 1014 p12dcx->errorValue = PORT_GetError(); | |
| 1015 goto loser; | |
| 1016 } | |
| 1017 SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx); | |
| 1018 if(p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) | |
| 1019 != SECSuccess)) { | |
| 1020 p12dcx->errorValue = PORT_GetError(); | |
| 1021 goto loser; | |
| 1022 } | |
| 1023 | |
| 1024 } | |
| 1025 | |
| 1026 return; | |
| 1027 | |
| 1028 loser: | |
| 1029 p12dcx->error = PR_TRUE; | |
| 1030 } | |
| 1031 | |
| 1032 /* default implementations of the open/close/read/write functions for | |
| 1033 SEC_PKCS12DecoderStart | |
| 1034 */ | |
| 1035 | |
| 1036 #define DEFAULT_TEMP_SIZE 4096 | |
| 1037 | |
| 1038 static SECStatus | |
| 1039 p12u_DigestOpen(void *arg, PRBool readData) | |
| 1040 { | |
| 1041 SEC_PKCS12DecoderContext* p12cxt = arg; | |
| 1042 | |
| 1043 p12cxt->currentpos = 0; | |
| 1044 | |
| 1045 if (PR_FALSE == readData) { | |
| 1046 /* allocate an initial buffer */ | |
| 1047 p12cxt->filesize = 0; | |
| 1048 p12cxt->allocated = DEFAULT_TEMP_SIZE; | |
| 1049 p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE); | |
| 1050 PR_ASSERT(p12cxt->buffer); | |
| 1051 } | |
| 1052 else | |
| 1053 { | |
| 1054 PR_ASSERT(p12cxt->buffer); | |
| 1055 if (!p12cxt->buffer) { | |
| 1056 return SECFailure; /* no data to read */ | |
| 1057 } | |
| 1058 } | |
| 1059 | |
| 1060 return SECSuccess; | |
| 1061 } | |
| 1062 | |
| 1063 static SECStatus | |
| 1064 p12u_DigestClose(void *arg, PRBool removeFile) | |
| 1065 { | |
| 1066 SEC_PKCS12DecoderContext* p12cxt = arg; | |
| 1067 | |
| 1068 PR_ASSERT(p12cxt); | |
| 1069 if (!p12cxt) { | |
| 1070 return SECFailure; | |
| 1071 } | |
| 1072 p12cxt->currentpos = 0; | |
| 1073 | |
| 1074 if (PR_TRUE == removeFile) { | |
| 1075 PR_ASSERT(p12cxt->buffer); | |
| 1076 if (!p12cxt->buffer) { | |
| 1077 return SECFailure; | |
| 1078 } | |
| 1079 if (p12cxt->buffer) { | |
| 1080 PORT_Free(p12cxt->buffer); | |
| 1081 p12cxt->buffer = NULL; | |
| 1082 p12cxt->allocated = 0; | |
| 1083 p12cxt->filesize = 0; | |
| 1084 } | |
| 1085 } | |
| 1086 | |
| 1087 return SECSuccess; | |
| 1088 } | |
| 1089 | |
| 1090 static int | |
| 1091 p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len) | |
| 1092 { | |
| 1093 int toread = len; | |
| 1094 SEC_PKCS12DecoderContext* p12cxt = arg; | |
| 1095 | |
| 1096 if(!buf || len == 0 || !p12cxt->buffer) { | |
| 1097 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1098 return -1; | |
| 1099 } | |
| 1100 | |
| 1101 if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) { | |
| 1102 /* trying to read past the end of the buffer */ | |
| 1103 toread = p12cxt->filesize - p12cxt->currentpos; | |
| 1104 } | |
| 1105 memcpy(buf, (char*)p12cxt->buffer + p12cxt->currentpos, toread); | |
| 1106 p12cxt->currentpos += toread; | |
| 1107 return toread; | |
| 1108 } | |
| 1109 | |
| 1110 static int | |
| 1111 p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len) | |
| 1112 { | |
| 1113 SEC_PKCS12DecoderContext* p12cxt = arg; | |
| 1114 | |
| 1115 if(!buf || len == 0) { | |
| 1116 return -1; | |
| 1117 } | |
| 1118 | |
| 1119 if (p12cxt->currentpos+(long)len > p12cxt->filesize) { | |
| 1120 p12cxt->filesize = p12cxt->currentpos + len; | |
| 1121 } | |
| 1122 else { | |
| 1123 p12cxt->filesize += len; | |
| 1124 } | |
| 1125 if (p12cxt->filesize > p12cxt->allocated) { | |
| 1126 void* newbuffer; | |
| 1127 size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE; | |
| 1128 newbuffer = PORT_Realloc(p12cxt->buffer, newsize); | |
| 1129 if (NULL == newbuffer) { | |
| 1130 return -1; /* can't extend the buffer */ | |
| 1131 } | |
| 1132 p12cxt->buffer = newbuffer; | |
| 1133 p12cxt->allocated = newsize; | |
| 1134 } | |
| 1135 PR_ASSERT(p12cxt->buffer); | |
| 1136 memcpy((char*)p12cxt->buffer + p12cxt->currentpos, buf, len); | |
| 1137 p12cxt->currentpos += len; | |
| 1138 return len; | |
| 1139 } | |
| 1140 | |
| 1141 /* SEC_PKCS12DecoderStart | |
| 1142 * Creates a decoder context for decoding a PKCS 12 PDU objct. | |
| 1143 * This function sets up the initial decoding context for the | |
| 1144 * PFX and sets the needed state variables. | |
| 1145 * | |
| 1146 * pwitem - the password for the hMac and any encoded safes. | |
| 1147 * this should be changed to take a callback which retrieves | |
| 1148 * the password. it may be possible for different safes to | |
| 1149 * have different passwords. also, the password is already | |
| 1150 * in unicode. it should probably be converted down below via | |
| 1151 * a unicode conversion callback. | |
| 1152 * slot - the slot to import the dataa into should multiple slots | |
| 1153 * be supported based on key type and cert type? | |
| 1154 * dOpen, dClose, dRead, dWrite - digest routines for writing data | |
| 1155 * to a file so it could be read back and the hmac recomputed | |
| 1156 * and verified. doesn't seem to be a way for both encoding | |
| 1157 * and decoding to be single pass, thus the need for these | |
| 1158 * routines. | |
| 1159 * dArg - the argument for dOpen, etc. | |
| 1160 * | |
| 1161 * if NULL == dOpen == dClose == dRead == dWrite == dArg, then default | |
| 1162 * implementations using a memory buffer are used | |
| 1163 * | |
| 1164 * This function returns the decoder context, if it was successful. | |
| 1165 * Otherwise, null is returned. | |
| 1166 */ | |
| 1167 SEC_PKCS12DecoderContext * | |
| 1168 SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx, | |
| 1169 digestOpenFn dOpen, digestCloseFn dClose, | |
| 1170 digestIOFn dRead, digestIOFn dWrite, void *dArg) | |
| 1171 { | |
| 1172 SEC_PKCS12DecoderContext *p12dcx; | |
| 1173 PLArenaPool *arena; | |
| 1174 | |
| 1175 arena = PORT_NewArena(2048); /* different size? */ | |
| 1176 if(!arena) { | |
| 1177 return NULL; /* error is already set */ | |
| 1178 } | |
| 1179 | |
| 1180 /* allocate the decoder context and set the state variables */ | |
| 1181 p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext); | |
| 1182 if(!p12dcx) { | |
| 1183 goto loser; /* error is already set */ | |
| 1184 } | |
| 1185 | |
| 1186 if (!dOpen && !dClose && !dRead && !dWrite && !dArg) { | |
| 1187 /* use default implementations */ | |
| 1188 dOpen = p12u_DigestOpen; | |
| 1189 dClose = p12u_DigestClose; | |
| 1190 dRead = p12u_DigestRead; | |
| 1191 dWrite = p12u_DigestWrite; | |
| 1192 dArg = (void*)p12dcx; | |
| 1193 } | |
| 1194 | |
| 1195 p12dcx->arena = arena; | |
| 1196 p12dcx->pwitem = pwitem; | |
| 1197 p12dcx->slot = (slot ? PK11_ReferenceSlot(slot) | |
| 1198 : PK11_GetInternalKeySlot()); | |
| 1199 p12dcx->wincx = wincx; | |
| 1200 p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs; | |
| 1201 #ifdef IS_LITTLE_ENDIAN | |
| 1202 p12dcx->swapUnicodeBytes = PR_TRUE; | |
| 1203 #else | |
| 1204 p12dcx->swapUnicodeBytes = PR_FALSE; | |
| 1205 #endif | |
| 1206 p12dcx->errorValue = 0; | |
| 1207 p12dcx->error = PR_FALSE; | |
| 1208 | |
| 1209 /* start the decoding of the PFX and set the notify proc | |
| 1210 * for the PFX item. | |
| 1211 */ | |
| 1212 p12dcx->pfxA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx, | |
| 1213 sec_PKCS12PFXItemTemplate); | |
| 1214 if(!p12dcx->pfxA1Dcx) { | |
| 1215 PK11_FreeSlot(p12dcx->slot); | |
| 1216 goto loser; | |
| 1217 } | |
| 1218 | |
| 1219 SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxA1Dcx, | |
| 1220 sec_pkcs12_decoder_pfx_notify_proc, | |
| 1221 p12dcx); | |
| 1222 | |
| 1223 /* set up digest functions */ | |
| 1224 p12dcx->dOpen = dOpen; | |
| 1225 p12dcx->dWrite = dWrite; | |
| 1226 p12dcx->dClose = dClose; | |
| 1227 p12dcx->dRead = dRead; | |
| 1228 p12dcx->dArg = dArg; | |
| 1229 p12dcx->dIsOpen = PR_FALSE; | |
| 1230 | |
| 1231 p12dcx->keyList = NULL; | |
| 1232 p12dcx->decitem.type = 0; | |
| 1233 p12dcx->decitem.der = NULL; | |
| 1234 p12dcx->decitem.hasKey = PR_FALSE; | |
| 1235 p12dcx->decitem.friendlyName = NULL; | |
| 1236 p12dcx->iteration = 0; | |
| 1237 | |
| 1238 return p12dcx; | |
| 1239 | |
| 1240 loser: | |
| 1241 PORT_FreeArena(arena, PR_TRUE); | |
| 1242 return NULL; | |
| 1243 } | |
| 1244 | |
| 1245 SECStatus | |
| 1246 SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx, | |
| 1247 SECPKCS12TargetTokenCAs tokenCAs) | |
| 1248 { | |
| 1249 if (!p12dcx || p12dcx->error) { | |
| 1250 return SECFailure; | |
| 1251 } | |
| 1252 p12dcx->tokenCAs = tokenCAs; | |
| 1253 return SECSuccess; | |
| 1254 } | |
| 1255 | |
| 1256 | |
| 1257 /* SEC_PKCS12DecoderUpdate | |
| 1258 * Streaming update sending more data to the decoder. If | |
| 1259 * an error occurs, SECFailure is returned. | |
| 1260 * | |
| 1261 * p12dcx - the decoder context | |
| 1262 * data, len - the data buffer and length of data to send to | |
| 1263 * the update functions. | |
| 1264 */ | |
| 1265 SECStatus | |
| 1266 SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx, | |
| 1267 unsigned char *data, unsigned long len) | |
| 1268 { | |
| 1269 SECStatus rv; | |
| 1270 | |
| 1271 if(!p12dcx || p12dcx->error) { | |
| 1272 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1273 return SECFailure; | |
| 1274 } | |
| 1275 | |
| 1276 /* update the PFX decoder context */ | |
| 1277 rv = SEC_ASN1DecoderUpdate(p12dcx->pfxA1Dcx, (const char *)data, len); | |
| 1278 if(rv != SECSuccess) { | |
| 1279 p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE; | |
| 1280 goto loser; | |
| 1281 } | |
| 1282 | |
| 1283 return SECSuccess; | |
| 1284 | |
| 1285 loser: | |
| 1286 | |
| 1287 p12dcx->error = PR_TRUE; | |
| 1288 return SECFailure; | |
| 1289 } | |
| 1290 | |
| 1291 /* This should be a nice sized buffer for reading in data (potentially large | |
| 1292 ** amounts) to be MACed. It should be MUCH larger than HASH_LENGTH_MAX. | |
| 1293 */ | |
| 1294 #define IN_BUF_LEN 1024 | |
| 1295 #ifdef DEBUG | |
| 1296 static const char bufferEnd[] = { "BufferEnd" } ; | |
| 1297 #endif | |
| 1298 #define FUDGE 128 /* must be as large as bufferEnd or more. */ | |
| 1299 | |
| 1300 /* verify the hmac by reading the data from the temporary file | |
| 1301 * using the routines specified when the decodingContext was | |
| 1302 * created and return SECSuccess if the hmac matches. | |
| 1303 */ | |
| 1304 static SECStatus | |
| 1305 sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx) | |
| 1306 { | |
| 1307 PK11Context * pk11cx = NULL; | |
| 1308 PK11SymKey * symKey = NULL; | |
| 1309 SECItem * params = NULL; | |
| 1310 unsigned char * buf; | |
| 1311 SECStatus rv = SECFailure; | |
| 1312 SECStatus lrv; | |
| 1313 unsigned int bufLen; | |
| 1314 int iteration; | |
| 1315 int bytesRead; | |
| 1316 SECOidTag algtag; | |
| 1317 SECItem hmacRes; | |
| 1318 SECItem ignore = {0}; | |
| 1319 CK_MECHANISM_TYPE integrityMech; | |
| 1320 | |
| 1321 if(!p12dcx || p12dcx->error) { | |
| 1322 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1323 return SECFailure; | |
| 1324 } | |
| 1325 buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE); | |
| 1326 if (!buf) | |
| 1327 return SECFailure; /* error code has been set. */ | |
| 1328 | |
| 1329 #ifdef DEBUG | |
| 1330 memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd); | |
| 1331 #endif | |
| 1332 | |
| 1333 /* generate hmac key */ | |
| 1334 if(p12dcx->macData.iter.data) { | |
| 1335 iteration = (int)DER_GetInteger(&p12dcx->macData.iter); | |
| 1336 } else { | |
| 1337 iteration = 1; | |
| 1338 } | |
| 1339 | |
| 1340 params = PK11_CreatePBEParams(&p12dcx->macData.macSalt, p12dcx->pwitem, | |
| 1341 iteration); | |
| 1342 | |
| 1343 algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm); | |
| 1344 switch (algtag) { | |
| 1345 case SEC_OID_SHA1: | |
| 1346 integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break; | |
| 1347 case SEC_OID_MD5: | |
| 1348 integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break; | |
| 1349 case SEC_OID_MD2: | |
| 1350 integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break; | |
| 1351 default: | |
| 1352 goto loser; | |
| 1353 } | |
| 1354 | |
| 1355 symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL); | |
| 1356 PK11_DestroyPBEParams(params); | |
| 1357 params = NULL; | |
| 1358 if (!symKey) goto loser; | |
| 1359 /* init hmac */ | |
| 1360 pk11cx = PK11_CreateContextBySymKey(sec_pkcs12_algtag_to_mech(algtag), | |
| 1361 CKA_SIGN, symKey, &ignore); | |
| 1362 if(!pk11cx) { | |
| 1363 goto loser; | |
| 1364 } | |
| 1365 lrv = PK11_DigestBegin(pk11cx); | |
| 1366 if (lrv == SECFailure ) { | |
| 1367 goto loser; | |
| 1368 } | |
| 1369 | |
| 1370 /* try to open the data for readback */ | |
| 1371 if(p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) | |
| 1372 != SECSuccess)) { | |
| 1373 goto loser; | |
| 1374 } | |
| 1375 | |
| 1376 /* read the data back IN_BUF_LEN bytes at a time and recompute | |
| 1377 * the hmac. if fewer bytes are read than are requested, it is | |
| 1378 * assumed that the end of file has been reached. if bytesRead | |
| 1379 * is returned as -1, then an error occurred reading from the | |
| 1380 * file. | |
| 1381 */ | |
| 1382 do { | |
| 1383 bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN); | |
| 1384 if (bytesRead < 0) { | |
| 1385 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ); | |
| 1386 goto loser; | |
| 1387 } | |
| 1388 PORT_Assert(bytesRead <= IN_BUF_LEN); | |
| 1389 PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd)); | |
| 1390 | |
| 1391 if (bytesRead > IN_BUF_LEN) { | |
| 1392 /* dRead callback overflowed buffer. */ | |
| 1393 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
| 1394 goto loser; | |
| 1395 } | |
| 1396 | |
| 1397 if (bytesRead) { | |
| 1398 lrv = PK11_DigestOp(pk11cx, buf, bytesRead); | |
| 1399 if (lrv == SECFailure) { | |
| 1400 goto loser; | |
| 1401 } | |
| 1402 } | |
| 1403 } while (bytesRead == IN_BUF_LEN); | |
| 1404 | |
| 1405 /* finish the hmac context */ | |
| 1406 lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN); | |
| 1407 if (lrv == SECFailure ) { | |
| 1408 goto loser; | |
| 1409 } | |
| 1410 | |
| 1411 hmacRes.data = buf; | |
| 1412 hmacRes.len = bufLen; | |
| 1413 | |
| 1414 /* is the hmac computed the same as the hmac which was decoded? */ | |
| 1415 rv = SECSuccess; | |
| 1416 if(SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) | |
| 1417 != SECEqual) { | |
| 1418 PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); | |
| 1419 rv = SECFailure; | |
| 1420 } | |
| 1421 | |
| 1422 loser: | |
| 1423 /* close the file and remove it */ | |
| 1424 if(p12dcx->dClose) { | |
| 1425 (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE); | |
| 1426 p12dcx->dIsOpen = PR_FALSE; | |
| 1427 } | |
| 1428 | |
| 1429 if(pk11cx) { | |
| 1430 PK11_DestroyContext(pk11cx, PR_TRUE); | |
| 1431 } | |
| 1432 if (params) { | |
| 1433 PK11_DestroyPBEParams(params); | |
| 1434 } | |
| 1435 if (symKey) { | |
| 1436 PK11_FreeSymKey(symKey); | |
| 1437 } | |
| 1438 PORT_ZFree(buf, IN_BUF_LEN + FUDGE); | |
| 1439 | |
| 1440 return rv; | |
| 1441 } | |
| 1442 | |
| 1443 /* SEC_PKCS12DecoderVerify | |
| 1444 * Verify the macData or the signature of the decoded PKCS 12 PDU. | |
| 1445 * If the signature or the macData do not match, SECFailure is | |
| 1446 * returned. | |
| 1447 * | |
| 1448 * p12dcx - the decoder context | |
| 1449 */ | |
| 1450 SECStatus | |
| 1451 SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx) | |
| 1452 { | |
| 1453 SECStatus rv = SECSuccess; | |
| 1454 | |
| 1455 /* make sure that no errors have occurred... */ | |
| 1456 if(!p12dcx) { | |
| 1457 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1458 return SECFailure; | |
| 1459 } | |
| 1460 if(p12dcx->error) { | |
| 1461 /* error code is already set! PORT_SetError(p12dcx->errorValue); */ | |
| 1462 return SECFailure; | |
| 1463 } | |
| 1464 | |
| 1465 rv = SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx); | |
| 1466 p12dcx->pfxA1Dcx = NULL; | |
| 1467 if(rv != SECSuccess) { | |
| 1468 return rv; | |
| 1469 } | |
| 1470 | |
| 1471 /* check the signature or the mac depending on the type of | |
| 1472 * integrity used. | |
| 1473 */ | |
| 1474 if(p12dcx->pfx.encodedMacData.len) { | |
| 1475 rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData, | |
| 1476 sec_PKCS12MacDataTemplate, | |
| 1477 &p12dcx->pfx.encodedMacData); | |
| 1478 if(rv == SECSuccess) { | |
| 1479 return sec_pkcs12_decoder_verify_mac(p12dcx); | |
| 1480 } | |
| 1481 return rv; | |
| 1482 } | |
| 1483 if (SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner, | |
| 1484 PR_FALSE)) { | |
| 1485 return SECSuccess; | |
| 1486 } | |
| 1487 PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC); | |
| 1488 return SECFailure; | |
| 1489 } | |
| 1490 | |
| 1491 /* SEC_PKCS12DecoderFinish | |
| 1492 * Free any open ASN1 or PKCS7 decoder contexts and then | |
| 1493 * free the arena pool which everything should be allocated | |
| 1494 * from. This function should be called upon completion of | |
| 1495 * decoding and installing of a pfx pdu. This should be | |
| 1496 * called even if an error occurs. | |
| 1497 * | |
| 1498 * p12dcx - the decoder context | |
| 1499 */ | |
| 1500 void | |
| 1501 SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx) | |
| 1502 { | |
| 1503 unsigned int i; | |
| 1504 | |
| 1505 if(!p12dcx) { | |
| 1506 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1507 return; | |
| 1508 } | |
| 1509 | |
| 1510 if(p12dcx->pfxA1Dcx) { | |
| 1511 SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx); | |
| 1512 p12dcx->pfxA1Dcx = NULL; | |
| 1513 } | |
| 1514 | |
| 1515 if(p12dcx->aSafeA1Dcx) { | |
| 1516 SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx); | |
| 1517 p12dcx->aSafeA1Dcx = NULL; | |
| 1518 } | |
| 1519 | |
| 1520 /* cleanup any old ASN1 decoder contexts */ | |
| 1521 for (i = 0; i < p12dcx->safeContentsCnt; ++i) { | |
| 1522 sec_PKCS12SafeContentsContext *safeContentsCtx, *nested; | |
| 1523 safeContentsCtx = p12dcx->safeContentsList[i]; | |
| 1524 if (safeContentsCtx) { | |
| 1525 nested = safeContentsCtx->nestedSafeContentsCtx; | |
| 1526 while (nested) { | |
| 1527 if (nested->safeContentsA1Dcx) { | |
| 1528 SEC_ASN1DecoderFinish(nested->safeContentsA1Dcx); | |
| 1529 nested->safeContentsA1Dcx = NULL; | |
| 1530 } | |
| 1531 nested = nested->nestedSafeContentsCtx; | |
| 1532 } | |
| 1533 if (safeContentsCtx->safeContentsA1Dcx) { | |
| 1534 SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx); | |
| 1535 safeContentsCtx->safeContentsA1Dcx = NULL; | |
| 1536 } | |
| 1537 } | |
| 1538 } | |
| 1539 | |
| 1540 if (p12dcx->currentASafeP7Dcx && | |
| 1541 p12dcx->currentASafeP7Dcx != p12dcx->aSafeP7Dcx) { | |
| 1542 SEC_PKCS7ContentInfo * cinfo; | |
| 1543 cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx); | |
| 1544 if (cinfo) { | |
| 1545 SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */ | |
| 1546 } | |
| 1547 } | |
| 1548 p12dcx->currentASafeP7Dcx = NULL; | |
| 1549 | |
| 1550 if(p12dcx->aSafeP7Dcx) { | |
| 1551 SEC_PKCS7ContentInfo * cinfo; | |
| 1552 cinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx); | |
| 1553 if (cinfo) { | |
| 1554 SEC_PKCS7DestroyContentInfo(cinfo); | |
| 1555 } | |
| 1556 p12dcx->aSafeP7Dcx = NULL; | |
| 1557 } | |
| 1558 | |
| 1559 if(p12dcx->aSafeCinfo) { | |
| 1560 SEC_PKCS7DestroyContentInfo(p12dcx->aSafeCinfo); | |
| 1561 p12dcx->aSafeCinfo = NULL; | |
| 1562 } | |
| 1563 | |
| 1564 if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) { | |
| 1565 SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE); | |
| 1566 } | |
| 1567 if (p12dcx->decitem.friendlyName != NULL) { | |
| 1568 SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE); | |
| 1569 } | |
| 1570 | |
| 1571 if(p12dcx->slot) { | |
| 1572 PK11_FreeSlot(p12dcx->slot); | |
| 1573 p12dcx->slot = NULL; | |
| 1574 } | |
| 1575 | |
| 1576 if(p12dcx->dIsOpen && p12dcx->dClose) { | |
| 1577 (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE); | |
| 1578 p12dcx->dIsOpen = PR_FALSE; | |
| 1579 } | |
| 1580 | |
| 1581 if(p12dcx->arena) { | |
| 1582 PORT_FreeArena(p12dcx->arena, PR_TRUE); | |
| 1583 } | |
| 1584 } | |
| 1585 | |
| 1586 static SECStatus | |
| 1587 sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag, | |
| 1588 SECOidTag attributeType, | |
| 1589 SECItem *attrValue) | |
| 1590 { | |
| 1591 int i = 0; | |
| 1592 SECOidData *oid; | |
| 1593 | |
| 1594 if(!bag || !attrValue) { | |
| 1595 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1596 return SECFailure; | |
| 1597 } | |
| 1598 | |
| 1599 oid = SECOID_FindOIDByTag(attributeType); | |
| 1600 if(!oid) { | |
| 1601 return SECFailure; | |
| 1602 } | |
| 1603 | |
| 1604 if(!bag->attribs) { | |
| 1605 bag->attribs = | |
| 1606 PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2); | |
| 1607 } else { | |
| 1608 while(bag->attribs[i]) | |
| 1609 i++; | |
| 1610 bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs, | |
| 1611 sec_PKCS12Attribute *, i + 1, i + 2); | |
| 1612 } | |
| 1613 | |
| 1614 if(!bag->attribs) { | |
| 1615 return SECFailure; | |
| 1616 } | |
| 1617 | |
| 1618 bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute); | |
| 1619 if(!bag->attribs) { | |
| 1620 return SECFailure; | |
| 1621 } | |
| 1622 | |
| 1623 bag->attribs[i]->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2); | |
| 1624 if(!bag->attribs[i]->attrValue) { | |
| 1625 return SECFailure; | |
| 1626 } | |
| 1627 | |
| 1628 bag->attribs[i+1] = NULL; | |
| 1629 bag->attribs[i]->attrValue[0] = attrValue; | |
| 1630 bag->attribs[i]->attrValue[1] = NULL; | |
| 1631 | |
| 1632 return SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid); | |
| 1633 } | |
| 1634 | |
| 1635 static SECItem * | |
| 1636 sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag, | |
| 1637 SECOidTag attributeType) | |
| 1638 { | |
| 1639 int i; | |
| 1640 | |
| 1641 if(!bag->attribs) { | |
| 1642 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1643 return NULL; | |
| 1644 } | |
| 1645 | |
| 1646 for (i = 0; bag->attribs[i] != NULL; i++) { | |
| 1647 if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == attributeType) { | |
| 1648 return bag->attribs[i]->attrValue[0]; | |
| 1649 } | |
| 1650 } | |
| 1651 return NULL; | |
| 1652 } | |
| 1653 | |
| 1654 /* For now, this function will merely remove any ":" | |
| 1655 * in the nickname which the PK11 functions may have | |
| 1656 * placed there. This will keep dual certs from appearing | |
| 1657 * twice under "Your" certificates when imported onto smart | |
| 1658 * cards. Once with the name "Slot:Cert" and another with | |
| 1659 * the nickname "Slot:Slot:Cert" | |
| 1660 */ | |
| 1661 static void | |
| 1662 sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick) | |
| 1663 { | |
| 1664 char *nickname; | |
| 1665 char *delimit; | |
| 1666 int delimitlen; | |
| 1667 | |
| 1668 nickname = (char*)nick->data; | |
| 1669 if ((delimit = PORT_Strchr(nickname, ':')) != NULL) { | |
| 1670 char *slotName; | |
| 1671 int slotNameLen; | |
| 1672 | |
| 1673 slotNameLen = delimit-nickname; | |
| 1674 slotName = PORT_NewArray(char, (slotNameLen+1)); | |
| 1675 PORT_Assert(slotName); | |
| 1676 if (slotName == NULL) { | |
| 1677 /* What else can we do?*/ | |
| 1678 return; | |
| 1679 } | |
| 1680 PORT_Memcpy(slotName, nickname, slotNameLen); | |
| 1681 slotName[slotNameLen] = '\0'; | |
| 1682 if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) { | |
| 1683 delimitlen = PORT_Strlen(delimit+1); | |
| 1684 PORT_Memmove(nickname, delimit+1, delimitlen+1); | |
| 1685 nick->len = delimitlen; | |
| 1686 } | |
| 1687 PORT_Free(slotName); | |
| 1688 } | |
| 1689 | |
| 1690 } | |
| 1691 | |
| 1692 static SECItem * | |
| 1693 sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag) | |
| 1694 { | |
| 1695 SECItem *src, *dest; | |
| 1696 | |
| 1697 if(!bag) { | |
| 1698 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1699 return NULL; | |
| 1700 } | |
| 1701 | |
| 1702 src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME); | |
| 1703 | |
| 1704 /* The return value src is 16-bit Unicode characters, in big-endian format. | |
| 1705 * Check if it is NULL or empty name. | |
| 1706 */ | |
| 1707 if(!src || !src->data || src->len < 2 || (!src->data[0] && !src->data[1])) { | |
| 1708 return NULL; | |
| 1709 } | |
| 1710 | |
| 1711 dest = (SECItem*)PORT_ZAlloc(sizeof(SECItem)); | |
| 1712 if(!dest) { | |
| 1713 goto loser; | |
| 1714 } | |
| 1715 if(!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE, | |
| 1716 PR_FALSE, PR_FALSE)) { | |
| 1717 goto loser; | |
| 1718 } | |
| 1719 | |
| 1720 sec_pkcs12_sanitize_nickname(bag->slot, dest); | |
| 1721 | |
| 1722 return dest; | |
| 1723 | |
| 1724 loser: | |
| 1725 if(dest) { | |
| 1726 SECITEM_ZfreeItem(dest, PR_TRUE); | |
| 1727 } | |
| 1728 | |
| 1729 bag->problem = PR_TRUE; | |
| 1730 bag->error = PORT_GetError(); | |
| 1731 return NULL; | |
| 1732 } | |
| 1733 | |
| 1734 static SECStatus | |
| 1735 sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name) | |
| 1736 { | |
| 1737 sec_PKCS12Attribute *attr = NULL; | |
| 1738 SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME); | |
| 1739 | |
| 1740 if(!bag || !bag->arena || !name) { | |
| 1741 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1742 return SECFailure; | |
| 1743 } | |
| 1744 | |
| 1745 if(!bag->attribs) { | |
| 1746 if(!oid) { | |
| 1747 goto loser; | |
| 1748 } | |
| 1749 | |
| 1750 bag->attribs = | |
| 1751 PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2); | |
| 1752 if(!bag->attribs) { | |
| 1753 goto loser; | |
| 1754 } | |
| 1755 bag->attribs[0] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute); | |
| 1756 if(!bag->attribs[0]) { | |
| 1757 goto loser; | |
| 1758 } | |
| 1759 bag->attribs[1] = NULL; | |
| 1760 | |
| 1761 attr = bag->attribs[0]; | |
| 1762 if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) | |
| 1763 != SECSuccess) { | |
| 1764 goto loser; | |
| 1765 } | |
| 1766 } else { | |
| 1767 int i; | |
| 1768 for (i = 0; bag->attribs[i]; i++) { | |
| 1769 if(SECOID_FindOIDTag(&bag->attribs[i]->attrType) | |
| 1770 == SEC_OID_PKCS9_FRIENDLY_NAME) { | |
| 1771 attr = bag->attribs[i]; | |
| 1772 break; | |
| 1773 } | |
| 1774 } | |
| 1775 if(!attr) { | |
| 1776 if(!oid) { | |
| 1777 goto loser; | |
| 1778 } | |
| 1779 bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs, | |
| 1780 sec_PKCS12Attribute *, i+1, i+2); | |
| 1781 if(!bag->attribs) { | |
| 1782 goto loser; | |
| 1783 } | |
| 1784 bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute); | |
| 1785 if(!bag->attribs[i]) { | |
| 1786 goto loser; | |
| 1787 } | |
| 1788 bag->attribs[i+1] = NULL; | |
| 1789 attr = bag->attribs[i]; | |
| 1790 if(SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) | |
| 1791 != SECSuccess) { | |
| 1792 goto loser; | |
| 1793 } | |
| 1794 } | |
| 1795 } | |
| 1796 | |
| 1797 PORT_Assert(attr); | |
| 1798 if(!attr->attrValue) { | |
| 1799 attr->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2); | |
| 1800 if(!attr->attrValue) { | |
| 1801 goto loser; | |
| 1802 } | |
| 1803 attr->attrValue[0] = PORT_ArenaZNew(bag->arena, SECItem); | |
| 1804 if(!attr->attrValue[0]) { | |
| 1805 goto loser; | |
| 1806 } | |
| 1807 attr->attrValue[1] = NULL; | |
| 1808 } | |
| 1809 | |
| 1810 name->len = PORT_Strlen((char *)name->data); | |
| 1811 if(!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0], | |
| 1812 name, PR_FALSE, PR_FALSE, PR_TRUE)) { | |
| 1813 goto loser; | |
| 1814 } | |
| 1815 | |
| 1816 return SECSuccess; | |
| 1817 | |
| 1818 loser: | |
| 1819 bag->problem = PR_TRUE; | |
| 1820 bag->error = PORT_GetError(); | |
| 1821 return SECFailure; | |
| 1822 } | |
| 1823 | |
| 1824 static SECStatus | |
| 1825 sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key) | |
| 1826 { | |
| 1827 int i = 0; | |
| 1828 SECKEYPrivateKeyInfo *pki = NULL; | |
| 1829 | |
| 1830 if(!key) { | |
| 1831 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1832 return SECFailure; | |
| 1833 } | |
| 1834 | |
| 1835 /* if the bag does *not* contain an unencrypted PrivateKeyInfo | |
| 1836 * then we cannot convert the attributes. We are propagating | |
| 1837 * attributes within the PrivateKeyInfo to the SafeBag level. | |
| 1838 */ | |
| 1839 if(SECOID_FindOIDTag(&(key->safeBagType)) != | |
| 1840 SEC_OID_PKCS12_V1_KEY_BAG_ID) { | |
| 1841 return SECSuccess; | |
| 1842 } | |
| 1843 | |
| 1844 pki = key->safeBagContent.pkcs8KeyBag; | |
| 1845 | |
| 1846 if(!pki || !pki->attributes) { | |
| 1847 return SECSuccess; | |
| 1848 } | |
| 1849 | |
| 1850 while(pki->attributes[i]) { | |
| 1851 SECOidTag tag = SECOID_FindOIDTag(&pki->attributes[i]->attrType); | |
| 1852 | |
| 1853 if (tag == SEC_OID_PKCS9_LOCAL_KEY_ID || | |
| 1854 tag == SEC_OID_PKCS9_FRIENDLY_NAME) { | |
| 1855 SECItem *attrValue = sec_pkcs12_get_attribute_value(key, tag); | |
| 1856 if(!attrValue) { | |
| 1857 if(sec_pkcs12_decoder_set_attribute_value(key, tag, | |
| 1858 pki->attributes[i]->attrValue[0]) | |
| 1859 != SECSuccess) { | |
| 1860 key->problem = PR_TRUE; | |
| 1861 key->error = PORT_GetError(); | |
| 1862 return SECFailure; | |
| 1863 } | |
| 1864 } | |
| 1865 } | |
| 1866 i++; | |
| 1867 } | |
| 1868 | |
| 1869 return SECSuccess; | |
| 1870 } | |
| 1871 | |
| 1872 /* retrieve the nickname for the certificate bag. first look | |
| 1873 * in the cert bag, otherwise get it from the key. | |
| 1874 */ | |
| 1875 static SECItem * | |
| 1876 sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert, | |
| 1877 sec_PKCS12SafeBag *key) | |
| 1878 { | |
| 1879 SECItem *nickname; | |
| 1880 | |
| 1881 if(!cert) { | |
| 1882 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1883 return NULL; | |
| 1884 } | |
| 1885 | |
| 1886 nickname = sec_pkcs12_get_nickname(cert); | |
| 1887 if(nickname) { | |
| 1888 return nickname; | |
| 1889 } | |
| 1890 | |
| 1891 if(key) { | |
| 1892 nickname = sec_pkcs12_get_nickname(key); | |
| 1893 | |
| 1894 if(nickname && sec_pkcs12_set_nickname(cert, nickname) | |
| 1895 != SECSuccess) { | |
| 1896 SECITEM_ZfreeItem(nickname, PR_TRUE); | |
| 1897 return NULL; | |
| 1898 } | |
| 1899 } | |
| 1900 | |
| 1901 return nickname; | |
| 1902 } | |
| 1903 | |
| 1904 /* set the nickname for the certificate */ | |
| 1905 static SECStatus | |
| 1906 sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert, | |
| 1907 sec_PKCS12SafeBag *key, | |
| 1908 SECItem *nickname) | |
| 1909 { | |
| 1910 if(!nickname || !cert) { | |
| 1911 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1912 return SECFailure; | |
| 1913 } | |
| 1914 | |
| 1915 if(sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) { | |
| 1916 return SECFailure; | |
| 1917 } | |
| 1918 | |
| 1919 if(key) { | |
| 1920 if(sec_pkcs12_set_nickname(key, nickname) != SECSuccess) { | |
| 1921 cert->problem = PR_TRUE; | |
| 1922 cert->error = key->error; | |
| 1923 return SECFailure; | |
| 1924 } | |
| 1925 } | |
| 1926 | |
| 1927 return SECSuccess; | |
| 1928 } | |
| 1929 | |
| 1930 /* retrieve the DER cert from the cert bag */ | |
| 1931 static SECItem * | |
| 1932 sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert) | |
| 1933 { | |
| 1934 if(!cert) { | |
| 1935 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1936 return NULL; | |
| 1937 } | |
| 1938 | |
| 1939 if(SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) { | |
| 1940 return NULL; | |
| 1941 } | |
| 1942 | |
| 1943 /* only support X509 certs not SDSI */ | |
| 1944 if(SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID) | |
| 1945 != SEC_OID_PKCS9_X509_CERT) { | |
| 1946 return NULL; | |
| 1947 } | |
| 1948 | |
| 1949 return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert)); | |
| 1950 } | |
| 1951 | |
| 1952 struct certNickInfo { | |
| 1953 PLArenaPool *arena; | |
| 1954 unsigned int nNicks; | |
| 1955 SECItem **nickList; | |
| 1956 unsigned int error; | |
| 1957 }; | |
| 1958 | |
| 1959 /* callback for traversing certificates to gather the nicknames | |
| 1960 * used in a particular traversal. for instance, when using | |
| 1961 * CERT_TraversePermCertsForSubject, gather the nicknames and | |
| 1962 * store them in the certNickInfo for a particular DN. | |
| 1963 * | |
| 1964 * this handles the case where multiple nicknames are allowed | |
| 1965 * for the same dn, which is not currently allowed, but may be | |
| 1966 * in the future. | |
| 1967 */ | |
| 1968 static SECStatus | |
| 1969 gatherNicknames(CERTCertificate *cert, void *arg) | |
| 1970 { | |
| 1971 struct certNickInfo *nickArg = (struct certNickInfo *)arg; | |
| 1972 SECItem tempNick; | |
| 1973 unsigned int i; | |
| 1974 | |
| 1975 if(!cert || !nickArg || nickArg->error) { | |
| 1976 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1977 return SECFailure; | |
| 1978 } | |
| 1979 | |
| 1980 if(!cert->nickname) { | |
| 1981 return SECSuccess; | |
| 1982 } | |
| 1983 | |
| 1984 tempNick.data = (unsigned char *)cert->nickname; | |
| 1985 tempNick.len = PORT_Strlen(cert->nickname) + 1; | |
| 1986 | |
| 1987 /* do we already have the nickname in the list? */ | |
| 1988 if(nickArg->nNicks > 0) { | |
| 1989 | |
| 1990 /* nicknames have been encountered, but there is no list -- bad */ | |
| 1991 if(!nickArg->nickList) { | |
| 1992 nickArg->error = SEC_ERROR_INVALID_ARGS; | |
| 1993 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 1994 return SECFailure; | |
| 1995 } | |
| 1996 | |
| 1997 for(i = 0; i < nickArg->nNicks; i++) { | |
| 1998 if(SECITEM_CompareItem(nickArg->nickList[i], &tempNick) | |
| 1999 == SECEqual) { | |
| 2000 return SECSuccess; | |
| 2001 } | |
| 2002 } | |
| 2003 } | |
| 2004 | |
| 2005 /* add the nickname to the list */ | |
| 2006 nickArg->nickList = (nickArg->nNicks == 0) | |
| 2007 ? PORT_ArenaZNewArray(nickArg->arena, SECItem *, 2) | |
| 2008 : PORT_ArenaGrowArray(nickArg->arena, nickArg->nickList, SECItem *, | |
| 2009 nickArg->nNicks + 1, nickArg->nNicks + 2); | |
| 2010 | |
| 2011 if(!nickArg->nickList) { | |
| 2012 nickArg->error = SEC_ERROR_NO_MEMORY; | |
| 2013 return SECFailure; | |
| 2014 } | |
| 2015 | |
| 2016 nickArg->nickList[nickArg->nNicks] = | |
| 2017 PORT_ArenaZNew(nickArg->arena, SECItem); | |
| 2018 if(!nickArg->nickList[nickArg->nNicks]) { | |
| 2019 nickArg->error = PORT_GetError(); | |
| 2020 return SECFailure; | |
| 2021 } | |
| 2022 | |
| 2023 | |
| 2024 if(SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks], | |
| 2025 &tempNick) != SECSuccess) { | |
| 2026 nickArg->error = PORT_GetError(); | |
| 2027 return SECFailure; | |
| 2028 } | |
| 2029 | |
| 2030 nickArg->nNicks++; | |
| 2031 | |
| 2032 return SECSuccess; | |
| 2033 } | |
| 2034 | |
| 2035 /* traverses the certs in the data base or in the token for the | |
| 2036 * DN to see if any certs currently have a nickname set. | |
| 2037 * If so, return it. | |
| 2038 */ | |
| 2039 static SECItem * | |
| 2040 sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert) | |
| 2041 { | |
| 2042 struct certNickInfo *nickArg = NULL; | |
| 2043 SECItem *derCert, *returnDn = NULL; | |
| 2044 PLArenaPool *arena = NULL; | |
| 2045 CERTCertificate *tempCert; | |
| 2046 | |
| 2047 if(!cert) { | |
| 2048 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2049 return NULL; | |
| 2050 } | |
| 2051 | |
| 2052 derCert = sec_pkcs12_get_der_cert(cert); | |
| 2053 if(!derCert) { | |
| 2054 return NULL; | |
| 2055 } | |
| 2056 | |
| 2057 tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL); | |
| 2058 if(!tempCert) { | |
| 2059 returnDn = NULL; | |
| 2060 goto loser; | |
| 2061 } | |
| 2062 | |
| 2063 arena = PORT_NewArena(1024); | |
| 2064 if(!arena) { | |
| 2065 returnDn = NULL; | |
| 2066 goto loser; | |
| 2067 } | |
| 2068 nickArg = PORT_ArenaZNew(arena, struct certNickInfo); | |
| 2069 if(!nickArg) { | |
| 2070 returnDn = NULL; | |
| 2071 goto loser; | |
| 2072 } | |
| 2073 nickArg->error = 0; | |
| 2074 nickArg->nNicks = 0; | |
| 2075 nickArg->nickList = NULL; | |
| 2076 nickArg->arena = arena; | |
| 2077 | |
| 2078 /* if the token is local, first traverse the cert database | |
| 2079 * then traverse the token. | |
| 2080 */ | |
| 2081 if(PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames, | |
| 2082 (void *)nickArg) != SECSuccess) { | |
| 2083 returnDn = NULL; | |
| 2084 goto loser; | |
| 2085 } | |
| 2086 | |
| 2087 if(nickArg->error) { | |
| 2088 /* XXX do we want to set the error? */ | |
| 2089 returnDn = NULL; | |
| 2090 goto loser; | |
| 2091 } | |
| 2092 | |
| 2093 if(nickArg->nNicks == 0) { | |
| 2094 returnDn = NULL; | |
| 2095 goto loser; | |
| 2096 } | |
| 2097 | |
| 2098 /* set it to the first name, for now. handle multiple names? */ | |
| 2099 returnDn = SECITEM_DupItem(nickArg->nickList[0]); | |
| 2100 | |
| 2101 loser: | |
| 2102 if(arena) { | |
| 2103 PORT_FreeArena(arena, PR_TRUE); | |
| 2104 } | |
| 2105 | |
| 2106 if(tempCert) { | |
| 2107 CERT_DestroyCertificate(tempCert); | |
| 2108 } | |
| 2109 | |
| 2110 if(derCert) { | |
| 2111 SECITEM_FreeItem(derCert, PR_TRUE); | |
| 2112 } | |
| 2113 | |
| 2114 return (returnDn); | |
| 2115 } | |
| 2116 | |
| 2117 /* counts certificates found for a given traversal function */ | |
| 2118 static SECStatus | |
| 2119 countCertificate(CERTCertificate *cert, void *arg) | |
| 2120 { | |
| 2121 unsigned int *nCerts = (unsigned int *)arg; | |
| 2122 | |
| 2123 if(!cert || !arg) { | |
| 2124 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2125 return SECFailure; | |
| 2126 } | |
| 2127 | |
| 2128 (*nCerts)++; | |
| 2129 return SECSuccess; | |
| 2130 } | |
| 2131 | |
| 2132 static PRBool | |
| 2133 sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot) | |
| 2134 { | |
| 2135 unsigned int nCerts = 0; | |
| 2136 | |
| 2137 if(!nickname || !slot) { | |
| 2138 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2139 return PR_TRUE; | |
| 2140 } | |
| 2141 | |
| 2142 /* we want to check the local database first if we are importing to it */ | |
| 2143 PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate, | |
| 2144 (void *)&nCerts); | |
| 2145 return (PRBool)(nCerts != 0); | |
| 2146 } | |
| 2147 | |
| 2148 /* validate cert nickname such that there is a one-to-one relation | |
| 2149 * between nicknames and dn's. we want to enforce the case that the | |
| 2150 * nickname is non-NULL and that there is only one nickname per DN. | |
| 2151 * | |
| 2152 * if there is a problem with a nickname or the nickname is not present, | |
| 2153 * the user will be prompted for it. | |
| 2154 */ | |
| 2155 static void | |
| 2156 sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert, | |
| 2157 sec_PKCS12SafeBag *key, | |
| 2158 SEC_PKCS12NicknameCollisionCallback nicknameCb, | |
| 2159 CERTCertificate *leafCert) | |
| 2160 { | |
| 2161 SECItem *certNickname, *existingDNNick; | |
| 2162 PRBool setNickname = PR_FALSE, cancel = PR_FALSE; | |
| 2163 SECItem *newNickname = NULL; | |
| 2164 | |
| 2165 if(!cert || !cert->hasKey) { | |
| 2166 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2167 return; | |
| 2168 } | |
| 2169 | |
| 2170 if(!nicknameCb) { | |
| 2171 cert->problem = PR_TRUE; | |
| 2172 cert->error = SEC_ERROR_INVALID_ARGS; | |
| 2173 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2174 return; | |
| 2175 } | |
| 2176 | |
| 2177 if(cert->hasKey && !key) { | |
| 2178 cert->problem = PR_TRUE; | |
| 2179 cert->error = SEC_ERROR_INVALID_ARGS; | |
| 2180 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2181 return; | |
| 2182 } | |
| 2183 | |
| 2184 certNickname = sec_pkcs12_get_nickname_for_cert(cert, key); | |
| 2185 existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert); | |
| 2186 | |
| 2187 /* nickname is already used w/ this dn, so it is safe to return */ | |
| 2188 if(certNickname && existingDNNick && | |
| 2189 SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) { | |
| 2190 goto loser; | |
| 2191 } | |
| 2192 | |
| 2193 /* nickname not set in pkcs 12 bags, but a nick is already used for | |
| 2194 * this dn. set the nicks in the p12 bags and finish. | |
| 2195 */ | |
| 2196 if(existingDNNick) { | |
| 2197 sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick); | |
| 2198 goto loser; | |
| 2199 } | |
| 2200 | |
| 2201 /* at this point, we have a certificate for which the DN is not located | |
| 2202 * on the token. the nickname specified may or may not be NULL. if it | |
| 2203 * is not null, we need to make sure that there are no other certificates | |
| 2204 * with this nickname in the token for it to be valid. this imposes a | |
| 2205 * one to one relationship between DN and nickname. | |
| 2206 * | |
| 2207 * if the nickname is null, we need the user to enter a nickname for | |
| 2208 * the certificate. | |
| 2209 * | |
| 2210 * once we have a nickname, we make sure that the nickname is unique | |
| 2211 * for the DN. if it is not, the user is reprompted to enter a new | |
| 2212 * nickname. | |
| 2213 * | |
| 2214 * in order to exit this loop, the nickname entered is either unique | |
| 2215 * or the user hits cancel and the certificate is not imported. | |
| 2216 */ | |
| 2217 setNickname = PR_FALSE; | |
| 2218 while(1) { | |
| 2219 /* we will use the nickname so long as no other certs have the | |
| 2220 * same nickname. and the nickname is not NULL. | |
| 2221 */ | |
| 2222 if (certNickname && certNickname->data && | |
| 2223 !sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) { | |
| 2224 if (setNickname) { | |
| 2225 sec_pkcs12_set_nickname_for_cert(cert, key, certNickname); | |
| 2226 } | |
| 2227 break; | |
| 2228 } | |
| 2229 | |
| 2230 setNickname = PR_FALSE; | |
| 2231 newNickname = (*nicknameCb)(certNickname, &cancel, leafCert); | |
| 2232 if(cancel) { | |
| 2233 cert->problem = PR_TRUE; | |
| 2234 cert->error = SEC_ERROR_USER_CANCELLED; | |
| 2235 break; | |
| 2236 } | |
| 2237 | |
| 2238 if(!newNickname) { | |
| 2239 cert->problem = PR_TRUE; | |
| 2240 cert->error = PORT_GetError(); | |
| 2241 break; | |
| 2242 } | |
| 2243 | |
| 2244 /* at this point we have a new nickname, if we have an existing | |
| 2245 * certNickname, we need to free it and assign the new nickname | |
| 2246 * to it to avoid a memory leak. happy? | |
| 2247 */ | |
| 2248 if(certNickname) { | |
| 2249 SECITEM_ZfreeItem(certNickname, PR_TRUE); | |
| 2250 certNickname = NULL; | |
| 2251 } | |
| 2252 | |
| 2253 certNickname = newNickname; | |
| 2254 setNickname = PR_TRUE; | |
| 2255 /* go back and recheck the new nickname */ | |
| 2256 } | |
| 2257 | |
| 2258 loser: | |
| 2259 if(certNickname) { | |
| 2260 SECITEM_ZfreeItem(certNickname, PR_TRUE); | |
| 2261 } | |
| 2262 | |
| 2263 if(existingDNNick) { | |
| 2264 SECITEM_ZfreeItem(existingDNNick, PR_TRUE); | |
| 2265 } | |
| 2266 } | |
| 2267 | |
| 2268 static void | |
| 2269 sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert, | |
| 2270 sec_PKCS12SafeBag *key, | |
| 2271 SEC_PKCS12NicknameCollisionCallback nicknameCb) | |
| 2272 { | |
| 2273 CERTCertificate *leafCert; | |
| 2274 | |
| 2275 if(!cert) { | |
| 2276 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2277 return; | |
| 2278 } | |
| 2279 | |
| 2280 cert->validated = PR_TRUE; | |
| 2281 | |
| 2282 if(!nicknameCb) { | |
| 2283 cert->noInstall = PR_TRUE; | |
| 2284 cert->problem = PR_TRUE; | |
| 2285 cert->error = SEC_ERROR_INVALID_ARGS; | |
| 2286 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2287 return; | |
| 2288 } | |
| 2289 | |
| 2290 if(!cert->safeBagContent.certBag) { | |
| 2291 cert->noInstall = PR_TRUE; | |
| 2292 cert->problem = PR_TRUE; | |
| 2293 cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE; | |
| 2294 return; | |
| 2295 } | |
| 2296 | |
| 2297 cert->noInstall = PR_FALSE; | |
| 2298 cert->unused = PR_FALSE; | |
| 2299 cert->problem = PR_FALSE; | |
| 2300 cert->error = 0; | |
| 2301 | |
| 2302 leafCert = CERT_DecodeDERCertificate( | |
| 2303 &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL); | |
| 2304 if(!leafCert) { | |
| 2305 cert->noInstall = PR_TRUE; | |
| 2306 cert->problem = PR_TRUE; | |
| 2307 cert->error = PORT_GetError(); | |
| 2308 return; | |
| 2309 } | |
| 2310 | |
| 2311 sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, leafCert); | |
| 2312 | |
| 2313 CERT_DestroyCertificate(leafCert); | |
| 2314 } | |
| 2315 | |
| 2316 static void | |
| 2317 sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key, | |
| 2318 void *wincx) | |
| 2319 { | |
| 2320 CERTCertificate *leafCert; | |
| 2321 SECKEYPrivateKey *privk; | |
| 2322 | |
| 2323 if(!key) { | |
| 2324 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2325 return; | |
| 2326 } | |
| 2327 | |
| 2328 key->validated = PR_TRUE; | |
| 2329 | |
| 2330 if(!cert) { | |
| 2331 key->problem = PR_TRUE; | |
| 2332 key->noInstall = PR_TRUE; | |
| 2333 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY; | |
| 2334 return; | |
| 2335 } | |
| 2336 | |
| 2337 leafCert = CERT_DecodeDERCertificate( | |
| 2338 &(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL); | |
| 2339 if(!leafCert) { | |
| 2340 key->problem = PR_TRUE; | |
| 2341 key->noInstall = PR_TRUE; | |
| 2342 key->error = PORT_GetError(); | |
| 2343 return; | |
| 2344 } | |
| 2345 | |
| 2346 privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx); | |
| 2347 if(!privk) { | |
| 2348 privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx); | |
| 2349 } | |
| 2350 | |
| 2351 if(privk) { | |
| 2352 SECKEY_DestroyPrivateKey(privk); | |
| 2353 key->noInstall = PR_TRUE; | |
| 2354 } | |
| 2355 | |
| 2356 CERT_DestroyCertificate(leafCert); | |
| 2357 } | |
| 2358 | |
| 2359 static SECStatus | |
| 2360 sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx) | |
| 2361 { | |
| 2362 SECItem *derCert, *nickName; | |
| 2363 char *nickData = NULL; | |
| 2364 PRBool isIntermediateCA; | |
| 2365 SECStatus rv; | |
| 2366 | |
| 2367 if(!cert) { | |
| 2368 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2369 return SECFailure; | |
| 2370 } | |
| 2371 | |
| 2372 if(cert->problem || cert->noInstall || cert->installed) { | |
| 2373 return SECSuccess; | |
| 2374 } | |
| 2375 | |
| 2376 derCert = &cert->safeBagContent.certBag->value.x509Cert; | |
| 2377 | |
| 2378 PORT_Assert(!cert->problem && !cert->noInstall); | |
| 2379 | |
| 2380 nickName = sec_pkcs12_get_nickname(cert); | |
| 2381 if(nickName) { | |
| 2382 nickData = (char *)nickName->data; | |
| 2383 } | |
| 2384 | |
| 2385 isIntermediateCA = CERT_IsCADERCert(derCert, NULL) && | |
| 2386 !CERT_IsRootDERCert(derCert); | |
| 2387 | |
| 2388 if(keyExists) { | |
| 2389 CERTCertificate *newCert; | |
| 2390 | |
| 2391 newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), | |
| 2392 derCert, NULL, PR_FALSE, PR_FALSE); | |
| 2393 if(!newCert) { | |
| 2394 if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE); | |
| 2395 cert->error = PORT_GetError(); | |
| 2396 cert->problem = PR_TRUE; | |
| 2397 return SECFailure; | |
| 2398 } | |
| 2399 | |
| 2400 rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData, | |
| 2401 PR_TRUE, wincx); | |
| 2402 CERT_DestroyCertificate(newCert); | |
| 2403 } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) || | |
| 2404 ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) && | |
| 2405 !isIntermediateCA)) { | |
| 2406 SECItem *certList[2]; | |
| 2407 certList[0] = derCert; | |
| 2408 certList[1] = NULL; | |
| 2409 | |
| 2410 rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport, | |
| 2411 1, certList, NULL, PR_TRUE, PR_FALSE, nickData); | |
| 2412 } else { | |
| 2413 rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE, | |
| 2414 nickData, PR_FALSE); | |
| 2415 } | |
| 2416 if (rv) { | |
| 2417 cert->problem = 1; | |
| 2418 cert->error = PORT_GetError(); | |
| 2419 } | |
| 2420 cert->installed = PR_TRUE; | |
| 2421 if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE); | |
| 2422 return rv; | |
| 2423 } | |
| 2424 | |
| 2425 static SECItem * | |
| 2426 sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey, KeyType *type); | |
| 2427 | |
| 2428 static SECStatus | |
| 2429 sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECKEYPublicKey *pubKey, | |
| 2430 unsigned int keyUsage, | |
| 2431 SECItem *nickName, void *wincx) | |
| 2432 { | |
| 2433 SECStatus rv; | |
| 2434 SECItem *publicValue = NULL; | |
| 2435 KeyType keyType; | |
| 2436 | |
| 2437 /* We should always have values for "key" and "pubKey" | |
| 2438 so they can be dereferenced later. */ | |
| 2439 if(!key || !pubKey) { | |
| 2440 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2441 return SECFailure; | |
| 2442 } | |
| 2443 | |
| 2444 if(key->problem || key->noInstall) { | |
| 2445 return SECSuccess; | |
| 2446 } | |
| 2447 | |
| 2448 /* get the value and type from the public key */ | |
| 2449 publicValue = sec_pkcs12_get_public_value_and_type(pubKey, &keyType); | |
| 2450 if (!publicValue) { | |
| 2451 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY; | |
| 2452 key->problem = PR_TRUE; | |
| 2453 return SECFailure; | |
| 2454 } | |
| 2455 | |
| 2456 switch(SECOID_FindOIDTag(&key->safeBagType)) | |
| 2457 { | |
| 2458 case SEC_OID_PKCS12_V1_KEY_BAG_ID: | |
| 2459 rv = PK11_ImportPrivateKeyInfo(key->slot, | |
| 2460 key->safeBagContent.pkcs8KeyBag, | |
| 2461 nickName, publicValue, PR_TRUE, PR_TRUE, | |
| 2462 keyUsage, wincx); | |
| 2463 break; | |
| 2464 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: | |
| 2465 rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot, | |
| 2466 key->safeBagContent.pkcs8ShroudedKeyBag, | |
| 2467 key->pwitem, nickName, publicValue, | |
| 2468 PR_TRUE, PR_TRUE, keyType, keyUsage, | |
| 2469 wincx); | |
| 2470 break; | |
| 2471 default: | |
| 2472 key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION; | |
| 2473 key->problem = PR_TRUE; | |
| 2474 if(nickName) { | |
| 2475 SECITEM_ZfreeItem(nickName, PR_TRUE); | |
| 2476 } | |
| 2477 return SECFailure; | |
| 2478 } | |
| 2479 | |
| 2480 if(rv != SECSuccess) { | |
| 2481 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY; | |
| 2482 key->problem = PR_TRUE; | |
| 2483 } else { | |
| 2484 /* try to import the public key. Failure to do so is not fatal, | |
| 2485 * not all tokens can store the public key */ | |
| 2486 if (pubKey) { | |
| 2487 PK11_ImportPublicKey(key->slot, pubKey, PR_TRUE); | |
| 2488 } | |
| 2489 key->installed = PR_TRUE; | |
| 2490 } | |
| 2491 | |
| 2492 return rv; | |
| 2493 } | |
| 2494 | |
| 2495 /* | |
| 2496 * The correctness of the code in this file ABSOLUTELY REQUIRES | |
| 2497 * that ALL BAGs share a single common arena. | |
| 2498 * | |
| 2499 * This function allocates the bag list from the arena of whatever bag | |
| 2500 * happens to be passed to it. Each time a new bag is handed to it, | |
| 2501 * it grows (resizes) the arena of the bag that was handed to it. | |
| 2502 * If the bags have different arenas, it will grow the wrong arena. | |
| 2503 * | |
| 2504 * Worse, if the bags had separate arenas, then while destroying the bags | |
| 2505 * in a bag list, when the bag whose arena contained the bag list was | |
| 2506 * destroyed, the baglist itself would be destroyed, making it difficult | |
| 2507 * or impossible to continue to destroy the bags in the destroyed list. | |
| 2508 */ | |
| 2509 static SECStatus | |
| 2510 sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList, | |
| 2511 sec_PKCS12SafeBag *bag) | |
| 2512 { | |
| 2513 sec_PKCS12SafeBag **newBagList = NULL; | |
| 2514 int i = 0; | |
| 2515 | |
| 2516 if(!bagList || !bag) { | |
| 2517 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2518 return SECFailure; | |
| 2519 } | |
| 2520 | |
| 2521 if(!(*bagList)) { | |
| 2522 newBagList = PORT_ArenaZNewArray(bag->arena, sec_PKCS12SafeBag *, 2); | |
| 2523 } else { | |
| 2524 while((*bagList)[i]) | |
| 2525 i++; | |
| 2526 newBagList = PORT_ArenaGrowArray(bag->arena, *bagList, | |
| 2527 sec_PKCS12SafeBag *, i + 1, i + 2); | |
| 2528 } | |
| 2529 | |
| 2530 if(!newBagList) { | |
| 2531 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 2532 return SECFailure; | |
| 2533 } | |
| 2534 | |
| 2535 newBagList[i] = bag; | |
| 2536 newBagList[i+1] = NULL; | |
| 2537 *bagList = newBagList; | |
| 2538 | |
| 2539 return SECSuccess; | |
| 2540 } | |
| 2541 | |
| 2542 static sec_PKCS12SafeBag ** | |
| 2543 sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags, | |
| 2544 sec_PKCS12SafeBag *key ) | |
| 2545 { | |
| 2546 sec_PKCS12SafeBag **certList = NULL; | |
| 2547 SECItem *keyId; | |
| 2548 int i; | |
| 2549 | |
| 2550 if(!safeBags || !safeBags[0]) { | |
| 2551 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2552 return NULL; | |
| 2553 } | |
| 2554 | |
| 2555 keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID); | |
| 2556 if(!keyId) { | |
| 2557 return NULL; | |
| 2558 } | |
| 2559 | |
| 2560 for (i = 0; safeBags[i]; i++) { | |
| 2561 if(SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) | |
| 2562 == SEC_OID_PKCS12_V1_CERT_BAG_ID) { | |
| 2563 SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i], | |
| 2564 SEC_OID_PKCS9_LOCAL_KEY_ID); | |
| 2565 | |
| 2566 if(certKeyId && (SECITEM_CompareItem(certKeyId, keyId) | |
| 2567 == SECEqual)) { | |
| 2568 if(sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i]) | |
| 2569 != SECSuccess) { | |
| 2570 /* This would leak the partial list of safeBags, | |
| 2571 * but that list is allocated from the arena of | |
| 2572 * one of the safebags, and will be destroyed when | |
| 2573 * that arena is destroyed. So this is not a real leak. | |
| 2574 */ | |
| 2575 return NULL; | |
| 2576 } | |
| 2577 } | |
| 2578 } | |
| 2579 } | |
| 2580 | |
| 2581 return certList; | |
| 2582 } | |
| 2583 | |
| 2584 CERTCertList * | |
| 2585 SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx) | |
| 2586 { | |
| 2587 CERTCertList *certList = NULL; | |
| 2588 sec_PKCS12SafeBag **safeBags; | |
| 2589 int i; | |
| 2590 | |
| 2591 if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) { | |
| 2592 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2593 return NULL; | |
| 2594 } | |
| 2595 | |
| 2596 safeBags = p12dcx->safeBags; | |
| 2597 certList = CERT_NewCertList(); | |
| 2598 | |
| 2599 if (certList == NULL) { | |
| 2600 return NULL; | |
| 2601 } | |
| 2602 | |
| 2603 for (i = 0; safeBags[i]; i++) { | |
| 2604 if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) | |
| 2605 == SEC_OID_PKCS12_V1_CERT_BAG_ID) { | |
| 2606 SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]) ; | |
| 2607 CERTCertificate *tempCert = NULL; | |
| 2608 | |
| 2609 if (derCert == NULL) | |
| 2610 continue; | |
| 2611 tempCert=CERT_NewTempCertificate(CERT_GetDefaultCertDB(), | |
| 2612 derCert, NULL, | |
| 2613 PR_FALSE, PR_TRUE); | |
| 2614 | |
| 2615 if (tempCert) { | |
| 2616 CERT_AddCertToListTail(certList,tempCert); | |
| 2617 } | |
| 2618 SECITEM_FreeItem(derCert,PR_TRUE); | |
| 2619 } | |
| 2620 /* fixed an infinite loop here, by ensuring that i gets incremented | |
| 2621 * if derCert is NULL above. | |
| 2622 */ | |
| 2623 } | |
| 2624 | |
| 2625 return certList; | |
| 2626 } | |
| 2627 static sec_PKCS12SafeBag ** | |
| 2628 sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags) | |
| 2629 { | |
| 2630 int i; | |
| 2631 sec_PKCS12SafeBag **keyList = NULL; | |
| 2632 SECOidTag bagType; | |
| 2633 | |
| 2634 if(!safeBags || !safeBags[0]) { | |
| 2635 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2636 return NULL; | |
| 2637 } | |
| 2638 | |
| 2639 for (i = 0; safeBags[i]; i++) { | |
| 2640 bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType)); | |
| 2641 switch(bagType) { | |
| 2642 case SEC_OID_PKCS12_V1_KEY_BAG_ID: | |
| 2643 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: | |
| 2644 if(sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i]) | |
| 2645 != SECSuccess) { | |
| 2646 /* This would leak, except that keyList is allocated | |
| 2647 * from the arena shared by all the safeBags. | |
| 2648 */ | |
| 2649 return NULL; | |
| 2650 } | |
| 2651 break; | |
| 2652 default: | |
| 2653 break; | |
| 2654 } | |
| 2655 } | |
| 2656 | |
| 2657 return keyList; | |
| 2658 } | |
| 2659 | |
| 2660 /* This function takes two passes over the bags, validating them | |
| 2661 * The two passes are intended to mirror exactly the two passes in | |
| 2662 * sec_pkcs12_install_bags. But they don't. :( | |
| 2663 */ | |
| 2664 static SECStatus | |
| 2665 sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags, | |
| 2666 SEC_PKCS12NicknameCollisionCallback nicknameCb, | |
| 2667 void *wincx) | |
| 2668 { | |
| 2669 sec_PKCS12SafeBag **keyList; | |
| 2670 int i; | |
| 2671 | |
| 2672 if(!safeBags || !nicknameCb) { | |
| 2673 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2674 return SECFailure; | |
| 2675 } | |
| 2676 | |
| 2677 if(!safeBags[0]) { | |
| 2678 return SECSuccess; | |
| 2679 } | |
| 2680 | |
| 2681 /* First pass. Find all the key bags. | |
| 2682 * Find the matching cert(s) for each key. | |
| 2683 */ | |
| 2684 keyList = sec_pkcs12_get_key_bags(safeBags); | |
| 2685 if(keyList) { | |
| 2686 for (i = 0; keyList[i]; ++i) { | |
| 2687 sec_PKCS12SafeBag *key = keyList[i]; | |
| 2688 sec_PKCS12SafeBag **certList = | |
| 2689 sec_pkcs12_find_certs_for_key(safeBags, key); | |
| 2690 | |
| 2691 if(certList) { | |
| 2692 int j; | |
| 2693 | |
| 2694 if(SECOID_FindOIDTag(&(key->safeBagType)) == | |
| 2695 SEC_OID_PKCS12_V1_KEY_BAG_ID) { | |
| 2696 /* if it is an unencrypted private key then make sure | |
| 2697 * the attributes are propageted to the appropriate | |
| 2698 * level | |
| 2699 */ | |
| 2700 if(sec_pkcs12_get_key_info(key) != SECSuccess) { | |
| 2701 return SECFailure; | |
| 2702 } | |
| 2703 } | |
| 2704 | |
| 2705 sec_pkcs12_validate_key_by_cert(certList[0], key, wincx); | |
| 2706 for (j = 0; certList[j]; ++j) { | |
| 2707 sec_PKCS12SafeBag *cert = certList[j]; | |
| 2708 cert->hasKey = PR_TRUE; | |
| 2709 if(key->problem) { | |
| 2710 cert->problem = PR_TRUE; | |
| 2711 cert->error = key->error; | |
| 2712 continue; | |
| 2713 } | |
| 2714 sec_pkcs12_validate_cert(cert, key, nicknameCb); | |
| 2715 if(cert->problem) { | |
| 2716 key->problem = cert->problem; | |
| 2717 key->error = cert->error; | |
| 2718 } | |
| 2719 } | |
| 2720 } | |
| 2721 } | |
| 2722 } | |
| 2723 | |
| 2724 /* Now take a second pass over the safebags and mark for installation any | |
| 2725 * certs that were neither installed nor disqualified by the first pass. | |
| 2726 */ | |
| 2727 for (i = 0; safeBags[i]; ++i) { | |
| 2728 sec_PKCS12SafeBag *bag = safeBags[i]; | |
| 2729 | |
| 2730 if(!bag->validated) { | |
| 2731 SECOidTag bagType = SECOID_FindOIDTag(&bag->safeBagType); | |
| 2732 | |
| 2733 switch(bagType) { | |
| 2734 case SEC_OID_PKCS12_V1_CERT_BAG_ID: | |
| 2735 sec_pkcs12_validate_cert(bag, NULL, nicknameCb); | |
| 2736 break; | |
| 2737 case SEC_OID_PKCS12_V1_KEY_BAG_ID: | |
| 2738 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: | |
| 2739 bag->noInstall = PR_TRUE; | |
| 2740 bag->problem = PR_TRUE; | |
| 2741 bag->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY; | |
| 2742 break; | |
| 2743 default: | |
| 2744 bag->noInstall = PR_TRUE; | |
| 2745 } | |
| 2746 } | |
| 2747 } | |
| 2748 | |
| 2749 return SECSuccess; | |
| 2750 } | |
| 2751 | |
| 2752 SECStatus | |
| 2753 SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx, | |
| 2754 SEC_PKCS12NicknameCollisionCallback nicknameCb) | |
| 2755 { | |
| 2756 SECStatus rv; | |
| 2757 int i, noInstallCnt, probCnt, bagCnt, errorVal = 0; | |
| 2758 if(!p12dcx || p12dcx->error || !p12dcx->safeBags) { | |
| 2759 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2760 return SECFailure; | |
| 2761 } | |
| 2762 | |
| 2763 rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx); | |
| 2764 if(rv == SECSuccess) { | |
| 2765 p12dcx->bagsVerified = PR_TRUE; | |
| 2766 } | |
| 2767 | |
| 2768 noInstallCnt = probCnt = bagCnt = 0; | |
| 2769 i = 0; | |
| 2770 while(p12dcx->safeBags[i]) { | |
| 2771 bagCnt++; | |
| 2772 if(p12dcx->safeBags[i]->noInstall) | |
| 2773 noInstallCnt++; | |
| 2774 if(p12dcx->safeBags[i]->problem) { | |
| 2775 probCnt++; | |
| 2776 errorVal = p12dcx->safeBags[i]->error; | |
| 2777 } | |
| 2778 i++; | |
| 2779 } | |
| 2780 | |
| 2781 /* formerly was erroneous code here that assumed that if all bags | |
| 2782 * failed to import, then the problem was duplicated data; | |
| 2783 * that is, it assume that the problem must be that the file had | |
| 2784 * previously been successfully imported. But importing a | |
| 2785 * previously imported file causes NO ERRORS at all, and this | |
| 2786 * false assumption caused real errors to be hidden behind false | |
| 2787 * errors about duplicated data. | |
| 2788 */ | |
| 2789 | |
| 2790 if(probCnt) { | |
| 2791 PORT_SetError(errorVal); | |
| 2792 return SECFailure; | |
| 2793 } | |
| 2794 | |
| 2795 return rv; | |
| 2796 } | |
| 2797 | |
| 2798 | |
| 2799 static SECKEYPublicKey * | |
| 2800 sec_pkcs12_get_public_key_and_usage(sec_PKCS12SafeBag *certBag, | |
| 2801 unsigned int *usage) | |
| 2802 { | |
| 2803 SECKEYPublicKey *pubKey = NULL; | |
| 2804 CERTCertificate *cert = NULL; | |
| 2805 | |
| 2806 if(!certBag || !usage) { | |
| 2807 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2808 return NULL; | |
| 2809 } | |
| 2810 | |
| 2811 *usage = 0; | |
| 2812 | |
| 2813 cert = CERT_DecodeDERCertificate( | |
| 2814 &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL); | |
| 2815 if(!cert) { | |
| 2816 return NULL; | |
| 2817 } | |
| 2818 | |
| 2819 *usage = cert->keyUsage; | |
| 2820 pubKey = CERT_ExtractPublicKey(cert); | |
| 2821 CERT_DestroyCertificate(cert); | |
| 2822 return pubKey; | |
| 2823 } | |
| 2824 | |
| 2825 static SECItem * | |
| 2826 sec_pkcs12_get_public_value_and_type(SECKEYPublicKey *pubKey, | |
| 2827 KeyType *type) | |
| 2828 { | |
| 2829 SECItem *pubValue = NULL; | |
| 2830 | |
| 2831 if(!type || !pubKey) { | |
| 2832 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2833 return NULL; | |
| 2834 } | |
| 2835 | |
| 2836 *type = pubKey->keyType; | |
| 2837 switch(pubKey->keyType) { | |
| 2838 case dsaKey: | |
| 2839 pubValue = &pubKey->u.dsa.publicValue; | |
| 2840 break; | |
| 2841 case dhKey: | |
| 2842 pubValue = &pubKey->u.dh.publicValue; | |
| 2843 break; | |
| 2844 case rsaKey: | |
| 2845 pubValue = &pubKey->u.rsa.modulus; | |
| 2846 break; | |
| 2847 case ecKey: | |
| 2848 pubValue = &pubKey->u.ec.publicValue; | |
| 2849 break; | |
| 2850 default: | |
| 2851 pubValue = NULL; | |
| 2852 } | |
| 2853 | |
| 2854 return pubValue; | |
| 2855 } | |
| 2856 | |
| 2857 /* This function takes two passes over the bags, installing them in the | |
| 2858 * desired slot. The two passes are intended to mirror exactly the | |
| 2859 * two passes in sec_pkcs12_validate_bags. | |
| 2860 */ | |
| 2861 static SECStatus | |
| 2862 sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, void *wincx) | |
| 2863 { | |
| 2864 sec_PKCS12SafeBag **keyList; | |
| 2865 int i; | |
| 2866 int failedKeys = 0; | |
| 2867 | |
| 2868 if(!safeBags) { | |
| 2869 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2870 return SECFailure; | |
| 2871 } | |
| 2872 | |
| 2873 if(!safeBags[0]) { | |
| 2874 return SECSuccess; | |
| 2875 } | |
| 2876 | |
| 2877 /* First pass. Find all the key bags. | |
| 2878 * Try to install them, and any certs associated with them. | |
| 2879 */ | |
| 2880 keyList = sec_pkcs12_get_key_bags(safeBags); | |
| 2881 if(keyList) { | |
| 2882 for (i = 0; keyList[i]; i++) { | |
| 2883 SECStatus rv; | |
| 2884 SECKEYPublicKey *pubKey = NULL; | |
| 2885 SECItem *nickName = NULL; | |
| 2886 sec_PKCS12SafeBag *key = keyList[i]; | |
| 2887 sec_PKCS12SafeBag **certList; | |
| 2888 unsigned int keyUsage; | |
| 2889 | |
| 2890 if(key->problem) { | |
| 2891 ++failedKeys; | |
| 2892 continue; | |
| 2893 } | |
| 2894 | |
| 2895 certList = sec_pkcs12_find_certs_for_key(safeBags, key); | |
| 2896 if(certList && certList[0]) { | |
| 2897 pubKey = sec_pkcs12_get_public_key_and_usage(certList[0], | |
| 2898 &keyUsage); | |
| 2899 /* use the cert's nickname, if it has one, else use the | |
| 2900 * key's nickname, else fail. | |
| 2901 */ | |
| 2902 nickName = sec_pkcs12_get_nickname_for_cert(certList[0], key); | |
| 2903 } else { | |
| 2904 nickName = sec_pkcs12_get_nickname(key); | |
| 2905 } | |
| 2906 if (!nickName) { | |
| 2907 key->error = SEC_ERROR_BAD_NICKNAME; | |
| 2908 key->problem = PR_TRUE; | |
| 2909 rv = SECFailure; | |
| 2910 } else if (!pubKey) { | |
| 2911 key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY; | |
| 2912 key->problem = PR_TRUE; | |
| 2913 rv = SECFailure; | |
| 2914 } else { | |
| 2915 rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName, wincx); | |
| 2916 } | |
| 2917 if (pubKey) { | |
| 2918 SECKEY_DestroyPublicKey(pubKey); | |
| 2919 pubKey = NULL; | |
| 2920 } | |
| 2921 if (nickName) { | |
| 2922 SECITEM_FreeItem(nickName, PR_TRUE); | |
| 2923 nickName = NULL; | |
| 2924 } | |
| 2925 if(rv != SECSuccess) { | |
| 2926 PORT_SetError(key->error); | |
| 2927 ++failedKeys; | |
| 2928 } | |
| 2929 | |
| 2930 if(certList) { | |
| 2931 int j; | |
| 2932 | |
| 2933 for (j = 0; certList[j]; j++) { | |
| 2934 sec_PKCS12SafeBag *cert = certList[j]; | |
| 2935 SECStatus certRv; | |
| 2936 | |
| 2937 if (!cert) | |
| 2938 continue; | |
| 2939 if(rv != SECSuccess) { | |
| 2940 cert->problem = key->problem; | |
| 2941 cert->error = key->error; | |
| 2942 cert->noInstall = PR_TRUE; | |
| 2943 continue; | |
| 2944 } | |
| 2945 | |
| 2946 certRv = sec_pkcs12_add_cert(cert, cert->hasKey, wincx); | |
| 2947 if(certRv != SECSuccess) { | |
| 2948 key->problem = cert->problem; | |
| 2949 key->error = cert->error; | |
| 2950 PORT_SetError(cert->error); | |
| 2951 return SECFailure; | |
| 2952 } | |
| 2953 } | |
| 2954 } | |
| 2955 } | |
| 2956 } | |
| 2957 if (failedKeys) | |
| 2958 return SECFailure; | |
| 2959 | |
| 2960 /* Now take a second pass over the safebags and install any certs | |
| 2961 * that were neither installed nor disqualified by the first pass. | |
| 2962 */ | |
| 2963 for (i = 0; safeBags[i]; i++) { | |
| 2964 sec_PKCS12SafeBag *bag = safeBags[i]; | |
| 2965 | |
| 2966 if (!bag->installed && !bag->problem && !bag->noInstall) { | |
| 2967 SECStatus rv; | |
| 2968 SECOidTag bagType = SECOID_FindOIDTag(&(bag->safeBagType)); | |
| 2969 | |
| 2970 switch(bagType) { | |
| 2971 case SEC_OID_PKCS12_V1_CERT_BAG_ID: | |
| 2972 rv = sec_pkcs12_add_cert(bag, bag->hasKey, wincx); | |
| 2973 if(rv != SECSuccess) { | |
| 2974 PORT_SetError(bag->error); | |
| 2975 return SECFailure; | |
| 2976 } | |
| 2977 break; | |
| 2978 case SEC_OID_PKCS12_V1_KEY_BAG_ID: | |
| 2979 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: | |
| 2980 default: | |
| 2981 break; | |
| 2982 } | |
| 2983 } | |
| 2984 } | |
| 2985 | |
| 2986 return SECSuccess; | |
| 2987 } | |
| 2988 | |
| 2989 SECStatus | |
| 2990 SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx) | |
| 2991 { | |
| 2992 if(!p12dcx || p12dcx->error) { | |
| 2993 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 2994 return SECFailure; | |
| 2995 } | |
| 2996 | |
| 2997 if(!p12dcx->bagsVerified) { | |
| 2998 return SECFailure; | |
| 2999 } | |
| 3000 | |
| 3001 return sec_pkcs12_install_bags(p12dcx->safeBags, p12dcx->wincx); | |
| 3002 } | |
| 3003 | |
| 3004 PRBool | |
| 3005 sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag) | |
| 3006 { | |
| 3007 int i; | |
| 3008 SECItem *keyId; | |
| 3009 SECItem *certKeyId; | |
| 3010 | |
| 3011 certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID); | |
| 3012 if (certKeyId == NULL) { | |
| 3013 return PR_FALSE; | |
| 3014 } | |
| 3015 | |
| 3016 for (i=0; p12dcx->keyList && p12dcx->keyList[i]; i++) { | |
| 3017 keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i], | |
| 3018 SEC_OID_PKCS9_LOCAL_KEY_ID); | |
| 3019 if(!keyId) { | |
| 3020 continue; | |
| 3021 } | |
| 3022 if(SECITEM_CompareItem(certKeyId, keyId) == SECEqual) { | |
| 3023 return PR_TRUE; | |
| 3024 } | |
| 3025 } | |
| 3026 return PR_FALSE; | |
| 3027 } | |
| 3028 | |
| 3029 SECItem * | |
| 3030 sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag) | |
| 3031 { | |
| 3032 SECItem *friendlyName; | |
| 3033 SECItem *tempnm; | |
| 3034 | |
| 3035 tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME); | |
| 3036 friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
| 3037 if (friendlyName) { | |
| 3038 if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName, | |
| 3039 tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) { | |
| 3040 SECITEM_FreeItem(friendlyName, PR_TRUE); | |
| 3041 friendlyName = NULL; | |
| 3042 } | |
| 3043 } | |
| 3044 return friendlyName; | |
| 3045 } | |
| 3046 | |
| 3047 /* Following two functions provide access to selected portions of the safe bags. | |
| 3048 * Iteration is implemented per decoder context and may be accessed after | |
| 3049 * SEC_PKCS12DecoderVerify() returns success. | |
| 3050 * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned | |
| 3051 * where item.type is always set; item.friendlyName is set if it is non-null; | |
| 3052 * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items. | |
| 3053 * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when | |
| 3054 * arguments are invalid; PORT_GetError() is 0 at end-of-list. | |
| 3055 * Caller has read-only access to decoder items. Any SECItems generated are | |
| 3056 * owned by the decoder context and are freed by ...DecoderFinish(). | |
| 3057 */ | |
| 3058 SECStatus | |
| 3059 SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx) | |
| 3060 { | |
| 3061 if(!p12dcx || p12dcx->error) { | |
| 3062 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3063 return SECFailure; | |
| 3064 } | |
| 3065 | |
| 3066 p12dcx->iteration = 0; | |
| 3067 return SECSuccess; | |
| 3068 } | |
| 3069 | |
| 3070 SECStatus | |
| 3071 SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx, | |
| 3072 const SEC_PKCS12DecoderItem **ipp) | |
| 3073 { | |
| 3074 sec_PKCS12SafeBag *bag; | |
| 3075 | |
| 3076 if(!p12dcx || p12dcx->error) { | |
| 3077 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3078 return SECFailure; | |
| 3079 } | |
| 3080 | |
| 3081 if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) { | |
| 3082 SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE); | |
| 3083 } | |
| 3084 if (p12dcx->decitem.shroudAlg != NULL) { | |
| 3085 SECOID_DestroyAlgorithmID(p12dcx->decitem.shroudAlg, PR_TRUE); | |
| 3086 } | |
| 3087 if (p12dcx->decitem.friendlyName != NULL) { | |
| 3088 SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE); | |
| 3089 } | |
| 3090 p12dcx->decitem.type = 0; | |
| 3091 p12dcx->decitem.der = NULL; | |
| 3092 p12dcx->decitem.shroudAlg = NULL; | |
| 3093 p12dcx->decitem.friendlyName = NULL; | |
| 3094 p12dcx->decitem.hasKey = PR_FALSE; | |
| 3095 *ipp = NULL; | |
| 3096 if (p12dcx->keyList == NULL) { | |
| 3097 p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags); | |
| 3098 } | |
| 3099 | |
| 3100 | |
| 3101 for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) { | |
| 3102 bag = p12dcx->safeBags[p12dcx->iteration]; | |
| 3103 if(bag == NULL || bag->problem) { | |
| 3104 continue; | |
| 3105 } | |
| 3106 p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType)); | |
| 3107 switch(p12dcx->decitem.type) { | |
| 3108 case SEC_OID_PKCS12_V1_CERT_BAG_ID: | |
| 3109 p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag); | |
| 3110 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag); | |
| 3111 p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag); | |
| 3112 break; | |
| 3113 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: | |
| 3114 p12dcx->decitem.shroudAlg = PORT_ZNew(SECAlgorithmID); | |
| 3115 if (p12dcx->decitem.shroudAlg) { | |
| 3116 SECOID_CopyAlgorithmID(NULL, p12dcx->decitem.shroudAlg, | |
| 3117 &bag->safeBagContent.pkcs8ShroudedKeyBag->algorithm); | |
| 3118 } | |
| 3119 case SEC_OID_PKCS12_V1_KEY_BAG_ID: | |
| 3120 p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag); | |
| 3121 break; | |
| 3122 default: | |
| 3123 /* return these even though we don't expect them */ | |
| 3124 break; | |
| 3125 case SEC_OID_UNKNOWN: | |
| 3126 /* ignore these */ | |
| 3127 continue; | |
| 3128 } | |
| 3129 *ipp = &p12dcx->decitem; | |
| 3130 p12dcx->iteration++; | |
| 3131 break; /* end for() */ | |
| 3132 } | |
| 3133 | |
| 3134 PORT_SetError(0); /* end-of-list is SECFailure with no PORT error */ | |
| 3135 return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess); | |
| 3136 } | |
| 3137 | |
| 3138 static SECStatus | |
| 3139 sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx, | |
| 3140 sec_PKCS12SafeBag *bag) | |
| 3141 { | |
| 3142 if(!p12dcx || p12dcx->error) { | |
| 3143 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3144 return SECFailure; | |
| 3145 } | |
| 3146 | |
| 3147 p12dcx->safeBags = !p12dcx->safeBagCount | |
| 3148 ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2) | |
| 3149 : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags, | |
| 3150 sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1, | |
| 3151 p12dcx->safeBagCount + 2); | |
| 3152 | |
| 3153 if(!p12dcx->safeBags) { | |
| 3154 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 3155 return SECFailure; | |
| 3156 } | |
| 3157 | |
| 3158 p12dcx->safeBags[p12dcx->safeBagCount] = bag; | |
| 3159 p12dcx->safeBags[p12dcx->safeBagCount+1] = NULL; | |
| 3160 p12dcx->safeBagCount++; | |
| 3161 | |
| 3162 return SECSuccess; | |
| 3163 } | |
| 3164 | |
| 3165 static sec_PKCS12SafeBag * | |
| 3166 sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx, | |
| 3167 void *key, PRBool isEspvk) | |
| 3168 { | |
| 3169 sec_PKCS12SafeBag *keyBag; | |
| 3170 SECOidData *oid; | |
| 3171 SECOidTag keyTag; | |
| 3172 SECItem *keyID, *nickName, *newNickName; | |
| 3173 | |
| 3174 if(!p12dcx || p12dcx->error || !key) { | |
| 3175 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3176 return NULL; | |
| 3177 } | |
| 3178 | |
| 3179 newNickName = PORT_ArenaZNew(p12dcx->arena, SECItem); | |
| 3180 keyBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag); | |
| 3181 if(!keyBag || !newNickName) { | |
| 3182 return NULL; | |
| 3183 } | |
| 3184 | |
| 3185 keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes; | |
| 3186 keyBag->slot = p12dcx->slot; | |
| 3187 keyBag->arena = p12dcx->arena; | |
| 3188 keyBag->pwitem = p12dcx->pwitem; | |
| 3189 keyBag->tokenCAs = p12dcx->tokenCAs; | |
| 3190 keyBag->oldBagType = PR_TRUE; | |
| 3191 | |
| 3192 keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID : | |
| 3193 SEC_OID_PKCS12_V1_KEY_BAG_ID; | |
| 3194 oid = SECOID_FindOIDByTag(keyTag); | |
| 3195 if(!oid) { | |
| 3196 return NULL; | |
| 3197 } | |
| 3198 | |
| 3199 if(SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid) | |
| 3200 != SECSuccess) { | |
| 3201 return NULL; | |
| 3202 } | |
| 3203 | |
| 3204 if(isEspvk) { | |
| 3205 SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key; | |
| 3206 keyBag->safeBagContent.pkcs8ShroudedKeyBag = | |
| 3207 espvk->espvkCipherText.pkcs8KeyShroud; | |
| 3208 nickName = &(espvk->espvkData.uniNickName); | |
| 3209 if(!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) { | |
| 3210 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); | |
| 3211 return NULL; | |
| 3212 } | |
| 3213 keyID = &espvk->espvkData.assocCerts[0]->digest; | |
| 3214 } else { | |
| 3215 SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key; | |
| 3216 keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data; | |
| 3217 nickName= &(pk->pvkData.uniNickName); | |
| 3218 if(!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) { | |
| 3219 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); | |
| 3220 return NULL; | |
| 3221 } | |
| 3222 keyID = &pk->pvkData.assocCerts[0]->digest; | |
| 3223 } | |
| 3224 | |
| 3225 if(nickName->len) { | |
| 3226 if(nickName->len >= 2) { | |
| 3227 if(nickName->data[0] && nickName->data[1]) { | |
| 3228 if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickNam
e, | |
| 3229 nickName, PR_FALSE, PR_FALSE, PR_TRUE))
{ | |
| 3230 return NULL; | |
| 3231 } | |
| 3232 nickName = newNickName; | |
| 3233 } else if(nickName->data[0] && !nickName->data[1]) { | |
| 3234 unsigned int j = 0; | |
| 3235 unsigned char t; | |
| 3236 for(j = 0; j < nickName->len; j+=2) { | |
| 3237 t = nickName->data[j+1]; | |
| 3238 nickName->data[j+1] = nickName->data[j]; | |
| 3239 nickName->data[j] = t; | |
| 3240 } | |
| 3241 } | |
| 3242 } else { | |
| 3243 if(!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName, | |
| 3244 nickName, PR_FALSE, PR_FALSE, PR_TRUE))
{ | |
| 3245 return NULL; | |
| 3246 } | |
| 3247 nickName = newNickName; | |
| 3248 } | |
| 3249 } | |
| 3250 | |
| 3251 if(sec_pkcs12_decoder_set_attribute_value(keyBag, | |
| 3252 SEC_OID_PKCS9_FRIENDLY_NAME, | |
| 3253 nickName) != SECSuccess) { | |
| 3254 return NULL; | |
| 3255 } | |
| 3256 | |
| 3257 if(sec_pkcs12_decoder_set_attribute_value(keyBag,SEC_OID_PKCS9_LOCAL_KEY_ID, | |
| 3258 keyID) != SECSuccess) { | |
| 3259 return NULL; | |
| 3260 } | |
| 3261 | |
| 3262 return keyBag; | |
| 3263 } | |
| 3264 | |
| 3265 static sec_PKCS12SafeBag * | |
| 3266 sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx, | |
| 3267 SECItem *derCert) | |
| 3268 { | |
| 3269 sec_PKCS12SafeBag *certBag; | |
| 3270 SECOidData *oid; | |
| 3271 SGNDigestInfo *digest; | |
| 3272 SECItem *keyId; | |
| 3273 SECStatus rv; | |
| 3274 | |
| 3275 if(!p12dcx || p12dcx->error || !derCert) { | |
| 3276 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3277 return NULL; | |
| 3278 } | |
| 3279 | |
| 3280 keyId = PORT_ArenaZNew(p12dcx->arena, SECItem); | |
| 3281 if(!keyId) { | |
| 3282 return NULL; | |
| 3283 } | |
| 3284 | |
| 3285 digest = sec_pkcs12_compute_thumbprint(derCert); | |
| 3286 if(!digest) { | |
| 3287 return NULL; | |
| 3288 } | |
| 3289 | |
| 3290 rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest); | |
| 3291 SGN_DestroyDigestInfo(digest); | |
| 3292 if(rv != SECSuccess) { | |
| 3293 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 3294 return NULL; | |
| 3295 } | |
| 3296 | |
| 3297 oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID); | |
| 3298 certBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag); | |
| 3299 if(!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena, | |
| 3300 &certBag->safeBagType, &oid->oid) != SECSuccess)) { | |
| 3301 return NULL; | |
| 3302 } | |
| 3303 | |
| 3304 certBag->slot = p12dcx->slot; | |
| 3305 certBag->pwitem = p12dcx->pwitem; | |
| 3306 certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes; | |
| 3307 certBag->arena = p12dcx->arena; | |
| 3308 certBag->tokenCAs = p12dcx->tokenCAs; | |
| 3309 | |
| 3310 oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT); | |
| 3311 certBag->safeBagContent.certBag = | |
| 3312 PORT_ArenaZNew(p12dcx->arena, sec_PKCS12CertBag); | |
| 3313 if(!certBag->safeBagContent.certBag || !oid || | |
| 3314 (SECITEM_CopyItem(p12dcx->arena, | |
| 3315 &certBag->safeBagContent.certBag->bagID, | |
| 3316 &oid->oid) != SECSuccess)) { | |
| 3317 return NULL; | |
| 3318 } | |
| 3319 | |
| 3320 if(SECITEM_CopyItem(p12dcx->arena, | |
| 3321 &(certBag->safeBagContent.certBag->value.x509Cert), | |
| 3322 derCert) != SECSuccess) { | |
| 3323 return NULL; | |
| 3324 } | |
| 3325 | |
| 3326 if(sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_I
D, | |
| 3327 keyId) != SECSuccess) { | |
| 3328 return NULL; | |
| 3329 } | |
| 3330 | |
| 3331 return certBag; | |
| 3332 } | |
| 3333 | |
| 3334 static sec_PKCS12SafeBag ** | |
| 3335 sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx, | |
| 3336 SEC_PKCS12CertAndCRL *oldCert) | |
| 3337 { | |
| 3338 sec_PKCS12SafeBag **certList; | |
| 3339 SECItem **derCertList; | |
| 3340 int i, j; | |
| 3341 | |
| 3342 if(!p12dcx || p12dcx->error || !oldCert) { | |
| 3343 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3344 return NULL; | |
| 3345 } | |
| 3346 | |
| 3347 derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL); | |
| 3348 if(!derCertList) { | |
| 3349 return NULL; | |
| 3350 } | |
| 3351 | |
| 3352 i = 0; | |
| 3353 while(derCertList[i]) i++; | |
| 3354 | |
| 3355 certList = PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, (i + 1)); | |
| 3356 if(!certList) { | |
| 3357 return NULL; | |
| 3358 } | |
| 3359 | |
| 3360 for(j = 0; j < i; j++) { | |
| 3361 certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]); | |
| 3362 if(!certList[j]) { | |
| 3363 return NULL; | |
| 3364 } | |
| 3365 } | |
| 3366 | |
| 3367 return certList; | |
| 3368 } | |
| 3369 | |
| 3370 static SECStatus | |
| 3371 sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx, | |
| 3372 void *oldKey, PRBool isEspvk, | |
| 3373 SEC_PKCS12SafeContents *safe, | |
| 3374 SEC_PKCS12Baggage *baggage) | |
| 3375 { | |
| 3376 sec_PKCS12SafeBag *key, **certList; | |
| 3377 SEC_PKCS12CertAndCRL *oldCert; | |
| 3378 SEC_PKCS12PVKSupportingData *pvkData; | |
| 3379 int i; | |
| 3380 SECItem *keyName; | |
| 3381 | |
| 3382 if(!p12dcx || !oldKey) { | |
| 3383 return SECFailure; | |
| 3384 } | |
| 3385 | |
| 3386 if(isEspvk) { | |
| 3387 pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData; | |
| 3388 } else { | |
| 3389 pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData; | |
| 3390 } | |
| 3391 | |
| 3392 if(!pvkData->assocCerts || !pvkData->assocCerts[0]) { | |
| 3393 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); | |
| 3394 return SECFailure; | |
| 3395 } | |
| 3396 | |
| 3397 oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage, | |
| 3398 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL, | |
| 3399 pvkData->assocCerts[0]); | |
| 3400 if(!oldCert) { | |
| 3401 PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE); | |
| 3402 return SECFailure; | |
| 3403 } | |
| 3404 | |
| 3405 key = sec_pkcs12_decoder_convert_old_key(p12dcx,oldKey, isEspvk); | |
| 3406 certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert); | |
| 3407 if(!key || !certList) { | |
| 3408 return SECFailure; | |
| 3409 } | |
| 3410 | |
| 3411 if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) { | |
| 3412 return SECFailure; | |
| 3413 } | |
| 3414 | |
| 3415 keyName = sec_pkcs12_get_nickname(key); | |
| 3416 if(!keyName) { | |
| 3417 return SECFailure; | |
| 3418 } | |
| 3419 | |
| 3420 i = 0; | |
| 3421 while(certList[i]) { | |
| 3422 if(sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i]) | |
| 3423 != SECSuccess) { | |
| 3424 return SECFailure; | |
| 3425 } | |
| 3426 i++; | |
| 3427 } | |
| 3428 | |
| 3429 certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key); | |
| 3430 if(!certList) { | |
| 3431 return SECFailure; | |
| 3432 } | |
| 3433 | |
| 3434 i = 0; | |
| 3435 while(certList[i] != 0) { | |
| 3436 if(sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) { | |
| 3437 return SECFailure; | |
| 3438 } | |
| 3439 i++; | |
| 3440 } | |
| 3441 | |
| 3442 return SECSuccess; | |
| 3443 } | |
| 3444 | |
| 3445 static SECStatus | |
| 3446 sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx, | |
| 3447 SEC_PKCS12SafeContents *safe, | |
| 3448 SEC_PKCS12Baggage *baggage) | |
| 3449 { | |
| 3450 SECStatus rv; | |
| 3451 | |
| 3452 if(!p12dcx || p12dcx->error) { | |
| 3453 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3454 return SECFailure; | |
| 3455 } | |
| 3456 | |
| 3457 if(safe && safe->contents) { | |
| 3458 int i = 0; | |
| 3459 while(safe->contents[i] != NULL) { | |
| 3460 if(SECOID_FindOIDTag(&safe->contents[i]->safeBagType) | |
| 3461 == SEC_OID_PKCS12_KEY_BAG_ID) { | |
| 3462 int j = 0; | |
| 3463 SEC_PKCS12PrivateKeyBag *privBag = | |
| 3464 safe->contents[i]->safeContent.keyBag; | |
| 3465 | |
| 3466 while(privBag->privateKeys[j] != NULL) { | |
| 3467 SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j]; | |
| 3468 rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx,pk, | |
| 3469 PR_FALSE, safe, baggage); | |
| 3470 if(rv != SECSuccess) { | |
| 3471 goto loser; | |
| 3472 } | |
| 3473 j++; | |
| 3474 } | |
| 3475 } | |
| 3476 i++; | |
| 3477 } | |
| 3478 } | |
| 3479 | |
| 3480 if(baggage && baggage->bags) { | |
| 3481 int i = 0; | |
| 3482 while(baggage->bags[i] != NULL) { | |
| 3483 SEC_PKCS12BaggageItem *bag = baggage->bags[i]; | |
| 3484 int j = 0; | |
| 3485 | |
| 3486 if(!bag->espvks) { | |
| 3487 i++; | |
| 3488 continue; | |
| 3489 } | |
| 3490 | |
| 3491 while(bag->espvks[j] != NULL) { | |
| 3492 SEC_PKCS12ESPVKItem *espvk = bag->espvks[j]; | |
| 3493 rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk, | |
| 3494 PR_TRUE, safe, baggage); | |
| 3495 if(rv != SECSuccess) { | |
| 3496 goto loser; | |
| 3497 } | |
| 3498 j++; | |
| 3499 } | |
| 3500 i++; | |
| 3501 } | |
| 3502 } | |
| 3503 | |
| 3504 return SECSuccess; | |
| 3505 | |
| 3506 loser: | |
| 3507 return SECFailure; | |
| 3508 } | |
| 3509 | |
| 3510 SEC_PKCS12DecoderContext * | |
| 3511 sec_PKCS12ConvertOldSafeToNew(PLArenaPool *arena, PK11SlotInfo *slot, | |
| 3512 PRBool swapUnicode, SECItem *pwitem, | |
| 3513 void *wincx, SEC_PKCS12SafeContents *safe, | |
| 3514 SEC_PKCS12Baggage *baggage) | |
| 3515 { | |
| 3516 SEC_PKCS12DecoderContext *p12dcx; | |
| 3517 | |
| 3518 if(!arena || !slot || !pwitem) { | |
| 3519 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3520 return NULL; | |
| 3521 } | |
| 3522 | |
| 3523 if(!safe && !baggage) { | |
| 3524 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 3525 return NULL; | |
| 3526 } | |
| 3527 | |
| 3528 p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext); | |
| 3529 if(!p12dcx) { | |
| 3530 return NULL; | |
| 3531 } | |
| 3532 | |
| 3533 p12dcx->arena = arena; | |
| 3534 p12dcx->slot = PK11_ReferenceSlot(slot); | |
| 3535 p12dcx->wincx = wincx; | |
| 3536 p12dcx->error = PR_FALSE; | |
| 3537 p12dcx->swapUnicodeBytes = swapUnicode; | |
| 3538 p12dcx->pwitem = pwitem; | |
| 3539 p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs; | |
| 3540 | |
| 3541 if(sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage) | |
| 3542 != SECSuccess) { | |
| 3543 p12dcx->error = PR_TRUE; | |
| 3544 return NULL; | |
| 3545 } | |
| 3546 | |
| 3547 return p12dcx; | |
| 3548 } | |
| OLD | NEW |