cmsrecinfo.c (26276B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 * CMS recipientInfo methods. 7 */ 8 9 #include "cmslocal.h" 10 11 #include "cert.h" 12 #include "keyhi.h" 13 #include "secasn1.h" 14 #include "secitem.h" 15 #include "secoid.h" 16 #include "pk11func.h" 17 #include "secerr.h" 18 #include "smime.h" 19 20 PRBool 21 nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri) 22 { 23 if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) { 24 NSSCMSRecipientIdentifier *rid; 25 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; 26 if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) { 27 return PR_TRUE; 28 } 29 } 30 return PR_FALSE; 31 } 32 33 /* 34 * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier 35 * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have 36 * been exported, and we would have added an ordinary enum to handle this 37 * check. Unfortunatly wo don't have that luxury so we are overloading the 38 * contentTypeTag field. NO code should every try to interpret this content tag 39 * as a real OID tag, or use any fields other than pwfn_arg or poolp of this 40 * CMSMessage for that matter */ 41 static const SECOidData fakeContent; 42 NSSCMSRecipientInfo * 43 nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, 44 NSSCMSRecipientIDSelector type, 45 CERTCertificate *cert, 46 SECKEYPublicKey *pubKey, 47 SECItem *subjKeyID, 48 void *pwfn_arg, 49 SECItem *DERinput) 50 { 51 NSSCMSRecipientInfo *ri; 52 void *mark; 53 SECOidTag certalgtag; 54 SECStatus rv = SECSuccess; 55 NSSCMSRecipientEncryptedKey *rek; 56 NSSCMSOriginatorIdentifierOrKey *oiok; 57 unsigned long version; 58 SECItem *dummy; 59 PLArenaPool *poolp; 60 CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; 61 NSSCMSRecipientIdentifier *rid; 62 extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; 63 64 if (!cmsg) { 65 /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc 66 * and a private arena pool */ 67 cmsg = NSS_CMSMessage_Create(NULL); 68 cmsg->pwfn_arg = pwfn_arg; 69 /* mark it as a special cms message */ 70 cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent; 71 } 72 73 poolp = cmsg->poolp; 74 75 mark = PORT_ArenaMark(poolp); 76 77 ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo)); 78 if (ri == NULL) 79 goto loser; 80 81 ri->cmsg = cmsg; 82 83 if (DERinput) { 84 /* decode everything from DER */ 85 SECItem newinput; 86 rv = SECITEM_CopyItem(poolp, &newinput, DERinput); 87 if (SECSuccess != rv) 88 goto loser; 89 rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput); 90 if (SECSuccess != rv) 91 goto loser; 92 } 93 94 switch (type) { 95 case NSSCMSRecipientID_IssuerSN: { 96 ri->cert = CERT_DupCertificate(cert); 97 if (NULL == ri->cert) 98 goto loser; 99 spki = &(cert->subjectPublicKeyInfo); 100 break; 101 } 102 103 case NSSCMSRecipientID_SubjectKeyID: { 104 PORT_Assert(pubKey); 105 spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); 106 break; 107 } 108 109 case NSSCMSRecipientID_BrandNew: 110 goto done; 111 break; 112 113 default: 114 /* unkown type */ 115 goto loser; 116 break; 117 } 118 119 certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); 120 121 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; 122 123 // This switch must match the switch in NSS_CMSRecipient_IsSupported. 124 switch (certalgtag) { 125 case SEC_OID_PKCS1_RSA_ENCRYPTION: 126 ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans; 127 rid->identifierType = type; 128 if (type == NSSCMSRecipientID_IssuerSN) { 129 rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); 130 if (rid->id.issuerAndSN == NULL) { 131 break; 132 } 133 } else if (type == NSSCMSRecipientID_SubjectKeyID) { 134 NSSCMSKeyTransRecipientInfoEx *riExtra; 135 136 rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); 137 if (rid->id.subjectKeyID == NULL) { 138 rv = SECFailure; 139 PORT_SetError(SEC_ERROR_NO_MEMORY); 140 break; 141 } 142 rv = SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); 143 if (rv != SECSuccess || rid->id.subjectKeyID->data == NULL) { 144 rv = SECFailure; 145 PORT_SetError(SEC_ERROR_NO_MEMORY); 146 break; 147 } 148 riExtra = &ri->ri.keyTransRecipientInfoEx; 149 riExtra->version = 0; 150 riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); 151 if (riExtra->pubKey == NULL) { 152 rv = SECFailure; 153 PORT_SetError(SEC_ERROR_NO_MEMORY); 154 break; 155 } 156 } else { 157 PORT_SetError(SEC_ERROR_INVALID_ARGS); 158 rv = SECFailure; 159 } 160 break; 161 case SEC_OID_ANSIX962_EC_PUBLIC_KEY: 162 PORT_Assert(type == NSSCMSRecipientID_IssuerSN); 163 if (type != NSSCMSRecipientID_IssuerSN) { 164 rv = SECFailure; 165 break; 166 } 167 /* a key agreement op */ 168 ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree; 169 170 /* we do not support the case where multiple recipients 171 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys 172 * in this case, we would need to walk all the recipientInfos, take the 173 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm 174 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ 175 176 /* only epheremal-static Diffie-Hellman is supported for now 177 * this is the only form of key agreement that provides potential anonymity 178 * of the sender, plus we do not have to include certs in the message */ 179 180 /* force single recipientEncryptedKey for now */ 181 if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) { 182 rv = SECFailure; 183 break; 184 } 185 186 /* hardcoded IssuerSN choice for now */ 187 rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN; 188 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { 189 rv = SECFailure; 190 break; 191 } 192 193 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); 194 195 /* see RFC2630 12.3.1.1 */ 196 oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey; 197 198 rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, 199 (void *)rek); 200 201 break; 202 default: 203 /* other algorithms not supported yet */ 204 /* NOTE that we do not support any KEK algorithm */ 205 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 206 rv = SECFailure; 207 break; 208 } 209 210 if (rv == SECFailure) 211 goto loser; 212 213 /* set version */ 214 switch (ri->recipientInfoType) { 215 case NSSCMSRecipientInfoID_KeyTrans: 216 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN) 217 version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; 218 else 219 version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; 220 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); 221 if (dummy == NULL) 222 goto loser; 223 break; 224 case NSSCMSRecipientInfoID_KeyAgree: 225 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), 226 NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); 227 if (dummy == NULL) 228 goto loser; 229 break; 230 case NSSCMSRecipientInfoID_KEK: 231 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ 232 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), 233 NSS_CMS_KEK_RECIPIENT_INFO_VERSION); 234 if (dummy == NULL) 235 goto loser; 236 break; 237 } 238 239 done: 240 PORT_ArenaUnmark(poolp, mark); 241 if (freeSpki) 242 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 243 return ri; 244 245 loser: 246 if (ri && ri->cert) { 247 CERT_DestroyCertificate(ri->cert); 248 } 249 if (freeSpki) { 250 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 251 } 252 PORT_ArenaRelease(poolp, mark); 253 if (cmsg->contentInfo.contentTypeTag == &fakeContent) { 254 NSS_CMSMessage_Destroy(cmsg); 255 } 256 return NULL; 257 } 258 259 /* 260 * NSS_CMSRecipient_IsSupported - checks for a support certificate 261 * 262 * Use this function to confirm that the given certificate will be 263 * accepted by NSS_CMSRecipientInfo_Create, which means that the 264 * certificate can be used with a supported encryption algorithm. 265 */ 266 PRBool 267 NSS_CMSRecipient_IsSupported(CERTCertificate *cert) 268 { 269 CERTSubjectPublicKeyInfo *spki = &(cert->subjectPublicKeyInfo); 270 SECOidTag certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); 271 272 switch (certalgtag) { 273 case SEC_OID_PKCS1_RSA_ENCRYPTION: 274 case SEC_OID_ANSIX962_EC_PUBLIC_KEY: 275 return PR_TRUE; 276 default: 277 return PR_FALSE; 278 } 279 } 280 281 /* 282 * NSS_CMSRecipientInfo_Create - 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 */ 288 NSSCMSRecipientInfo * 289 NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert) 290 { 291 return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert, 292 NULL, NULL, NULL, NULL); 293 } 294 295 NSSCMSRecipientInfo * 296 NSS_CMSRecipientInfo_CreateNew(void *pwfn_arg) 297 { 298 return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, 299 NULL, NULL, pwfn_arg, NULL); 300 } 301 302 NSSCMSRecipientInfo * 303 NSS_CMSRecipientInfo_CreateFromDER(SECItem *input, void *pwfn_arg) 304 { 305 return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, 306 NULL, NULL, pwfn_arg, input); 307 } 308 309 NSSCMSRecipientInfo * 310 NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, 311 SECItem *subjKeyID, 312 SECKEYPublicKey *pubKey) 313 { 314 return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID, 315 NULL, pubKey, subjKeyID, NULL, NULL); 316 } 317 318 NSSCMSRecipientInfo * 319 NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg, 320 CERTCertificate *cert) 321 { 322 SECKEYPublicKey *pubKey = NULL; 323 SECItem subjKeyID = { siBuffer, NULL, 0 }; 324 NSSCMSRecipientInfo *retVal = NULL; 325 326 if (!cmsg || !cert) { 327 return NULL; 328 } 329 pubKey = CERT_ExtractPublicKey(cert); 330 if (!pubKey) { 331 goto done; 332 } 333 if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess || 334 subjKeyID.data == NULL) { 335 goto done; 336 } 337 retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey); 338 done: 339 if (pubKey) 340 SECKEY_DestroyPublicKey(pubKey); 341 342 if (subjKeyID.data) 343 SECITEM_FreeItem(&subjKeyID, PR_FALSE); 344 345 return retVal; 346 } 347 348 void 349 NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri) 350 { 351 if (!ri) { 352 return; 353 } 354 /* version was allocated on the pool, so no need to destroy it */ 355 /* issuerAndSN was allocated on the pool, so no need to destroy it */ 356 if (ri->cert != NULL) 357 CERT_DestroyCertificate(ri->cert); 358 359 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) { 360 NSSCMSKeyTransRecipientInfoEx *extra; 361 extra = &ri->ri.keyTransRecipientInfoEx; 362 if (extra->pubKey) 363 SECKEY_DestroyPublicKey(extra->pubKey); 364 } 365 if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) { 366 NSS_CMSMessage_Destroy(ri->cmsg); 367 } 368 369 /* we're done. */ 370 } 371 372 int 373 NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri) 374 { 375 unsigned long version; 376 SECItem *versionitem = NULL; 377 378 switch (ri->recipientInfoType) { 379 case NSSCMSRecipientInfoID_KeyTrans: 380 /* ignore subIndex */ 381 versionitem = &(ri->ri.keyTransRecipientInfo.version); 382 break; 383 case NSSCMSRecipientInfoID_KEK: 384 /* ignore subIndex */ 385 versionitem = &(ri->ri.kekRecipientInfo.version); 386 break; 387 case NSSCMSRecipientInfoID_KeyAgree: 388 versionitem = &(ri->ri.keyAgreeRecipientInfo.version); 389 break; 390 } 391 392 PORT_Assert(versionitem); 393 if (versionitem == NULL) 394 return 0; 395 396 /* always take apart the SECItem */ 397 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess) 398 return 0; 399 else 400 return (int)version; 401 } 402 403 SECItem * 404 NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex) 405 { 406 SECItem *enckey = NULL; 407 408 switch (ri->recipientInfoType) { 409 case NSSCMSRecipientInfoID_KeyTrans: 410 /* ignore subIndex */ 411 enckey = &(ri->ri.keyTransRecipientInfo.encKey); 412 break; 413 case NSSCMSRecipientInfoID_KEK: 414 /* ignore subIndex */ 415 enckey = &(ri->ri.kekRecipientInfo.encKey); 416 break; 417 case NSSCMSRecipientInfoID_KeyAgree: 418 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); 419 break; 420 } 421 return enckey; 422 } 423 424 SECOidTag 425 NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri) 426 { 427 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */ 428 429 switch (ri->recipientInfoType) { 430 case NSSCMSRecipientInfoID_KeyTrans: 431 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); 432 break; 433 case NSSCMSRecipientInfoID_KeyAgree: 434 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); 435 break; 436 case NSSCMSRecipientInfoID_KEK: 437 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); 438 break; 439 } 440 return encalgtag; 441 } 442 443 SECStatus 444 NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, 445 SECOidTag bulkalgtag) 446 { 447 CERTCertificate *cert; 448 SECOidTag certalgtag; 449 SECStatus rv = SECSuccess; 450 NSSCMSRecipientEncryptedKey *rek; 451 NSSCMSOriginatorIdentifierOrKey *oiok; 452 CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; 453 PLArenaPool *poolp; 454 NSSCMSKeyTransRecipientInfoEx *extra = NULL; 455 PRBool usesSubjKeyID; 456 void *wincx = NULL; 457 458 poolp = ri->cmsg->poolp; 459 cert = ri->cert; 460 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); 461 if (cert) { 462 spki = &cert->subjectPublicKeyInfo; 463 } else if (usesSubjKeyID) { 464 extra = &ri->ri.keyTransRecipientInfoEx; 465 /* sanity check */ 466 PORT_Assert(extra->pubKey); 467 if (!extra->pubKey) { 468 PORT_SetError(SEC_ERROR_INVALID_ARGS); 469 return SECFailure; 470 } 471 spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey); 472 } else { 473 PORT_SetError(SEC_ERROR_INVALID_ARGS); 474 return SECFailure; 475 } 476 477 /* XXX set ri->recipientInfoType to the proper value here */ 478 /* or should we look if it's been set already ? */ 479 480 certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm); 481 if (!NSS_SMIMEUtil_KeyEncodingAllowed(&spki->algorithm, cert, extra ? extra->pubKey : NULL)) { 482 PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); 483 rv = SECFailure; 484 goto loser; 485 } 486 switch (certalgtag) { 487 case SEC_OID_PKCS1_RSA_ENCRYPTION: 488 /* wrap the symkey */ 489 if (cert) { 490 rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, 491 &ri->ri.keyTransRecipientInfo.encKey); 492 if (rv != SECSuccess) 493 break; 494 } else if (usesSubjKeyID) { 495 PORT_Assert(extra != NULL); 496 rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey, 497 bulkkey, &ri->ri.keyTransRecipientInfo.encKey); 498 if (rv != SECSuccess) 499 break; 500 } 501 502 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); 503 break; 504 case SEC_OID_ANSIX962_EC_PUBLIC_KEY: 505 rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; 506 if (rek == NULL) { 507 rv = SECFailure; 508 break; 509 } 510 511 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); 512 PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey); 513 514 /* see RFC2630 12.3.1.1 */ 515 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, 516 certalgtag, NULL) != SECSuccess) { 517 rv = SECFailure; 518 break; 519 } 520 521 /* this will generate a key pair, compute the shared secret, */ 522 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ 523 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ 524 switch (certalgtag) { 525 case SEC_OID_ANSIX962_EC_PUBLIC_KEY: 526 if (ri->cmsg) { 527 wincx = ri->cmsg->pwfn_arg; 528 } else { 529 wincx = PK11_GetWindow(bulkkey); 530 } 531 rv = NSS_CMSUtil_EncryptSymKey_ESECDH(poolp, cert, bulkkey, 532 &rek->encKey, 533 PR_TRUE, 534 &ri->ri.keyAgreeRecipientInfo.ukm, 535 &ri->ri.keyAgreeRecipientInfo.keyEncAlg, 536 &oiok->id.originatorPublicKey.publicKey, 537 wincx); 538 break; 539 540 default: 541 /* Not reached. Added to silence enum warnings. */ 542 PORT_Assert(0); 543 break; 544 } 545 break; 546 default: 547 /* other algorithms not supported yet */ 548 /* NOTE that we do not support any KEK algorithm */ 549 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 550 rv = SECFailure; 551 } 552 loser: 553 if (freeSpki) 554 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); 555 556 return rv; 557 } 558 559 PK11SymKey * 560 NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, 561 CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag) 562 { 563 PK11SymKey *bulkkey = NULL; 564 SECAlgorithmID *algid; 565 SECOidTag encalgtag; 566 SECItem *enckey = NULL, *ukm = NULL, *parameters = NULL; 567 NSSCMSOriginatorIdentifierOrKey *oiok = NULL; 568 int error; 569 void *wincx = NULL; 570 571 ri->cert = CERT_DupCertificate(cert); 572 /* mark the recipientInfo so we can find it later */ 573 574 switch (ri->recipientInfoType) { 575 case NSSCMSRecipientInfoID_KeyTrans: 576 algid = &(ri->ri.keyTransRecipientInfo.keyEncAlg); 577 parameters = &(ri->ri.keyTransRecipientInfo.keyEncAlg.parameters); 578 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */ 579 break; 580 case NSSCMSRecipientInfoID_KeyAgree: 581 algid = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg); 582 parameters = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg.parameters); 583 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); 584 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); 585 ukm = &(ri->ri.keyAgreeRecipientInfo.ukm); 586 break; 587 case NSSCMSRecipientInfoID_KEK: 588 algid = &(ri->ri.kekRecipientInfo.keyEncAlg); 589 parameters = &(ri->ri.kekRecipientInfo.keyEncAlg.parameters); 590 enckey = &(ri->ri.kekRecipientInfo.encKey); 591 /* not supported yet */ 592 default: 593 error = SEC_ERROR_UNSUPPORTED_KEYALG; 594 goto loser; 595 break; 596 } 597 if (!NSS_SMIMEUtil_KeyDecodingAllowed(algid, privkey)) { 598 error = SEC_ERROR_BAD_EXPORT_ALGORITHM; 599 goto loser; 600 } 601 encalgtag = SECOID_GetAlgorithmTag(algid); 602 switch (encalgtag) { 603 case SEC_OID_PKCS1_RSA_ENCRYPTION: 604 /* RSA encryption algorithm: */ 605 if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyTrans) { 606 error = SEC_ERROR_UNSUPPORTED_KEYALG; 607 goto loser; 608 } 609 /* get the symmetric (bulk) key by unwrapping it using our private key */ 610 bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag); 611 break; 612 case SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION: 613 /* RSA OAEP encryption algorithm: */ 614 if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyTrans) { 615 error = SEC_ERROR_UNSUPPORTED_KEYALG; 616 goto loser; 617 } 618 /* get the symmetric (bulk) key by unwrapping it using our private key */ 619 bulkkey = NSS_CMSUtil_DecryptSymKey_RSA_OAEP(privkey, parameters, enckey, 620 bulkalgtag); 621 break; 622 case SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME: 623 case SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME: 624 case SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME: 625 case SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME: 626 case SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME: 627 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME: 628 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME: 629 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME: 630 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME: 631 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME: 632 if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyAgree) { 633 error = SEC_ERROR_UNSUPPORTED_KEYALG; 634 goto loser; 635 } 636 if (ri->cmsg) { 637 wincx = ri->cmsg->pwfn_arg; 638 } 639 bulkkey = NSS_CMSUtil_DecryptSymKey_ECDH(privkey, enckey, algid, 640 bulkalgtag, ukm, oiok, wincx); 641 break; 642 default: 643 error = SEC_ERROR_UNSUPPORTED_KEYALG; 644 goto loser; 645 } 646 /* XXXX continue here */ 647 return bulkkey; 648 649 loser: 650 PORT_SetError(error); 651 return NULL; 652 } 653 654 SECStatus 655 NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri, 656 CERTCertificate **retcert, 657 SECKEYPrivateKey **retkey) 658 { 659 CERTCertificate *cert = NULL; 660 NSSCMSRecipient **recipients = NULL; 661 NSSCMSRecipientInfo *recipientInfos[2]; 662 SECStatus rv = SECSuccess; 663 SECKEYPrivateKey *key = NULL; 664 665 if (!ri) 666 return SECFailure; 667 668 if (!retcert && !retkey) { 669 /* nothing requested, nothing found, success */ 670 return SECSuccess; 671 } 672 673 if (retcert) { 674 *retcert = NULL; 675 } 676 if (retkey) { 677 *retkey = NULL; 678 } 679 680 if (ri->cert) { 681 cert = CERT_DupCertificate(ri->cert); 682 if (!cert) { 683 rv = SECFailure; 684 } 685 } 686 if (SECSuccess == rv && !cert) { 687 /* we don't have the cert, we have to look for it */ 688 /* first build an NSS_CMSRecipient */ 689 recipientInfos[0] = ri; 690 recipientInfos[1] = NULL; 691 692 recipients = nss_cms_recipient_list_create(recipientInfos); 693 if (recipients) { 694 /* now look for the cert and key */ 695 if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients, 696 ri->cmsg->pwfn_arg)) { 697 cert = CERT_DupCertificate(recipients[0]->cert); 698 key = SECKEY_CopyPrivateKey(recipients[0]->privkey); 699 } else { 700 rv = SECFailure; 701 } 702 703 nss_cms_recipient_list_destroy(recipients); 704 } else { 705 rv = SECFailure; 706 } 707 } else if (SECSuccess == rv && cert && retkey) { 708 /* we have the cert, we just need the key now */ 709 key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg); 710 } 711 if (retcert) { 712 *retcert = cert; 713 } else { 714 if (cert) { 715 CERT_DestroyCertificate(cert); 716 } 717 } 718 if (retkey) { 719 *retkey = key; 720 } else { 721 if (key) { 722 SECKEY_DestroyPrivateKey(key); 723 } 724 } 725 726 return rv; 727 } 728 729 SECStatus 730 NSS_CMSRecipientInfo_Encode(PLArenaPool *poolp, 731 const NSSCMSRecipientInfo *src, 732 SECItem *returned) 733 { 734 extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; 735 SECStatus rv = SECFailure; 736 if (!src || !returned) { 737 PORT_SetError(SEC_ERROR_INVALID_ARGS); 738 } else if (SEC_ASN1EncodeItem(poolp, returned, src, 739 NSSCMSRecipientInfoTemplate)) { 740 rv = SECSuccess; 741 } 742 return rv; 743 }