pk11hpke.c (42401B)
1 /* 2 * draft-irtf-cfrg-hpke-07 3 * 4 * This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 7 */ 8 9 #include "keyhi.h" 10 #include "pkcs11t.h" 11 #include "pk11func.h" 12 #include "pk11hpke.h" 13 #include "pk11pqg.h" 14 #include "secerr.h" 15 #include "secitem.h" 16 #include "secmod.h" 17 #include "secmodi.h" 18 #include "secmodti.h" 19 #include "secutil.h" 20 21 #define SERIALIZATION_VERSION 2 22 23 static const char *V1_LABEL = "HPKE-v1"; 24 static const char *EXP_LABEL = "exp"; 25 static const char *HPKE_LABEL = "HPKE"; 26 static const char *INFO_LABEL = "info_hash"; 27 static const char *KEM_LABEL = "KEM"; 28 static const char *KEY_LABEL = "key"; 29 static const char *NONCE_LABEL = "base_nonce"; 30 static const char *PSK_ID_LABEL = "psk_id_hash"; 31 static const char *SECRET_LABEL = "secret"; 32 static const char *SEC_LABEL = "sec"; 33 static const char *EAE_PRK_LABEL = "eae_prk"; 34 static const char *SH_SEC_LABEL = "shared_secret"; 35 36 struct HpkeContextStr { 37 const hpkeKemParams *kemParams; 38 const hpkeKdfParams *kdfParams; 39 const hpkeAeadParams *aeadParams; 40 PRUint8 mode; /* Base and PSK modes supported. */ 41 SECItem *encapPubKey; /* Marshalled public key, sent to receiver. */ 42 SECItem *baseNonce; /* Deterministic nonce for AEAD. */ 43 SECItem *pskId; /* PSK identifier (non-secret). */ 44 PK11Context *aeadContext; /* AEAD context used by Seal/Open. */ 45 PRUint64 sequenceNumber; /* seqNo for decrypt IV construction. */ 46 PK11SymKey *sharedSecret; /* ExtractAndExpand output key. */ 47 PK11SymKey *key; /* Key used with the AEAD. */ 48 PK11SymKey *exporterSecret; /* Derivation key for ExportSecret. */ 49 PK11SymKey *psk; /* PSK imported by the application. */ 50 }; 51 52 static const hpkeKemParams kemParams[] = { 53 /* KEM, Nsk, Nsecret, Npk, oidTag, Hash mechanism */ 54 { HpkeDhKemX25519Sha256, 32, 32, 32, SEC_OID_CURVE25519, CKM_SHA256 }, 55 }; 56 57 #define MAX_WRAPPED_EXP_LEN 72 // Largest kdfParams->Nh + 8 58 static const hpkeKdfParams kdfParams[] = { 59 /* KDF, Nh, mechanism */ 60 { HpkeKdfHkdfSha256, SHA256_LENGTH, CKM_SHA256 }, 61 { HpkeKdfHkdfSha384, SHA384_LENGTH, CKM_SHA384 }, 62 { HpkeKdfHkdfSha512, SHA512_LENGTH, CKM_SHA512 }, 63 }; 64 #define MAX_WRAPPED_KEY_LEN 40 // Largest aeadParams->Nk + 8 65 static const hpkeAeadParams aeadParams[] = { 66 /* AEAD, Nk, Nn, tagLen, mechanism */ 67 { HpkeAeadAes128Gcm, 16, 12, 16, CKM_AES_GCM }, 68 { HpkeAeadAes256Gcm, 32, 12, 16, CKM_AES_GCM }, 69 { HpkeAeadChaCha20Poly1305, 32, 12, 16, CKM_CHACHA20_POLY1305 }, 70 }; 71 72 static inline const hpkeKemParams * 73 kemId2Params(HpkeKemId kemId) 74 { 75 switch (kemId) { 76 case HpkeDhKemX25519Sha256: 77 return &kemParams[0]; 78 default: 79 return NULL; 80 } 81 } 82 83 static inline const hpkeKdfParams * 84 kdfId2Params(HpkeKdfId kdfId) 85 { 86 switch (kdfId) { 87 case HpkeKdfHkdfSha256: 88 return &kdfParams[0]; 89 case HpkeKdfHkdfSha384: 90 return &kdfParams[1]; 91 case HpkeKdfHkdfSha512: 92 return &kdfParams[2]; 93 default: 94 return NULL; 95 } 96 } 97 98 static const inline hpkeAeadParams * 99 aeadId2Params(HpkeAeadId aeadId) 100 { 101 switch (aeadId) { 102 case HpkeAeadAes128Gcm: 103 return &aeadParams[0]; 104 case HpkeAeadAes256Gcm: 105 return &aeadParams[1]; 106 case HpkeAeadChaCha20Poly1305: 107 return &aeadParams[2]; 108 default: 109 return NULL; 110 } 111 } 112 113 static PRUint8 * 114 encodeNumber(PRUint64 value, PRUint8 *b, size_t count) 115 { 116 PRUint64 encoded; 117 PORT_Assert(b && count > 0 && count <= sizeof(encoded)); 118 119 encoded = PR_htonll(value); 120 PORT_Memcpy(b, ((unsigned char *)(&encoded)) + (sizeof(encoded) - count), 121 count); 122 return b + count; 123 } 124 125 static PRUint8 * 126 decodeNumber(PRUint64 *value, PRUint8 *b, size_t count) 127 { 128 unsigned int i; 129 PRUint64 number = 0; 130 PORT_Assert(b && value && count <= sizeof(*value)); 131 132 for (i = 0; i < count; i++) { 133 number = (number << 8) + b[i]; 134 } 135 *value = number; 136 return b + count; 137 } 138 139 SECStatus 140 PK11_HPKE_ValidateParameters(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId) 141 { 142 /* If more variants are added, ensure the combination is also 143 * legal. For now it is, since only the AEAD may vary. */ 144 const hpkeKemParams *kem = kemId2Params(kemId); 145 const hpkeKdfParams *kdf = kdfId2Params(kdfId); 146 const hpkeAeadParams *aead = aeadId2Params(aeadId); 147 if (!kem || !kdf || !aead) { 148 PORT_SetError(SEC_ERROR_INVALID_ARGS); 149 return SECFailure; 150 } 151 return SECSuccess; 152 } 153 154 HpkeContext * 155 PK11_HPKE_NewContext(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId, 156 PK11SymKey *psk, const SECItem *pskId) 157 { 158 SECStatus rv = SECSuccess; 159 PK11SlotInfo *slot = NULL; 160 HpkeContext *cx = NULL; 161 /* Both the PSK and the PSK ID default to empty. */ 162 SECItem emptyItem = { siBuffer, NULL, 0 }; 163 164 cx = PORT_ZNew(HpkeContext); 165 if (!cx) { 166 return NULL; 167 } 168 cx->mode = psk ? HpkeModePsk : HpkeModeBase; 169 cx->kemParams = kemId2Params(kemId); 170 cx->kdfParams = kdfId2Params(kdfId); 171 cx->aeadParams = aeadId2Params(aeadId); 172 CHECK_FAIL_ERR((!!psk != !!pskId), SEC_ERROR_INVALID_ARGS); 173 CHECK_FAIL_ERR(!cx->kemParams || !cx->kdfParams || !cx->aeadParams, 174 SEC_ERROR_INVALID_ARGS); 175 176 /* Import the provided PSK or the default. */ 177 slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL); 178 CHECK_FAIL(!slot); 179 if (psk) { 180 cx->psk = PK11_ReferenceSymKey(psk); 181 cx->pskId = SECITEM_DupItem(pskId); 182 } else { 183 cx->psk = PK11_ImportDataKey(slot, CKM_HKDF_DATA, PK11_OriginUnwrap, 184 CKA_DERIVE, &emptyItem, NULL); 185 cx->pskId = SECITEM_DupItem(&emptyItem); 186 } 187 CHECK_FAIL(!cx->psk); 188 CHECK_FAIL(!cx->pskId); 189 190 CLEANUP: 191 if (rv != SECSuccess) { 192 PK11_FreeSymKey(cx->psk); 193 SECITEM_FreeItem(cx->pskId, PR_TRUE); 194 cx->pskId = NULL; 195 cx->psk = NULL; 196 PORT_Free(cx); 197 cx = NULL; 198 } 199 if (slot) { 200 PK11_FreeSlot(slot); 201 } 202 return cx; 203 } 204 205 void 206 PK11_HPKE_DestroyContext(HpkeContext *cx, PRBool freeit) 207 { 208 if (!cx) { 209 return; 210 } 211 212 if (cx->aeadContext) { 213 PK11_DestroyContext((PK11Context *)cx->aeadContext, PR_TRUE); 214 cx->aeadContext = NULL; 215 } 216 PK11_FreeSymKey(cx->exporterSecret); 217 PK11_FreeSymKey(cx->sharedSecret); 218 PK11_FreeSymKey(cx->key); 219 PK11_FreeSymKey(cx->psk); 220 SECITEM_FreeItem(cx->pskId, PR_TRUE); 221 SECITEM_FreeItem(cx->baseNonce, PR_TRUE); 222 SECITEM_FreeItem(cx->encapPubKey, PR_TRUE); 223 cx->exporterSecret = NULL; 224 cx->sharedSecret = NULL; 225 cx->key = NULL; 226 cx->psk = NULL; 227 cx->pskId = NULL; 228 cx->baseNonce = NULL; 229 cx->encapPubKey = NULL; 230 if (freeit) { 231 PORT_ZFree(cx, sizeof(HpkeContext)); 232 } 233 } 234 235 /* Export Format: 236 struct { 237 uint8 serilizationVersion; 238 uint16 kemId; 239 uint16 kdfId; 240 uint16 aeadId; 241 uint16 modeId; 242 uint64 sequenceNumber; 243 opaque senderPubKey<1..2^16-1>; 244 opaque baseNonce<1..2^16-1>; 245 opaque key<1..2^16-1>; 246 opaque exporterSecret<1..2^16-1>; 247 } HpkeSerializedContext 248 */ 249 #define EXPORTED_CTX_BASE_LEN 25 /* Fixed size plus 2B for each variable. */ 250 #define REMAINING_BYTES(walker, buf) \ 251 buf->len - (walker - buf->data) 252 SECStatus 253 PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **serialized) 254 { 255 SECStatus rv; 256 size_t allocLen; 257 PRUint8 *walker; 258 SECItem *keyBytes = NULL; // Maybe wrapped 259 SECItem *exporterBytes = NULL; // Maybe wrapped 260 SECItem *serializedCx = NULL; 261 PRUint8 wrappedKeyBytes[MAX_WRAPPED_KEY_LEN] = { 0 }; 262 PRUint8 wrappedExpBytes[MAX_WRAPPED_EXP_LEN] = { 0 }; 263 SECItem wrappedKey = { siBuffer, wrappedKeyBytes, sizeof(wrappedKeyBytes) }; 264 SECItem wrappedExp = { siBuffer, wrappedExpBytes, sizeof(wrappedExpBytes) }; 265 266 CHECK_FAIL_ERR((!cx || !cx->aeadContext || !serialized), SEC_ERROR_INVALID_ARGS); 267 CHECK_FAIL_ERR((cx->aeadContext->operation != (CKA_NSS_MESSAGE | CKA_DECRYPT)), 268 SEC_ERROR_NOT_A_RECIPIENT); 269 270 /* If a wrapping key was provided, do the wrap first 271 * so that we know what size to allocate. */ 272 if (wrapKey) { 273 rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP, NULL, wrapKey, 274 cx->key, &wrappedKey); 275 CHECK_RV(rv); 276 rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP, NULL, wrapKey, 277 cx->exporterSecret, &wrappedExp); 278 CHECK_RV(rv); 279 280 keyBytes = &wrappedKey; 281 exporterBytes = &wrappedExp; 282 } else { 283 rv = PK11_ExtractKeyValue(cx->key); 284 CHECK_RV(rv); 285 keyBytes = PK11_GetKeyData(cx->key); 286 CHECK_FAIL(!keyBytes); 287 PORT_Assert(keyBytes->len == cx->aeadParams->Nk); 288 289 rv = PK11_ExtractKeyValue(cx->exporterSecret); 290 CHECK_RV(rv); 291 exporterBytes = PK11_GetKeyData(cx->exporterSecret); 292 CHECK_FAIL(!exporterBytes); 293 PORT_Assert(exporterBytes->len == cx->kdfParams->Nh); 294 } 295 296 allocLen = EXPORTED_CTX_BASE_LEN + cx->baseNonce->len + cx->encapPubKey->len; 297 allocLen += wrapKey ? wrappedKey.len : cx->aeadParams->Nk; 298 allocLen += wrapKey ? wrappedExp.len : cx->kdfParams->Nh; 299 300 serializedCx = SECITEM_AllocItem(NULL, NULL, allocLen); 301 CHECK_FAIL(!serializedCx); 302 303 walker = &serializedCx->data[0]; 304 *(walker)++ = (PRUint8)SERIALIZATION_VERSION; 305 306 walker = encodeNumber(cx->kemParams->id, walker, 2); 307 walker = encodeNumber(cx->kdfParams->id, walker, 2); 308 walker = encodeNumber(cx->aeadParams->id, walker, 2); 309 walker = encodeNumber(cx->mode, walker, 2); 310 walker = encodeNumber(cx->sequenceNumber, walker, 8); 311 312 /* sender public key, serialized. */ 313 walker = encodeNumber(cx->encapPubKey->len, walker, 2); 314 PORT_Memcpy(walker, cx->encapPubKey->data, cx->encapPubKey->len); 315 walker += cx->encapPubKey->len; 316 317 /* base nonce */ 318 walker = encodeNumber(cx->baseNonce->len, walker, 2); 319 PORT_Memcpy(walker, cx->baseNonce->data, cx->baseNonce->len); 320 walker += cx->baseNonce->len; 321 322 /* key. */ 323 walker = encodeNumber(keyBytes->len, walker, 2); 324 PORT_Memcpy(walker, keyBytes->data, keyBytes->len); 325 walker += keyBytes->len; 326 327 /* exporter_secret. */ 328 walker = encodeNumber(exporterBytes->len, walker, 2); 329 PORT_Memcpy(walker, exporterBytes->data, exporterBytes->len); 330 walker += exporterBytes->len; 331 332 CHECK_FAIL_ERR(REMAINING_BYTES(walker, serializedCx) != 0, 333 SEC_ERROR_LIBRARY_FAILURE); 334 *serialized = serializedCx; 335 336 CLEANUP: 337 if (rv != SECSuccess) { 338 SECITEM_ZfreeItem(serializedCx, PR_TRUE); 339 } 340 return rv; 341 } 342 343 HpkeContext * 344 PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey) 345 { 346 SECStatus rv = SECSuccess; 347 HpkeContext *cx = NULL; 348 PRUint8 *walker; 349 PRUint64 tmpn; 350 PRUint8 tmp8; 351 HpkeKemId kem; 352 HpkeKdfId kdf; 353 HpkeAeadId aead; 354 PK11SlotInfo *slot = NULL; 355 PK11SymKey *tmpKey = NULL; 356 SECItem tmpItem = { siBuffer, NULL, 0 }; 357 SECItem emptyItem = { siBuffer, NULL, 0 }; 358 359 CHECK_FAIL_ERR((!serialized || !serialized->data || serialized->len == 0), 360 SEC_ERROR_INVALID_ARGS); 361 CHECK_FAIL_ERR((serialized->len < EXPORTED_CTX_BASE_LEN), SEC_ERROR_BAD_DATA); 362 363 walker = serialized->data; 364 365 tmp8 = *(walker++); 366 CHECK_FAIL_ERR((tmp8 != SERIALIZATION_VERSION), SEC_ERROR_BAD_DATA); 367 368 walker = decodeNumber(&tmpn, walker, 2); 369 kem = (HpkeKemId)tmpn; 370 371 walker = decodeNumber(&tmpn, walker, 2); 372 kdf = (HpkeKdfId)tmpn; 373 374 walker = decodeNumber(&tmpn, walker, 2); 375 aead = (HpkeAeadId)tmpn; 376 377 /* Create context. We'll manually set the mode, though we 378 * no longer have the PSK and have no need for it. */ 379 cx = PK11_HPKE_NewContext(kem, kdf, aead, NULL, NULL); 380 CHECK_FAIL(!cx); 381 382 walker = decodeNumber(&tmpn, walker, 2); 383 CHECK_FAIL_ERR((tmpn != HpkeModeBase && tmpn != HpkeModePsk), 384 SEC_ERROR_BAD_DATA); 385 cx->mode = (HpkeModeId)tmpn; 386 387 walker = decodeNumber(&cx->sequenceNumber, walker, 8); 388 slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL); 389 CHECK_FAIL(!slot); 390 391 /* Import sender public key (serialized). */ 392 walker = decodeNumber(&tmpn, walker, 2); 393 CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized), 394 SEC_ERROR_BAD_DATA); 395 tmpItem.data = walker; 396 tmpItem.len = tmpn; 397 cx->encapPubKey = SECITEM_DupItem(&tmpItem); 398 CHECK_FAIL(!cx->encapPubKey); 399 walker += tmpItem.len; 400 401 /* Import base_nonce. */ 402 walker = decodeNumber(&tmpn, walker, 2); 403 CHECK_FAIL_ERR(tmpn != cx->aeadParams->Nn, SEC_ERROR_BAD_DATA); 404 CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized), 405 SEC_ERROR_BAD_DATA); 406 tmpItem.data = walker; 407 tmpItem.len = tmpn; 408 cx->baseNonce = SECITEM_DupItem(&tmpItem); 409 CHECK_FAIL(!cx->baseNonce); 410 walker += tmpItem.len; 411 412 /* Import key */ 413 walker = decodeNumber(&tmpn, walker, 2); 414 CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized), 415 SEC_ERROR_BAD_DATA); 416 tmpItem.data = walker; 417 tmpItem.len = tmpn; 418 walker += tmpItem.len; 419 if (wrapKey) { 420 cx->key = PK11_UnwrapSymKey(wrapKey, CKM_AES_KEY_WRAP_KWP, 421 NULL, &tmpItem, cx->aeadParams->mech, 422 CKA_NSS_MESSAGE | CKA_DECRYPT, 0); 423 CHECK_FAIL(!cx->key); 424 } else { 425 CHECK_FAIL_ERR(tmpn != cx->aeadParams->Nk, SEC_ERROR_BAD_DATA); 426 tmpKey = PK11_ImportSymKey(slot, cx->aeadParams->mech, 427 PK11_OriginUnwrap, CKA_NSS_MESSAGE | CKA_DECRYPT, 428 &tmpItem, NULL); 429 CHECK_FAIL(!tmpKey); 430 cx->key = tmpKey; 431 } 432 433 /* Import exporter_secret. */ 434 walker = decodeNumber(&tmpn, walker, 2); 435 CHECK_FAIL_ERR(tmpn != REMAINING_BYTES(walker, serialized), 436 SEC_ERROR_BAD_DATA); 437 tmpItem.data = walker; 438 tmpItem.len = tmpn; 439 walker += tmpItem.len; 440 441 if (wrapKey) { 442 cx->exporterSecret = PK11_UnwrapSymKey(wrapKey, CKM_AES_KEY_WRAP_KWP, 443 NULL, &tmpItem, cx->kdfParams->mech, 444 CKM_HKDF_DERIVE, 0); 445 CHECK_FAIL(!cx->exporterSecret); 446 } else { 447 CHECK_FAIL_ERR(tmpn != cx->kdfParams->Nh, SEC_ERROR_BAD_DATA); 448 tmpKey = PK11_ImportSymKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap, 449 CKA_DERIVE, &tmpItem, NULL); 450 CHECK_FAIL(!tmpKey); 451 cx->exporterSecret = tmpKey; 452 } 453 454 cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech, 455 CKA_NSS_MESSAGE | CKA_DECRYPT, 456 cx->key, &emptyItem); 457 458 CLEANUP: 459 if (rv != SECSuccess) { 460 PK11_FreeSymKey(tmpKey); 461 PK11_HPKE_DestroyContext(cx, PR_TRUE); 462 cx = NULL; 463 } 464 if (slot) { 465 PK11_FreeSlot(slot); 466 } 467 468 return cx; 469 } 470 471 SECStatus 472 PK11_HPKE_Serialize(const SECKEYPublicKey *pk, PRUint8 *buf, unsigned int *len, unsigned int maxLen) 473 { 474 if (!pk || !len || pk->keyType != ecKey) { 475 PORT_SetError(SEC_ERROR_INVALID_ARGS); 476 return SECFailure; 477 } 478 479 /* If no buffer provided, return the length required for 480 * the serialized public key. */ 481 if (!buf) { 482 *len = pk->u.ec.publicValue.len; 483 return SECSuccess; 484 } 485 486 if (maxLen < pk->u.ec.publicValue.len) { 487 PORT_SetError(SEC_ERROR_INPUT_LEN); 488 return SECFailure; 489 } 490 491 PORT_Memcpy(buf, pk->u.ec.publicValue.data, pk->u.ec.publicValue.len); 492 *len = pk->u.ec.publicValue.len; 493 return SECSuccess; 494 }; 495 496 SECStatus 497 PK11_HPKE_Deserialize(const HpkeContext *cx, const PRUint8 *enc, 498 unsigned int encLen, SECKEYPublicKey **outPubKey) 499 { 500 SECStatus rv; 501 SECKEYPublicKey *pubKey = NULL; 502 SECOidData *oidData = NULL; 503 PLArenaPool *arena; 504 505 if (!cx || !enc || encLen == 0 || !outPubKey) { 506 PORT_SetError(SEC_ERROR_INVALID_ARGS); 507 return SECFailure; 508 } 509 510 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 511 CHECK_FAIL(!arena); 512 pubKey = PORT_ArenaZNew(arena, SECKEYPublicKey); 513 CHECK_FAIL(!pubKey); 514 515 pubKey->arena = arena; 516 pubKey->keyType = ecKey; 517 pubKey->pkcs11Slot = NULL; 518 pubKey->pkcs11ID = CK_INVALID_HANDLE; 519 520 rv = SECITEM_MakeItem(pubKey->arena, &pubKey->u.ec.publicValue, 521 enc, encLen); 522 CHECK_RV(rv); 523 pubKey->u.ec.encoding = ECPoint_Undefined; 524 pubKey->u.ec.size = 0; 525 526 oidData = SECOID_FindOIDByTag(cx->kemParams->oidTag); 527 CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM); 528 529 // Create parameters. 530 CHECK_FAIL(!SECITEM_AllocItem(pubKey->arena, &pubKey->u.ec.DEREncodedParams, 531 2 + oidData->oid.len)); 532 533 // Set parameters. 534 pubKey->u.ec.DEREncodedParams.data[0] = SEC_ASN1_OBJECT_ID; 535 pubKey->u.ec.DEREncodedParams.data[1] = oidData->oid.len; 536 PORT_Memcpy(pubKey->u.ec.DEREncodedParams.data + 2, oidData->oid.data, oidData->oid.len); 537 *outPubKey = pubKey; 538 539 CLEANUP: 540 if (rv != SECSuccess) { 541 SECKEY_DestroyPublicKey(pubKey); 542 } 543 return rv; 544 }; 545 546 static SECStatus 547 pk11_hpke_CheckKeys(const HpkeContext *cx, const SECKEYPublicKey *pk, 548 const SECKEYPrivateKey *sk) 549 { 550 SECOidTag pkTag; 551 unsigned int i; 552 if (pk->keyType != ecKey || (sk && sk->keyType != ecKey)) { 553 PORT_SetError(SEC_ERROR_BAD_KEY); 554 return SECFailure; 555 } 556 pkTag = SECKEY_GetECCOid(&pk->u.ec.DEREncodedParams); 557 if (pkTag != cx->kemParams->oidTag) { 558 PORT_SetError(SEC_ERROR_BAD_KEY); 559 return SECFailure; 560 } 561 for (i = 0; i < PR_ARRAY_SIZE(kemParams); i++) { 562 if (cx->kemParams->oidTag == kemParams[i].oidTag) { 563 return SECSuccess; 564 } 565 } 566 567 return SECFailure; 568 } 569 570 static SECStatus 571 pk11_hpke_GenerateKeyPair(const HpkeContext *cx, SECKEYPublicKey **pkE, 572 SECKEYPrivateKey **skE) 573 { 574 SECStatus rv = SECSuccess; 575 SECKEYPrivateKey *privKey = NULL; 576 SECKEYPublicKey *pubKey = NULL; 577 SECOidData *oidData = NULL; 578 SECKEYECParams ecp; 579 PK11SlotInfo *slot = NULL; 580 ecp.data = NULL; 581 PORT_Assert(cx && skE && pkE); 582 583 oidData = SECOID_FindOIDByTag(cx->kemParams->oidTag); 584 CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM); 585 ecp.data = PORT_Alloc(2 + oidData->oid.len); 586 CHECK_FAIL(!ecp.data); 587 588 ecp.len = 2 + oidData->oid.len; 589 ecp.type = siDEROID; 590 ecp.data[0] = SEC_ASN1_OBJECT_ID; 591 ecp.data[1] = oidData->oid.len; 592 PORT_Memcpy(&ecp.data[2], oidData->oid.data, oidData->oid.len); 593 594 slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL); 595 CHECK_FAIL(!slot); 596 597 privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &ecp, &pubKey, 598 PR_FALSE, PR_TRUE, NULL); 599 CHECK_FAIL_ERR((!privKey || !pubKey), SEC_ERROR_KEYGEN_FAIL); 600 PORT_Assert(rv == SECSuccess); 601 *skE = privKey; 602 *pkE = pubKey; 603 604 CLEANUP: 605 if (rv != SECSuccess) { 606 SECKEY_DestroyPrivateKey(privKey); 607 SECKEY_DestroyPublicKey(pubKey); 608 } 609 if (slot) { 610 PK11_FreeSlot(slot); 611 } 612 PORT_Free(ecp.data); 613 return rv; 614 } 615 616 static inline SECItem * 617 pk11_hpke_MakeExtractLabel(const char *prefix, unsigned int prefixLen, 618 const char *label, unsigned int labelLen, 619 const SECItem *suiteId, const SECItem *ikm) 620 { 621 SECItem *out = NULL; 622 PRUint8 *walker; 623 out = SECITEM_AllocItem(NULL, NULL, prefixLen + labelLen + suiteId->len + (ikm ? ikm->len : 0)); 624 if (!out) { 625 return NULL; 626 } 627 628 walker = out->data; 629 PORT_Memcpy(walker, prefix, prefixLen); 630 walker += prefixLen; 631 PORT_Memcpy(walker, suiteId->data, suiteId->len); 632 walker += suiteId->len; 633 PORT_Memcpy(walker, label, labelLen); 634 walker += labelLen; 635 if (ikm && ikm->data) { 636 PORT_Memcpy(walker, ikm->data, ikm->len); 637 } 638 639 return out; 640 } 641 642 static SECStatus 643 pk11_hpke_LabeledExtractData(const HpkeContext *cx, SECItem *salt, 644 const SECItem *suiteId, const char *label, 645 unsigned int labelLen, const SECItem *ikm, SECItem **out) 646 { 647 SECStatus rv; 648 CK_HKDF_PARAMS params = { 0 }; 649 PK11SymKey *importedIkm = NULL; 650 PK11SymKey *prk = NULL; 651 PK11SlotInfo *slot = NULL; 652 SECItem *borrowed; 653 SECItem *outDerived = NULL; 654 SECItem *labeledIkm; 655 SECItem paramsItem = { siBuffer, (unsigned char *)¶ms, 656 sizeof(params) }; 657 PORT_Assert(cx && ikm && label && labelLen && out && suiteId); 658 659 labeledIkm = pk11_hpke_MakeExtractLabel(V1_LABEL, strlen(V1_LABEL), label, labelLen, suiteId, ikm); 660 CHECK_FAIL(!labeledIkm); 661 params.bExtract = CK_TRUE; 662 params.bExpand = CK_FALSE; 663 params.prfHashMechanism = cx->kdfParams->mech; 664 params.ulSaltType = salt ? CKF_HKDF_SALT_DATA : CKF_HKDF_SALT_NULL; 665 params.pSalt = salt ? (CK_BYTE_PTR)salt->data : NULL; 666 params.ulSaltLen = salt ? salt->len : 0; 667 params.pInfo = labeledIkm->data; 668 params.ulInfoLen = labeledIkm->len; 669 670 slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL); 671 CHECK_FAIL(!slot); 672 673 importedIkm = PK11_ImportDataKey(slot, CKM_HKDF_DATA, PK11_OriginUnwrap, 674 CKA_DERIVE, labeledIkm, NULL); 675 CHECK_FAIL(!importedIkm); 676 prk = PK11_Derive(importedIkm, CKM_HKDF_DATA, ¶msItem, 677 CKM_HKDF_DERIVE, CKA_DERIVE, 0); 678 CHECK_FAIL(!prk); 679 rv = PK11_ExtractKeyValue(prk); 680 CHECK_RV(rv); 681 borrowed = PK11_GetKeyData(prk); 682 CHECK_FAIL(!borrowed); 683 outDerived = SECITEM_DupItem(borrowed); 684 CHECK_FAIL(!outDerived); 685 686 *out = outDerived; 687 688 CLEANUP: 689 PK11_FreeSymKey(importedIkm); 690 PK11_FreeSymKey(prk); 691 SECITEM_FreeItem(labeledIkm, PR_TRUE); 692 if (slot) { 693 PK11_FreeSlot(slot); 694 } 695 return rv; 696 } 697 698 static SECStatus 699 pk11_hpke_LabeledExtract(const HpkeContext *cx, PK11SymKey *salt, 700 const SECItem *suiteId, const char *label, CK_MECHANISM_TYPE hashMech, 701 unsigned int labelLen, PK11SymKey *ikm, PK11SymKey **out) 702 { 703 SECStatus rv = SECSuccess; 704 SECItem *innerLabel = NULL; 705 PK11SymKey *labeledIkm = NULL; 706 PK11SymKey *prk = NULL; 707 CK_HKDF_PARAMS params = { 0 }; 708 CK_KEY_DERIVATION_STRING_DATA labelData; 709 SECItem labelDataItem = { siBuffer, NULL, 0 }; 710 SECItem paramsItem = { siBuffer, (unsigned char *)¶ms, 711 sizeof(params) }; 712 PORT_Assert(cx && ikm && label && labelLen && out && suiteId); 713 714 innerLabel = pk11_hpke_MakeExtractLabel(V1_LABEL, strlen(V1_LABEL), label, labelLen, suiteId, NULL); 715 CHECK_FAIL(!innerLabel); 716 labelData.pData = innerLabel->data; 717 labelData.ulLen = innerLabel->len; 718 labelDataItem.data = (PRUint8 *)&labelData; 719 labelDataItem.len = sizeof(labelData); 720 labeledIkm = PK11_Derive(ikm, CKM_CONCATENATE_DATA_AND_BASE, 721 &labelDataItem, CKM_GENERIC_SECRET_KEY_GEN, CKA_DERIVE, 0); 722 CHECK_FAIL(!labeledIkm); 723 724 params.bExtract = CK_TRUE; 725 params.bExpand = CK_FALSE; 726 params.prfHashMechanism = hashMech; 727 params.ulSaltType = salt ? CKF_HKDF_SALT_KEY : CKF_HKDF_SALT_NULL; 728 params.hSaltKey = salt ? PK11_GetSymKeyHandle(salt) : CK_INVALID_HANDLE; 729 730 prk = PK11_Derive(labeledIkm, CKM_HKDF_DERIVE, ¶msItem, 731 CKM_HKDF_DERIVE, CKA_DERIVE, 0); 732 CHECK_FAIL(!prk); 733 *out = prk; 734 735 CLEANUP: 736 PK11_FreeSymKey(labeledIkm); 737 SECITEM_ZfreeItem(innerLabel, PR_TRUE); 738 return rv; 739 } 740 741 static SECStatus 742 pk11_hpke_LabeledExpand(const HpkeContext *cx, PK11SymKey *prk, const SECItem *suiteId, 743 const char *label, unsigned int labelLen, const SECItem *info, 744 unsigned int L, CK_MECHANISM_TYPE hashMech, PK11SymKey **outKey, 745 SECItem **outItem) 746 { 747 SECStatus rv = SECSuccess; 748 CK_MECHANISM_TYPE keyMech; 749 CK_MECHANISM_TYPE deriveMech; 750 CK_HKDF_PARAMS params = { 0 }; 751 PK11SymKey *derivedKey = NULL; 752 SECItem *labeledInfoItem = NULL; 753 SECItem paramsItem = { siBuffer, (unsigned char *)¶ms, 754 sizeof(params) }; 755 SECItem *derivedKeyData; 756 PRUint8 encodedL[2]; 757 PRUint8 *walker = encodedL; 758 size_t len; 759 PORT_Assert(cx && prk && label && (!!outKey != !!outItem)); 760 761 walker = encodeNumber(L, walker, 2); 762 len = info ? info->len : 0; 763 len += sizeof(encodedL) + strlen(V1_LABEL) + suiteId->len + labelLen; 764 labeledInfoItem = SECITEM_AllocItem(NULL, NULL, len); 765 CHECK_FAIL(!labeledInfoItem); 766 767 walker = labeledInfoItem->data; 768 PORT_Memcpy(walker, encodedL, sizeof(encodedL)); 769 walker += sizeof(encodedL); 770 PORT_Memcpy(walker, V1_LABEL, strlen(V1_LABEL)); 771 walker += strlen(V1_LABEL); 772 PORT_Memcpy(walker, suiteId->data, suiteId->len); 773 walker += suiteId->len; 774 PORT_Memcpy(walker, label, labelLen); 775 walker += labelLen; 776 if (info) { 777 PORT_Memcpy(walker, info->data, info->len); 778 } 779 780 params.bExtract = CK_FALSE; 781 params.bExpand = CK_TRUE; 782 params.prfHashMechanism = hashMech; 783 params.ulSaltType = CKF_HKDF_SALT_NULL; 784 params.pInfo = labeledInfoItem->data; 785 params.ulInfoLen = labeledInfoItem->len; 786 deriveMech = outItem ? CKM_HKDF_DATA : CKM_HKDF_DERIVE; 787 /* If we're expanding to the encryption key use the appropriate mechanism. */ 788 keyMech = (label && !strcmp(KEY_LABEL, label)) ? cx->aeadParams->mech : CKM_HKDF_DERIVE; 789 790 derivedKey = PK11_Derive(prk, deriveMech, ¶msItem, keyMech, CKA_DERIVE, L); 791 CHECK_FAIL(!derivedKey); 792 793 if (outItem) { 794 /* Don't allow export of real keys. */ 795 CHECK_FAIL_ERR(deriveMech != CKM_HKDF_DATA, SEC_ERROR_LIBRARY_FAILURE); 796 rv = PK11_ExtractKeyValue(derivedKey); 797 CHECK_RV(rv); 798 derivedKeyData = PK11_GetKeyData(derivedKey); 799 CHECK_FAIL_ERR((!derivedKeyData), SEC_ERROR_NO_KEY); 800 *outItem = SECITEM_DupItem(derivedKeyData); 801 CHECK_FAIL(!*outItem); 802 PK11_FreeSymKey(derivedKey); 803 } else { 804 *outKey = derivedKey; 805 } 806 807 CLEANUP: 808 if (rv != SECSuccess) { 809 PK11_FreeSymKey(derivedKey); 810 } 811 SECITEM_ZfreeItem(labeledInfoItem, PR_TRUE); 812 return rv; 813 } 814 815 static SECStatus 816 pk11_hpke_ExtractAndExpand(const HpkeContext *cx, PK11SymKey *ikm, 817 const SECItem *kemContext, PK11SymKey **out) 818 { 819 SECStatus rv; 820 PK11SymKey *eaePrk = NULL; 821 PK11SymKey *sharedSecret = NULL; 822 PRUint8 suiteIdBuf[5]; 823 PRUint8 *walker; 824 PORT_Memcpy(suiteIdBuf, KEM_LABEL, strlen(KEM_LABEL)); 825 SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) }; 826 PORT_Assert(cx && ikm && kemContext && out); 827 828 walker = &suiteIdBuf[3]; 829 walker = encodeNumber(cx->kemParams->id, walker, 2); 830 831 rv = pk11_hpke_LabeledExtract(cx, NULL, &suiteIdItem, EAE_PRK_LABEL, 832 cx->kemParams->hashMech, strlen(EAE_PRK_LABEL), 833 ikm, &eaePrk); 834 CHECK_RV(rv); 835 836 rv = pk11_hpke_LabeledExpand(cx, eaePrk, &suiteIdItem, SH_SEC_LABEL, strlen(SH_SEC_LABEL), 837 kemContext, cx->kemParams->Nsecret, cx->kemParams->hashMech, 838 &sharedSecret, NULL); 839 CHECK_RV(rv); 840 *out = sharedSecret; 841 842 CLEANUP: 843 if (rv != SECSuccess) { 844 PK11_FreeSymKey(sharedSecret); 845 } 846 PK11_FreeSymKey(eaePrk); 847 return rv; 848 } 849 850 static SECStatus 851 pk11_hpke_Encap(HpkeContext *cx, const SECKEYPublicKey *pkE, SECKEYPrivateKey *skE, 852 SECKEYPublicKey *pkR) 853 { 854 SECStatus rv; 855 PK11SymKey *dh = NULL; 856 SECItem *kemContext = NULL; 857 SECItem *encPkR = NULL; 858 unsigned int tmpLen; 859 860 PORT_Assert(cx && skE && pkE && pkR); 861 862 rv = pk11_hpke_CheckKeys(cx, pkE, skE); 863 CHECK_RV(rv); 864 rv = pk11_hpke_CheckKeys(cx, pkR, NULL); 865 CHECK_RV(rv); 866 867 dh = PK11_PubDeriveWithKDF(skE, pkR, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, 868 CKM_SHA512_HMAC /* unused */, CKA_DERIVE, 0, 869 CKD_NULL, NULL, NULL); 870 CHECK_FAIL(!dh); 871 872 /* Encapsulate our sender public key. Many use cases 873 * (including ECH) require that the application fetch 874 * this value, so do it once and store into the cx. */ 875 rv = PK11_HPKE_Serialize(pkE, NULL, &tmpLen, 0); 876 CHECK_RV(rv); 877 cx->encapPubKey = SECITEM_AllocItem(NULL, NULL, tmpLen); 878 CHECK_FAIL(!cx->encapPubKey); 879 rv = PK11_HPKE_Serialize(pkE, cx->encapPubKey->data, 880 &cx->encapPubKey->len, cx->encapPubKey->len); 881 CHECK_RV(rv); 882 883 rv = PK11_HPKE_Serialize(pkR, NULL, &tmpLen, 0); 884 CHECK_RV(rv); 885 886 kemContext = SECITEM_AllocItem(NULL, NULL, cx->encapPubKey->len + tmpLen); 887 CHECK_FAIL(!kemContext); 888 889 PORT_Memcpy(kemContext->data, cx->encapPubKey->data, cx->encapPubKey->len); 890 rv = PK11_HPKE_Serialize(pkR, &kemContext->data[cx->encapPubKey->len], &tmpLen, tmpLen); 891 CHECK_RV(rv); 892 893 rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret); 894 CHECK_RV(rv); 895 896 CLEANUP: 897 if (rv != SECSuccess) { 898 PK11_FreeSymKey(cx->sharedSecret); 899 cx->sharedSecret = NULL; 900 } 901 SECITEM_FreeItem(encPkR, PR_TRUE); 902 SECITEM_FreeItem(kemContext, PR_TRUE); 903 PK11_FreeSymKey(dh); 904 return rv; 905 } 906 907 SECStatus 908 PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info, unsigned int L, 909 PK11SymKey **out) 910 { 911 SECStatus rv; 912 PK11SymKey *exported; 913 PRUint8 suiteIdBuf[10]; 914 PRUint8 *walker; 915 PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL)); 916 SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) }; 917 918 /* Arbitrary info length limit well under the specified max. */ 919 if (!cx || !info || (!info->data && info->len) || info->len > 0xFFFF || 920 !L || (L > 255 * cx->kdfParams->Nh)) { 921 PORT_SetError(SEC_ERROR_INVALID_ARGS); 922 return SECFailure; 923 } 924 925 walker = &suiteIdBuf[4]; 926 walker = encodeNumber(cx->kemParams->id, walker, 2); 927 walker = encodeNumber(cx->kdfParams->id, walker, 2); 928 walker = encodeNumber(cx->aeadParams->id, walker, 2); 929 930 rv = pk11_hpke_LabeledExpand(cx, cx->exporterSecret, &suiteIdItem, SEC_LABEL, 931 strlen(SEC_LABEL), info, L, cx->kdfParams->mech, 932 &exported, NULL); 933 CHECK_RV(rv); 934 *out = exported; 935 936 CLEANUP: 937 return rv; 938 } 939 940 PK11SymKey * 941 PK11_HPKE_GetSharedSecret(const HpkeContext *cx) 942 { 943 return cx->sharedSecret; 944 } 945 946 static SECStatus 947 pk11_hpke_Decap(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *skR, 948 const SECItem *encS) 949 { 950 SECStatus rv; 951 PK11SymKey *dh = NULL; 952 SECItem *encR = NULL; 953 SECItem *kemContext = NULL; 954 SECKEYPublicKey *pkS = NULL; 955 unsigned int tmpLen; 956 957 if (!cx || !skR || !pkR || !encS || !encS->data || !encS->len) { 958 PORT_SetError(SEC_ERROR_INVALID_ARGS); 959 return SECFailure; 960 } 961 962 rv = PK11_HPKE_Deserialize(cx, encS->data, encS->len, &pkS); 963 CHECK_RV(rv); 964 965 rv = pk11_hpke_CheckKeys(cx, pkR, skR); 966 CHECK_RV(rv); 967 rv = pk11_hpke_CheckKeys(cx, pkS, NULL); 968 CHECK_RV(rv); 969 970 dh = PK11_PubDeriveWithKDF(skR, pkS, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, 971 CKM_SHA512_HMAC /* unused */, CKA_DERIVE, 0, 972 CKD_NULL, NULL, NULL); 973 CHECK_FAIL(!dh); 974 975 /* kem_context = concat(enc, pkRm) */ 976 rv = PK11_HPKE_Serialize(pkR, NULL, &tmpLen, 0); 977 CHECK_RV(rv); 978 979 kemContext = SECITEM_AllocItem(NULL, NULL, encS->len + tmpLen); 980 CHECK_FAIL(!kemContext); 981 982 PORT_Memcpy(kemContext->data, encS->data, encS->len); 983 rv = PK11_HPKE_Serialize(pkR, &kemContext->data[encS->len], &tmpLen, 984 kemContext->len - encS->len); 985 CHECK_RV(rv); 986 rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret); 987 CHECK_RV(rv); 988 989 /* Store the sender serialized public key, which 990 * may be required by application use cases. */ 991 cx->encapPubKey = SECITEM_DupItem(encS); 992 CHECK_FAIL(!cx->encapPubKey); 993 994 CLEANUP: 995 if (rv != SECSuccess) { 996 PK11_FreeSymKey(cx->sharedSecret); 997 cx->sharedSecret = NULL; 998 } 999 PK11_FreeSymKey(dh); 1000 SECKEY_DestroyPublicKey(pkS); 1001 SECITEM_FreeItem(encR, PR_TRUE); 1002 SECITEM_ZfreeItem(kemContext, PR_TRUE); 1003 return rv; 1004 } 1005 1006 const SECItem * 1007 PK11_HPKE_GetEncapPubKey(const HpkeContext *cx) 1008 { 1009 if (!cx) { 1010 return NULL; 1011 } 1012 return cx->encapPubKey; 1013 } 1014 1015 static SECStatus 1016 pk11_hpke_KeySchedule(HpkeContext *cx, const SECItem *info) 1017 { 1018 SECStatus rv; 1019 SECItem contextItem = { siBuffer, NULL, 0 }; 1020 unsigned int len; 1021 unsigned int off; 1022 PK11SymKey *secret = NULL; 1023 SECItem *pskIdHash = NULL; 1024 SECItem *infoHash = NULL; 1025 PRUint8 suiteIdBuf[10]; 1026 PRUint8 *walker; 1027 PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL)); 1028 SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) }; 1029 PORT_Assert(cx && info && cx->psk && cx->pskId); 1030 1031 walker = &suiteIdBuf[4]; 1032 walker = encodeNumber(cx->kemParams->id, walker, 2); 1033 walker = encodeNumber(cx->kdfParams->id, walker, 2); 1034 walker = encodeNumber(cx->aeadParams->id, walker, 2); 1035 1036 rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, PSK_ID_LABEL, 1037 strlen(PSK_ID_LABEL), cx->pskId, &pskIdHash); 1038 CHECK_RV(rv); 1039 rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, INFO_LABEL, 1040 strlen(INFO_LABEL), info, &infoHash); 1041 CHECK_RV(rv); 1042 1043 // Make the context string 1044 len = sizeof(cx->mode) + pskIdHash->len + infoHash->len; 1045 CHECK_FAIL(!SECITEM_AllocItem(NULL, &contextItem, len)); 1046 off = 0; 1047 PORT_Memcpy(&contextItem.data[off], &cx->mode, sizeof(cx->mode)); 1048 off += sizeof(cx->mode); 1049 PORT_Memcpy(&contextItem.data[off], pskIdHash->data, pskIdHash->len); 1050 off += pskIdHash->len; 1051 PORT_Memcpy(&contextItem.data[off], infoHash->data, infoHash->len); 1052 off += infoHash->len; 1053 1054 // Compute the keys 1055 rv = pk11_hpke_LabeledExtract(cx, cx->sharedSecret, &suiteIdItem, SECRET_LABEL, 1056 cx->kdfParams->mech, strlen(SECRET_LABEL), 1057 cx->psk, &secret); 1058 CHECK_RV(rv); 1059 rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, KEY_LABEL, strlen(KEY_LABEL), 1060 &contextItem, cx->aeadParams->Nk, cx->kdfParams->mech, 1061 &cx->key, NULL); 1062 CHECK_RV(rv); 1063 rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, NONCE_LABEL, strlen(NONCE_LABEL), 1064 &contextItem, cx->aeadParams->Nn, cx->kdfParams->mech, 1065 NULL, &cx->baseNonce); 1066 CHECK_RV(rv); 1067 rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, EXP_LABEL, strlen(EXP_LABEL), 1068 &contextItem, cx->kdfParams->Nh, cx->kdfParams->mech, 1069 &cx->exporterSecret, NULL); 1070 CHECK_RV(rv); 1071 1072 CLEANUP: 1073 /* If !SECSuccess, callers will tear down the context. */ 1074 PK11_FreeSymKey(secret); 1075 SECITEM_FreeItem(&contextItem, PR_FALSE); 1076 SECITEM_FreeItem(infoHash, PR_TRUE); 1077 SECITEM_FreeItem(pskIdHash, PR_TRUE); 1078 return rv; 1079 } 1080 1081 SECStatus 1082 PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *skR, 1083 const SECItem *enc, const SECItem *info) 1084 { 1085 SECStatus rv; 1086 SECItem empty = { siBuffer, NULL, 0 }; 1087 1088 CHECK_FAIL_ERR((!cx || !skR || !info || !enc || !enc->data || !enc->len), 1089 SEC_ERROR_INVALID_ARGS); 1090 /* Already setup */ 1091 CHECK_FAIL_ERR((cx->aeadContext), SEC_ERROR_INVALID_STATE); 1092 1093 rv = pk11_hpke_Decap(cx, pkR, skR, enc); 1094 CHECK_RV(rv); 1095 rv = pk11_hpke_KeySchedule(cx, info); 1096 CHECK_RV(rv); 1097 1098 /* Store the key context for subsequent calls to Open(). 1099 * PK11_CreateContextBySymKey refs the key internally. */ 1100 PORT_Assert(cx->key); 1101 cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech, 1102 CKA_NSS_MESSAGE | CKA_DECRYPT, 1103 cx->key, &empty); 1104 CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE); 1105 1106 CLEANUP: 1107 if (rv != SECSuccess) { 1108 /* Clear everything past NewContext. */ 1109 PK11_HPKE_DestroyContext(cx, PR_FALSE); 1110 } 1111 return rv; 1112 } 1113 1114 SECStatus 1115 PK11_HPKE_SetupS(HpkeContext *cx, const SECKEYPublicKey *pkE, SECKEYPrivateKey *skE, 1116 SECKEYPublicKey *pkR, const SECItem *info) 1117 { 1118 SECStatus rv; 1119 SECItem empty = { siBuffer, NULL, 0 }; 1120 SECKEYPublicKey *tmpPkE = NULL; 1121 SECKEYPrivateKey *tmpSkE = NULL; 1122 CHECK_FAIL_ERR((!cx || !pkR || !info || (!!skE != !!pkE)), SEC_ERROR_INVALID_ARGS); 1123 /* Already setup */ 1124 CHECK_FAIL_ERR((cx->aeadContext), SEC_ERROR_INVALID_STATE); 1125 1126 /* If NULL was passed for the local keypair, generate one. */ 1127 if (skE == NULL) { 1128 rv = pk11_hpke_GenerateKeyPair(cx, &tmpPkE, &tmpSkE); 1129 if (rv != SECSuccess) { 1130 /* Code set */ 1131 return SECFailure; 1132 } 1133 rv = pk11_hpke_Encap(cx, tmpPkE, tmpSkE, pkR); 1134 } else { 1135 rv = pk11_hpke_Encap(cx, pkE, skE, pkR); 1136 } 1137 CHECK_RV(rv); 1138 1139 SECItem defaultInfo = { siBuffer, NULL, 0 }; 1140 if (!info || !info->data) { 1141 info = &defaultInfo; 1142 } 1143 rv = pk11_hpke_KeySchedule(cx, info); 1144 CHECK_RV(rv); 1145 1146 PORT_Assert(cx->key); 1147 cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech, 1148 CKA_NSS_MESSAGE | CKA_ENCRYPT, 1149 cx->key, &empty); 1150 CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE); 1151 1152 CLEANUP: 1153 if (rv != SECSuccess) { 1154 /* Clear everything past NewContext. */ 1155 PK11_HPKE_DestroyContext(cx, PR_FALSE); 1156 } 1157 SECKEY_DestroyPrivateKey(tmpSkE); 1158 SECKEY_DestroyPublicKey(tmpPkE); 1159 return rv; 1160 } 1161 1162 SECStatus 1163 PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt, 1164 SECItem **out) 1165 { 1166 SECStatus rv; 1167 PRUint8 ivOut[12] = { 0 }; 1168 SECItem *ct = NULL; 1169 size_t maxOut; 1170 unsigned char tagBuf[HASH_LENGTH_MAX]; 1171 size_t tagLen; 1172 unsigned int fixedBits; 1173 1174 /* aad may be NULL, PT may be zero-length but not NULL. */ 1175 if (!cx || !cx->aeadContext || 1176 (aad && aad->len && !aad->data) || 1177 !pt || (pt->len && !pt->data) || 1178 !out) { 1179 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1180 return SECFailure; 1181 } 1182 1183 PORT_Assert(cx->baseNonce->len == sizeof(ivOut)); 1184 PORT_Memcpy(ivOut, cx->baseNonce->data, cx->baseNonce->len); 1185 1186 tagLen = cx->aeadParams->tagLen; 1187 maxOut = pt->len + tagLen; 1188 fixedBits = (cx->baseNonce->len - 8) * 8; 1189 ct = SECITEM_AllocItem(NULL, NULL, maxOut); 1190 CHECK_FAIL(!ct); 1191 1192 rv = PK11_AEADOp(cx->aeadContext, 1193 CKG_GENERATE_COUNTER_XOR, fixedBits, 1194 ivOut, sizeof(ivOut), 1195 aad ? aad->data : NULL, 1196 aad ? aad->len : 0, 1197 ct->data, (int *)&ct->len, maxOut, 1198 tagBuf, tagLen, 1199 pt->data, pt->len); 1200 CHECK_RV(rv); 1201 CHECK_FAIL_ERR((ct->len > maxOut - tagLen), SEC_ERROR_LIBRARY_FAILURE); 1202 1203 /* Append the tag to the ciphertext. */ 1204 PORT_Memcpy(&ct->data[ct->len], tagBuf, tagLen); 1205 ct->len += tagLen; 1206 *out = ct; 1207 1208 CLEANUP: 1209 if (rv != SECSuccess) { 1210 SECITEM_ZfreeItem(ct, PR_TRUE); 1211 } 1212 return rv; 1213 } 1214 1215 /* PKCS #11 defines the IV generator function to be ignored on 1216 * decrypt (i.e. it uses the nonce input, as provided, as the IV). 1217 * The sequence number is kept independently on each endpoint and 1218 * the XORed IV is not transmitted, so we have to do our own IV 1219 * construction XOR outside of the token. */ 1220 static SECStatus 1221 pk11_hpke_makeIv(HpkeContext *cx, PRUint8 *iv, size_t ivLen) 1222 { 1223 unsigned int counterLen = sizeof(cx->sequenceNumber); 1224 PORT_Assert(cx->baseNonce->len == ivLen); 1225 PORT_Assert(counterLen == 8); 1226 if (cx->sequenceNumber == PR_UINT64(0xffffffffffffffff)) { 1227 /* Overflow */ 1228 PORT_SetError(SEC_ERROR_INVALID_KEY); 1229 return SECFailure; 1230 } 1231 1232 PORT_Memcpy(iv, cx->baseNonce->data, cx->baseNonce->len); 1233 for (size_t i = 0; i < counterLen; i++) { 1234 iv[cx->baseNonce->len - 1 - i] ^= 1235 PORT_GET_BYTE_BE(cx->sequenceNumber, 1236 counterLen - 1 - i, counterLen); 1237 } 1238 return SECSuccess; 1239 } 1240 1241 SECStatus 1242 PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad, 1243 const SECItem *ct, SECItem **out) 1244 { 1245 SECStatus rv; 1246 PRUint8 constructedNonce[12] = { 0 }; 1247 unsigned int tagLen; 1248 SECItem *pt = NULL; 1249 1250 /* aad may be NULL, CT may be zero-length but not NULL. */ 1251 if ((!cx || !cx->aeadContext || !ct || !out) || 1252 (aad && aad->len && !aad->data) || 1253 (!ct->data || (ct->data && !ct->len))) { 1254 PORT_SetError(SEC_ERROR_INVALID_ARGS); 1255 return SECFailure; 1256 } 1257 tagLen = cx->aeadParams->tagLen; 1258 CHECK_FAIL_ERR((ct->len < tagLen), SEC_ERROR_INVALID_ARGS); 1259 1260 pt = SECITEM_AllocItem(NULL, NULL, ct->len); 1261 CHECK_FAIL(!pt); 1262 1263 rv = pk11_hpke_makeIv(cx, constructedNonce, sizeof(constructedNonce)); 1264 CHECK_RV(rv); 1265 1266 rv = PK11_AEADOp(cx->aeadContext, CKG_NO_GENERATE, 0, 1267 constructedNonce, sizeof(constructedNonce), 1268 aad ? aad->data : NULL, 1269 aad ? aad->len : 0, 1270 pt->data, (int *)&pt->len, pt->len, 1271 &ct->data[ct->len - tagLen], tagLen, 1272 ct->data, ct->len - tagLen); 1273 CHECK_RV(rv); 1274 cx->sequenceNumber++; 1275 *out = pt; 1276 1277 CLEANUP: 1278 if (rv != SECSuccess) { 1279 SECITEM_ZfreeItem(pt, PR_TRUE); 1280 } 1281 return rv; 1282 }