crmfcont.c (33346B)
1 /* -*- Mode: C; tab-width: 8 -*-*/ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "crmf.h" 7 #include "crmfi.h" 8 #include "pk11func.h" 9 #include "keyhi.h" 10 #include "secoid.h" 11 12 static SECStatus 13 crmf_modify_control_array(CRMFCertRequest *inCertReq, int count) 14 { 15 if (count > 0) { 16 void *dummy = PORT_Realloc(inCertReq->controls, 17 sizeof(CRMFControl *) * (count + 2)); 18 if (dummy == NULL) { 19 return SECFailure; 20 } 21 inCertReq->controls = dummy; 22 } else { 23 inCertReq->controls = PORT_ZNewArray(CRMFControl *, 2); 24 } 25 return (inCertReq->controls == NULL) ? SECFailure : SECSuccess; 26 } 27 28 static SECStatus 29 crmf_add_new_control(CRMFCertRequest *inCertReq, SECOidTag inTag, 30 CRMFControl **destControl) 31 { 32 SECOidData *oidData; 33 SECStatus rv; 34 PLArenaPool *poolp; 35 int numControls = 0; 36 CRMFControl *newControl; 37 CRMFControl **controls; 38 void *mark; 39 40 poolp = inCertReq->poolp; 41 if (poolp == NULL) { 42 return SECFailure; 43 } 44 mark = PORT_ArenaMark(poolp); 45 if (inCertReq->controls != NULL) { 46 while (inCertReq->controls[numControls] != NULL) 47 numControls++; 48 } 49 rv = crmf_modify_control_array(inCertReq, numControls); 50 if (rv != SECSuccess) { 51 goto loser; 52 } 53 controls = inCertReq->controls; 54 oidData = SECOID_FindOIDByTag(inTag); 55 newControl = *destControl = PORT_ArenaZNew(poolp, CRMFControl); 56 if (newControl == NULL) { 57 goto loser; 58 } 59 rv = SECITEM_CopyItem(poolp, &newControl->derTag, &oidData->oid); 60 if (rv != SECSuccess) { 61 goto loser; 62 } 63 newControl->tag = inTag; 64 controls[numControls] = newControl; 65 controls[numControls + 1] = NULL; 66 PORT_ArenaUnmark(poolp, mark); 67 return SECSuccess; 68 69 loser: 70 PORT_ArenaRelease(poolp, mark); 71 *destControl = NULL; 72 return SECFailure; 73 } 74 75 static SECStatus 76 crmf_add_secitem_control(CRMFCertRequest *inCertReq, SECItem *value, 77 SECOidTag inTag) 78 { 79 SECStatus rv; 80 CRMFControl *newControl; 81 void *mark; 82 83 rv = crmf_add_new_control(inCertReq, inTag, &newControl); 84 if (rv != SECSuccess) { 85 return rv; 86 } 87 mark = PORT_ArenaMark(inCertReq->poolp); 88 rv = SECITEM_CopyItem(inCertReq->poolp, &newControl->derValue, value); 89 if (rv != SECSuccess) { 90 PORT_ArenaRelease(inCertReq->poolp, mark); 91 return rv; 92 } 93 PORT_ArenaUnmark(inCertReq->poolp, mark); 94 return SECSuccess; 95 } 96 97 SECStatus 98 CRMF_CertRequestSetRegTokenControl(CRMFCertRequest *inCertReq, SECItem *value) 99 { 100 return crmf_add_secitem_control(inCertReq, value, 101 SEC_OID_PKIX_REGCTRL_REGTOKEN); 102 } 103 104 SECStatus 105 CRMF_CertRequestSetAuthenticatorControl(CRMFCertRequest *inCertReq, 106 SECItem *value) 107 { 108 return crmf_add_secitem_control(inCertReq, value, 109 SEC_OID_PKIX_REGCTRL_AUTHENTICATOR); 110 } 111 112 SECStatus 113 crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue, PRBool freeit) 114 { 115 if (inEncrValue != NULL) { 116 if (inEncrValue->intendedAlg) { 117 SECOID_DestroyAlgorithmID(inEncrValue->intendedAlg, PR_TRUE); 118 inEncrValue->intendedAlg = NULL; 119 } 120 if (inEncrValue->symmAlg) { 121 SECOID_DestroyAlgorithmID(inEncrValue->symmAlg, PR_TRUE); 122 inEncrValue->symmAlg = NULL; 123 } 124 if (inEncrValue->encSymmKey.data) { 125 PORT_Free(inEncrValue->encSymmKey.data); 126 inEncrValue->encSymmKey.data = NULL; 127 } 128 if (inEncrValue->keyAlg) { 129 SECOID_DestroyAlgorithmID(inEncrValue->keyAlg, PR_TRUE); 130 inEncrValue->keyAlg = NULL; 131 } 132 if (inEncrValue->valueHint.data) { 133 PORT_Free(inEncrValue->valueHint.data); 134 inEncrValue->valueHint.data = NULL; 135 } 136 if (inEncrValue->encValue.data) { 137 PORT_Free(inEncrValue->encValue.data); 138 inEncrValue->encValue.data = NULL; 139 } 140 if (freeit) { 141 PORT_Free(inEncrValue); 142 } 143 } 144 return SECSuccess; 145 } 146 147 SECStatus 148 CRMF_DestroyEncryptedValue(CRMFEncryptedValue *inEncrValue) 149 { 150 return crmf_destroy_encrypted_value(inEncrValue, PR_TRUE); 151 } 152 153 SECStatus 154 crmf_copy_encryptedvalue_secalg(PLArenaPool *poolp, 155 SECAlgorithmID *srcAlgId, 156 SECAlgorithmID **destAlgId) 157 { 158 SECAlgorithmID *newAlgId; 159 SECStatus rv; 160 161 newAlgId = (poolp != NULL) ? PORT_ArenaZNew(poolp, SECAlgorithmID) : PORT_ZNew(SECAlgorithmID); 162 if (newAlgId == NULL) { 163 return SECFailure; 164 } 165 166 rv = SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId); 167 if (rv != SECSuccess) { 168 if (!poolp) { 169 SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE); 170 } 171 return rv; 172 } 173 *destAlgId = newAlgId; 174 175 return rv; 176 } 177 178 SECStatus 179 crmf_copy_encryptedvalue(PLArenaPool *poolp, 180 CRMFEncryptedValue *srcValue, 181 CRMFEncryptedValue *destValue) 182 { 183 SECStatus rv; 184 185 if (srcValue->intendedAlg != NULL) { 186 rv = crmf_copy_encryptedvalue_secalg(poolp, 187 srcValue->intendedAlg, 188 &destValue->intendedAlg); 189 if (rv != SECSuccess) { 190 goto loser; 191 } 192 } 193 if (srcValue->symmAlg != NULL) { 194 rv = crmf_copy_encryptedvalue_secalg(poolp, 195 srcValue->symmAlg, 196 &destValue->symmAlg); 197 if (rv != SECSuccess) { 198 goto loser; 199 } 200 } 201 if (srcValue->encSymmKey.data != NULL) { 202 rv = crmf_make_bitstring_copy(poolp, 203 &destValue->encSymmKey, 204 &srcValue->encSymmKey); 205 if (rv != SECSuccess) { 206 goto loser; 207 } 208 } 209 if (srcValue->keyAlg != NULL) { 210 rv = crmf_copy_encryptedvalue_secalg(poolp, 211 srcValue->keyAlg, 212 &destValue->keyAlg); 213 if (rv != SECSuccess) { 214 goto loser; 215 } 216 } 217 if (srcValue->valueHint.data != NULL) { 218 rv = SECITEM_CopyItem(poolp, 219 &destValue->valueHint, 220 &srcValue->valueHint); 221 if (rv != SECSuccess) { 222 goto loser; 223 } 224 } 225 if (srcValue->encValue.data != NULL) { 226 rv = crmf_make_bitstring_copy(poolp, 227 &destValue->encValue, 228 &srcValue->encValue); 229 if (rv != SECSuccess) { 230 goto loser; 231 } 232 } 233 return SECSuccess; 234 loser: 235 if (poolp == NULL && destValue != NULL) { 236 crmf_destroy_encrypted_value(destValue, PR_FALSE); 237 } 238 return SECFailure; 239 } 240 241 SECStatus 242 crmf_copy_encryptedkey(PLArenaPool *poolp, 243 CRMFEncryptedKey *srcEncrKey, 244 CRMFEncryptedKey *destEncrKey) 245 { 246 SECStatus rv; 247 void *mark = NULL; 248 249 if (poolp != NULL) { 250 mark = PORT_ArenaMark(poolp); 251 } 252 253 switch (srcEncrKey->encKeyChoice) { 254 case crmfEncryptedValueChoice: 255 rv = crmf_copy_encryptedvalue(poolp, 256 &srcEncrKey->value.encryptedValue, 257 &destEncrKey->value.encryptedValue); 258 break; 259 case crmfEnvelopedDataChoice: 260 destEncrKey->value.envelopedData = 261 SEC_PKCS7CopyContentInfo(srcEncrKey->value.envelopedData); 262 rv = (destEncrKey->value.envelopedData != NULL) ? SECSuccess : SECFailure; 263 break; 264 default: 265 rv = SECFailure; 266 } 267 if (rv != SECSuccess) { 268 goto loser; 269 } 270 destEncrKey->encKeyChoice = srcEncrKey->encKeyChoice; 271 if (mark) { 272 PORT_ArenaUnmark(poolp, mark); 273 } 274 return SECSuccess; 275 276 loser: 277 if (mark) { 278 PORT_ArenaRelease(poolp, mark); 279 } 280 return SECFailure; 281 } 282 283 static CRMFPKIArchiveOptions * 284 crmf_create_encr_pivkey_option(CRMFEncryptedKey *inEncryptedKey) 285 { 286 CRMFPKIArchiveOptions *newArchOpt; 287 SECStatus rv; 288 289 newArchOpt = PORT_ZNew(CRMFPKIArchiveOptions); 290 if (newArchOpt == NULL) { 291 goto loser; 292 } 293 294 rv = crmf_copy_encryptedkey(NULL, inEncryptedKey, 295 &newArchOpt->option.encryptedKey); 296 297 if (rv != SECSuccess) { 298 goto loser; 299 } 300 newArchOpt->archOption = crmfEncryptedPrivateKey; 301 return newArchOpt; 302 loser: 303 if (newArchOpt != NULL) { 304 CRMF_DestroyPKIArchiveOptions(newArchOpt); 305 } 306 return NULL; 307 } 308 309 static CRMFPKIArchiveOptions * 310 crmf_create_keygen_param_option(SECItem *inKeyGenParams) 311 { 312 CRMFPKIArchiveOptions *newArchOptions; 313 SECStatus rv; 314 315 newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions); 316 if (newArchOptions == NULL) { 317 goto loser; 318 } 319 newArchOptions->archOption = crmfKeyGenParameters; 320 rv = SECITEM_CopyItem(NULL, &newArchOptions->option.keyGenParameters, 321 inKeyGenParams); 322 if (rv != SECSuccess) { 323 goto loser; 324 } 325 return newArchOptions; 326 loser: 327 if (newArchOptions != NULL) { 328 CRMF_DestroyPKIArchiveOptions(newArchOptions); 329 } 330 return NULL; 331 } 332 333 static CRMFPKIArchiveOptions * 334 crmf_create_arch_rem_gen_privkey(PRBool archiveRemGenPrivKey) 335 { 336 unsigned char value; 337 SECItem *dummy; 338 CRMFPKIArchiveOptions *newArchOptions; 339 340 value = (archiveRemGenPrivKey) ? hexTrue : hexFalse; 341 newArchOptions = PORT_ZNew(CRMFPKIArchiveOptions); 342 if (newArchOptions == NULL) { 343 goto loser; 344 } 345 dummy = SEC_ASN1EncodeItem(NULL, 346 &newArchOptions->option.archiveRemGenPrivKey, 347 &value, SEC_ASN1_GET(SEC_BooleanTemplate)); 348 PORT_Assert(dummy == &newArchOptions->option.archiveRemGenPrivKey); 349 if (dummy != &newArchOptions->option.archiveRemGenPrivKey) { 350 SECITEM_FreeItem(dummy, PR_TRUE); 351 goto loser; 352 } 353 newArchOptions->archOption = crmfArchiveRemGenPrivKey; 354 return newArchOptions; 355 loser: 356 if (newArchOptions != NULL) { 357 CRMF_DestroyPKIArchiveOptions(newArchOptions); 358 } 359 return NULL; 360 } 361 362 CRMFPKIArchiveOptions * 363 CRMF_CreatePKIArchiveOptions(CRMFPKIArchiveOptionsType inType, void *data) 364 { 365 CRMFPKIArchiveOptions *retOptions; 366 367 PORT_Assert(data != NULL); 368 if (data == NULL) { 369 return NULL; 370 } 371 switch (inType) { 372 case crmfEncryptedPrivateKey: 373 retOptions = crmf_create_encr_pivkey_option((CRMFEncryptedKey *)data); 374 break; 375 case crmfKeyGenParameters: 376 retOptions = crmf_create_keygen_param_option((SECItem *)data); 377 break; 378 case crmfArchiveRemGenPrivKey: 379 retOptions = crmf_create_arch_rem_gen_privkey(*(PRBool *)data); 380 break; 381 default: 382 retOptions = NULL; 383 } 384 return retOptions; 385 } 386 387 static SECStatus 388 crmf_destroy_encrypted_key(CRMFEncryptedKey *inEncrKey, PRBool freeit) 389 { 390 PORT_Assert(inEncrKey != NULL); 391 if (inEncrKey != NULL) { 392 switch (inEncrKey->encKeyChoice) { 393 case crmfEncryptedValueChoice: 394 crmf_destroy_encrypted_value(&inEncrKey->value.encryptedValue, 395 PR_FALSE); 396 break; 397 case crmfEnvelopedDataChoice: 398 SEC_PKCS7DestroyContentInfo(inEncrKey->value.envelopedData); 399 break; 400 default: 401 break; 402 } 403 if (freeit) { 404 PORT_Free(inEncrKey); 405 } 406 } 407 return SECSuccess; 408 } 409 410 SECStatus 411 crmf_destroy_pkiarchiveoptions(CRMFPKIArchiveOptions *inArchOptions, 412 PRBool freeit) 413 { 414 PORT_Assert(inArchOptions != NULL); 415 if (inArchOptions != NULL) { 416 switch (inArchOptions->archOption) { 417 case crmfEncryptedPrivateKey: 418 crmf_destroy_encrypted_key(&inArchOptions->option.encryptedKey, 419 PR_FALSE); 420 break; 421 case crmfKeyGenParameters: 422 case crmfArchiveRemGenPrivKey: 423 /* This is a union, so having a pointer to one is like 424 * having a pointer to both. 425 */ 426 SECITEM_FreeItem(&inArchOptions->option.keyGenParameters, 427 PR_FALSE); 428 break; 429 case crmfNoArchiveOptions: 430 break; 431 } 432 if (freeit) { 433 PORT_Free(inArchOptions); 434 } 435 } 436 return SECSuccess; 437 } 438 439 SECStatus 440 CRMF_DestroyPKIArchiveOptions(CRMFPKIArchiveOptions *inArchOptions) 441 { 442 return crmf_destroy_pkiarchiveoptions(inArchOptions, PR_TRUE); 443 } 444 445 static CK_MECHANISM_TYPE 446 crmf_get_non_pad_mechanism(CK_MECHANISM_TYPE type) 447 { 448 switch (type) { 449 case CKM_DES3_CBC_PAD: 450 return CKM_DES3_CBC; 451 case CKM_CAST5_CBC_PAD: 452 return CKM_CAST5_CBC; 453 case CKM_DES_CBC_PAD: 454 return CKM_DES_CBC; 455 case CKM_IDEA_CBC_PAD: 456 return CKM_IDEA_CBC; 457 case CKM_CAST3_CBC_PAD: 458 return CKM_CAST3_CBC; 459 case CKM_CAST_CBC_PAD: 460 return CKM_CAST_CBC; 461 case CKM_RC5_CBC_PAD: 462 return CKM_RC5_CBC; 463 case CKM_RC2_CBC_PAD: 464 return CKM_RC2_CBC; 465 case CKM_CDMF_CBC_PAD: 466 return CKM_CDMF_CBC; 467 } 468 return type; 469 } 470 471 static CK_MECHANISM_TYPE 472 crmf_get_pad_mech_from_tag(SECOidTag oidTag) 473 { 474 CK_MECHANISM_TYPE mechType; 475 SECOidData *oidData; 476 477 oidData = SECOID_FindOIDByTag(oidTag); 478 mechType = (CK_MECHANISM_TYPE)oidData->mechanism; 479 return PK11_GetPadMechanism(mechType); 480 } 481 482 static CK_MECHANISM_TYPE 483 crmf_get_best_privkey_wrap_mechanism(PK11SlotInfo *slot) 484 { 485 CK_MECHANISM_TYPE privKeyPadMechs[] = { CKM_DES3_CBC_PAD, 486 CKM_CAST5_CBC_PAD, 487 CKM_DES_CBC_PAD, 488 CKM_IDEA_CBC_PAD, 489 CKM_CAST3_CBC_PAD, 490 CKM_CAST_CBC_PAD, 491 CKM_RC5_CBC_PAD, 492 CKM_RC2_CBC_PAD, 493 CKM_CDMF_CBC_PAD }; 494 int mechCount = sizeof(privKeyPadMechs) / sizeof(privKeyPadMechs[0]); 495 int i; 496 497 for (i = 0; i < mechCount; i++) { 498 if (PK11_DoesMechanism(slot, privKeyPadMechs[i])) { 499 return privKeyPadMechs[i]; 500 } 501 } 502 return CKM_INVALID_MECHANISM; 503 } 504 505 CK_MECHANISM_TYPE 506 CRMF_GetBestWrapPadMechanism(PK11SlotInfo *slot) 507 { 508 return crmf_get_best_privkey_wrap_mechanism(slot); 509 } 510 511 static SECItem * 512 crmf_get_iv(CK_MECHANISM_TYPE mechType) 513 { 514 int iv_size = PK11_GetIVLength(mechType); 515 SECItem *iv; 516 SECStatus rv; 517 518 iv = PORT_ZNew(SECItem); 519 if (iv == NULL) { 520 return NULL; 521 } 522 if (iv_size == 0) { 523 iv->data = NULL; 524 iv->len = 0; 525 return iv; 526 } 527 iv->data = PORT_NewArray(unsigned char, iv_size); 528 if (iv->data == NULL) { 529 iv->len = 0; 530 return iv; 531 } 532 iv->len = iv_size; 533 rv = PK11_GenerateRandom(iv->data, iv->len); 534 if (rv != SECSuccess) { 535 PORT_Free(iv->data); 536 iv->data = NULL; 537 iv->len = 0; 538 } 539 return iv; 540 } 541 542 SECItem * 543 CRMF_GetIVFromMechanism(CK_MECHANISM_TYPE mechType) 544 { 545 return crmf_get_iv(mechType); 546 } 547 548 CK_MECHANISM_TYPE 549 crmf_get_mechanism_from_public_key(SECKEYPublicKey *inPubKey) 550 { 551 CERTSubjectPublicKeyInfo *spki = NULL; 552 SECOidTag tag; 553 554 spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey); 555 if (spki == NULL) { 556 return CKM_INVALID_MECHANISM; 557 } 558 tag = SECOID_FindOIDTag(&spki->algorithm.algorithm); 559 SECKEY_DestroySubjectPublicKeyInfo(spki); 560 spki = NULL; 561 return PK11_AlgtagToMechanism(tag); 562 } 563 564 SECItem * 565 crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest) 566 { 567 const SECItem *src = PK11_GetPublicValueFromPublicKey(pubKey); 568 569 if (!src) { 570 PORT_SetError(SEC_ERROR_INVALID_ARGS); 571 return NULL; 572 } 573 574 if (dest != NULL) { 575 SECStatus rv = SECITEM_CopyItem(NULL, dest, src); 576 if (rv != SECSuccess) { 577 dest = NULL; 578 } 579 } else { 580 dest = SECITEM_ArenaDupItem(NULL, src); 581 } 582 return dest; 583 } 584 585 static SECItem * 586 crmf_decode_params(SECItem *inParams) 587 { 588 SECItem *params; 589 SECStatus rv = SECFailure; 590 PLArenaPool *poolp; 591 592 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); 593 if (poolp == NULL) { 594 return NULL; 595 } 596 597 params = PORT_ArenaZNew(poolp, SECItem); 598 if (params) { 599 rv = SEC_ASN1DecodeItem(poolp, params, 600 SEC_ASN1_GET(SEC_OctetStringTemplate), 601 inParams); 602 } 603 params = (rv == SECSuccess) ? SECITEM_ArenaDupItem(NULL, params) : NULL; 604 PORT_FreeArena(poolp, PR_FALSE); 605 return params; 606 } 607 608 static int 609 crmf_get_key_size_from_mech(CK_MECHANISM_TYPE mechType) 610 { 611 CK_MECHANISM_TYPE keyGen = PK11_GetKeyGen(mechType); 612 613 switch (keyGen) { 614 case CKM_CDMF_KEY_GEN: 615 case CKM_DES_KEY_GEN: 616 return 8; 617 case CKM_DES2_KEY_GEN: 618 return 16; 619 case CKM_DES3_KEY_GEN: 620 return 24; 621 } 622 return 0; 623 } 624 625 SECStatus 626 crmf_encrypted_value_unwrap_priv_key(PLArenaPool *poolp, 627 CRMFEncryptedValue *encValue, 628 SECKEYPrivateKey *privKey, 629 SECKEYPublicKey *newPubKey, 630 SECItem *nickname, 631 PK11SlotInfo *slot, 632 unsigned char keyUsage, 633 SECKEYPrivateKey **unWrappedKey, 634 void *wincx) 635 { 636 PK11SymKey *wrappingKey = NULL; 637 CK_MECHANISM_TYPE wrapMechType; 638 SECOidTag oidTag; 639 SECItem *params = NULL, *publicValue = NULL; 640 int keySize, origLen; 641 642 oidTag = SECOID_GetAlgorithmTag(encValue->symmAlg); 643 wrapMechType = crmf_get_pad_mech_from_tag(oidTag); 644 keySize = crmf_get_key_size_from_mech(wrapMechType); 645 wrappingKey = PK11_PubUnwrapSymKey(privKey, &encValue->encSymmKey, 646 wrapMechType, CKA_UNWRAP, keySize); 647 if (wrappingKey == NULL) { 648 goto loser; 649 } /* Make the length a byte length instead of bit length*/ 650 params = (encValue->symmAlg != NULL) ? crmf_decode_params(&encValue->symmAlg->parameters) 651 : NULL; 652 origLen = encValue->encValue.len; 653 encValue->encValue.len = CRMF_BITS_TO_BYTES(origLen); 654 publicValue = crmf_get_public_value(newPubKey, NULL); 655 656 *unWrappedKey = PK11_UnwrapPrivKeyByKeyType(slot, wrappingKey, 657 wrapMechType, params, 658 &encValue->encValue, 659 nickname, publicValue, 660 PR_TRUE, PR_TRUE, 661 newPubKey->keyType, 662 keyUsage, wincx); 663 encValue->encValue.len = origLen; 664 if (*unWrappedKey == NULL) { 665 goto loser; 666 } 667 SECITEM_FreeItem(publicValue, PR_TRUE); 668 if (params != NULL) { 669 SECITEM_FreeItem(params, PR_TRUE); 670 } 671 PK11_FreeSymKey(wrappingKey); 672 return SECSuccess; 673 loser: 674 *unWrappedKey = NULL; 675 return SECFailure; 676 } 677 678 CRMFEncryptedValue * 679 crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey, 680 SECKEYPublicKey *inCAKey, 681 CRMFEncryptedValue *destValue) 682 { 683 SECItem wrappedPrivKey, wrappedSymKey; 684 SECItem encodedParam, *dummy; 685 SECStatus rv; 686 CK_MECHANISM_TYPE pubMechType, symKeyType; 687 unsigned char *wrappedSymKeyBits; 688 unsigned char *wrappedPrivKeyBits; 689 SECItem *iv = NULL; 690 SECOidTag tag; 691 PK11SymKey *symKey; 692 PK11SlotInfo *slot; 693 SECAlgorithmID *symmAlg; 694 CRMFEncryptedValue *myEncrValue = NULL; 695 696 encodedParam.data = NULL; 697 wrappedSymKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN); 698 wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN); 699 if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) { 700 goto loser; 701 } 702 if (destValue == NULL) { 703 myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue); 704 if (destValue == NULL) { 705 goto loser; 706 } 707 } 708 709 pubMechType = crmf_get_mechanism_from_public_key(inCAKey); 710 if (pubMechType == CKM_INVALID_MECHANISM) { 711 /* XXX I should probably do something here for non-RSA 712 * keys that are in certs. (ie DSA) 713 * XXX or at least SET AN ERROR CODE. 714 */ 715 goto loser; 716 } 717 slot = inPrivKey->pkcs11Slot; 718 PORT_Assert(slot != NULL); 719 symKeyType = crmf_get_best_privkey_wrap_mechanism(slot); 720 symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL); 721 if (symKey == NULL) { 722 goto loser; 723 } 724 725 wrappedSymKey.data = wrappedSymKeyBits; 726 wrappedSymKey.len = MAX_WRAPPED_KEY_LEN; 727 rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey); 728 if (rv != SECSuccess) { 729 goto loser; 730 } 731 /* Make the length of the result a Bit String length. */ 732 wrappedSymKey.len <<= 3; 733 734 wrappedPrivKey.data = wrappedPrivKeyBits; 735 wrappedPrivKey.len = MAX_WRAPPED_KEY_LEN; 736 iv = crmf_get_iv(symKeyType); 737 rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv, 738 &wrappedPrivKey, NULL); 739 PK11_FreeSymKey(symKey); 740 if (rv != SECSuccess) { 741 goto loser; 742 } 743 /* Make the length of the result a Bit String length. */ 744 wrappedPrivKey.len <<= 3; 745 rv = crmf_make_bitstring_copy(NULL, 746 &destValue->encValue, 747 &wrappedPrivKey); 748 if (rv != SECSuccess) { 749 goto loser; 750 } 751 752 rv = crmf_make_bitstring_copy(NULL, 753 &destValue->encSymmKey, 754 &wrappedSymKey); 755 if (rv != SECSuccess) { 756 goto loser; 757 } 758 destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID); 759 if (symmAlg == NULL) { 760 goto loser; 761 } 762 763 dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv, 764 SEC_ASN1_GET(SEC_OctetStringTemplate)); 765 if (dummy != &encodedParam) { 766 SECITEM_FreeItem(dummy, PR_TRUE); 767 goto loser; 768 } 769 770 symKeyType = crmf_get_non_pad_mechanism(symKeyType); 771 tag = PK11_MechanismToAlgtag(symKeyType); 772 rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam); 773 if (rv != SECSuccess) { 774 goto loser; 775 } 776 SECITEM_FreeItem(&encodedParam, PR_FALSE); 777 PORT_Free(wrappedPrivKeyBits); 778 PORT_Free(wrappedSymKeyBits); 779 SECITEM_FreeItem(iv, PR_TRUE); 780 return destValue; 781 loser: 782 if (iv != NULL) { 783 SECITEM_FreeItem(iv, PR_TRUE); 784 } 785 if (myEncrValue != NULL) { 786 crmf_destroy_encrypted_value(myEncrValue, PR_TRUE); 787 } 788 if (wrappedSymKeyBits != NULL) { 789 PORT_Free(wrappedSymKeyBits); 790 } 791 if (wrappedPrivKeyBits != NULL) { 792 PORT_Free(wrappedPrivKeyBits); 793 } 794 if (encodedParam.data != NULL) { 795 SECITEM_FreeItem(&encodedParam, PR_FALSE); 796 } 797 return NULL; 798 } 799 800 CRMFEncryptedKey * 801 CRMF_CreateEncryptedKeyWithEncryptedValue(SECKEYPrivateKey *inPrivKey, 802 CERTCertificate *inCACert) 803 { 804 SECKEYPublicKey *caPubKey = NULL; 805 CRMFEncryptedKey *encKey = NULL; 806 807 PORT_Assert(inPrivKey != NULL && inCACert != NULL); 808 if (inPrivKey == NULL || inCACert == NULL) { 809 return NULL; 810 } 811 812 caPubKey = CERT_ExtractPublicKey(inCACert); 813 if (caPubKey == NULL) { 814 goto loser; 815 } 816 817 encKey = PORT_ZNew(CRMFEncryptedKey); 818 if (encKey == NULL) { 819 goto loser; 820 } 821 #ifdef DEBUG 822 { 823 CRMFEncryptedValue *dummy = 824 crmf_create_encrypted_value_wrapped_privkey( 825 inPrivKey, caPubKey, &encKey->value.encryptedValue); 826 PORT_Assert(dummy == &encKey->value.encryptedValue); 827 } 828 #else 829 crmf_create_encrypted_value_wrapped_privkey( 830 inPrivKey, caPubKey, &encKey->value.encryptedValue); 831 #endif 832 /* We won't add the der value here, but rather when it 833 * becomes part of a certificate request. 834 */ 835 SECKEY_DestroyPublicKey(caPubKey); 836 encKey->encKeyChoice = crmfEncryptedValueChoice; 837 return encKey; 838 loser: 839 if (encKey != NULL) { 840 CRMF_DestroyEncryptedKey(encKey); 841 } 842 if (caPubKey != NULL) { 843 SECKEY_DestroyPublicKey(caPubKey); 844 } 845 return NULL; 846 } 847 848 SECStatus 849 CRMF_DestroyEncryptedKey(CRMFEncryptedKey *inEncrKey) 850 { 851 return crmf_destroy_encrypted_key(inEncrKey, PR_TRUE); 852 } 853 854 SECStatus 855 crmf_copy_pkiarchiveoptions(PLArenaPool *poolp, 856 CRMFPKIArchiveOptions *destOpt, 857 CRMFPKIArchiveOptions *srcOpt) 858 { 859 SECStatus rv; 860 destOpt->archOption = srcOpt->archOption; 861 switch (srcOpt->archOption) { 862 case crmfEncryptedPrivateKey: 863 rv = crmf_copy_encryptedkey(poolp, 864 &srcOpt->option.encryptedKey, 865 &destOpt->option.encryptedKey); 866 break; 867 case crmfKeyGenParameters: 868 case crmfArchiveRemGenPrivKey: 869 /* We've got a union, so having a pointer to one is just 870 * like having a pointer to the other one. 871 */ 872 rv = SECITEM_CopyItem(poolp, 873 &destOpt->option.keyGenParameters, 874 &srcOpt->option.keyGenParameters); 875 break; 876 default: 877 rv = SECFailure; 878 } 879 return rv; 880 } 881 882 static SECStatus 883 crmf_check_and_adjust_archoption(CRMFControl *inControl) 884 { 885 CRMFPKIArchiveOptions *options; 886 887 options = &inControl->value.archiveOptions; 888 if (options->archOption == crmfNoArchiveOptions) { 889 /* It hasn't been set, so figure it out from the 890 * der. 891 */ 892 switch (inControl->derValue.data[0] & 0x0f) { 893 case 0: 894 options->archOption = crmfEncryptedPrivateKey; 895 break; 896 case 1: 897 options->archOption = crmfKeyGenParameters; 898 break; 899 case 2: 900 options->archOption = crmfArchiveRemGenPrivKey; 901 break; 902 default: 903 /* We've got bad DER. Return an error. */ 904 return SECFailure; 905 } 906 } 907 return SECSuccess; 908 } 909 910 static const SEC_ASN1Template * 911 crmf_get_pkiarchive_subtemplate(CRMFControl *inControl) 912 { 913 const SEC_ASN1Template *retTemplate; 914 SECStatus rv; 915 /* 916 * We could be in the process of decoding, in which case the 917 * archOption field will not be set. Let's check it and set 918 * it accordingly. 919 */ 920 921 rv = crmf_check_and_adjust_archoption(inControl); 922 if (rv != SECSuccess) { 923 return NULL; 924 } 925 926 switch (inControl->value.archiveOptions.archOption) { 927 case crmfEncryptedPrivateKey: 928 retTemplate = CRMFEncryptedKeyWithEncryptedValueTemplate; 929 inControl->value.archiveOptions.option.encryptedKey.encKeyChoice = 930 crmfEncryptedValueChoice; 931 break; 932 default: 933 retTemplate = NULL; 934 } 935 return retTemplate; 936 } 937 938 const SEC_ASN1Template * 939 crmf_get_pkiarchiveoptions_subtemplate(CRMFControl *inControl) 940 { 941 const SEC_ASN1Template *retTemplate; 942 943 switch (inControl->tag) { 944 case SEC_OID_PKIX_REGCTRL_REGTOKEN: 945 case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR: 946 retTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate); 947 break; 948 case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: 949 retTemplate = crmf_get_pkiarchive_subtemplate(inControl); 950 break; 951 case SEC_OID_PKIX_REGCTRL_PKIPUBINFO: 952 case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID: 953 case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: 954 /* We don't support these controls, so we fail for now.*/ 955 retTemplate = NULL; 956 break; 957 default: 958 retTemplate = NULL; 959 } 960 return retTemplate; 961 } 962 963 static SECStatus 964 crmf_encode_pkiarchiveoptions(PLArenaPool *poolp, CRMFControl *inControl) 965 { 966 const SEC_ASN1Template *asn1Template; 967 968 asn1Template = crmf_get_pkiarchiveoptions_subtemplate(inControl); 969 /* We've got a union, so passing a pointer to one element of the 970 * union, is the same as passing a pointer to any of the other 971 * members of the union. 972 */ 973 SEC_ASN1EncodeItem(poolp, &inControl->derValue, 974 &inControl->value.archiveOptions, asn1Template); 975 976 if (inControl->derValue.data == NULL) { 977 goto loser; 978 } 979 return SECSuccess; 980 loser: 981 return SECFailure; 982 } 983 984 SECStatus 985 CRMF_CertRequestSetPKIArchiveOptions(CRMFCertRequest *inCertReq, 986 CRMFPKIArchiveOptions *inOptions) 987 { 988 CRMFControl *newControl; 989 PLArenaPool *poolp; 990 SECStatus rv; 991 void *mark; 992 993 PORT_Assert(inCertReq != NULL && inOptions != NULL); 994 if (inCertReq == NULL || inOptions == NULL) { 995 return SECFailure; 996 } 997 poolp = inCertReq->poolp; 998 mark = PORT_ArenaMark(poolp); 999 rv = crmf_add_new_control(inCertReq, 1000 SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS, 1001 &newControl); 1002 if (rv != SECSuccess) { 1003 goto loser; 1004 } 1005 1006 rv = crmf_copy_pkiarchiveoptions(poolp, 1007 &newControl->value.archiveOptions, 1008 inOptions); 1009 if (rv != SECSuccess) { 1010 goto loser; 1011 } 1012 1013 rv = crmf_encode_pkiarchiveoptions(poolp, newControl); 1014 if (rv != SECSuccess) { 1015 goto loser; 1016 } 1017 PORT_ArenaUnmark(poolp, mark); 1018 return SECSuccess; 1019 loser: 1020 PORT_ArenaRelease(poolp, mark); 1021 return SECFailure; 1022 } 1023 1024 static SECStatus 1025 crmf_destroy_control(CRMFControl *inControl, PRBool freeit) 1026 { 1027 PORT_Assert(inControl != NULL); 1028 if (inControl != NULL) { 1029 SECITEM_FreeItem(&inControl->derTag, PR_FALSE); 1030 SECITEM_FreeItem(&inControl->derValue, PR_FALSE); 1031 /* None of the other tags require special processing at 1032 * the moment when freeing because they are not supported, 1033 * but if/when they are, add the necessary routines here. 1034 * If all controls are supported, then every member of the 1035 * union inControl->value will have a case that deals with 1036 * it in the following switch statement. 1037 */ 1038 switch (inControl->tag) { 1039 case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: 1040 crmf_destroy_pkiarchiveoptions(&inControl->value.archiveOptions, 1041 PR_FALSE); 1042 break; 1043 default: 1044 /* Put this here to get rid of all those annoying warnings.*/ 1045 break; 1046 } 1047 if (freeit) { 1048 PORT_Free(inControl); 1049 } 1050 } 1051 return SECSuccess; 1052 } 1053 1054 SECStatus 1055 CRMF_DestroyControl(CRMFControl *inControl) 1056 { 1057 return crmf_destroy_control(inControl, PR_TRUE); 1058 } 1059 1060 static SECOidTag 1061 crmf_controltype_to_tag(CRMFControlType inControlType) 1062 { 1063 SECOidTag retVal; 1064 1065 switch (inControlType) { 1066 case crmfRegTokenControl: 1067 retVal = SEC_OID_PKIX_REGCTRL_REGTOKEN; 1068 break; 1069 case crmfAuthenticatorControl: 1070 retVal = SEC_OID_PKIX_REGCTRL_AUTHENTICATOR; 1071 break; 1072 case crmfPKIPublicationInfoControl: 1073 retVal = SEC_OID_PKIX_REGCTRL_PKIPUBINFO; 1074 break; 1075 case crmfPKIArchiveOptionsControl: 1076 retVal = SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS; 1077 break; 1078 case crmfOldCertIDControl: 1079 retVal = SEC_OID_PKIX_REGCTRL_OLD_CERT_ID; 1080 break; 1081 case crmfProtocolEncrKeyControl: 1082 retVal = SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY; 1083 break; 1084 default: 1085 retVal = SEC_OID_UNKNOWN; 1086 break; 1087 } 1088 return retVal; 1089 } 1090 1091 PRBool 1092 CRMF_CertRequestIsControlPresent(CRMFCertRequest *inCertReq, 1093 CRMFControlType inControlType) 1094 { 1095 SECOidTag controlTag; 1096 int i; 1097 1098 PORT_Assert(inCertReq != NULL); 1099 if (inCertReq == NULL || inCertReq->controls == NULL) { 1100 return PR_FALSE; 1101 } 1102 controlTag = crmf_controltype_to_tag(inControlType); 1103 for (i = 0; inCertReq->controls[i] != NULL; i++) { 1104 if (inCertReq->controls[i]->tag == controlTag) { 1105 return PR_TRUE; 1106 } 1107 } 1108 return PR_FALSE; 1109 }