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