p12e.c (70123B)
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 #include "p12t.h" 6 #include "p12.h" 7 #include "plarena.h" 8 #include "secitem.h" 9 #include "secoid.h" 10 #include "seccomon.h" 11 #include "secport.h" 12 #include "cert.h" 13 #include "secpkcs5.h" 14 #include "secpkcs7.h" 15 #include "secasn1.h" 16 #include "secerr.h" 17 #include "sechash.h" 18 #include "pk11func.h" 19 #include "p12plcy.h" 20 #include "p12local.h" 21 #include "prcpucfg.h" 22 23 extern const int NSS_PBE_DEFAULT_ITERATION_COUNT; /* defined in p7create.c */ 24 25 /* 26 ** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder 27 ** contexts. It can be difficult to keep straight. Here's a picture: 28 ** 29 ** "outer" ASN.1 encoder. The output goes to the library caller's CB. 30 ** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder. 31 ** "middle" ASN1 encoder. Encodes the encrypted aSafes. 32 ** Feeds the "middle" P7 encoder above. 33 ** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes) 34 ** Feeds the "middle" ASN.1 encoder above. 35 ** "inner" ASN.1 encoder. Encodes the unencrypted aSafes. 36 ** Feeds the "inner" P7 enocder above. 37 ** 38 ** Buffering has been added at each point where the output of an ASN.1 39 ** encoder feeds the input of a PKCS7 encoder. 40 */ 41 42 /********************************* 43 * Output buffer object, used to buffer output from ASN.1 encoder 44 * before passing data on down to the next PKCS7 encoder. 45 *********************************/ 46 47 #define PK12_OUTPUT_BUFFER_SIZE 8192 48 49 struct sec_pkcs12OutputBufferStr { 50 SEC_PKCS7EncoderContext *p7eCx; 51 PK11Context *hmacCx; 52 unsigned int numBytes; 53 unsigned int bufBytes; 54 char buf[PK12_OUTPUT_BUFFER_SIZE]; 55 }; 56 typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer; 57 58 /********************************* 59 * Structures used in exporting the PKCS 12 blob 60 *********************************/ 61 62 /* A SafeInfo is used for each ContentInfo which makes up the 63 * sequence of safes in the AuthenticatedSafe portion of the 64 * PFX structure. 65 */ 66 struct SEC_PKCS12SafeInfoStr { 67 PLArenaPool *arena; 68 69 /* information for setting up password encryption */ 70 SECItem pwitem; 71 SECOidTag algorithm; 72 PK11SymKey *encryptionKey; 73 74 /* how many items have been stored in this safe, 75 * we will skip any safe which does not contain any 76 * items 77 */ 78 unsigned int itemCount; 79 80 /* the content info for the safe */ 81 SEC_PKCS7ContentInfo *cinfo; 82 83 sec_PKCS12SafeContents *safe; 84 }; 85 86 /* An opaque structure which contains information needed for exporting 87 * certificates and keys through PKCS 12. 88 */ 89 struct SEC_PKCS12ExportContextStr { 90 PLArenaPool *arena; 91 PK11SlotInfo *slot; 92 void *wincx; 93 94 /* integrity information */ 95 PRBool integrityEnabled; 96 PRBool pwdIntegrity; 97 union { 98 struct sec_PKCS12PasswordModeInfo pwdInfo; 99 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo; 100 } integrityInfo; 101 102 /* helper functions */ 103 /* retrieve the password call back */ 104 SECKEYGetPasswordKey pwfn; 105 void *pwfnarg; 106 107 /* safe contents bags */ 108 SEC_PKCS12SafeInfo **safeInfos; 109 unsigned int safeInfoCount; 110 111 /* the sequence of safes */ 112 sec_PKCS12AuthenticatedSafe authSafe; 113 114 /* information needing deletion */ 115 CERTCertificate **certList; 116 }; 117 118 /* structures for passing information to encoder callbacks when processing 119 * data through the ASN1 engine. 120 */ 121 struct sec_pkcs12_encoder_output { 122 SEC_PKCS12EncoderOutputCallback outputfn; 123 void *outputarg; 124 }; 125 126 struct sec_pkcs12_hmac_and_output_info { 127 void *arg; 128 struct sec_pkcs12_encoder_output output; 129 }; 130 131 /* An encoder context which is used for the actual encoding 132 * portion of PKCS 12. 133 */ 134 typedef struct sec_PKCS12EncoderContextStr { 135 PLArenaPool *arena; 136 SEC_PKCS12ExportContext *p12exp; 137 138 /* encoder information - this is set up based on whether 139 * password based or public key pased privacy is being used 140 */ 141 SEC_ASN1EncoderContext *outerA1ecx; 142 union { 143 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo; 144 struct sec_pkcs12_encoder_output encOutput; 145 } output; 146 147 /* structures for encoding of PFX and MAC */ 148 sec_PKCS12PFXItem pfx; 149 sec_PKCS12MacData mac; 150 151 /* authenticated safe encoding tracking information */ 152 SEC_PKCS7ContentInfo *aSafeCinfo; 153 SEC_PKCS7EncoderContext *middleP7ecx; 154 SEC_ASN1EncoderContext *middleA1ecx; 155 unsigned int currentSafe; 156 157 /* hmac context */ 158 PK11Context *hmacCx; 159 160 /* output buffers */ 161 sec_pkcs12OutputBuffer middleBuf; 162 sec_pkcs12OutputBuffer innerBuf; 163 164 } sec_PKCS12EncoderContext; 165 166 /********************************* 167 * Export setup routines 168 *********************************/ 169 170 /* SEC_PKCS12CreateExportContext 171 * Creates an export context and sets the unicode and password retrieval 172 * callbacks. This is the first call which must be made when exporting 173 * a PKCS 12 blob. 174 * 175 * pwfn, pwfnarg - password retrieval callback and argument. these are 176 * required for password-authentication mode. 177 */ 178 SEC_PKCS12ExportContext * 179 SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg, 180 PK11SlotInfo *slot, void *wincx) 181 { 182 PLArenaPool *arena = NULL; 183 SEC_PKCS12ExportContext *p12ctxt = NULL; 184 185 /* allocate the arena and create the context */ 186 arena = PORT_NewArena(4096); 187 if (!arena) { 188 PORT_SetError(SEC_ERROR_NO_MEMORY); 189 return NULL; 190 } 191 192 p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena, 193 sizeof(SEC_PKCS12ExportContext)); 194 if (!p12ctxt) { 195 PORT_SetError(SEC_ERROR_NO_MEMORY); 196 goto loser; 197 } 198 199 /* password callback for key retrieval */ 200 p12ctxt->pwfn = pwfn; 201 p12ctxt->pwfnarg = pwfnarg; 202 203 p12ctxt->integrityEnabled = PR_FALSE; 204 p12ctxt->arena = arena; 205 p12ctxt->wincx = wincx; 206 p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot(); 207 208 return p12ctxt; 209 210 loser: 211 if (arena) { 212 PORT_FreeArena(arena, PR_TRUE); 213 } 214 215 return NULL; 216 } 217 218 /* 219 * Adding integrity mode 220 */ 221 222 /* SEC_PKCS12AddPasswordIntegrity 223 * Add password integrity to the exported data. If an integrity method 224 * has already been set, then return an error. 225 * 226 * p12ctxt - the export context 227 * pwitem - the password for integrity mode 228 * integAlg - the integrity algorithm to use for authentication. 229 */ 230 SECStatus 231 SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt, 232 SECItem *pwitem, SECOidTag integAlg) 233 { 234 if (!p12ctxt || p12ctxt->integrityEnabled) { 235 return SECFailure; 236 } 237 238 /* set up integrity information */ 239 p12ctxt->pwdIntegrity = PR_TRUE; 240 p12ctxt->integrityInfo.pwdInfo.password = 241 (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem)); 242 if (!p12ctxt->integrityInfo.pwdInfo.password) { 243 PORT_SetError(SEC_ERROR_NO_MEMORY); 244 return SECFailure; 245 } 246 if (SECITEM_CopyItem(p12ctxt->arena, 247 p12ctxt->integrityInfo.pwdInfo.password, pwitem) != SECSuccess) { 248 PORT_SetError(SEC_ERROR_NO_MEMORY); 249 return SECFailure; 250 } 251 p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg; 252 p12ctxt->integrityEnabled = PR_TRUE; 253 254 return SECSuccess; 255 } 256 257 /* SEC_PKCS12AddPublicKeyIntegrity 258 * Add public key integrity to the exported data. If an integrity method 259 * has already been set, then return an error. The certificate must be 260 * allowed to be used as a signing cert. 261 * 262 * p12ctxt - the export context 263 * cert - signer certificate 264 * certDb - the certificate database 265 * algorithm - signing algorithm 266 * keySize - size of the signing key (?) 267 */ 268 SECStatus 269 SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt, 270 CERTCertificate *cert, CERTCertDBHandle *certDb, 271 SECOidTag algorithm, int keySize) 272 { 273 if (!p12ctxt) { 274 return SECFailure; 275 } 276 277 p12ctxt->integrityInfo.pubkeyInfo.cert = cert; 278 p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb; 279 p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm; 280 p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize; 281 p12ctxt->integrityEnabled = PR_TRUE; 282 283 return SECSuccess; 284 } 285 286 /* 287 * Adding safes - encrypted (password/public key) or unencrypted 288 * Each of the safe creation routines return an opaque pointer which 289 * are later passed into the routines for exporting certificates and 290 * keys. 291 */ 292 293 /* append the newly created safeInfo to list of safeInfos in the export 294 * context. 295 */ 296 static SECStatus 297 sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info) 298 { 299 void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL; 300 301 if (!p12ctxt || !info) { 302 return SECFailure; 303 } 304 305 mark = PORT_ArenaMark(p12ctxt->arena); 306 307 /* if no safeInfos have been set, create the list, otherwise expand it. */ 308 if (!p12ctxt->safeInfoCount) { 309 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAlloc(p12ctxt->arena, 310 2 * sizeof(SEC_PKCS12SafeInfo *)); 311 dummy1 = p12ctxt->safeInfos; 312 p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena, 313 2 * sizeof(SECItem *)); 314 dummy2 = p12ctxt->authSafe.encodedSafes; 315 } else { 316 dummy1 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->safeInfos, 317 (p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12SafeInfo *), 318 (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *)); 319 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1; 320 dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes, 321 (p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *), 322 (p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *)); 323 p12ctxt->authSafe.encodedSafes = (SECItem **)dummy2; 324 } 325 if (!dummy1 || !dummy2) { 326 PORT_SetError(SEC_ERROR_NO_MEMORY); 327 goto loser; 328 } 329 330 /* append the new safeInfo and null terminate the list */ 331 p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info; 332 p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL; 333 p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] = 334 (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem)); 335 if (!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) { 336 PORT_SetError(SEC_ERROR_NO_MEMORY); 337 goto loser; 338 } 339 p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL; 340 341 PORT_ArenaUnmark(p12ctxt->arena, mark); 342 return SECSuccess; 343 344 loser: 345 PORT_ArenaRelease(p12ctxt->arena, mark); 346 return SECFailure; 347 } 348 349 /* SEC_PKCS12CreatePasswordPrivSafe 350 * Create a password privacy safe to store exported information in. 351 * 352 * p12ctxt - export context 353 * pwitem - password for encryption 354 * privAlg - pbe algorithm through which encryption is done. 355 */ 356 SEC_PKCS12SafeInfo * 357 SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt, 358 SECItem *pwitem, SECOidTag privAlg) 359 { 360 SEC_PKCS12SafeInfo *safeInfo = NULL; 361 void *mark = NULL; 362 PK11SlotInfo *slot = NULL; 363 SECAlgorithmID *algId; 364 SECItem uniPwitem = { siBuffer, NULL, 0 }; 365 366 if (!p12ctxt) { 367 return NULL; 368 } 369 370 /* allocate the safe info */ 371 mark = PORT_ArenaMark(p12ctxt->arena); 372 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena, 373 sizeof(SEC_PKCS12SafeInfo)); 374 if (!safeInfo) { 375 PORT_SetError(SEC_ERROR_NO_MEMORY); 376 goto loser; 377 } 378 379 safeInfo->itemCount = 0; 380 381 /* create the encrypted safe */ 382 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(privAlg)) { 383 SECOidTag prfAlg = SEC_OID_UNKNOWN; 384 /* if we have password integrity set, use that to set the integrity 385 * hash algorithm to set our password PRF. If we haven't set it, just 386 * let the low level code pick it */ 387 if (p12ctxt->integrityEnabled && p12ctxt->pwdIntegrity) { 388 SECOidTag integrityAlg = p12ctxt->integrityInfo.pwdInfo.algorithm; 389 prfAlg = integrityAlg; 390 /* verify that integrityAlg is an HMAC */ 391 if (HASH_GetHashOidTagByHMACOidTag(integrityAlg) == SEC_OID_UNKNOWN) { 392 /* it's not, find the hmac */ 393 prfAlg = HASH_GetHMACOidTagByHashOidTag(integrityAlg); 394 /* if prfAlg is SEC_OID_UNKNOWN at this point we'll 395 * default to SEC_OID_HMAC_SHA1 in the low level pbe code. */ 396 } 397 } 398 if (!SEC_PKCS12CipherAllowed(privAlg, prfAlg)) { 399 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); 400 goto loser; 401 } 402 safeInfo->cinfo = SEC_PKCS7CreateEncryptedDataWithPBEV2(SEC_OID_PKCS5_PBES2, 403 privAlg, 404 prfAlg, 405 0, 406 p12ctxt->pwfn, 407 p12ctxt->pwfnarg); 408 } else { 409 if (!SEC_PKCS12CipherAllowed(privAlg, SEC_OID_UNKNOWN)) { 410 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); 411 goto loser; 412 } 413 safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn, 414 p12ctxt->pwfnarg); 415 } 416 if (!safeInfo->cinfo) { 417 PORT_SetError(SEC_ERROR_NO_MEMORY); 418 goto loser; 419 } 420 safeInfo->arena = p12ctxt->arena; 421 422 if (!sec_pkcs12_encode_password(NULL, &uniPwitem, privAlg, pwitem)) { 423 PORT_SetError(SEC_ERROR_NO_MEMORY); 424 goto loser; 425 } 426 if (SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) { 427 PORT_SetError(SEC_ERROR_NO_MEMORY); 428 goto loser; 429 } 430 431 /* generate the encryption key */ 432 slot = PK11_ReferenceSlot(p12ctxt->slot); 433 if (!slot) { 434 slot = PK11_GetInternalKeySlot(); 435 if (!slot) { 436 PORT_SetError(SEC_ERROR_NO_MEMORY); 437 goto loser; 438 } 439 } 440 441 algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo); 442 safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem, 443 PR_FALSE, p12ctxt->wincx); 444 if (!safeInfo->encryptionKey) { 445 goto loser; 446 } 447 448 safeInfo->arena = p12ctxt->arena; 449 safeInfo->safe = NULL; 450 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) { 451 goto loser; 452 } 453 454 if (uniPwitem.data) { 455 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE); 456 } 457 PORT_ArenaUnmark(p12ctxt->arena, mark); 458 459 if (slot) { 460 PK11_FreeSlot(slot); 461 } 462 return safeInfo; 463 464 loser: 465 if (slot) { 466 PK11_FreeSlot(slot); 467 } 468 if (safeInfo && safeInfo->cinfo) { 469 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo); 470 } 471 472 if (uniPwitem.data) { 473 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE); 474 } 475 476 PORT_ArenaRelease(p12ctxt->arena, mark); 477 return NULL; 478 } 479 480 /* SEC_PKCS12CreateUnencryptedSafe 481 * Creates an unencrypted safe within the export context. 482 * 483 * p12ctxt - the export context 484 */ 485 SEC_PKCS12SafeInfo * 486 SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt) 487 { 488 SEC_PKCS12SafeInfo *safeInfo = NULL; 489 void *mark = NULL; 490 491 if (!p12ctxt) { 492 return NULL; 493 } 494 495 /* create the safe info */ 496 mark = PORT_ArenaMark(p12ctxt->arena); 497 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena, 498 sizeof(SEC_PKCS12SafeInfo)); 499 if (!safeInfo) { 500 PORT_ArenaRelease(p12ctxt->arena, mark); 501 PORT_SetError(SEC_ERROR_NO_MEMORY); 502 return NULL; 503 } 504 505 safeInfo->itemCount = 0; 506 507 /* create the safe content */ 508 safeInfo->cinfo = SEC_PKCS7CreateData(); 509 if (!safeInfo->cinfo) { 510 PORT_SetError(SEC_ERROR_NO_MEMORY); 511 goto loser; 512 } 513 514 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) { 515 goto loser; 516 } 517 518 PORT_ArenaUnmark(p12ctxt->arena, mark); 519 return safeInfo; 520 521 loser: 522 if (safeInfo->cinfo) { 523 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo); 524 } 525 526 PORT_ArenaRelease(p12ctxt->arena, mark); 527 return NULL; 528 } 529 530 /* SEC_PKCS12CreatePubKeyEncryptedSafe 531 * Creates a safe which is protected by public key encryption. 532 * 533 * p12ctxt - the export context 534 * certDb - the certificate database 535 * signer - the signer's certificate 536 * recipients - the list of recipient certificates. 537 * algorithm - the encryption algorithm to use 538 * keysize - the algorithms key size (?) 539 */ 540 SEC_PKCS12SafeInfo * 541 SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt, 542 CERTCertDBHandle *certDb, 543 CERTCertificate *signer, 544 CERTCertificate **recipients, 545 SECOidTag algorithm, int keysize) 546 { 547 SEC_PKCS12SafeInfo *safeInfo = NULL; 548 void *mark = NULL; 549 550 if (!p12ctxt || !signer || !recipients || !(*recipients)) { 551 return NULL; 552 } 553 554 /* allocate the safeInfo */ 555 mark = PORT_ArenaMark(p12ctxt->arena); 556 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena, 557 sizeof(SEC_PKCS12SafeInfo)); 558 if (!safeInfo) { 559 PORT_ArenaRelease(p12ctxt->arena, mark); 560 PORT_SetError(SEC_ERROR_NO_MEMORY); 561 return NULL; 562 } 563 564 safeInfo->itemCount = 0; 565 safeInfo->arena = p12ctxt->arena; 566 567 /* create the enveloped content info using certUsageEmailSigner currently. 568 * XXX We need to eventually use something other than certUsageEmailSigner 569 */ 570 safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner, 571 certDb, algorithm, keysize, 572 p12ctxt->pwfn, p12ctxt->pwfnarg); 573 if (!safeInfo->cinfo) { 574 PORT_SetError(SEC_ERROR_NO_MEMORY); 575 goto loser; 576 } 577 578 /* add recipients */ 579 if (recipients) { 580 unsigned int i = 0; 581 while (recipients[i] != NULL) { 582 SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i], 583 certUsageEmailRecipient, certDb); 584 if (rv != SECSuccess) { 585 goto loser; 586 } 587 i++; 588 } 589 } 590 591 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) { 592 goto loser; 593 } 594 595 PORT_ArenaUnmark(p12ctxt->arena, mark); 596 return safeInfo; 597 598 loser: 599 if (safeInfo->cinfo) { 600 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo); 601 safeInfo->cinfo = NULL; 602 } 603 604 PORT_ArenaRelease(p12ctxt->arena, mark); 605 return NULL; 606 } 607 608 /********************************* 609 * Routines to handle the exporting of the keys and certificates 610 *********************************/ 611 612 /* creates a safe contents which safeBags will be appended to */ 613 sec_PKCS12SafeContents * 614 sec_PKCS12CreateSafeContents(PLArenaPool *arena) 615 { 616 sec_PKCS12SafeContents *safeContents; 617 618 if (arena == NULL) { 619 return NULL; 620 } 621 622 /* create the safe contents */ 623 safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena, 624 sizeof(sec_PKCS12SafeContents)); 625 if (!safeContents) { 626 PORT_SetError(SEC_ERROR_NO_MEMORY); 627 goto loser; 628 } 629 630 /* set up the internal contents info */ 631 safeContents->safeBags = NULL; 632 safeContents->arena = arena; 633 safeContents->bagCount = 0; 634 635 return safeContents; 636 637 loser: 638 return NULL; 639 } 640 641 /* appends a safe bag to a safeContents using the specified arena. 642 */ 643 SECStatus 644 sec_pkcs12_append_bag_to_safe_contents(PLArenaPool *arena, 645 sec_PKCS12SafeContents *safeContents, 646 sec_PKCS12SafeBag *safeBag) 647 { 648 void *mark = NULL, *dummy = NULL; 649 650 if (!arena || !safeBag || !safeContents) { 651 return SECFailure; 652 } 653 654 mark = PORT_ArenaMark(arena); 655 if (!mark) { 656 PORT_SetError(SEC_ERROR_NO_MEMORY); 657 return SECFailure; 658 } 659 660 /* allocate space for the list, or reallocate to increase space */ 661 if (!safeContents->safeBags) { 662 safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(arena, 663 (2 * sizeof(sec_PKCS12SafeBag *))); 664 dummy = safeContents->safeBags; 665 safeContents->bagCount = 0; 666 } else { 667 dummy = PORT_ArenaGrow(arena, safeContents->safeBags, 668 (safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag *), 669 (safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag *)); 670 safeContents->safeBags = (sec_PKCS12SafeBag **)dummy; 671 } 672 673 if (!dummy) { 674 PORT_ArenaRelease(arena, mark); 675 PORT_SetError(SEC_ERROR_NO_MEMORY); 676 return SECFailure; 677 } 678 679 /* append the bag at the end and null terminate the list */ 680 safeContents->safeBags[safeContents->bagCount++] = safeBag; 681 safeContents->safeBags[safeContents->bagCount] = NULL; 682 683 PORT_ArenaUnmark(arena, mark); 684 685 return SECSuccess; 686 } 687 688 /* appends a safeBag to a specific safeInfo. 689 */ 690 SECStatus 691 sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt, 692 SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag) 693 { 694 sec_PKCS12SafeContents *dest; 695 SECStatus rv = SECFailure; 696 697 if (!p12ctxt || !safeBag || !safeInfo) { 698 return SECFailure; 699 } 700 701 if (!safeInfo->safe) { 702 safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena); 703 if (!safeInfo->safe) { 704 return SECFailure; 705 } 706 } 707 708 dest = safeInfo->safe; 709 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag); 710 if (rv == SECSuccess) { 711 safeInfo->itemCount++; 712 } 713 714 return rv; 715 } 716 717 /* Creates a safeBag of the specified type, and if bagData is specified, 718 * the contents are set. The contents could be set later by the calling 719 * routine. 720 */ 721 sec_PKCS12SafeBag * 722 sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType, 723 void *bagData) 724 { 725 sec_PKCS12SafeBag *safeBag; 726 void *mark = NULL; 727 SECStatus rv = SECSuccess; 728 SECOidData *oidData = NULL; 729 730 if (!p12ctxt) { 731 return NULL; 732 } 733 734 mark = PORT_ArenaMark(p12ctxt->arena); 735 if (!mark) { 736 PORT_SetError(SEC_ERROR_NO_MEMORY); 737 return NULL; 738 } 739 740 safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena, 741 sizeof(sec_PKCS12SafeBag)); 742 if (!safeBag) { 743 PORT_ArenaRelease(p12ctxt->arena, mark); 744 PORT_SetError(SEC_ERROR_NO_MEMORY); 745 return NULL; 746 } 747 748 /* set the bags content based upon bag type */ 749 switch (bagType) { 750 case SEC_OID_PKCS12_V1_KEY_BAG_ID: 751 safeBag->safeBagContent.pkcs8KeyBag = 752 (SECKEYPrivateKeyInfo *)bagData; 753 break; 754 case SEC_OID_PKCS12_V1_CERT_BAG_ID: 755 safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData; 756 break; 757 case SEC_OID_PKCS12_V1_CRL_BAG_ID: 758 safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData; 759 break; 760 case SEC_OID_PKCS12_V1_SECRET_BAG_ID: 761 safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData; 762 break; 763 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: 764 safeBag->safeBagContent.pkcs8ShroudedKeyBag = 765 (SECKEYEncryptedPrivateKeyInfo *)bagData; 766 break; 767 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID: 768 safeBag->safeBagContent.safeContents = 769 (sec_PKCS12SafeContents *)bagData; 770 break; 771 default: 772 goto loser; 773 } 774 775 oidData = SECOID_FindOIDByTag(bagType); 776 if (oidData) { 777 rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid); 778 if (rv != SECSuccess) { 779 PORT_SetError(SEC_ERROR_NO_MEMORY); 780 goto loser; 781 } 782 } else { 783 goto loser; 784 } 785 786 safeBag->arena = p12ctxt->arena; 787 PORT_ArenaUnmark(p12ctxt->arena, mark); 788 789 return safeBag; 790 791 loser: 792 if (mark) { 793 PORT_ArenaRelease(p12ctxt->arena, mark); 794 } 795 796 return NULL; 797 } 798 799 /* Creates a new certificate bag and returns a pointer to it. If an error 800 * occurs NULL is returned. 801 */ 802 sec_PKCS12CertBag * 803 sec_PKCS12NewCertBag(PLArenaPool *arena, SECOidTag certType) 804 { 805 sec_PKCS12CertBag *certBag = NULL; 806 SECOidData *bagType = NULL; 807 SECStatus rv; 808 void *mark = NULL; 809 810 if (!arena) { 811 return NULL; 812 } 813 814 mark = PORT_ArenaMark(arena); 815 certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena, 816 sizeof(sec_PKCS12CertBag)); 817 if (!certBag) { 818 PORT_ArenaRelease(arena, mark); 819 PORT_SetError(SEC_ERROR_NO_MEMORY); 820 return NULL; 821 } 822 823 bagType = SECOID_FindOIDByTag(certType); 824 if (!bagType) { 825 PORT_SetError(SEC_ERROR_NO_MEMORY); 826 goto loser; 827 } 828 829 rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid); 830 if (rv != SECSuccess) { 831 PORT_SetError(SEC_ERROR_NO_MEMORY); 832 goto loser; 833 } 834 835 PORT_ArenaUnmark(arena, mark); 836 return certBag; 837 838 loser: 839 PORT_ArenaRelease(arena, mark); 840 return NULL; 841 } 842 843 /* Creates a new CRL bag and returns a pointer to it. If an error 844 * occurs NULL is returned. 845 */ 846 sec_PKCS12CRLBag * 847 sec_PKCS12NewCRLBag(PLArenaPool *arena, SECOidTag crlType) 848 { 849 sec_PKCS12CRLBag *crlBag = NULL; 850 SECOidData *bagType = NULL; 851 SECStatus rv; 852 void *mark = NULL; 853 854 if (!arena) { 855 return NULL; 856 } 857 858 mark = PORT_ArenaMark(arena); 859 crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena, 860 sizeof(sec_PKCS12CRLBag)); 861 if (!crlBag) { 862 PORT_ArenaRelease(arena, mark); 863 PORT_SetError(SEC_ERROR_NO_MEMORY); 864 return NULL; 865 } 866 867 bagType = SECOID_FindOIDByTag(crlType); 868 if (!bagType) { 869 PORT_SetError(SEC_ERROR_NO_MEMORY); 870 goto loser; 871 } 872 873 rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid); 874 if (rv != SECSuccess) { 875 PORT_SetError(SEC_ERROR_NO_MEMORY); 876 goto loser; 877 } 878 879 PORT_ArenaUnmark(arena, mark); 880 return crlBag; 881 882 loser: 883 PORT_ArenaRelease(arena, mark); 884 return NULL; 885 } 886 887 /* sec_PKCS12AddAttributeToBag 888 * adds an attribute to a safeBag. currently, the only attributes supported 889 * are those which are specified within PKCS 12. 890 * 891 * p12ctxt - the export context 892 * safeBag - the safeBag to which attributes are appended 893 * attrType - the attribute type 894 * attrData - the attribute data 895 */ 896 SECStatus 897 sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt, 898 sec_PKCS12SafeBag *safeBag, SECOidTag attrType, 899 SECItem *attrData) 900 { 901 sec_PKCS12Attribute *attribute; 902 void *mark = NULL, *dummy = NULL; 903 SECOidData *oiddata = NULL; 904 SECItem unicodeName = { siBuffer, NULL, 0 }; 905 void *src = NULL; 906 unsigned int nItems = 0; 907 SECStatus rv; 908 909 PORT_Assert(p12ctxt->arena == safeBag->arena); 910 if (!safeBag || !p12ctxt || p12ctxt->arena != safeBag->arena) { 911 PORT_SetError(SEC_ERROR_INVALID_ARGS); 912 return SECFailure; 913 } 914 915 mark = PORT_ArenaMark(safeBag->arena); 916 917 /* allocate the attribute */ 918 attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena, 919 sizeof(sec_PKCS12Attribute)); 920 if (!attribute) { 921 PORT_SetError(SEC_ERROR_NO_MEMORY); 922 goto loser; 923 } 924 925 /* set up the attribute */ 926 oiddata = SECOID_FindOIDByTag(attrType); 927 if (!oiddata) { 928 PORT_SetError(SEC_ERROR_NO_MEMORY); 929 goto loser; 930 } 931 if (SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) != 932 SECSuccess) { 933 PORT_SetError(SEC_ERROR_NO_MEMORY); 934 goto loser; 935 } 936 937 nItems = 1; 938 switch (attrType) { 939 case SEC_OID_PKCS9_LOCAL_KEY_ID: { 940 src = attrData; 941 break; 942 } 943 case SEC_OID_PKCS9_FRIENDLY_NAME: { 944 if (!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, 945 &unicodeName, attrData, PR_FALSE, 946 PR_FALSE, PR_TRUE)) { 947 goto loser; 948 } 949 src = &unicodeName; 950 break; 951 } 952 default: 953 goto loser; 954 } 955 956 /* append the attribute to the attribute value list */ 957 attribute->attrValue = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena, 958 ((nItems + 1) * sizeof(SECItem *))); 959 if (!attribute->attrValue) { 960 PORT_SetError(SEC_ERROR_NO_MEMORY); 961 goto loser; 962 } 963 964 /* XXX this will need to be changed if attributes requiring more than 965 * one element are ever used. 966 */ 967 attribute->attrValue[0] = (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena, 968 sizeof(SECItem)); 969 if (!attribute->attrValue[0]) { 970 PORT_SetError(SEC_ERROR_NO_MEMORY); 971 goto loser; 972 } 973 attribute->attrValue[1] = NULL; 974 975 rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0], 976 (SECItem *)src); 977 if (rv != SECSuccess) { 978 PORT_SetError(SEC_ERROR_NO_MEMORY); 979 goto loser; 980 } 981 982 /* append the attribute to the safeBag attributes */ 983 if (safeBag->nAttribs) { 984 dummy = PORT_ArenaGrow(p12ctxt->arena, safeBag->attribs, 985 ((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)), 986 ((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *))); 987 safeBag->attribs = (sec_PKCS12Attribute **)dummy; 988 } else { 989 safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->arena, 990 2 * sizeof(sec_PKCS12Attribute *)); 991 dummy = safeBag->attribs; 992 } 993 if (!dummy) { 994 goto loser; 995 } 996 997 safeBag->attribs[safeBag->nAttribs] = attribute; 998 safeBag->attribs[++safeBag->nAttribs] = NULL; 999 1000 PORT_ArenaUnmark(p12ctxt->arena, mark); 1001 return SECSuccess; 1002 1003 loser: 1004 if (mark) { 1005 PORT_ArenaRelease(p12ctxt->arena, mark); 1006 } 1007 1008 return SECFailure; 1009 } 1010 1011 /* SEC_PKCS12AddCert 1012 * Adds a certificate to the data being exported. 1013 * 1014 * p12ctxt - the export context 1015 * safe - the safeInfo to which the certificate is placed 1016 * nestedDest - if the cert is to be placed within a nested safeContents then, 1017 * this value is to be specified with the destination 1018 * cert - the cert to export 1019 * certDb - the certificate database handle 1020 * keyId - a unique identifier to associate a certificate/key pair 1021 * includeCertChain - PR_TRUE if the certificate chain is to be included. 1022 */ 1023 SECStatus 1024 SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe, 1025 void *nestedDest, CERTCertificate *cert, 1026 CERTCertDBHandle *certDb, SECItem *keyId, 1027 PRBool includeCertChain) 1028 { 1029 sec_PKCS12CertBag *certBag; 1030 sec_PKCS12SafeBag *safeBag; 1031 void *mark; 1032 SECStatus rv; 1033 SECItem nick = { siBuffer, NULL, 0 }; 1034 1035 if (!p12ctxt || !cert) { 1036 return SECFailure; 1037 } 1038 mark = PORT_ArenaMark(p12ctxt->arena); 1039 1040 /* allocate the cert bag */ 1041 certBag = sec_PKCS12NewCertBag(p12ctxt->arena, 1042 SEC_OID_PKCS9_X509_CERT); 1043 if (!certBag) { 1044 goto loser; 1045 } 1046 1047 if (SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert, 1048 &cert->derCert) != SECSuccess) { 1049 PORT_SetError(SEC_ERROR_NO_MEMORY); 1050 goto loser; 1051 } 1052 1053 /* if the cert chain is to be included, we should only be exporting 1054 * the cert from our internal database. 1055 */ 1056 if (includeCertChain) { 1057 CERTCertificateList *certList = CERT_CertChainFromCert(cert, 1058 certUsageSSLClient, 1059 PR_TRUE); 1060 unsigned int count = 0; 1061 if (!certList) { 1062 PORT_SetError(SEC_ERROR_NO_MEMORY); 1063 goto loser; 1064 } 1065 1066 /* add cert chain */ 1067 for (count = 0; count < (unsigned int)certList->len; count++) { 1068 if (SECITEM_CompareItem(&certList->certs[count], &cert->derCert) != SECEqual) { 1069 CERTCertificate *tempCert; 1070 1071 /* decode the certificate */ 1072 /* XXX 1073 * This was rather silly. The chain is constructed above 1074 * by finding all of the CERTCertificate's in the database. 1075 * Then the chain is put into a CERTCertificateList, which only 1076 * contains the DER. Finally, the DER was decoded, and the 1077 * decoded cert was sent recursively back to this function. 1078 * Beyond being inefficent, this causes data loss (specifically, 1079 * the nickname). Instead, for 3.4, we'll do a lookup by the 1080 * DER, which should return the cached entry. 1081 */ 1082 tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), 1083 &certList->certs[count]); 1084 if (!tempCert) { 1085 CERT_DestroyCertificateList(certList); 1086 goto loser; 1087 } 1088 1089 /* add the certificate */ 1090 if (SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert, 1091 certDb, NULL, PR_FALSE) != SECSuccess) { 1092 CERT_DestroyCertificate(tempCert); 1093 CERT_DestroyCertificateList(certList); 1094 goto loser; 1095 } 1096 CERT_DestroyCertificate(tempCert); 1097 } 1098 } 1099 CERT_DestroyCertificateList(certList); 1100 } 1101 1102 /* if the certificate has a nickname, we will set the friendly name 1103 * to that. 1104 */ 1105 if (cert->nickname) { 1106 if (cert->slot && !PK11_IsInternal(cert->slot)) { 1107 /* 1108 * The cert is coming off of an external token, 1109 * let's strip the token name from the nickname 1110 * and only add what comes after the colon as the 1111 * nickname. -javi 1112 */ 1113 char *delimit; 1114 1115 delimit = PORT_Strchr(cert->nickname, ':'); 1116 if (delimit == NULL) { 1117 nick.data = (unsigned char *)cert->nickname; 1118 nick.len = PORT_Strlen(cert->nickname); 1119 } else { 1120 delimit++; 1121 nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena, 1122 delimit); 1123 nick.len = PORT_Strlen(delimit); 1124 } 1125 } else { 1126 nick.data = (unsigned char *)cert->nickname; 1127 nick.len = PORT_Strlen(cert->nickname); 1128 } 1129 } 1130 1131 safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID, 1132 certBag); 1133 if (!safeBag) { 1134 goto loser; 1135 } 1136 1137 /* add the friendly name and keyId attributes, if necessary */ 1138 if (nick.data) { 1139 if (sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, 1140 SEC_OID_PKCS9_FRIENDLY_NAME, &nick) != SECSuccess) { 1141 goto loser; 1142 } 1143 } 1144 1145 if (keyId) { 1146 if (sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID, 1147 keyId) != SECSuccess) { 1148 goto loser; 1149 } 1150 } 1151 1152 /* append the cert safeBag */ 1153 if (nestedDest) { 1154 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, 1155 (sec_PKCS12SafeContents *)nestedDest, 1156 safeBag); 1157 } else { 1158 rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag); 1159 } 1160 1161 if (rv != SECSuccess) { 1162 goto loser; 1163 } 1164 1165 PORT_ArenaUnmark(p12ctxt->arena, mark); 1166 return SECSuccess; 1167 1168 loser: 1169 if (mark) { 1170 PORT_ArenaRelease(p12ctxt->arena, mark); 1171 } 1172 1173 return SECFailure; 1174 } 1175 1176 /* SEC_PKCS12AddKeyForCert 1177 * Extracts the key associated with a particular certificate and exports 1178 * it. 1179 * 1180 * p12ctxt - the export context 1181 * safe - the safeInfo to place the key in 1182 * nestedDest - the nested safeContents to place a key 1183 * cert - the certificate which the key belongs to 1184 * shroudKey - encrypt the private key for export. This value should 1185 * always be true. lower level code will not allow the export 1186 * of unencrypted private keys. 1187 * algorithm - the algorithm with which to encrypt the private key 1188 * pwitem - the password to encrypt the private key with 1189 * keyId - the keyID attribute 1190 * nickName - the nickname attribute 1191 */ 1192 SECStatus 1193 SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe, 1194 void *nestedDest, CERTCertificate *cert, 1195 PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem, 1196 SECItem *keyId, SECItem *nickName) 1197 { 1198 void *mark; 1199 void *keyItem; 1200 SECOidTag keyType; 1201 SECStatus rv = SECFailure; 1202 SECItem nickname = { siBuffer, NULL, 0 }, uniPwitem = { siBuffer, NULL, 0 }; 1203 sec_PKCS12SafeBag *returnBag; 1204 1205 if (!p12ctxt || !cert || !safe) { 1206 return SECFailure; 1207 } 1208 1209 mark = PORT_ArenaMark(p12ctxt->arena); 1210 1211 /* retrieve the key based upon the type that it is and 1212 * specify the type of safeBag to store the key in 1213 */ 1214 if (!shroudKey) { 1215 1216 /* extract the key unencrypted. this will most likely go away */ 1217 SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert, 1218 p12ctxt->wincx); 1219 if (!pki) { 1220 PORT_ArenaRelease(p12ctxt->arena, mark); 1221 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); 1222 return SECFailure; 1223 } 1224 keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo)); 1225 if (!keyItem) { 1226 PORT_SetError(SEC_ERROR_NO_MEMORY); 1227 goto loser; 1228 } 1229 rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena, 1230 (SECKEYPrivateKeyInfo *)keyItem, pki); 1231 keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID; 1232 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE); 1233 } else { 1234 1235 /* extract the key encrypted */ 1236 SECKEYEncryptedPrivateKeyInfo *epki = NULL; 1237 PK11SlotInfo *slot = NULL; 1238 SECOidTag prfAlg = SEC_OID_UNKNOWN; 1239 1240 if (!sec_pkcs12_encode_password(p12ctxt->arena, &uniPwitem, algorithm, 1241 pwitem)) { 1242 PORT_SetError(SEC_ERROR_NO_MEMORY); 1243 goto loser; 1244 } 1245 1246 /* if we have password integrity set, use that to set the integrity 1247 * hash algorithm to set our password PRF. If we haven't set it, just 1248 * let the low level code pick it */ 1249 if (p12ctxt->integrityEnabled && p12ctxt->pwdIntegrity) { 1250 SECOidTag integrityAlg = p12ctxt->integrityInfo.pwdInfo.algorithm; 1251 prfAlg = integrityAlg; 1252 /* verify that integrityAlg is an HMAC */ 1253 if (HASH_GetHashOidTagByHMACOidTag(integrityAlg) == SEC_OID_UNKNOWN) { 1254 /* it's not, find the hmac */ 1255 prfAlg = HASH_GetHMACOidTagByHashOidTag(integrityAlg); 1256 /* if prfAlg is SEC_OID_UNKNOWN at this point we'll 1257 * default to SEC_OID_HMAC_SHA1 in the low level pbe code. */ 1258 } 1259 } 1260 1261 if (!SEC_PKCS12CipherAllowed(algorithm, prfAlg)) { 1262 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); 1263 goto loser; 1264 } 1265 1266 /* we want to make sure to take the key out of the key slot */ 1267 if (PK11_IsInternal(p12ctxt->slot)) { 1268 slot = PK11_GetInternalKeySlot(); 1269 } else { 1270 slot = PK11_ReferenceSlot(p12ctxt->slot); 1271 } 1272 1273 /* passing algorithm as the pbe will force the PBE code to 1274 * automatically handle the selection between using the algorithm 1275 * as a the pbe algorithm, or using the algorithm as a cipher 1276 * and building a pkcs5 pbe */ 1277 epki = PK11_ExportEncryptedPrivateKeyInfoV2(slot, algorithm, 1278 SEC_OID_UNKNOWN, prfAlg, 1279 &uniPwitem, cert, 1280 NSS_PBE_DEFAULT_ITERATION_COUNT, 1281 p12ctxt->wincx); 1282 PK11_FreeSlot(slot); 1283 if (!epki) { 1284 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY); 1285 goto loser; 1286 } 1287 1288 keyItem = PORT_ArenaZAlloc(p12ctxt->arena, 1289 sizeof(SECKEYEncryptedPrivateKeyInfo)); 1290 if (!keyItem) { 1291 PORT_SetError(SEC_ERROR_NO_MEMORY); 1292 goto loser; 1293 } 1294 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena, 1295 (SECKEYEncryptedPrivateKeyInfo *)keyItem, 1296 epki); 1297 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID; 1298 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE); 1299 } 1300 1301 if (rv != SECSuccess) { 1302 goto loser; 1303 } 1304 1305 /* if no nickname specified, let's see if the certificate has a 1306 * nickname. 1307 */ 1308 if (!nickName) { 1309 if (cert->nickname) { 1310 nickname.data = (unsigned char *)cert->nickname; 1311 nickname.len = PORT_Strlen(cert->nickname); 1312 nickName = &nickname; 1313 } 1314 } 1315 1316 /* create the safe bag and set any attributes */ 1317 returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem); 1318 if (!returnBag) { 1319 rv = SECFailure; 1320 goto loser; 1321 } 1322 1323 if (nickName) { 1324 if (sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, 1325 SEC_OID_PKCS9_FRIENDLY_NAME, nickName) != SECSuccess) { 1326 goto loser; 1327 } 1328 } 1329 1330 if (keyId) { 1331 if (sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID, 1332 keyId) != SECSuccess) { 1333 goto loser; 1334 } 1335 } 1336 1337 if (nestedDest) { 1338 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, 1339 (sec_PKCS12SafeContents *)nestedDest, 1340 returnBag); 1341 } else { 1342 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag); 1343 } 1344 1345 loser: 1346 1347 if (rv != SECSuccess) { 1348 PORT_ArenaRelease(p12ctxt->arena, mark); 1349 } else { 1350 PORT_ArenaUnmark(p12ctxt->arena, mark); 1351 } 1352 1353 return rv; 1354 } 1355 1356 /* SEC_PKCS12AddCertOrChainAndKey 1357 * Add a certificate and key pair to be exported. 1358 * 1359 * p12ctxt - the export context 1360 * certSafe - the safeInfo where the cert is stored 1361 * certNestedDest - the nested safeContents to store the cert 1362 * keySafe - the safeInfo where the key is stored 1363 * keyNestedDest - the nested safeContents to store the key 1364 * shroudKey - extract the private key encrypted? 1365 * pwitem - the password with which the key is encrypted 1366 * algorithm - the algorithm with which the key is encrypted 1367 * includeCertChain - also add certs from chain to bag. 1368 */ 1369 SECStatus 1370 SEC_PKCS12AddCertOrChainAndKey(SEC_PKCS12ExportContext *p12ctxt, 1371 void *certSafe, void *certNestedDest, 1372 CERTCertificate *cert, CERTCertDBHandle *certDb, 1373 void *keySafe, void *keyNestedDest, 1374 PRBool shroudKey, SECItem *pwitem, 1375 SECOidTag algorithm, PRBool includeCertChain) 1376 { 1377 SECStatus rv = SECFailure; 1378 SGNDigestInfo *digest = NULL; 1379 void *mark = NULL; 1380 1381 if (!p12ctxt || !certSafe || !keySafe || !cert) { 1382 return SECFailure; 1383 } 1384 1385 mark = PORT_ArenaMark(p12ctxt->arena); 1386 1387 /* generate the thumbprint of the cert to use as a keyId */ 1388 digest = sec_pkcs12_compute_thumbprint(&cert->derCert); 1389 if (!digest) { 1390 PORT_ArenaRelease(p12ctxt->arena, mark); 1391 return SECFailure; 1392 } 1393 1394 /* add the certificate */ 1395 rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo *)certSafe, 1396 (SEC_PKCS12SafeInfo *)certNestedDest, cert, certDb, 1397 &digest->digest, includeCertChain); 1398 if (rv != SECSuccess) { 1399 goto loser; 1400 } 1401 1402 /* add the key */ 1403 rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo *)keySafe, 1404 keyNestedDest, cert, 1405 shroudKey, algorithm, pwitem, 1406 &digest->digest, NULL); 1407 if (rv != SECSuccess) { 1408 goto loser; 1409 } 1410 1411 SGN_DestroyDigestInfo(digest); 1412 1413 PORT_ArenaUnmark(p12ctxt->arena, mark); 1414 return SECSuccess; 1415 1416 loser: 1417 SGN_DestroyDigestInfo(digest); 1418 PORT_ArenaRelease(p12ctxt->arena, mark); 1419 1420 return SECFailure; 1421 } 1422 1423 /* like SEC_PKCS12AddCertOrChainAndKey, but always adds cert chain */ 1424 SECStatus 1425 SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt, 1426 void *certSafe, void *certNestedDest, 1427 CERTCertificate *cert, CERTCertDBHandle *certDb, 1428 void *keySafe, void *keyNestedDest, 1429 PRBool shroudKey, SECItem *pwItem, SECOidTag algorithm) 1430 { 1431 return SEC_PKCS12AddCertOrChainAndKey(p12ctxt, certSafe, certNestedDest, 1432 cert, certDb, keySafe, keyNestedDest, shroudKey, pwItem, 1433 algorithm, PR_TRUE); 1434 } 1435 1436 /* SEC_PKCS12CreateNestedSafeContents 1437 * Allows nesting of safe contents to be implemented. No limit imposed on 1438 * depth. 1439 * 1440 * p12ctxt - the export context 1441 * baseSafe - the base safeInfo 1442 * nestedDest - a parent safeContents (?) 1443 */ 1444 void * 1445 SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt, 1446 void *baseSafe, void *nestedDest) 1447 { 1448 sec_PKCS12SafeContents *newSafe; 1449 sec_PKCS12SafeBag *safeContentsBag; 1450 void *mark; 1451 SECStatus rv; 1452 1453 if (!p12ctxt || !baseSafe) { 1454 return NULL; 1455 } 1456 1457 mark = PORT_ArenaMark(p12ctxt->arena); 1458 1459 newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena); 1460 if (!newSafe) { 1461 PORT_ArenaRelease(p12ctxt->arena, mark); 1462 PORT_SetError(SEC_ERROR_NO_MEMORY); 1463 return NULL; 1464 } 1465 1466 /* create the safeContents safeBag */ 1467 safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt, 1468 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID, 1469 newSafe); 1470 if (!safeContentsBag) { 1471 goto loser; 1472 } 1473 1474 /* append the safeContents to the appropriate area */ 1475 if (nestedDest) { 1476 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, 1477 (sec_PKCS12SafeContents *)nestedDest, 1478 safeContentsBag); 1479 } else { 1480 rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo *)baseSafe, 1481 safeContentsBag); 1482 } 1483 if (rv != SECSuccess) { 1484 goto loser; 1485 } 1486 1487 PORT_ArenaUnmark(p12ctxt->arena, mark); 1488 return newSafe; 1489 1490 loser: 1491 PORT_ArenaRelease(p12ctxt->arena, mark); 1492 return NULL; 1493 } 1494 1495 /********************************* 1496 * Encoding routines 1497 *********************************/ 1498 1499 /* Clean up the resources allocated by a sec_PKCS12EncoderContext. */ 1500 static void 1501 sec_pkcs12_encoder_destroy_context(sec_PKCS12EncoderContext *p12enc) 1502 { 1503 if (p12enc) { 1504 if (p12enc->outerA1ecx) { 1505 SEC_ASN1EncoderFinish(p12enc->outerA1ecx); 1506 p12enc->outerA1ecx = NULL; 1507 } 1508 if (p12enc->aSafeCinfo) { 1509 SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo); 1510 p12enc->aSafeCinfo = NULL; 1511 } 1512 if (p12enc->middleP7ecx) { 1513 SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12enc->p12exp->pwfn, 1514 p12enc->p12exp->pwfnarg); 1515 p12enc->middleP7ecx = NULL; 1516 } 1517 if (p12enc->middleA1ecx) { 1518 SEC_ASN1EncoderFinish(p12enc->middleA1ecx); 1519 p12enc->middleA1ecx = NULL; 1520 } 1521 if (p12enc->hmacCx) { 1522 PK11_DestroyContext(p12enc->hmacCx, PR_TRUE); 1523 p12enc->hmacCx = NULL; 1524 } 1525 } 1526 } 1527 1528 /* set up the encoder context based on information in the export context 1529 * and return the newly allocated enocoder context. A return of NULL 1530 * indicates an error occurred. 1531 */ 1532 static sec_PKCS12EncoderContext * 1533 sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp) 1534 { 1535 sec_PKCS12EncoderContext *p12enc = NULL; 1536 unsigned int i, nonEmptyCnt; 1537 SECStatus rv; 1538 SECItem ignore = { 0 }; 1539 void *mark; 1540 SECItem *salt = NULL; 1541 SECItem pwd = { siBuffer, NULL, 0 }; 1542 1543 if (!p12exp || !p12exp->safeInfos) { 1544 return NULL; 1545 } 1546 1547 /* check for any empty safes and skip them */ 1548 i = nonEmptyCnt = 0; 1549 while (p12exp->safeInfos[i]) { 1550 if (p12exp->safeInfos[i]->itemCount) { 1551 nonEmptyCnt++; 1552 } 1553 i++; 1554 } 1555 if (nonEmptyCnt == 0) { 1556 return NULL; 1557 } 1558 p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL; 1559 1560 /* allocate the encoder context */ 1561 mark = PORT_ArenaMark(p12exp->arena); 1562 p12enc = PORT_ArenaZNew(p12exp->arena, sec_PKCS12EncoderContext); 1563 if (!p12enc) { 1564 PORT_SetError(SEC_ERROR_NO_MEMORY); 1565 return NULL; 1566 } 1567 1568 p12enc->arena = p12exp->arena; 1569 p12enc->p12exp = p12exp; 1570 1571 /* set up the PFX version and information */ 1572 PORT_Memset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem)); 1573 if (!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->pfx.version), 1574 SEC_PKCS12_VERSION)) { 1575 PORT_SetError(SEC_ERROR_NO_MEMORY); 1576 goto loser; 1577 } 1578 1579 /* set up the authenticated safe content info based on the 1580 * type of integrity being used. this should be changed to 1581 * enforce integrity mode, but will not be implemented until 1582 * it is confirmed that integrity must be in place 1583 */ 1584 if (p12exp->integrityEnabled && !p12exp->pwdIntegrity) { 1585 /* create public key integrity mode */ 1586 p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData( 1587 p12exp->integrityInfo.pubkeyInfo.cert, 1588 certUsageEmailSigner, 1589 p12exp->integrityInfo.pubkeyInfo.certDb, 1590 p12exp->integrityInfo.pubkeyInfo.algorithm, 1591 NULL, 1592 p12exp->pwfn, 1593 p12exp->pwfnarg); 1594 if (!p12enc->aSafeCinfo) { 1595 goto loser; 1596 } 1597 if (SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo, NULL) != SECSuccess) { 1598 goto loser; 1599 } 1600 PORT_CheckSuccess(SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo)); 1601 } else { 1602 p12enc->aSafeCinfo = SEC_PKCS7CreateData(); 1603 1604 /* init password pased integrity mode */ 1605 if (p12exp->integrityEnabled) { 1606 PK11SymKey *symKey; 1607 CK_MECHANISM_TYPE hmacMechType; 1608 SECOidTag hmacAlgTag; 1609 SECOidTag hashAlgTag; 1610 1611 salt = sec_pkcs12_generate_salt(); 1612 1613 /* zero out macData and set values */ 1614 PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData)); 1615 1616 if (!salt) { 1617 PORT_SetError(SEC_ERROR_NO_MEMORY); 1618 goto loser; 1619 } 1620 if (SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt) != SECSuccess) { 1621 PORT_SetError(SEC_ERROR_NO_MEMORY); 1622 goto loser; 1623 } 1624 if (!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->mac.iter), 1625 NSS_PBE_DEFAULT_ITERATION_COUNT)) { 1626 goto loser; 1627 } 1628 1629 /* generate HMAC key */ 1630 if (!sec_pkcs12_convert_item_to_unicode(NULL, &pwd, 1631 p12exp->integrityInfo.pwdInfo.password, PR_TRUE, 1632 PR_TRUE, PR_TRUE)) { 1633 goto loser; 1634 } 1635 1636 /* create the digest info */ 1637 hmacAlgTag = p12exp->integrityInfo.pwdInfo.algorithm; 1638 hashAlgTag = HASH_GetHashOidTagByHMACOidTag(hmacAlgTag); 1639 if (hashAlgTag != SEC_OID_UNKNOWN) { 1640 /* if the application asks for hmac explicitly, then use 1641 * pkcs5v2 mac1 encoding */ 1642 SECAlgorithmID *algID; 1643 int keyLength; 1644 1645 keyLength = HASH_ResultLenByOidTag(hashAlgTag); 1646 if (keyLength == 0) { 1647 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1648 return NULL; 1649 } 1650 /* create PB_MAC1 params */ 1651 algID = PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBMAC1, 1652 hmacAlgTag, 1653 hmacAlgTag, keyLength, 1654 NSS_PBE_DEFAULT_ITERATION_COUNT, 1655 &p12enc->mac.macSalt); 1656 if (algID == NULL) { 1657 goto loser; 1658 } 1659 rv = SECOID_CopyAlgorithmID(p12enc->arena, 1660 &p12enc->mac.safeMac.digestAlgorithm, 1661 algID); 1662 SECOID_DestroyAlgorithmID(algID, PR_TRUE); 1663 if (rv != SECSuccess) { 1664 PORT_SetError(SEC_ERROR_NO_MEMORY); 1665 goto loser; 1666 } 1667 } else if (HASH_GetHashTypeByOidTag(hmacAlgTag) != HASH_AlgNULL) { 1668 /* encode the algid now for sec_pkcs12_integrity_key to use */ 1669 /* this must be a valid hash function, SECOID_SetAlgorithmID 1670 * knows to encode the hash algid with an explicit 1671 * null parameter */ 1672 rv = SECOID_SetAlgorithmID(p12enc->arena, 1673 &p12enc->mac.safeMac.digestAlgorithm, 1674 hmacAlgTag, NULL); 1675 if (rv != SECSuccess) { 1676 goto loser; 1677 } 1678 } else { 1679 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 1680 goto loser; 1681 } 1682 1683 /* generate HMAC key */ 1684 SECITEM_ZfreeItem(salt, PR_TRUE); 1685 salt = NULL; 1686 symKey = sec_pkcs12_integrity_key(p12exp->slot, &p12enc->mac, 1687 &pwd, &hmacMechType, PR_FALSE, 1688 p12exp->wincx); 1689 SECITEM_ZfreeItem(&pwd, PR_FALSE); 1690 1691 if (!symKey) { 1692 goto loser; 1693 } 1694 1695 /* initialize HMAC */ 1696 p12enc->hmacCx = PK11_CreateContextBySymKey(hmacMechType, 1697 CKA_SIGN, symKey, &ignore); 1698 1699 PK11_FreeSymKey(symKey); 1700 if (!p12enc->hmacCx) { 1701 PORT_SetError(SEC_ERROR_NO_MEMORY); 1702 goto loser; 1703 } 1704 rv = PK11_DigestBegin(p12enc->hmacCx); 1705 if (rv != SECSuccess) 1706 goto loser; 1707 } 1708 } 1709 1710 if (!p12enc->aSafeCinfo) { 1711 goto loser; 1712 } 1713 1714 PORT_ArenaUnmark(p12exp->arena, mark); 1715 1716 return p12enc; 1717 1718 loser: 1719 sec_pkcs12_encoder_destroy_context(p12enc); 1720 if (p12exp->arena != NULL) { 1721 PORT_ArenaRelease(p12exp->arena, mark); 1722 } 1723 if (salt) { 1724 SECITEM_ZfreeItem(salt, PR_TRUE); 1725 } 1726 if (pwd.data) { 1727 SECITEM_ZfreeItem(&pwd, PR_FALSE); 1728 } 1729 1730 return NULL; 1731 } 1732 1733 /* The outermost ASN.1 encoder calls this function for output. 1734 ** This function calls back to the library caller's output routine, 1735 ** which typically writes to a PKCS12 file. 1736 */ 1737 static void 1738 sec_P12A1OutputCB_Outer(void *arg, const char *buf, unsigned long len, 1739 int depth, SEC_ASN1EncodingPart data_kind) 1740 { 1741 struct sec_pkcs12_encoder_output *output; 1742 1743 output = (struct sec_pkcs12_encoder_output *)arg; 1744 (*output->outputfn)(output->outputarg, buf, len); 1745 } 1746 1747 /* The "middle" and "inner" ASN.1 encoders call this function to output. 1748 ** This function does HMACing, if appropriate, and then buffers the data. 1749 ** The buffered data is eventually passed down to the underlying PKCS7 encoder. 1750 */ 1751 static void 1752 sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf, 1753 unsigned long len, 1754 int depth, 1755 SEC_ASN1EncodingPart data_kind) 1756 { 1757 sec_pkcs12OutputBuffer *bufcx = (sec_pkcs12OutputBuffer *)arg; 1758 1759 if (!buf || !len) 1760 return; 1761 1762 if (bufcx->hmacCx) { 1763 PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len); 1764 } 1765 1766 /* buffer */ 1767 if (bufcx->numBytes > 0) { 1768 int toCopy; 1769 if (len + bufcx->numBytes <= bufcx->bufBytes) { 1770 memcpy(bufcx->buf + bufcx->numBytes, buf, len); 1771 bufcx->numBytes += len; 1772 if (bufcx->numBytes < bufcx->bufBytes) 1773 return; 1774 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes); 1775 bufcx->numBytes = 0; 1776 return; 1777 } 1778 toCopy = bufcx->bufBytes - bufcx->numBytes; 1779 memcpy(bufcx->buf + bufcx->numBytes, buf, toCopy); 1780 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes); 1781 bufcx->numBytes = 0; 1782 len -= toCopy; 1783 buf += toCopy; 1784 } 1785 /* buffer is presently empty */ 1786 if (len >= bufcx->bufBytes) { 1787 /* Just pass it through */ 1788 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len); 1789 } else { 1790 /* copy it all into the buffer, and return */ 1791 memcpy(bufcx->buf, buf, len); 1792 bufcx->numBytes = len; 1793 } 1794 } 1795 1796 void 1797 sec_FlushPkcs12OutputBuffer(sec_pkcs12OutputBuffer *bufcx) 1798 { 1799 if (bufcx->numBytes > 0) { 1800 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes); 1801 bufcx->numBytes = 0; 1802 } 1803 } 1804 1805 /* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder. 1806 ** This function is used by both the inner and middle PCS7 encoders. 1807 */ 1808 static void 1809 sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len) 1810 { 1811 SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext *)arg; 1812 1813 if (!buf || !len) 1814 return; 1815 1816 SEC_ASN1EncoderUpdate(cx, buf, len); 1817 } 1818 1819 /* this function encodes content infos which are part of the 1820 * sequence of content infos labeled AuthenticatedSafes 1821 */ 1822 static SECStatus 1823 sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx) 1824 { 1825 SEC_PKCS7EncoderContext *innerP7ecx; 1826 SEC_PKCS7ContentInfo *cinfo; 1827 PK11SymKey *bulkKey = NULL; 1828 SEC_ASN1EncoderContext *innerA1ecx = NULL; 1829 SECStatus rv = SECSuccess; 1830 1831 if (p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) { 1832 SEC_PKCS12SafeInfo *safeInfo; 1833 SECOidTag cinfoType; 1834 1835 safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe]; 1836 1837 /* skip empty safes */ 1838 if (safeInfo->itemCount == 0) { 1839 return SECSuccess; 1840 } 1841 1842 cinfo = safeInfo->cinfo; 1843 cinfoType = SEC_PKCS7ContentType(cinfo); 1844 1845 /* determine the safe type and set the appropriate argument */ 1846 switch (cinfoType) { 1847 case SEC_OID_PKCS7_DATA: 1848 case SEC_OID_PKCS7_ENVELOPED_DATA: 1849 break; 1850 case SEC_OID_PKCS7_ENCRYPTED_DATA: 1851 bulkKey = safeInfo->encryptionKey; 1852 PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL); 1853 break; 1854 default: 1855 return SECFailure; 1856 } 1857 1858 /* start the PKCS7 encoder */ 1859 innerP7ecx = SEC_PKCS7EncoderStart(cinfo, 1860 sec_P12P7OutputCB_CallA1Update, 1861 p12ecx->middleA1ecx, bulkKey); 1862 if (!innerP7ecx) { 1863 goto loser; 1864 } 1865 1866 /* encode safe contents */ 1867 p12ecx->innerBuf.p7eCx = innerP7ecx; 1868 p12ecx->innerBuf.hmacCx = NULL; 1869 p12ecx->innerBuf.numBytes = 0; 1870 p12ecx->innerBuf.bufBytes = sizeof p12ecx->innerBuf.buf; 1871 1872 innerA1ecx = SEC_ASN1EncoderStart(safeInfo->safe, 1873 sec_PKCS12SafeContentsTemplate, 1874 sec_P12A1OutputCB_HmacP7Update, 1875 &p12ecx->innerBuf); 1876 if (!innerA1ecx) { 1877 goto loser; 1878 } 1879 rv = SEC_ASN1EncoderUpdate(innerA1ecx, NULL, 0); 1880 SEC_ASN1EncoderFinish(innerA1ecx); 1881 sec_FlushPkcs12OutputBuffer(&p12ecx->innerBuf); 1882 innerA1ecx = NULL; 1883 if (rv != SECSuccess) { 1884 goto loser; 1885 } 1886 1887 /* finish up safe content info */ 1888 rv = SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn, 1889 p12ecx->p12exp->pwfnarg); 1890 if (rv != SECSuccess) { 1891 goto loser; 1892 } 1893 } 1894 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf); 1895 return SECSuccess; 1896 1897 loser: 1898 if (innerP7ecx) { 1899 SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn, 1900 p12ecx->p12exp->pwfnarg); 1901 } 1902 1903 if (innerA1ecx) { 1904 SEC_ASN1EncoderFinish(innerA1ecx); 1905 } 1906 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf); 1907 return SECFailure; 1908 } 1909 1910 /* finish the HMAC and encode the macData so that it can be 1911 * encoded. 1912 */ 1913 static SECStatus 1914 sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx) 1915 { 1916 unsigned char hmacData[HASH_LENGTH_MAX]; 1917 unsigned int hmacLen; 1918 SECStatus rv; 1919 SGNDigestInfo *di = NULL; 1920 void *dummy; 1921 1922 if (!p12ecx) { 1923 return SECFailure; 1924 } 1925 1926 /* make sure we are using password integrity mode */ 1927 if (!p12ecx->p12exp->integrityEnabled) { 1928 return SECSuccess; 1929 } 1930 1931 if (!p12ecx->p12exp->pwdIntegrity) { 1932 return SECSuccess; 1933 } 1934 1935 /* finish the hmac */ 1936 1937 rv = PK11_DigestFinal(p12ecx->hmacCx, hmacData, &hmacLen, HASH_LENGTH_MAX); 1938 1939 if (rv != SECSuccess) { 1940 PORT_SetError(SEC_ERROR_NO_MEMORY); 1941 goto loser; 1942 } 1943 1944 /* finish the digest info, algorithm ID is already set */ 1945 rv = SECITEM_MakeItem(p12ecx->arena, &p12ecx->mac.safeMac.digest, 1946 hmacData, hmacLen); 1947 if (rv != SECSuccess) { 1948 goto loser; 1949 } 1950 1951 /* encode the mac data */ 1952 dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData, 1953 &p12ecx->mac, sec_PKCS12MacDataTemplate); 1954 if (!dummy) { 1955 PORT_SetError(SEC_ERROR_NO_MEMORY); 1956 rv = SECFailure; 1957 } 1958 1959 loser: 1960 if (di) { 1961 SGN_DestroyDigestInfo(di); 1962 } 1963 PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE); 1964 p12ecx->hmacCx = NULL; 1965 PORT_Memset(hmacData, 0, hmacLen); 1966 1967 return rv; 1968 } 1969 1970 /* pfx notify function for ASN1 encoder. 1971 * We want to stop encoding once we reach the authenticated safe. 1972 * At that point, the encoder will be updated via streaming 1973 * as the authenticated safe is encoded. 1974 */ 1975 static void 1976 sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth) 1977 { 1978 sec_PKCS12EncoderContext *p12ecx; 1979 1980 if (!before) { 1981 return; 1982 } 1983 1984 /* look for authenticated safe */ 1985 p12ecx = (sec_PKCS12EncoderContext *)arg; 1986 if (dest != &p12ecx->pfx.encodedAuthSafe) { 1987 return; 1988 } 1989 1990 SEC_ASN1EncoderSetTakeFromBuf(p12ecx->outerA1ecx); 1991 SEC_ASN1EncoderSetStreaming(p12ecx->outerA1ecx); 1992 SEC_ASN1EncoderClearNotifyProc(p12ecx->outerA1ecx); 1993 } 1994 1995 /* SEC_PKCS12Encode 1996 * Encodes the PFX item and returns it to the output function, via 1997 * callback. the output function must be capable of multiple updates. 1998 * 1999 * p12exp - the export context 2000 * output - the output function callback, will be called more than once, 2001 * must be able to accept streaming data. 2002 * outputarg - argument for the output callback. 2003 */ 2004 SECStatus 2005 SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp, 2006 SEC_PKCS12EncoderOutputCallback output, void *outputarg) 2007 { 2008 sec_PKCS12EncoderContext *p12enc; 2009 struct sec_pkcs12_encoder_output outInfo; 2010 SECStatus rv; 2011 2012 if (!p12exp || !output) { 2013 return SECFailure; 2014 } 2015 2016 /* get the encoder context */ 2017 p12enc = sec_pkcs12_encoder_start_context(p12exp); 2018 if (!p12enc) { 2019 return SECFailure; 2020 } 2021 2022 outInfo.outputfn = output; 2023 outInfo.outputarg = outputarg; 2024 2025 /* set up PFX encoder, the "outer" encoder. Set it for streaming */ 2026 p12enc->outerA1ecx = SEC_ASN1EncoderStart(&p12enc->pfx, 2027 sec_PKCS12PFXItemTemplate, 2028 sec_P12A1OutputCB_Outer, 2029 &outInfo); 2030 if (!p12enc->outerA1ecx) { 2031 PORT_SetError(SEC_ERROR_NO_MEMORY); 2032 rv = SECFailure; 2033 goto loser; 2034 } 2035 SEC_ASN1EncoderSetStreaming(p12enc->outerA1ecx); 2036 SEC_ASN1EncoderSetNotifyProc(p12enc->outerA1ecx, 2037 sec_pkcs12_encoder_pfx_notify, p12enc); 2038 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0); 2039 if (rv != SECSuccess) { 2040 rv = SECFailure; 2041 goto loser; 2042 } 2043 2044 /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */ 2045 p12enc->middleP7ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo, 2046 sec_P12P7OutputCB_CallA1Update, 2047 p12enc->outerA1ecx, NULL); 2048 if (!p12enc->middleP7ecx) { 2049 rv = SECFailure; 2050 goto loser; 2051 } 2052 2053 /* encode asafe */ 2054 p12enc->middleBuf.p7eCx = p12enc->middleP7ecx; 2055 p12enc->middleBuf.hmacCx = NULL; 2056 p12enc->middleBuf.numBytes = 0; 2057 p12enc->middleBuf.bufBytes = sizeof p12enc->middleBuf.buf; 2058 2059 /* Setup the "inner ASN.1 encoder for Authenticated Safes. */ 2060 if (p12enc->p12exp->integrityEnabled && 2061 p12enc->p12exp->pwdIntegrity) { 2062 p12enc->middleBuf.hmacCx = p12enc->hmacCx; 2063 } 2064 p12enc->middleA1ecx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe, 2065 sec_PKCS12AuthenticatedSafeTemplate, 2066 sec_P12A1OutputCB_HmacP7Update, 2067 &p12enc->middleBuf); 2068 if (!p12enc->middleA1ecx) { 2069 rv = SECFailure; 2070 goto loser; 2071 } 2072 SEC_ASN1EncoderSetStreaming(p12enc->middleA1ecx); 2073 SEC_ASN1EncoderSetTakeFromBuf(p12enc->middleA1ecx); 2074 2075 /* encode each of the safes */ 2076 while (p12enc->currentSafe != p12enc->p12exp->safeInfoCount) { 2077 sec_pkcs12_encoder_asafe_process(p12enc); 2078 p12enc->currentSafe++; 2079 } 2080 SEC_ASN1EncoderClearTakeFromBuf(p12enc->middleA1ecx); 2081 SEC_ASN1EncoderClearStreaming(p12enc->middleA1ecx); 2082 SEC_ASN1EncoderUpdate(p12enc->middleA1ecx, NULL, 0); 2083 SEC_ASN1EncoderFinish(p12enc->middleA1ecx); 2084 p12enc->middleA1ecx = NULL; 2085 2086 sec_FlushPkcs12OutputBuffer(&p12enc->middleBuf); 2087 2088 /* finish the encoding of the authenticated safes */ 2089 rv = SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12exp->pwfn, 2090 p12exp->pwfnarg); 2091 p12enc->middleP7ecx = NULL; 2092 if (rv != SECSuccess) { 2093 goto loser; 2094 } 2095 2096 SEC_ASN1EncoderClearTakeFromBuf(p12enc->outerA1ecx); 2097 SEC_ASN1EncoderClearStreaming(p12enc->outerA1ecx); 2098 2099 /* update the mac, if necessary */ 2100 rv = sec_Pkcs12FinishMac(p12enc); 2101 if (rv != SECSuccess) { 2102 goto loser; 2103 } 2104 2105 /* finish encoding the pfx */ 2106 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0); 2107 2108 SEC_ASN1EncoderFinish(p12enc->outerA1ecx); 2109 p12enc->outerA1ecx = NULL; 2110 2111 loser: 2112 sec_pkcs12_encoder_destroy_context(p12enc); 2113 return rv; 2114 } 2115 2116 void 2117 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx) 2118 { 2119 int i = 0; 2120 2121 if (!p12ecx) { 2122 return; 2123 } 2124 2125 if (p12ecx->safeInfos) { 2126 i = 0; 2127 while (p12ecx->safeInfos[i] != NULL) { 2128 if (p12ecx->safeInfos[i]->encryptionKey) { 2129 PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey); 2130 } 2131 if (p12ecx->safeInfos[i]->cinfo) { 2132 SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo); 2133 } 2134 i++; 2135 } 2136 } 2137 2138 PK11_FreeSlot(p12ecx->slot); 2139 2140 PORT_FreeArena(p12ecx->arena, PR_TRUE); 2141 }