1/* 2 * The contents of this file are subject to the Mozilla Public 3 * License Version 1.1 (the "License"); you may not use this file 4 * except in compliance with the License. You may obtain a copy of 5 * the License at http://www.mozilla.org/MPL/ 6 * 7 * Software distributed under the License is distributed on an "AS 8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 9 * implied. See the License for the specific language governing 10 * rights and limitations under the License. 11 * 12 * The Original Code is the Netscape security libraries. 13 * 14 * The Initial Developer of the Original Code is Netscape 15 * Communications Corporation. Portions created by Netscape are 16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All 17 * Rights Reserved. 18 * 19 * Contributor(s): 20 * 21 * Alternatively, the contents of this file may be used under the 22 * terms of the GNU General Public License Version 2 or later (the 23 * "GPL"), in which case the provisions of the GPL are applicable 24 * instead of those above. If you wish to allow use of your 25 * version of this file only under the terms of the GPL and not to 26 * allow others to use your version of this file under the MPL, 27 * indicate your decision by deleting the provisions above and 28 * replace them with the notice and other provisions required by 29 * the GPL. If you do not delete the provisions above, a recipient 30 * may use your version of this file under either the MPL or the 31 * GPL. 32 */ 33 34/* 35 * CMS recipientInfo methods. 36 */ 37 38#include "cmslocal.h" 39 40#include "cert.h" 41#include "SecAsn1Item.h" 42#include "secoid.h" 43 44#include <security_asn1/secasn1.h> 45#include <security_asn1/secerr.h> 46#include <security_asn1/secport.h> 47 48#include <Security/SecKeyPriv.h> 49#include <Security/SecCertificatePriv.h> 50#include <Security/SecCertificateInternal.h> 51 52#include "SecCmsRecipientInfo.h" 53 54static Boolean 55nss_cmsrecipientinfo_usessubjectkeyid(SecCmsRecipientInfoRef ri) 56{ 57 if (ri->recipientInfoType == SecCmsRecipientInfoIDKeyTrans) { 58 SecCmsRecipientIdentifier *rid; 59 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; 60 if (rid->identifierType == SecCmsRecipientIDSubjectKeyID) { 61 return PR_TRUE; 62 } 63 } 64 return PR_FALSE; 65} 66 67 68static SecCmsRecipientInfoRef 69nss_cmsrecipientinfo_create(SecCmsEnvelopedDataRef envd, SecCmsRecipientIDSelector type, 70 SecCertificateRef cert, SecPublicKeyRef pubKey, 71 const SecAsn1Item *subjKeyID) 72{ 73 SecCmsRecipientInfoRef ri; 74 void *mark; 75 SECOidTag certalgtag; 76 OSStatus rv = SECSuccess; 77 SecCmsRecipientEncryptedKey *rek; 78 SecCmsOriginatorIdentifierOrKey *oiok; 79 unsigned long version; 80 SecAsn1Item * dummy; 81 PLArenaPool *poolp; 82 const SECAlgorithmID *algid; 83 SECAlgorithmID freeAlgID; 84 85 SecCmsRecipientIdentifier *rid; 86 87 poolp = envd->contentInfo.cmsg->poolp; 88 89 mark = PORT_ArenaMark(poolp); 90 91 ri = (SecCmsRecipientInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsRecipientInfo)); 92 if (ri == NULL) 93 goto loser; 94 95 ri->envelopedData = envd; 96 97#if USE_CDSA_CRYPTO 98 if (type == SecCmsRecipientIDIssuerSN) 99 { 100 rv = SecCertificateGetAlgorithmID(cert,&algid); 101 } else { 102 PORT_Assert(pubKey); 103 rv = SecKeyGetAlgorithmID(pubKey,&algid); 104 } 105#else 106 ri->cert = CERT_DupCertificate(cert); 107 if (ri->cert == NULL) 108 goto loser; 109 110 const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert); 111 freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data; 112 freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length; 113 freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; 114 freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; 115 algid = &freeAlgID; 116#endif 117 118 certalgtag = SECOID_GetAlgorithmTag(algid); 119 120 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; 121 switch (certalgtag) { 122 case SEC_OID_PKCS1_RSA_ENCRYPTION: 123 ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans; 124 rid->identifierType = type; 125 if (type == SecCmsRecipientIDIssuerSN) { 126 rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); 127 if (rid->id.issuerAndSN == NULL) { 128 break; 129 } 130 } else if (type == SecCmsRecipientIDSubjectKeyID){ 131 132 rid->id.subjectKeyID = PORT_ArenaNew(poolp, SecAsn1Item); 133 if (rid->id.subjectKeyID == NULL) { 134 rv = SECFailure; 135 PORT_SetError(SEC_ERROR_NO_MEMORY); 136 break; 137 } 138 SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); 139 if (rid->id.subjectKeyID->Data == NULL) { 140 rv = SECFailure; 141 PORT_SetError(SEC_ERROR_NO_MEMORY); 142 break; 143 } 144 145#if 0 146 SecCmsKeyTransRecipientInfoEx *riExtra; 147 riExtra = &ri->ri.keyTransRecipientInfoEx; 148 riExtra->version = 0; 149 riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); 150 if (riExtra->pubKey == NULL) { 151 rv = SECFailure; 152 PORT_SetError(SEC_ERROR_NO_MEMORY); 153 break; 154 } 155#endif 156 } else { 157 PORT_SetError(SEC_ERROR_INVALID_ARGS); 158 rv = SECFailure; 159 } 160 break; 161 case SEC_OID_MISSI_KEA_DSS_OLD: 162 case SEC_OID_MISSI_KEA_DSS: 163 case SEC_OID_MISSI_KEA: 164 PORT_Assert(type != SecCmsRecipientIDSubjectKeyID); 165 if (type == SecCmsRecipientIDSubjectKeyID) { 166 rv = SECFailure; 167 break; 168 } 169 /* backward compatibility - this is not really a keytrans operation */ 170 ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans; 171 /* hardcoded issuerSN choice for now */ 172 ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = SecCmsRecipientIDIssuerSN; 173 ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); 174 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { 175 rv = SECFailure; 176 break; 177 } 178 break; 179 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ 180 PORT_Assert(type != SecCmsRecipientIDSubjectKeyID); 181 if (type == SecCmsRecipientIDSubjectKeyID) { 182 rv = SECFailure; 183 break; 184 } 185 /* a key agreement op */ 186 ri->recipientInfoType = SecCmsRecipientInfoIDKeyAgree; 187 188 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { 189 rv = SECFailure; 190 break; 191 } 192 /* we do not support the case where multiple recipients 193 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys 194 * in this case, we would need to walk all the recipientInfos, take the 195 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm 196 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ 197 198 /* only epheremal-static Diffie-Hellman is supported for now 199 * this is the only form of key agreement that provides potential anonymity 200 * of the sender, plus we do not have to include certs in the message */ 201 202 /* force single recipientEncryptedKey for now */ 203 if ((rek = SecCmsRecipientEncryptedKeyCreate(poolp)) == NULL) { 204 rv = SECFailure; 205 break; 206 } 207 208 /* hardcoded IssuerSN choice for now */ 209 rek->recipientIdentifier.identifierType = SecCmsKeyAgreeRecipientIDIssuerSN; 210 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { 211 rv = SECFailure; 212 break; 213 } 214 215 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); 216 217 /* see RFC2630 12.3.1.1 */ 218 oiok->identifierType = SecCmsOriginatorIDOrKeyOriginatorPublicKey; 219 220 rv = SecCmsArrayAdd(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, 221 (void *)rek); 222 223 break; 224 default: 225 /* other algorithms not supported yet */ 226 /* NOTE that we do not support any KEK algorithm */ 227 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 228 rv = SECFailure; 229 break; 230 } 231 232 if (rv == SECFailure) 233 goto loser; 234 235 /* set version */ 236 switch (ri->recipientInfoType) { 237 case SecCmsRecipientInfoIDKeyTrans: 238 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == SecCmsRecipientIDIssuerSN) 239 version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; 240 else 241 version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; 242 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); 243 if (dummy == NULL) 244 goto loser; 245 break; 246 case SecCmsRecipientInfoIDKeyAgree: 247 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), 248 SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); 249 if (dummy == NULL) 250 goto loser; 251 break; 252 case SecCmsRecipientInfoIDKEK: 253 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ 254 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), 255 SEC_CMS_KEK_RECIPIENT_INFO_VERSION); 256 if (dummy == NULL) 257 goto loser; 258 break; 259 260 } 261 262 if (SecCmsEnvelopedDataAddRecipient(envd, ri)) 263 goto loser; 264 265 PORT_ArenaUnmark (poolp, mark); 266#if 0 267 if (freeSpki) 268 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 269#endif 270 return ri; 271 272loser: 273#if 0 274 if (freeSpki) 275 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 276#endif 277 PORT_ArenaRelease (poolp, mark); 278 return NULL; 279} 280 281/* 282 * SecCmsRecipientInfoCreate - create a recipientinfo 283 * 284 * we currently do not create KeyAgreement recipientinfos with multiple 285 * recipientEncryptedKeys the certificate is supposed to have been 286 * verified by the caller 287 */ 288SecCmsRecipientInfoRef 289SecCmsRecipientInfoCreate(SecCmsEnvelopedDataRef envd, SecCertificateRef cert) 290{ 291#if 0 292 SecCmsRecipientInfoRef info = SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(envd, cert); 293 294 if (info) 295 return info; 296 else 297#endif 298 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDIssuerSN, cert, 299 NULL, NULL); 300} 301 302SecCmsRecipientInfoRef 303SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd, 304 const SecAsn1Item * subjKeyID, 305 SecPublicKeyRef pubKey) 306{ 307 return nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID, 308 NULL, pubKey, subjKeyID); 309} 310 311#if USE_CDSA_CRYPTO 312SecCmsRecipientInfoRef 313SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd, 314 SecCertificateRef cert) 315{ 316 SecPublicKeyRef pubKey = NULL; 317 SecAsn1Item subjKeyID = {0, NULL}; 318 SecCmsRecipientInfoRef retVal = NULL; 319 320 if (!envd || !cert) { 321 return NULL; 322 } 323 pubKey = CERT_ExtractPublicKey(cert); 324 if (!pubKey) { 325 goto done; 326 } 327 if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess || 328 subjKeyID.Data == NULL) { 329 goto done; 330 } 331 retVal = SecCmsRecipientInfoCreateWithSubjKeyID(envd, &subjKeyID, pubKey); 332done: 333 if (pubKey) 334 SECKEY_DestroyPublicKey(pubKey); 335 336 if (subjKeyID.Data) 337 SECITEM_FreeItem(&subjKeyID, PR_FALSE); 338 339 return retVal; 340} 341#else 342SecCmsRecipientInfoRef 343SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd, 344 SecCertificateRef cert) 345{ 346 SecPublicKeyRef pubKey = NULL; 347 SecAsn1Item subjKeyID = {0, NULL}; 348 SecCmsRecipientInfoRef retVal = NULL; 349 CFDataRef subjectKeyIDData = NULL; 350 351 if (!envd || !cert) { 352 return NULL; 353 } 354 subjectKeyIDData = SecCertificateGetSubjectKeyID(cert); 355 if (!subjectKeyIDData) 356 goto done; 357 subjKeyID.Length = 358 CFDataGetLength(subjectKeyIDData); 359 subjKeyID.Data = (uint8_t *)CFDataGetBytePtr(subjectKeyIDData); 360 retVal = nss_cmsrecipientinfo_create(envd, SecCmsRecipientIDSubjectKeyID, 361 cert, pubKey, &subjKeyID); 362 363done: 364 365 return retVal; 366} 367#endif 368 369void 370SecCmsRecipientInfoDestroy(SecCmsRecipientInfoRef ri) 371{ 372 /* version was allocated on the pool, so no need to destroy it */ 373 /* issuerAndSN was allocated on the pool, so no need to destroy it */ 374 if (ri->cert != NULL) 375 CERT_DestroyCertificate(ri->cert); 376 377 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) { 378 SecCmsKeyTransRecipientInfoEx *extra; 379 extra = &ri->ri.keyTransRecipientInfoEx; 380 if (extra->pubKey) 381 SECKEY_DestroyPublicKey(extra->pubKey); 382 } 383 384 /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */ 385 /* we're done. */ 386} 387 388int 389SecCmsRecipientInfoGetVersion(SecCmsRecipientInfoRef ri) 390{ 391 unsigned long version; 392 SecAsn1Item * versionitem = NULL; 393 394 switch (ri->recipientInfoType) { 395 case SecCmsRecipientInfoIDKeyTrans: 396 /* ignore subIndex */ 397 versionitem = &(ri->ri.keyTransRecipientInfo.version); 398 break; 399 case SecCmsRecipientInfoIDKEK: 400 /* ignore subIndex */ 401 versionitem = &(ri->ri.kekRecipientInfo.version); 402 break; 403 case SecCmsRecipientInfoIDKeyAgree: 404 versionitem = &(ri->ri.keyAgreeRecipientInfo.version); 405 break; 406 } 407 408 PORT_Assert(versionitem); 409 if (versionitem == NULL) 410 return 0; 411 412 /* always take apart the SecAsn1Item */ 413 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess) 414 return 0; 415 else 416 return (int)version; 417} 418 419SecAsn1Item * 420SecCmsRecipientInfoGetEncryptedKey(SecCmsRecipientInfoRef ri, int subIndex) 421{ 422 SecAsn1Item * enckey = NULL; 423 424 switch (ri->recipientInfoType) { 425 case SecCmsRecipientInfoIDKeyTrans: 426 /* ignore subIndex */ 427 enckey = &(ri->ri.keyTransRecipientInfo.encKey); 428 break; 429 case SecCmsRecipientInfoIDKEK: 430 /* ignore subIndex */ 431 enckey = &(ri->ri.kekRecipientInfo.encKey); 432 break; 433 case SecCmsRecipientInfoIDKeyAgree: 434 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); 435 break; 436 } 437 return enckey; 438} 439 440 441SECOidTag 442SecCmsRecipientInfoGetKeyEncryptionAlgorithmTag(SecCmsRecipientInfoRef ri) 443{ 444 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */ 445 446 switch (ri->recipientInfoType) { 447 case SecCmsRecipientInfoIDKeyTrans: 448 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); 449 break; 450 case SecCmsRecipientInfoIDKeyAgree: 451 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); 452 break; 453 case SecCmsRecipientInfoIDKEK: 454 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); 455 break; 456 } 457 return encalgtag; 458} 459 460OSStatus 461SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, 462 SECOidTag bulkalgtag) 463{ 464 SecCertificateRef cert; 465 SECOidTag certalgtag; 466 OSStatus rv = SECSuccess; 467#if 0 468 SecAsn1Item * params = NULL; 469 SecCmsRecipientEncryptedKey *rek; 470 SecCmsOriginatorIdentifierOrKey *oiok; 471#endif /* 0 */ 472 const SECAlgorithmID *algid; 473 PLArenaPool *poolp; 474 SecCmsKeyTransRecipientInfoEx *extra = NULL; 475 Boolean usesSubjKeyID; 476 477 poolp = ri->envelopedData->contentInfo.cmsg->poolp; 478 cert = ri->cert; 479 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); 480 if (cert) { 481#if USE_CDSA_CRYPTO 482 rv = SecCertificateGetAlgorithmID(cert,&algid); 483 if (rv) 484 return SECFailure; 485#else 486 SECAlgorithmID freeAlgID; 487 const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert); 488 freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data; 489 freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length; 490 freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; 491 freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; 492 algid = &freeAlgID; 493#endif 494 } else if (usesSubjKeyID) { 495 extra = &ri->ri.keyTransRecipientInfoEx; 496 /* sanity check */ 497 PORT_Assert(extra->pubKey); 498 if (!extra->pubKey) { 499 PORT_SetError(SEC_ERROR_INVALID_ARGS); 500 return SECFailure; 501 } 502#if USE_CDSA_CRYPTO 503 rv = SecKeyGetAlgorithmID(extra->pubKey,&algid); 504 if (rv) 505#endif 506 return SECFailure; 507 certalgtag = SECOID_GetAlgorithmTag(algid); 508 } else { 509 PORT_SetError(SEC_ERROR_INVALID_ARGS); 510 return SECFailure; 511 } 512 513 /* XXX set ri->recipientInfoType to the proper value here */ 514 /* or should we look if it's been set already ? */ 515 516 certalgtag = SECOID_GetAlgorithmTag(algid); 517 switch (certalgtag) { 518 case SEC_OID_PKCS1_RSA_ENCRYPTION: 519 /* wrap the symkey */ 520 if (cert) { 521 rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, 522 &ri->ri.keyTransRecipientInfo.encKey); 523 if (rv != SECSuccess) 524 break; 525 } else if (usesSubjKeyID) { 526 PORT_Assert(extra != NULL); 527 rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey, 528 bulkkey, &ri->ri.keyTransRecipientInfo.encKey); 529 if (rv != SECSuccess) 530 break; 531 } 532 533 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); 534 break; 535#if 0 536 case SEC_OID_MISSI_KEA_DSS_OLD: 537 case SEC_OID_MISSI_KEA_DSS: 538 case SEC_OID_MISSI_KEA: 539 rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey, 540 bulkalgtag, 541 &ri->ri.keyTransRecipientInfo.encKey, 542 ¶ms, ri->cmsg->pwfn_arg); 543 if (rv != SECSuccess) 544 break; 545 546 /* here, we DO need to pass the params to the wrap function because, with 547 * RSA, there is no funny stuff going on with generation of IV vectors or so */ 548 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params); 549 break; 550 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ 551 rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; 552 if (rek == NULL) { 553 rv = SECFailure; 554 break; 555 } 556 557 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); 558 PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); 559 560 /* see RFC2630 12.3.1.1 */ 561 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, 562 SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { 563 rv = SECFailure; 564 break; 565 } 566 567 /* this will generate a key pair, compute the shared secret, */ 568 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ 569 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ 570 rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey, 571 &rek->encKey, 572 &ri->ri.keyAgreeRecipientInfo.ukm, 573 &ri->ri.keyAgreeRecipientInfo.keyEncAlg, 574 &oiok->id.originatorPublicKey.publicKey); 575 576 break; 577#endif /* 0 */ 578 default: 579 /* other algorithms not supported yet */ 580 /* NOTE that we do not support any KEK algorithm */ 581 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 582 rv = SECFailure; 583 break; 584 } 585#if 0 586 if (freeSpki) 587 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 588#endif 589 590 return rv; 591} 592 593SecSymmetricKeyRef 594SecCmsRecipientInfoUnwrapBulkKey(SecCmsRecipientInfoRef ri, int subIndex, 595 SecCertificateRef cert, SecPrivateKeyRef privkey, SECOidTag bulkalgtag) 596{ 597 SecSymmetricKeyRef bulkkey = NULL; 598 SECAlgorithmID *encalg; 599 SECOidTag encalgtag; 600 SecAsn1Item * enckey; 601 int error; 602 603 ri->cert = CERT_DupCertificate(cert); 604 /* mark the recipientInfo so we can find it later */ 605 606 switch (ri->recipientInfoType) { 607 case SecCmsRecipientInfoIDKeyTrans: 608 encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg); 609 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); 610 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */ 611 switch (encalgtag) { 612 case SEC_OID_PKCS1_RSA_ENCRYPTION: 613 /* RSA encryption algorithm: */ 614 /* get the symmetric (bulk) key by unwrapping it using our private key */ 615 bulkkey = SecCmsUtilDecryptSymKeyRSA(privkey, enckey, bulkalgtag); 616 break; 617#if 0 618 case SEC_OID_NETSCAPE_SMIME_KEA: 619 /* FORTEZZA key exchange algorithm */ 620 /* the supplemental data is in the parameters of encalg */ 621 bulkkey = SecCmsUtilDecryptSymKeyMISSI(privkey, enckey, encalg, bulkalgtag, ri->cmsg->pwfn_arg); 622 break; 623#endif /* 0 */ 624 default: 625 error = SEC_ERROR_UNSUPPORTED_KEYALG; 626 goto loser; 627 } 628 break; 629 case SecCmsRecipientInfoIDKeyAgree: 630 encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg); 631 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); 632 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); 633 switch (encalgtag) { 634 case SEC_OID_X942_DIFFIE_HELMAN_KEY: 635 /* Diffie-Helman key exchange */ 636 /* XXX not yet implemented */ 637 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */ 638 /* we support ephemeral-static DH only, so if the recipientinfo */ 639 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */ 640 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */ 641 /* content encryption key using a Unwrap op */ 642 /* the derive operation has to generate the key using the algorithm in RFC2631 */ 643 error = SEC_ERROR_UNSUPPORTED_KEYALG; 644 break; 645 default: 646 error = SEC_ERROR_UNSUPPORTED_KEYALG; 647 goto loser; 648 } 649 break; 650 case SecCmsRecipientInfoIDKEK: 651 encalg = &(ri->ri.kekRecipientInfo.keyEncAlg); 652 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); 653 enckey = &(ri->ri.kekRecipientInfo.encKey); 654 /* not supported yet */ 655 error = SEC_ERROR_UNSUPPORTED_KEYALG; 656 goto loser; 657 break; 658 } 659 /* XXXX continue here */ 660 return bulkkey; 661 662loser: 663 return NULL; 664} 665