cmspubkey.c (23033B)
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 public key crypto 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 "secder.h" 19 #include "prerr.h" 20 #include "sechash.h" 21 22 /* ====== RSA ======================================================================= */ 23 24 /* 25 * NSS_CMSUtil_EncryptSymKey_RSA - wrap a symmetric key with RSA 26 * 27 * this function takes a symmetric key and encrypts it using an RSA public key 28 * according to PKCS#1 and RFC2633 (S/MIME) 29 */ 30 SECStatus 31 NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert, 32 PK11SymKey *bulkkey, 33 SECItem *encKey) 34 { 35 SECStatus rv; 36 SECKEYPublicKey *publickey; 37 38 publickey = CERT_ExtractPublicKey(cert); 39 if (publickey == NULL) 40 return SECFailure; 41 42 rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, publickey, bulkkey, encKey); 43 SECKEY_DestroyPublicKey(publickey); 44 return rv; 45 } 46 47 SECStatus 48 NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp, 49 SECKEYPublicKey *publickey, 50 PK11SymKey *bulkkey, SECItem *encKey) 51 { 52 SECStatus rv; 53 int data_len; 54 KeyType keyType; 55 void *mark = NULL; 56 57 mark = PORT_ArenaMark(poolp); 58 if (!mark) 59 goto loser; 60 61 /* sanity check */ 62 keyType = SECKEY_GetPublicKeyType(publickey); 63 PORT_Assert(keyType == rsaKey); 64 if (keyType != rsaKey) { 65 goto loser; 66 } 67 /* allocate memory for the encrypted key */ 68 data_len = SECKEY_PublicKeyStrength(publickey); /* block size (assumed to be > keylen) */ 69 encKey->data = (unsigned char *)PORT_ArenaAlloc(poolp, data_len); 70 encKey->len = data_len; 71 if (encKey->data == NULL) 72 goto loser; 73 74 /* encrypt the key now */ 75 rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(SEC_OID_PKCS1_RSA_ENCRYPTION), 76 publickey, bulkkey, encKey); 77 78 if (rv != SECSuccess) 79 goto loser; 80 81 PORT_ArenaUnmark(poolp, mark); 82 return SECSuccess; 83 84 loser: 85 if (mark) { 86 PORT_ArenaRelease(poolp, mark); 87 } 88 return SECFailure; 89 } 90 91 /* 92 * NSS_CMSUtil_DecryptSymKey_RSA - unwrap a RSA-wrapped symmetric key 93 * 94 * this function takes an RSA-wrapped symmetric key and unwraps it, returning a symmetric 95 * key handle. Please note that the actual unwrapped key data may not be allowed to leave 96 * a hardware token... 97 */ 98 PK11SymKey * 99 NSS_CMSUtil_DecryptSymKey_RSA(SECKEYPrivateKey *privkey, SECItem *encKey, SECOidTag bulkalgtag) 100 { 101 /* that's easy */ 102 CK_MECHANISM_TYPE target; 103 PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN); 104 target = PK11_AlgtagToMechanism(bulkalgtag); 105 if (bulkalgtag == SEC_OID_UNKNOWN || target == CKM_INVALID_MECHANISM) { 106 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 107 return NULL; 108 } 109 return PK11_PubUnwrapSymKey(privkey, encKey, target, CKA_DECRYPT, 0); 110 } 111 112 typedef struct RSA_OAEP_CMS_paramsStr RSA_OAEP_CMS_params; 113 struct RSA_OAEP_CMS_paramsStr { 114 SECAlgorithmID *hashFunc; 115 SECAlgorithmID *maskGenFunc; 116 SECAlgorithmID *pSourceFunc; 117 }; 118 119 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 120 SEC_ASN1_MKSUB(SEC_OctetStringTemplate) 121 122 static const SEC_ASN1Template seckey_PointerToAlgorithmIDTemplate[] = { 123 { SEC_ASN1_POINTER | SEC_ASN1_XTRN, 0, 124 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) } 125 }; 126 127 static const SEC_ASN1Template RSA_OAEP_CMS_paramsTemplate[] = { 128 { SEC_ASN1_SEQUENCE, 129 0, NULL, sizeof(RSA_OAEP_CMS_params) }, 130 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 131 SEC_ASN1_CONTEXT_SPECIFIC | 0, 132 offsetof(RSA_OAEP_CMS_params, hashFunc), 133 seckey_PointerToAlgorithmIDTemplate }, 134 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 135 SEC_ASN1_CONTEXT_SPECIFIC | 1, 136 offsetof(RSA_OAEP_CMS_params, maskGenFunc), 137 seckey_PointerToAlgorithmIDTemplate }, 138 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 139 SEC_ASN1_CONTEXT_SPECIFIC | 2, 140 offsetof(RSA_OAEP_CMS_params, pSourceFunc), 141 seckey_PointerToAlgorithmIDTemplate }, 142 { 0 } 143 }; 144 145 /* 146 * NSS_CMSUtil_DecryptSymKey_RSA_OAEP - unwrap a RSA-wrapped symmetric key 147 * 148 * this function takes an RSA-OAEP-wrapped symmetric key and unwraps it, returning a symmetric 149 * key handle. Please note that the actual unwrapped key data may not be allowed to leave 150 * a hardware token... 151 */ 152 PK11SymKey * 153 NSS_CMSUtil_DecryptSymKey_RSA_OAEP(SECKEYPrivateKey *privkey, SECItem *parameters, SECItem *encKey, SECOidTag bulkalgtag) 154 { 155 CK_RSA_PKCS_OAEP_PARAMS oaep_params; 156 RSA_OAEP_CMS_params encoded_params; 157 SECAlgorithmID mgf1hashAlg; 158 SECOidTag mgfAlgtag, pSourcetag; 159 SECItem encoding_params, params; 160 PK11SymKey *bulkkey = NULL; 161 SECStatus rv; 162 163 CK_MECHANISM_TYPE target; 164 PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN); 165 target = PK11_AlgtagToMechanism(bulkalgtag); 166 if (bulkalgtag == SEC_OID_UNKNOWN || target == CKM_INVALID_MECHANISM) { 167 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 168 return NULL; 169 } 170 171 PORT_Memset(&encoded_params, 0, sizeof(RSA_OAEP_CMS_params)); 172 PORT_Memset(&mgf1hashAlg, 0, sizeof(SECAlgorithmID)); 173 PORT_Memset(&encoding_params, 0, sizeof(SECItem)); 174 175 /* Set default values for the OAEP parameters */ 176 oaep_params.hashAlg = CKM_SHA_1; 177 oaep_params.mgf = CKG_MGF1_SHA1; 178 oaep_params.source = CKZ_DATA_SPECIFIED; 179 oaep_params.pSourceData = NULL; 180 oaep_params.ulSourceDataLen = 0; 181 182 if (parameters->len == 2) { 183 /* For some reason SEC_ASN1DecodeItem cannot process parameters if it is an emtpy SEQUENCE */ 184 /* Just check that this is a properly encoded empty SEQUENCE */ 185 /* TODO: Investigate if there a better way to handle this as part of decoding. */ 186 if ((parameters->data[0] != 0x30) || (parameters->data[1] != 0)) { 187 return NULL; 188 } 189 } else { 190 rv = SEC_ASN1DecodeItem(NULL, &encoded_params, RSA_OAEP_CMS_paramsTemplate, parameters); 191 if (rv != SECSuccess) { 192 goto loser; 193 } 194 if (encoded_params.hashFunc != NULL) { 195 oaep_params.hashAlg = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(encoded_params.hashFunc)); 196 } 197 if (encoded_params.maskGenFunc != NULL) { 198 mgfAlgtag = SECOID_GetAlgorithmTag(encoded_params.maskGenFunc); 199 if (mgfAlgtag != SEC_OID_PKCS1_MGF1) { 200 /* MGF1 is the only supported mask generation function */ 201 goto loser; 202 } 203 /* The parameters field contains an AlgorithmIdentifier specifying the 204 * hash function to use with MGF1. 205 */ 206 rv = SEC_ASN1DecodeItem(NULL, &mgf1hashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), 207 &encoded_params.maskGenFunc->parameters); 208 if (rv != SECSuccess) { 209 goto loser; 210 } 211 oaep_params.mgf = SEC_GetMgfTypeByOidTag(SECOID_GetAlgorithmTag(&mgf1hashAlg)); 212 if (!oaep_params.mgf) { 213 goto loser; 214 } 215 } 216 if (encoded_params.pSourceFunc != NULL) { 217 pSourcetag = SECOID_GetAlgorithmTag(encoded_params.pSourceFunc); 218 if (pSourcetag != SEC_OID_PKCS1_PSPECIFIED) { 219 goto loser; 220 } 221 /* The encoding parameters (P) are provided as an OCTET STRING in the parameters field. */ 222 if (encoded_params.pSourceFunc->parameters.len != 0) { 223 rv = SEC_ASN1DecodeItem(NULL, &encoding_params, SEC_ASN1_GET(SEC_OctetStringTemplate), 224 &encoded_params.pSourceFunc->parameters); 225 if (rv != SECSuccess) { 226 goto loser; 227 } 228 oaep_params.ulSourceDataLen = encoding_params.len; 229 oaep_params.pSourceData = encoding_params.data; 230 } 231 } 232 } 233 params.type = siBuffer; 234 params.data = (unsigned char *)&oaep_params; 235 params.len = sizeof(CK_RSA_PKCS_OAEP_PARAMS); 236 bulkkey = PK11_PubUnwrapSymKeyWithMechanism(privkey, CKM_RSA_PKCS_OAEP, ¶ms, 237 encKey, target, CKA_DECRYPT, 0); 238 239 loser: 240 PORT_Free(oaep_params.pSourceData); 241 if (encoded_params.hashFunc) { 242 SECOID_DestroyAlgorithmID(encoded_params.hashFunc, PR_TRUE); 243 } 244 if (encoded_params.maskGenFunc) { 245 SECOID_DestroyAlgorithmID(encoded_params.maskGenFunc, PR_TRUE); 246 } 247 if (encoded_params.pSourceFunc) { 248 SECOID_DestroyAlgorithmID(encoded_params.pSourceFunc, PR_TRUE); 249 } 250 SECOID_DestroyAlgorithmID(&mgf1hashAlg, PR_FALSE); 251 return bulkkey; 252 } 253 254 /* ====== ESECDH (Ephemeral-Static Elliptic Curve Diffie-Hellman) =========== */ 255 256 typedef struct ECC_CMS_SharedInfoStr ECC_CMS_SharedInfo; 257 struct ECC_CMS_SharedInfoStr { 258 SECAlgorithmID *keyInfo; /* key-encryption algorithm */ 259 SECItem entityUInfo; /* ukm */ 260 SECItem suppPubInfo; /* length of KEK in bits as 32-bit number */ 261 }; 262 263 static const SEC_ASN1Template ECC_CMS_SharedInfoTemplate[] = { 264 { SEC_ASN1_SEQUENCE, 265 0, NULL, sizeof(ECC_CMS_SharedInfo) }, 266 { SEC_ASN1_XTRN | SEC_ASN1_POINTER, 267 offsetof(ECC_CMS_SharedInfo, keyInfo), 268 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 269 { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | 270 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 271 offsetof(ECC_CMS_SharedInfo, entityUInfo), 272 SEC_ASN1_SUB(SEC_OctetStringTemplate) }, 273 { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | 274 SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2, 275 offsetof(ECC_CMS_SharedInfo, suppPubInfo), 276 SEC_ASN1_SUB(SEC_OctetStringTemplate) }, 277 { 0 } 278 }; 279 280 /* Inputs: 281 * keyInfo: key-encryption algorithm 282 * ukm: ukm field of KeyAgreeRecipientInfo 283 * KEKsize: length of KEK in bytes 284 * 285 * Output: DER encoded ECC-CMS-SharedInfo 286 */ 287 static SECItem * 288 Create_ECC_CMS_SharedInfo(PLArenaPool *poolp, 289 SECAlgorithmID *keyInfo, SECItem *ukm, unsigned int KEKsize) 290 { 291 ECC_CMS_SharedInfo SI; 292 unsigned char suppPubInfo[4] = { 0 }; 293 294 SI.keyInfo = keyInfo; 295 SI.entityUInfo.type = ukm->type; 296 SI.entityUInfo.data = ukm->data; 297 SI.entityUInfo.len = ukm->len; 298 299 SI.suppPubInfo.type = siBuffer; 300 SI.suppPubInfo.data = suppPubInfo; 301 SI.suppPubInfo.len = sizeof(suppPubInfo); 302 303 if (KEKsize > 0x1FFFFFFF) { // ensure KEKsize * 8 fits in 4 bytes. 304 return NULL; 305 } 306 KEKsize *= 8; 307 suppPubInfo[0] = (KEKsize & 0xFF000000) >> 24; 308 suppPubInfo[1] = (KEKsize & 0xFF0000) >> 16; 309 suppPubInfo[2] = (KEKsize & 0xFF00) >> 8; 310 suppPubInfo[3] = KEKsize & 0xFF; 311 312 return SEC_ASN1EncodeItem(poolp, NULL, &SI, ECC_CMS_SharedInfoTemplate); 313 } 314 315 /* this will generate a key pair, compute the shared secret, */ 316 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ 317 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. 318 * The ukm is optional per RFC 5753. Pass a NULL value to request an empty ukm. 319 * Pass a SECItem with the size set to zero, to request allocating a random 320 * ukm of a default size. Or provide an explicit ukm that was defined by the caller. 321 */ 322 SECStatus 323 NSS_CMSUtil_EncryptSymKey_ESECDH(PLArenaPool *poolp, CERTCertificate *cert, 324 PK11SymKey *bulkkey, SECItem *encKey, 325 PRBool genUkm, SECItem *ukm, 326 SECAlgorithmID *keyEncAlg, SECItem *pubKey, 327 void *wincx) 328 { 329 SECOidTag certalgtag; /* the certificate's encryption algorithm */ 330 SECStatus rv; 331 SECStatus err; 332 PK11SymKey *kek; 333 SECKEYPublicKey *publickey = NULL; 334 SECKEYPublicKey *ourPubKey = NULL; 335 SECKEYPrivateKey *ourPrivKey = NULL; 336 unsigned int bulkkey_size, kek_size; 337 SECAlgorithmID keyWrapAlg; 338 SECOidTag keyEncAlgtag; 339 SECItem keyWrapAlg_params, *keyEncAlg_params, *SharedInfo; 340 CK_MECHANISM_TYPE keyDerivationType, keyWrapMech; 341 CK_ULONG kdf; 342 343 if (genUkm && (ukm->len != 0 || ukm->data != NULL)) { 344 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); 345 return SECFailure; 346 } 347 348 certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); 349 PORT_Assert(certalgtag == SEC_OID_ANSIX962_EC_PUBLIC_KEY); 350 if (certalgtag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) { 351 return SECFailure; 352 } 353 354 /* Get the public key of the recipient. */ 355 publickey = CERT_ExtractPublicKey(cert); 356 if (publickey == NULL) 357 goto loser; 358 359 ourPrivKey = SECKEY_CreateECPrivateKey(&publickey->u.ec.DEREncodedParams, 360 &ourPubKey, wincx); 361 if (!ourPrivKey || !ourPubKey) { 362 goto loser; 363 } 364 365 rv = SECITEM_CopyItem(poolp, pubKey, &ourPubKey->u.ec.publicValue); 366 if (rv != SECSuccess) { 367 goto loser; 368 } 369 370 /* pubKey will be encoded as a BIT STRING, so pubKey->len must be length in bits 371 * rather than bytes */ 372 pubKey->len = pubKey->len * 8; 373 374 SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */ 375 ourPubKey = NULL; 376 377 bulkkey_size = PK11_GetKeyLength(bulkkey); 378 if (bulkkey_size == 0) { 379 goto loser; 380 } 381 382 /* Parameters are supposed to be absent for AES key wrap algorithms. 383 * However, Microsoft Outlook cannot decrypt message unless 384 * parameters field is NULL. */ 385 keyWrapAlg_params.len = 2; 386 keyWrapAlg_params.data = (unsigned char *)PORT_ArenaAlloc(poolp, keyWrapAlg_params.len); 387 if (keyWrapAlg_params.data == NULL) 388 goto loser; 389 390 keyWrapAlg_params.data[0] = SEC_ASN1_NULL; 391 keyWrapAlg_params.data[1] = 0; 392 393 /* RFC5753 specifies id-aes128-wrap as the mandatory to support algorithm. 394 * So, use id-aes128-wrap unless bulkkey provides more than 128 bits of 395 * security. If bulkkey provides more than 128 bits of security, use 396 * the algorithms from KE Set 2 in RFC 6318. */ 397 398 /* TODO: NIST Special Publication SP 800-56A requires the use of 399 * Cofactor ECDH. However, RFC 6318 specifies the use of 400 * dhSinglePass-stdDH-sha256kdf-scheme or dhSinglePass-stdDH-sha384kdf-scheme 401 * for Suite B. The reason for this is that all of the NIST recommended 402 * prime curves in FIPS 186-3 (including the Suite B curves) have a cofactor 403 * of 1, and so for these curves standard and cofactor ECDH are the same. 404 * This code should really look at the key's parameters and choose cofactor 405 * ECDH if the curve has a cofactor other than 1. */ 406 if ((PK11_GetMechanism(bulkkey) == CKM_AES_CBC) && (bulkkey_size > 16)) { 407 rv = SECOID_SetAlgorithmID(poolp, &keyWrapAlg, SEC_OID_AES_256_KEY_WRAP, &keyWrapAlg_params); 408 kek_size = 32; 409 keyWrapMech = CKM_NSS_AES_KEY_WRAP; 410 kdf = CKD_SHA384_KDF; 411 keyEncAlgtag = SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME; 412 keyDerivationType = CKM_ECDH1_DERIVE; 413 } else { 414 rv = SECOID_SetAlgorithmID(poolp, &keyWrapAlg, SEC_OID_AES_128_KEY_WRAP, &keyWrapAlg_params); 415 kek_size = 16; 416 keyWrapMech = CKM_NSS_AES_KEY_WRAP; 417 kdf = CKD_SHA256_KDF; 418 keyEncAlgtag = SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME; 419 keyDerivationType = CKM_ECDH1_DERIVE; 420 } 421 if (rv != SECSuccess) { 422 goto loser; 423 } 424 425 /* ukm is optional, but RFC 5753 says that originators SHOULD include the ukm. 426 * I made ukm 64 bytes, since RFC 2631 states that UserKeyingMaterial must 427 * contain 512 bits for Diffie-Hellman key agreement. */ 428 429 if (genUkm) { 430 ukm->type = siBuffer; 431 ukm->len = 64; 432 ukm->data = (unsigned char *)PORT_ArenaAlloc(poolp, ukm->len); 433 434 if (ukm->data == NULL) { 435 goto loser; 436 } 437 rv = PK11_GenerateRandom(ukm->data, ukm->len); 438 if (rv != SECSuccess) { 439 goto loser; 440 } 441 } 442 443 SharedInfo = Create_ECC_CMS_SharedInfo(poolp, &keyWrapAlg, 444 ukm, 445 kek_size); 446 if (!SharedInfo) { 447 goto loser; 448 } 449 450 /* Generate the KEK (key exchange key) according to RFC5753 which we use 451 * to wrap the bulk encryption key. */ 452 kek = PK11_PubDeriveWithKDF(ourPrivKey, publickey, PR_TRUE, 453 NULL, NULL, 454 keyDerivationType, keyWrapMech, 455 CKA_WRAP, kek_size, kdf, SharedInfo, NULL); 456 if (!kek) { 457 goto loser; 458 } 459 460 SECKEY_DestroyPublicKey(publickey); 461 SECKEY_DestroyPrivateKey(ourPrivKey); 462 publickey = NULL; 463 ourPrivKey = NULL; 464 465 /* allocate space for the encrypted CEK (bulk key) */ 466 /* AES key wrap produces an output 64-bits longer than 467 * the input AES CEK (RFC 3565, Section 2.3.2) */ 468 encKey->len = bulkkey_size + 8; 469 encKey->data = (unsigned char *)PORT_ArenaAlloc(poolp, encKey->len); 470 471 if (encKey->data == NULL) { 472 PK11_FreeSymKey(kek); 473 goto loser; 474 } 475 476 err = PK11_WrapSymKey(keyWrapMech, NULL, kek, bulkkey, encKey); 477 478 PK11_FreeSymKey(kek); /* we do not need the KEK anymore */ 479 if (err != SECSuccess) { 480 goto loser; 481 } 482 483 keyEncAlg_params = SEC_ASN1EncodeItem(poolp, NULL, &keyWrapAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); 484 if (keyEncAlg_params == NULL) 485 goto loser; 486 keyEncAlg_params->type = siBuffer; 487 488 /* now set keyEncAlg */ 489 rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, keyEncAlgtag, keyEncAlg_params); 490 if (rv != SECSuccess) { 491 goto loser; 492 } 493 494 return SECSuccess; 495 496 loser: 497 if (publickey) { 498 SECKEY_DestroyPublicKey(publickey); 499 } 500 if (ourPubKey) { 501 SECKEY_DestroyPublicKey(ourPubKey); 502 } 503 if (ourPrivKey) { 504 SECKEY_DestroyPrivateKey(ourPrivKey); 505 } 506 return SECFailure; 507 } 508 509 /* TODO: Move to pk11wrap and export? */ 510 static int 511 cms_GetKekSizeFromKeyWrapAlgTag(SECOidTag keyWrapAlgtag) 512 { 513 switch (keyWrapAlgtag) { 514 case SEC_OID_AES_128_KEY_WRAP: 515 return 16; 516 case SEC_OID_AES_192_KEY_WRAP: 517 return 24; 518 case SEC_OID_AES_256_KEY_WRAP: 519 return 32; 520 default: 521 break; 522 } 523 return 0; 524 } 525 526 /* TODO: Move to smimeutil and export? */ 527 static CK_ULONG 528 cms_GetKdfFromKeyEncAlgTag(SECOidTag keyEncAlgtag) 529 { 530 switch (keyEncAlgtag) { 531 case SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME: 532 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME: 533 return CKD_SHA1_KDF; 534 case SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME: 535 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME: 536 return CKD_SHA224_KDF; 537 case SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME: 538 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME: 539 return CKD_SHA256_KDF; 540 case SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME: 541 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME: 542 return CKD_SHA384_KDF; 543 case SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME: 544 case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME: 545 return CKD_SHA512_KDF; 546 default: 547 break; 548 } 549 return 0; 550 } 551 552 PK11SymKey * 553 NSS_CMSUtil_DecryptSymKey_ECDH(SECKEYPrivateKey *privkey, SECItem *encKey, 554 SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, 555 SECItem *ukm, NSSCMSOriginatorIdentifierOrKey *oiok, 556 void *wincx) 557 { 558 SECAlgorithmID keyWrapAlg; 559 SECOidTag keyEncAlgtag, keyWrapAlgtag; 560 CK_MECHANISM_TYPE target, keyDerivationType, keyWrapMech; 561 CK_ULONG kdf; 562 PK11SymKey *kek = NULL, *bulkkey = NULL; 563 int kek_size; 564 SECKEYPublicKey originatorpublickey; 565 SECItem *oiok_publicKey, *SharedInfo = NULL; 566 SECStatus rv; 567 568 PORT_Memset(&keyWrapAlg, 0, sizeof(SECAlgorithmID)); 569 570 PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN); 571 target = PK11_AlgtagToMechanism(bulkalgtag); 572 if (bulkalgtag == SEC_OID_UNKNOWN || target == CKM_INVALID_MECHANISM) { 573 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 574 goto loser; 575 } 576 577 keyEncAlgtag = SECOID_GetAlgorithmTag(keyEncAlg); 578 keyDerivationType = PK11_AlgtagToMechanism(keyEncAlgtag); 579 if ((keyEncAlgtag == SEC_OID_UNKNOWN) || 580 (keyDerivationType == CKM_INVALID_MECHANISM)) { 581 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 582 goto loser; 583 } 584 585 rv = SEC_ASN1DecodeItem(NULL, &keyWrapAlg, 586 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), &(keyEncAlg->parameters)); 587 if (rv != SECSuccess) { 588 goto loser; 589 } 590 591 keyWrapAlgtag = SECOID_GetAlgorithmTag(&keyWrapAlg); 592 keyWrapMech = PK11_AlgtagToMechanism(keyWrapAlgtag); 593 if ((keyWrapAlgtag == SEC_OID_UNKNOWN) || 594 (keyWrapMech == CKM_INVALID_MECHANISM)) { 595 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 596 goto loser; 597 } 598 599 kek_size = cms_GetKekSizeFromKeyWrapAlgTag(keyWrapAlgtag); 600 if (!kek_size) { 601 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 602 goto loser; 603 } 604 605 kdf = cms_GetKdfFromKeyEncAlgTag(keyEncAlgtag); 606 if (!kdf) { 607 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 608 goto loser; 609 } 610 611 /* Get originator's public key */ 612 /* TODO: Add support for static-static ECDH */ 613 if (oiok->identifierType != NSSCMSOriginatorIDOrKey_OriginatorPublicKey) { 614 PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE); 615 goto loser; 616 } 617 618 /* PK11_PubDeriveWithKDF only uses the keyType u.ec.publicValue.data 619 * and u.ec.publicValue.len from the originator's public key. */ 620 oiok_publicKey = &(oiok->id.originatorPublicKey.publicKey); 621 originatorpublickey.keyType = ecKey; 622 originatorpublickey.u.ec.publicValue.data = oiok_publicKey->data; 623 originatorpublickey.u.ec.publicValue.len = oiok_publicKey->len / 8; 624 625 SharedInfo = Create_ECC_CMS_SharedInfo(NULL, &keyWrapAlg, ukm, kek_size); 626 if (!SharedInfo) { 627 goto loser; 628 } 629 630 /* Generate the KEK (key exchange key) according to RFC5753 which we use 631 * to wrap the bulk encryption key. */ 632 kek = PK11_PubDeriveWithKDF(privkey, &originatorpublickey, PR_TRUE, 633 NULL, NULL, 634 keyDerivationType, keyWrapMech, 635 CKA_WRAP, kek_size, kdf, SharedInfo, wincx); 636 637 SECITEM_FreeItem(SharedInfo, PR_TRUE); 638 639 if (kek == NULL) { 640 goto loser; 641 } 642 643 bulkkey = PK11_UnwrapSymKey(kek, keyWrapMech, NULL, encKey, target, CKA_UNWRAP, 0); 644 PK11_FreeSymKey(kek); /* we do not need the KEK anymore */ 645 loser: 646 SECOID_DestroyAlgorithmID(&keyWrapAlg, PR_FALSE); 647 return bulkkey; 648 }