1 /* 2 * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* An OpenSSL-based HPKE implementation of RFC9180 */ 11 12 #include <string.h> 13 #include <openssl/rand.h> 14 #include <openssl/kdf.h> 15 #include <openssl/core_names.h> 16 #include <openssl/hpke.h> 17 #include <openssl/sha.h> 18 #include <openssl/evp.h> 19 #include <openssl/err.h> 20 #include "internal/hpke_util.h" 21 #include "internal/nelem.h" 22 #include "internal/common.h" 23 24 /* default buffer size for keys and internal buffers we use */ 25 #define OSSL_HPKE_MAXSIZE 512 26 27 /* Define HPKE labels from RFC9180 in hex for EBCDIC compatibility */ 28 /* "HPKE" - "suite_id" label for section 5.1 */ 29 static const char OSSL_HPKE_SEC51LABEL[] = "\x48\x50\x4b\x45"; 30 /* "psk_id_hash" - in key_schedule_context */ 31 static const char OSSL_HPKE_PSKIDHASH_LABEL[] = "\x70\x73\x6b\x5f\x69\x64\x5f\x68\x61\x73\x68"; 32 /* "info_hash" - in key_schedule_context */ 33 static const char OSSL_HPKE_INFOHASH_LABEL[] = "\x69\x6e\x66\x6f\x5f\x68\x61\x73\x68"; 34 /* "base_nonce" - base nonce calc label */ 35 static const char OSSL_HPKE_NONCE_LABEL[] = "\x62\x61\x73\x65\x5f\x6e\x6f\x6e\x63\x65"; 36 /* "exp" - internal exporter secret generation label */ 37 static const char OSSL_HPKE_EXP_LABEL[] = "\x65\x78\x70"; 38 /* "sec" - external label for exporting secret */ 39 static const char OSSL_HPKE_EXP_SEC_LABEL[] = "\x73\x65\x63"; 40 /* "key" - label for use when generating key from shared secret */ 41 static const char OSSL_HPKE_KEY_LABEL[] = "\x6b\x65\x79"; 42 /* "secret" - for generating shared secret */ 43 static const char OSSL_HPKE_SECRET_LABEL[] = "\x73\x65\x63\x72\x65\x74"; 44 45 /** 46 * @brief sender or receiver context 47 */ 48 struct ossl_hpke_ctx_st { 49 OSSL_LIB_CTX *libctx; /* library context */ 50 char *propq; /* properties */ 51 int mode; /* HPKE mode */ 52 OSSL_HPKE_SUITE suite; /* suite */ 53 const OSSL_HPKE_KEM_INFO *kem_info; 54 const OSSL_HPKE_KDF_INFO *kdf_info; 55 const OSSL_HPKE_AEAD_INFO *aead_info; 56 EVP_CIPHER *aead_ciph; 57 int role; /* sender(0) or receiver(1) */ 58 uint64_t seq; /* aead sequence number */ 59 unsigned char *shared_secret; /* KEM output, zz */ 60 size_t shared_secretlen; 61 unsigned char *key; /* final aead key */ 62 size_t keylen; 63 unsigned char *nonce; /* aead base nonce */ 64 size_t noncelen; 65 unsigned char *exportersec; /* exporter secret */ 66 size_t exporterseclen; 67 char *pskid; /* PSK stuff */ 68 unsigned char *psk; 69 size_t psklen; 70 EVP_PKEY *authpriv; /* sender's authentication private key */ 71 unsigned char *authpub; /* auth public key */ 72 size_t authpublen; 73 unsigned char *ikme; /* IKM for sender deterministic key gen */ 74 size_t ikmelen; 75 }; 76 77 /** 78 * @brief check if KEM uses NIST curve or not 79 * @param kem_id is the externally supplied kem_id 80 * @return 1 for NIST curves, 0 for other 81 */ 82 static int hpke_kem_id_nist_curve(uint16_t kem_id) 83 { 84 const OSSL_HPKE_KEM_INFO *kem_info; 85 86 kem_info = ossl_HPKE_KEM_INFO_find_id(kem_id); 87 return kem_info != NULL && kem_info->groupname != NULL; 88 } 89 90 /** 91 * @brief wrapper to import NIST curve public key as easily as x25519/x448 92 * @param libctx is the context to use 93 * @param propq is a properties string 94 * @param gname is the curve groupname 95 * @param buf is the binary buffer with the (uncompressed) public value 96 * @param buflen is the length of the private key buffer 97 * @return a working EVP_PKEY * or NULL 98 * 99 * Note that this could be a useful function to make public in 100 * future, but would likely require a name change. 101 */ 102 static EVP_PKEY *evp_pkey_new_raw_nist_public_key(OSSL_LIB_CTX *libctx, 103 const char *propq, 104 const char *gname, 105 const unsigned char *buf, 106 size_t buflen) 107 { 108 OSSL_PARAM params[2]; 109 EVP_PKEY *ret = NULL; 110 EVP_PKEY_CTX *cctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq); 111 112 params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, 113 (char *)gname, 0); 114 params[1] = OSSL_PARAM_construct_end(); 115 if (cctx == NULL 116 || EVP_PKEY_paramgen_init(cctx) <= 0 117 || EVP_PKEY_CTX_set_params(cctx, params) <= 0 118 || EVP_PKEY_paramgen(cctx, &ret) <= 0 119 || EVP_PKEY_set1_encoded_public_key(ret, buf, buflen) != 1) { 120 EVP_PKEY_CTX_free(cctx); 121 EVP_PKEY_free(ret); 122 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 123 return NULL; 124 } 125 EVP_PKEY_CTX_free(cctx); 126 return ret; 127 } 128 129 /** 130 * @brief do the AEAD decryption 131 * @param hctx is the context to use 132 * @param iv is the initialisation vector 133 * @param aad is the additional authenticated data 134 * @param aadlen is the length of the aad 135 * @param ct is the ciphertext buffer 136 * @param ctlen is the ciphertext length (including tag). 137 * @param pt is the output buffer 138 * @param ptlen input/output, better be big enough on input, exact on output 139 * @return 1 on success, 0 otherwise 140 */ 141 static int hpke_aead_dec(OSSL_HPKE_CTX *hctx, const unsigned char *iv, 142 const unsigned char *aad, size_t aadlen, 143 const unsigned char *ct, size_t ctlen, 144 unsigned char *pt, size_t *ptlen) 145 { 146 int erv = 0; 147 EVP_CIPHER_CTX *ctx = NULL; 148 int len = 0; 149 size_t taglen; 150 151 taglen = hctx->aead_info->taglen; 152 if (ctlen <= taglen || *ptlen < ctlen - taglen) { 153 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 154 return 0; 155 } 156 /* Create and initialise the context */ 157 if ((ctx = EVP_CIPHER_CTX_new()) == NULL) 158 return 0; 159 /* Initialise the decryption operation. */ 160 if (EVP_DecryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) { 161 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 162 goto err; 163 } 164 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 165 hctx->noncelen, NULL) 166 != 1) { 167 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 168 goto err; 169 } 170 /* Initialise key and IV */ 171 if (EVP_DecryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) { 172 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 173 goto err; 174 } 175 /* Provide AAD. */ 176 if (aadlen != 0 && aad != NULL) { 177 if (EVP_DecryptUpdate(ctx, NULL, &len, aad, aadlen) != 1) { 178 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 179 goto err; 180 } 181 } 182 if (EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen - taglen) != 1) { 183 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 184 goto err; 185 } 186 *ptlen = len; 187 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 188 taglen, (void *)(ct + ctlen - taglen))) { 189 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 190 goto err; 191 } 192 /* Finalise decryption. */ 193 if (EVP_DecryptFinal_ex(ctx, pt + len, &len) <= 0) { 194 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 195 goto err; 196 } 197 erv = 1; 198 199 err: 200 if (erv != 1) 201 OPENSSL_cleanse(pt, *ptlen); 202 EVP_CIPHER_CTX_free(ctx); 203 return erv; 204 } 205 206 /** 207 * @brief do AEAD encryption as per the RFC 208 * @param hctx is the context to use 209 * @param iv is the initialisation vector 210 * @param aad is the additional authenticated data 211 * @param aadlen is the length of the aad 212 * @param pt is the plaintext buffer 213 * @param ptlen is the length of pt 214 * @param ct is the output buffer 215 * @param ctlen input/output, needs space for tag on input, exact on output 216 * @return 1 for success, 0 otherwise 217 */ 218 static int hpke_aead_enc(OSSL_HPKE_CTX *hctx, const unsigned char *iv, 219 const unsigned char *aad, size_t aadlen, 220 const unsigned char *pt, size_t ptlen, 221 unsigned char *ct, size_t *ctlen) 222 { 223 int erv = 0; 224 EVP_CIPHER_CTX *ctx = NULL; 225 int len; 226 size_t taglen = 0; 227 unsigned char tag[EVP_MAX_AEAD_TAG_LENGTH]; 228 229 taglen = hctx->aead_info->taglen; 230 if (*ctlen <= taglen || ptlen > *ctlen - taglen) { 231 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 232 return 0; 233 } 234 if (!ossl_assert(taglen <= sizeof(tag))) { 235 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 236 return 0; 237 } 238 /* Create and initialise the context */ 239 if ((ctx = EVP_CIPHER_CTX_new()) == NULL) 240 return 0; 241 /* Initialise the encryption operation. */ 242 if (EVP_EncryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) { 243 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 244 goto err; 245 } 246 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 247 hctx->noncelen, NULL) 248 != 1) { 249 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 250 goto err; 251 } 252 /* Initialise key and IV */ 253 if (EVP_EncryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) { 254 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 255 goto err; 256 } 257 /* Provide any AAD data. */ 258 if (aadlen != 0 && aad != NULL) { 259 if (EVP_EncryptUpdate(ctx, NULL, &len, aad, aadlen) != 1) { 260 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 261 goto err; 262 } 263 } 264 if (EVP_EncryptUpdate(ctx, ct, &len, pt, ptlen) != 1) { 265 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 266 goto err; 267 } 268 *ctlen = len; 269 /* Finalise the encryption. */ 270 if (EVP_EncryptFinal_ex(ctx, ct + len, &len) != 1) { 271 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 272 goto err; 273 } 274 *ctlen += len; 275 /* Get tag. Not a duplicate so needs to be added to the ciphertext */ 276 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, tag) != 1) { 277 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 278 goto err; 279 } 280 memcpy(ct + *ctlen, tag, taglen); 281 *ctlen += taglen; 282 erv = 1; 283 284 err: 285 if (erv != 1) 286 OPENSSL_cleanse(ct, *ctlen); 287 EVP_CIPHER_CTX_free(ctx); 288 return erv; 289 } 290 291 /** 292 * @brief check mode is in-range and supported 293 * @param mode is the caller's chosen mode 294 * @return 1 for good mode, 0 otherwise 295 */ 296 static int hpke_mode_check(unsigned int mode) 297 { 298 switch (mode) { 299 case OSSL_HPKE_MODE_BASE: 300 case OSSL_HPKE_MODE_PSK: 301 case OSSL_HPKE_MODE_AUTH: 302 case OSSL_HPKE_MODE_PSKAUTH: 303 break; 304 default: 305 return 0; 306 } 307 return 1; 308 } 309 310 /** 311 * @brief check if a suite is supported locally 312 * @param suite is the suite to check 313 * @return 1 for good, 0 otherwise 314 */ 315 static int hpke_suite_check(OSSL_HPKE_SUITE suite, 316 const OSSL_HPKE_KEM_INFO **kem_info, 317 const OSSL_HPKE_KDF_INFO **kdf_info, 318 const OSSL_HPKE_AEAD_INFO **aead_info) 319 { 320 const OSSL_HPKE_KEM_INFO *kem_info_; 321 const OSSL_HPKE_KDF_INFO *kdf_info_; 322 const OSSL_HPKE_AEAD_INFO *aead_info_; 323 324 /* check KEM, KDF and AEAD are supported here */ 325 if ((kem_info_ = ossl_HPKE_KEM_INFO_find_id(suite.kem_id)) == NULL) 326 return 0; 327 if ((kdf_info_ = ossl_HPKE_KDF_INFO_find_id(suite.kdf_id)) == NULL) 328 return 0; 329 if ((aead_info_ = ossl_HPKE_AEAD_INFO_find_id(suite.aead_id)) == NULL) 330 return 0; 331 332 if (kem_info != NULL) 333 *kem_info = kem_info_; 334 if (kdf_info != NULL) 335 *kdf_info = kdf_info_; 336 if (aead_info != NULL) 337 *aead_info = aead_info_; 338 339 return 1; 340 } 341 342 /* 343 * @brief randomly pick a suite 344 * @param libctx is the context to use 345 * @param propq is a properties string 346 * @param suite is the result 347 * @return 1 for success, 0 otherwise 348 */ 349 static int hpke_random_suite(OSSL_LIB_CTX *libctx, 350 const char *propq, 351 OSSL_HPKE_SUITE *suite) 352 { 353 const OSSL_HPKE_KEM_INFO *kem_info = NULL; 354 const OSSL_HPKE_KDF_INFO *kdf_info = NULL; 355 const OSSL_HPKE_AEAD_INFO *aead_info = NULL; 356 357 /* random kem, kdf and aead */ 358 kem_info = ossl_HPKE_KEM_INFO_find_random(libctx); 359 if (kem_info == NULL) 360 return 0; 361 suite->kem_id = kem_info->kem_id; 362 kdf_info = ossl_HPKE_KDF_INFO_find_random(libctx); 363 if (kdf_info == NULL) 364 return 0; 365 suite->kdf_id = kdf_info->kdf_id; 366 aead_info = ossl_HPKE_AEAD_INFO_find_random(libctx); 367 if (aead_info == NULL) 368 return 0; 369 suite->aead_id = aead_info->aead_id; 370 return 1; 371 } 372 373 /* 374 * @brief tell the caller how big the ciphertext will be 375 * 376 * AEAD algorithms add a tag for data authentication. 377 * Those are almost always, but not always, 16 octets 378 * long, and who knows what will be true in the future. 379 * So this function allows a caller to find out how 380 * much data expansion they will see with a given suite. 381 * 382 * "enc" is the name used in RFC9180 for the encapsulated 383 * public value of the sender, who calls OSSL_HPKE_seal(), 384 * that is sent to the recipient, who calls OSSL_HPKE_open(). 385 * 386 * @param suite is the suite to be used 387 * @param enclen points to what will be enc length 388 * @param clearlen is the length of plaintext 389 * @param cipherlen points to what will be ciphertext length (including tag) 390 * @return 1 for success, 0 otherwise 391 */ 392 static int hpke_expansion(OSSL_HPKE_SUITE suite, 393 size_t *enclen, 394 size_t clearlen, 395 size_t *cipherlen) 396 { 397 const OSSL_HPKE_AEAD_INFO *aead_info = NULL; 398 const OSSL_HPKE_KEM_INFO *kem_info = NULL; 399 400 if (cipherlen == NULL || enclen == NULL) { 401 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 402 return 0; 403 } 404 if (hpke_suite_check(suite, &kem_info, NULL, &aead_info) != 1) { 405 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 406 return 0; 407 } 408 *cipherlen = clearlen + aead_info->taglen; 409 *enclen = kem_info->Nenc; 410 return 1; 411 } 412 413 /* 414 * @brief expand and XOR the 64-bit unsigned seq with (nonce) buffer 415 * @param ctx is the HPKE context 416 * @param buf is the buffer for the XOR'd seq and nonce 417 * @param blen is the size of buf 418 * @return 0 for error, otherwise blen 419 */ 420 static size_t hpke_seqnonce2buf(OSSL_HPKE_CTX *ctx, 421 unsigned char *buf, size_t blen) 422 { 423 size_t i; 424 uint64_t seq_copy; 425 426 if (ctx == NULL || blen < sizeof(seq_copy) || blen != ctx->noncelen) 427 return 0; 428 seq_copy = ctx->seq; 429 memset(buf, 0, blen); 430 for (i = 0; i < sizeof(seq_copy); i++) { 431 buf[blen - i - 1] = seq_copy & 0xff; 432 seq_copy >>= 8; 433 } 434 for (i = 0; i < blen; i++) 435 buf[i] ^= ctx->nonce[i]; 436 return blen; 437 } 438 439 /* 440 * @brief call the underlying KEM to encap 441 * @param ctx is the OSSL_HPKE_CTX 442 * @param enc is a buffer for the sender's ephemeral public value 443 * @param enclen is the size of enc on input, number of octets used on output 444 * @param pub is the recipient's public value 445 * @param publen is the length of pub 446 * @return 1 for success, 0 for error 447 */ 448 static int hpke_encap(OSSL_HPKE_CTX *ctx, unsigned char *enc, size_t *enclen, 449 const unsigned char *pub, size_t publen) 450 { 451 int erv = 0; 452 OSSL_PARAM params[3], *p = params; 453 size_t lsslen = 0, lenclen = 0; 454 EVP_PKEY_CTX *pctx = NULL; 455 EVP_PKEY *pkR = NULL; 456 const OSSL_HPKE_KEM_INFO *kem_info = NULL; 457 458 if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0 459 || pub == NULL || publen == 0) { 460 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 461 return 0; 462 } 463 if (ctx->shared_secret != NULL) { 464 /* only run the KEM once per OSSL_HPKE_CTX */ 465 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 466 return 0; 467 } 468 kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id); 469 if (kem_info == NULL) { 470 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 471 return 0; 472 } 473 if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) { 474 pkR = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq, 475 kem_info->groupname, 476 pub, publen); 477 } else { 478 pkR = EVP_PKEY_new_raw_public_key_ex(ctx->libctx, 479 kem_info->keytype, 480 ctx->propq, pub, publen); 481 } 482 if (pkR == NULL) { 483 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 484 goto err; 485 } 486 pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkR, ctx->propq); 487 if (pctx == NULL) { 488 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 489 goto err; 490 } 491 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION, 492 OSSL_KEM_PARAM_OPERATION_DHKEM, 493 0); 494 if (ctx->ikme != NULL) { 495 *p++ = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME, 496 ctx->ikme, ctx->ikmelen); 497 } 498 *p = OSSL_PARAM_construct_end(); 499 if (ctx->mode == OSSL_HPKE_MODE_AUTH 500 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) { 501 if (EVP_PKEY_auth_encapsulate_init(pctx, ctx->authpriv, 502 params) 503 != 1) { 504 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 505 goto err; 506 } 507 } else { 508 if (EVP_PKEY_encapsulate_init(pctx, params) != 1) { 509 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 510 goto err; 511 } 512 } 513 lenclen = *enclen; 514 if (EVP_PKEY_encapsulate(pctx, NULL, &lenclen, NULL, &lsslen) != 1) { 515 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 516 goto err; 517 } 518 if (lenclen > *enclen) { 519 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 520 goto err; 521 } 522 ctx->shared_secret = OPENSSL_malloc(lsslen); 523 if (ctx->shared_secret == NULL) 524 goto err; 525 ctx->shared_secretlen = lsslen; 526 if (EVP_PKEY_encapsulate(pctx, enc, enclen, ctx->shared_secret, 527 &ctx->shared_secretlen) 528 != 1) { 529 ctx->shared_secretlen = 0; 530 OPENSSL_free(ctx->shared_secret); 531 ctx->shared_secret = NULL; 532 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 533 goto err; 534 } 535 erv = 1; 536 537 err: 538 EVP_PKEY_CTX_free(pctx); 539 EVP_PKEY_free(pkR); 540 return erv; 541 } 542 543 /* 544 * @brief call the underlying KEM to decap 545 * @param ctx is the OSSL_HPKE_CTX 546 * @param enc is a buffer for the sender's ephemeral public value 547 * @param enclen is the length of enc 548 * @param priv is the recipient's private value 549 * @return 1 for success, 0 for error 550 */ 551 static int hpke_decap(OSSL_HPKE_CTX *ctx, 552 const unsigned char *enc, size_t enclen, 553 EVP_PKEY *priv) 554 { 555 int erv = 0; 556 EVP_PKEY_CTX *pctx = NULL; 557 EVP_PKEY *spub = NULL; 558 OSSL_PARAM params[2], *p = params; 559 size_t lsslen = 0; 560 561 if (ctx == NULL || enc == NULL || enclen == 0 || priv == NULL) { 562 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 563 return 0; 564 } 565 if (ctx->shared_secret != NULL) { 566 /* only run the KEM once per OSSL_HPKE_CTX */ 567 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 568 return 0; 569 } 570 pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, priv, ctx->propq); 571 if (pctx == NULL) { 572 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 573 goto err; 574 } 575 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION, 576 OSSL_KEM_PARAM_OPERATION_DHKEM, 577 0); 578 *p = OSSL_PARAM_construct_end(); 579 if (ctx->mode == OSSL_HPKE_MODE_AUTH 580 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) { 581 const OSSL_HPKE_KEM_INFO *kem_info = NULL; 582 583 kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id); 584 if (kem_info == NULL) { 585 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 586 goto err; 587 } 588 if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) { 589 spub = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq, 590 kem_info->groupname, 591 ctx->authpub, 592 ctx->authpublen); 593 } else { 594 spub = EVP_PKEY_new_raw_public_key_ex(ctx->libctx, 595 kem_info->keytype, 596 ctx->propq, 597 ctx->authpub, 598 ctx->authpublen); 599 } 600 if (spub == NULL) { 601 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 602 goto err; 603 } 604 if (EVP_PKEY_auth_decapsulate_init(pctx, spub, params) != 1) { 605 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 606 goto err; 607 } 608 } else { 609 if (EVP_PKEY_decapsulate_init(pctx, params) != 1) { 610 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 611 goto err; 612 } 613 } 614 if (EVP_PKEY_decapsulate(pctx, NULL, &lsslen, enc, enclen) != 1) { 615 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 616 goto err; 617 } 618 ctx->shared_secret = OPENSSL_malloc(lsslen); 619 if (ctx->shared_secret == NULL) 620 goto err; 621 if (EVP_PKEY_decapsulate(pctx, ctx->shared_secret, &lsslen, 622 enc, enclen) 623 != 1) { 624 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 625 goto err; 626 } 627 ctx->shared_secretlen = lsslen; 628 erv = 1; 629 630 err: 631 EVP_PKEY_CTX_free(pctx); 632 EVP_PKEY_free(spub); 633 if (erv == 0) { 634 OPENSSL_free(ctx->shared_secret); 635 ctx->shared_secret = NULL; 636 ctx->shared_secretlen = 0; 637 } 638 return erv; 639 } 640 641 /* 642 * @brief do "middle" of HPKE, between KEM and AEAD 643 * @param ctx is the OSSL_HPKE_CTX 644 * @param info is a buffer for the added binding information 645 * @param infolen is the length of info 646 * @return 0 for error, 1 for success 647 * 648 * This does all the HPKE extracts and expands as defined in RFC9180 649 * section 5.1, (badly termed there as a "key schedule") and sets the 650 * ctx fields for the shared_secret, nonce, key and exporter_secret 651 */ 652 static int hpke_do_middle(OSSL_HPKE_CTX *ctx, 653 const unsigned char *info, size_t infolen) 654 { 655 int erv = 0; 656 size_t ks_contextlen = OSSL_HPKE_MAXSIZE; 657 unsigned char ks_context[OSSL_HPKE_MAXSIZE]; 658 size_t halflen = 0; 659 size_t pskidlen = 0; 660 const OSSL_HPKE_AEAD_INFO *aead_info = NULL; 661 const OSSL_HPKE_KDF_INFO *kdf_info = NULL; 662 size_t secretlen = OSSL_HPKE_MAXSIZE; 663 unsigned char secret[OSSL_HPKE_MAXSIZE]; 664 EVP_KDF_CTX *kctx = NULL; 665 unsigned char suitebuf[6]; 666 const char *mdname = NULL; 667 668 /* only let this be done once */ 669 if (ctx->exportersec != NULL) { 670 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 671 return 0; 672 } 673 if (ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id) == NULL) { 674 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 675 return 0; 676 } 677 aead_info = ossl_HPKE_AEAD_INFO_find_id(ctx->suite.aead_id); 678 if (aead_info == NULL) { 679 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 680 return 0; 681 } 682 kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id); 683 if (kdf_info == NULL) { 684 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 685 return 0; 686 } 687 mdname = kdf_info->mdname; 688 /* create key schedule context */ 689 memset(ks_context, 0, sizeof(ks_context)); 690 ks_context[0] = (unsigned char)(ctx->mode % 256); 691 ks_contextlen--; /* remaining space */ 692 halflen = kdf_info->Nh; 693 if ((2 * halflen) > ks_contextlen) { 694 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 695 return 0; 696 } 697 /* check a psk was set if in that mode */ 698 if (ctx->mode == OSSL_HPKE_MODE_PSK 699 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) { 700 if (ctx->psk == NULL || ctx->psklen == 0 || ctx->pskid == NULL) { 701 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 702 return 0; 703 } 704 } 705 kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq); 706 if (kctx == NULL) { 707 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 708 return 0; 709 } 710 pskidlen = (ctx->psk == NULL ? 0 : strlen(ctx->pskid)); 711 /* full suite details as per RFC9180 sec 5.1 */ 712 suitebuf[0] = ctx->suite.kem_id / 256; 713 suitebuf[1] = ctx->suite.kem_id % 256; 714 suitebuf[2] = ctx->suite.kdf_id / 256; 715 suitebuf[3] = ctx->suite.kdf_id % 256; 716 suitebuf[4] = ctx->suite.aead_id / 256; 717 suitebuf[5] = ctx->suite.aead_id % 256; 718 /* Extract and Expand variously... */ 719 if (ossl_hpke_labeled_extract(kctx, ks_context + 1, halflen, 720 NULL, 0, OSSL_HPKE_SEC51LABEL, 721 suitebuf, sizeof(suitebuf), 722 OSSL_HPKE_PSKIDHASH_LABEL, 723 (unsigned char *)ctx->pskid, pskidlen) 724 != 1) { 725 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 726 goto err; 727 } 728 if (ossl_hpke_labeled_extract(kctx, ks_context + 1 + halflen, halflen, 729 NULL, 0, OSSL_HPKE_SEC51LABEL, 730 suitebuf, sizeof(suitebuf), 731 OSSL_HPKE_INFOHASH_LABEL, 732 (unsigned char *)info, infolen) 733 != 1) { 734 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 735 goto err; 736 } 737 ks_contextlen = 1 + 2 * halflen; 738 secretlen = kdf_info->Nh; 739 if (secretlen > OSSL_HPKE_MAXSIZE) { 740 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 741 goto err; 742 } 743 if (ossl_hpke_labeled_extract(kctx, secret, secretlen, 744 ctx->shared_secret, ctx->shared_secretlen, 745 OSSL_HPKE_SEC51LABEL, 746 suitebuf, sizeof(suitebuf), 747 OSSL_HPKE_SECRET_LABEL, 748 ctx->psk, ctx->psklen) 749 != 1) { 750 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 751 goto err; 752 } 753 if (ctx->suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) { 754 /* we only need nonce/key for non export AEADs */ 755 ctx->noncelen = aead_info->Nn; 756 ctx->nonce = OPENSSL_malloc(ctx->noncelen); 757 if (ctx->nonce == NULL) 758 goto err; 759 if (ossl_hpke_labeled_expand(kctx, ctx->nonce, ctx->noncelen, 760 secret, secretlen, OSSL_HPKE_SEC51LABEL, 761 suitebuf, sizeof(suitebuf), 762 OSSL_HPKE_NONCE_LABEL, 763 ks_context, ks_contextlen) 764 != 1) { 765 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 766 goto err; 767 } 768 ctx->keylen = aead_info->Nk; 769 ctx->key = OPENSSL_malloc(ctx->keylen); 770 if (ctx->key == NULL) 771 goto err; 772 if (ossl_hpke_labeled_expand(kctx, ctx->key, ctx->keylen, 773 secret, secretlen, OSSL_HPKE_SEC51LABEL, 774 suitebuf, sizeof(suitebuf), 775 OSSL_HPKE_KEY_LABEL, 776 ks_context, ks_contextlen) 777 != 1) { 778 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 779 goto err; 780 } 781 } 782 ctx->exporterseclen = kdf_info->Nh; 783 ctx->exportersec = OPENSSL_malloc(ctx->exporterseclen); 784 if (ctx->exportersec == NULL) 785 goto err; 786 if (ossl_hpke_labeled_expand(kctx, ctx->exportersec, ctx->exporterseclen, 787 secret, secretlen, OSSL_HPKE_SEC51LABEL, 788 suitebuf, sizeof(suitebuf), 789 OSSL_HPKE_EXP_LABEL, 790 ks_context, ks_contextlen) 791 != 1) { 792 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 793 goto err; 794 } 795 erv = 1; 796 797 err: 798 OPENSSL_cleanse(ks_context, OSSL_HPKE_MAXSIZE); 799 OPENSSL_cleanse(secret, OSSL_HPKE_MAXSIZE); 800 EVP_KDF_CTX_free(kctx); 801 return erv; 802 } 803 804 /* 805 * externally visible functions from below here, API documentation is 806 * in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication 807 */ 808 809 OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role, 810 OSSL_LIB_CTX *libctx, const char *propq) 811 { 812 OSSL_HPKE_CTX *ctx = NULL; 813 const OSSL_HPKE_KEM_INFO *kem_info; 814 const OSSL_HPKE_KDF_INFO *kdf_info; 815 const OSSL_HPKE_AEAD_INFO *aead_info; 816 817 if (hpke_mode_check(mode) != 1) { 818 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 819 return NULL; 820 } 821 if (hpke_suite_check(suite, &kem_info, &kdf_info, &aead_info) != 1) { 822 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 823 return NULL; 824 } 825 if (role != OSSL_HPKE_ROLE_SENDER && role != OSSL_HPKE_ROLE_RECEIVER) { 826 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 827 return 0; 828 } 829 ctx = OPENSSL_zalloc(sizeof(*ctx)); 830 if (ctx == NULL) 831 return NULL; 832 ctx->libctx = libctx; 833 if (propq != NULL) { 834 ctx->propq = OPENSSL_strdup(propq); 835 if (ctx->propq == NULL) 836 goto err; 837 } 838 if (suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) { 839 ctx->aead_ciph = EVP_CIPHER_fetch(libctx, aead_info->name, propq); 840 if (ctx->aead_ciph == NULL) { 841 ERR_raise(ERR_LIB_CRYPTO, ERR_R_FETCH_FAILED); 842 goto err; 843 } 844 } 845 ctx->role = role; 846 ctx->mode = mode; 847 ctx->suite = suite; 848 ctx->kem_info = kem_info; 849 ctx->kdf_info = kdf_info; 850 ctx->aead_info = aead_info; 851 return ctx; 852 853 err: 854 EVP_CIPHER_free(ctx->aead_ciph); 855 OPENSSL_free(ctx->propq); 856 OPENSSL_free(ctx); 857 return NULL; 858 } 859 860 void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX *ctx) 861 { 862 if (ctx == NULL) 863 return; 864 EVP_CIPHER_free(ctx->aead_ciph); 865 OPENSSL_free(ctx->propq); 866 OPENSSL_clear_free(ctx->exportersec, ctx->exporterseclen); 867 OPENSSL_free(ctx->pskid); 868 OPENSSL_clear_free(ctx->psk, ctx->psklen); 869 OPENSSL_clear_free(ctx->key, ctx->keylen); 870 OPENSSL_clear_free(ctx->nonce, ctx->noncelen); 871 OPENSSL_clear_free(ctx->shared_secret, ctx->shared_secretlen); 872 OPENSSL_clear_free(ctx->ikme, ctx->ikmelen); 873 EVP_PKEY_free(ctx->authpriv); 874 OPENSSL_free(ctx->authpub); 875 876 OPENSSL_free(ctx); 877 return; 878 } 879 880 int OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX *ctx, 881 const char *pskid, 882 const unsigned char *psk, size_t psklen) 883 { 884 if (ctx == NULL || pskid == NULL || psk == NULL || psklen == 0) { 885 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 886 return 0; 887 } 888 if (psklen > OSSL_HPKE_MAX_PARMLEN) { 889 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 890 return 0; 891 } 892 if (psklen < OSSL_HPKE_MIN_PSKLEN) { 893 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 894 return 0; 895 } 896 if (strlen(pskid) > OSSL_HPKE_MAX_PARMLEN) { 897 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 898 return 0; 899 } 900 if (strlen(pskid) == 0) { 901 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 902 return 0; 903 } 904 if (ctx->mode != OSSL_HPKE_MODE_PSK 905 && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) { 906 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 907 return 0; 908 } 909 /* free previous values if any */ 910 OPENSSL_clear_free(ctx->psk, ctx->psklen); 911 ctx->psk = OPENSSL_memdup(psk, psklen); 912 if (ctx->psk == NULL) 913 return 0; 914 ctx->psklen = psklen; 915 OPENSSL_free(ctx->pskid); 916 ctx->pskid = OPENSSL_strdup(pskid); 917 if (ctx->pskid == NULL) { 918 OPENSSL_clear_free(ctx->psk, ctx->psklen); 919 ctx->psk = NULL; 920 ctx->psklen = 0; 921 return 0; 922 } 923 return 1; 924 } 925 926 int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX *ctx, 927 const unsigned char *ikme, size_t ikmelen) 928 { 929 if (ctx == NULL || ikme == NULL) { 930 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER); 931 return 0; 932 } 933 if (ikmelen == 0 || ikmelen > OSSL_HPKE_MAX_PARMLEN) { 934 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 935 return 0; 936 } 937 if (ctx->role != OSSL_HPKE_ROLE_SENDER) { 938 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 939 return 0; 940 } 941 OPENSSL_clear_free(ctx->ikme, ctx->ikmelen); 942 ctx->ikme = OPENSSL_memdup(ikme, ikmelen); 943 if (ctx->ikme == NULL) 944 return 0; 945 ctx->ikmelen = ikmelen; 946 return 1; 947 } 948 949 int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX *ctx, EVP_PKEY *priv) 950 { 951 if (ctx == NULL || priv == NULL) { 952 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER); 953 return 0; 954 } 955 if (ctx->mode != OSSL_HPKE_MODE_AUTH 956 && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) { 957 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 958 return 0; 959 } 960 if (ctx->role != OSSL_HPKE_ROLE_SENDER) { 961 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 962 return 0; 963 } 964 EVP_PKEY_free(ctx->authpriv); 965 ctx->authpriv = EVP_PKEY_dup(priv); 966 if (ctx->authpriv == NULL) 967 return 0; 968 return 1; 969 } 970 971 int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX *ctx, 972 const unsigned char *pub, size_t publen) 973 { 974 int erv = 0; 975 EVP_PKEY *pubp = NULL; 976 unsigned char *lpub = NULL; 977 size_t lpublen = 0; 978 const OSSL_HPKE_KEM_INFO *kem_info = NULL; 979 980 if (ctx == NULL || pub == NULL || publen == 0) { 981 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER); 982 return 0; 983 } 984 if (ctx->mode != OSSL_HPKE_MODE_AUTH 985 && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) { 986 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 987 return 0; 988 } 989 if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) { 990 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 991 return 0; 992 } 993 /* check the value seems like a good public key for this kem */ 994 kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id); 995 if (kem_info == NULL) 996 return 0; 997 if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) { 998 pubp = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq, 999 kem_info->groupname, 1000 pub, publen); 1001 } else { 1002 pubp = EVP_PKEY_new_raw_public_key_ex(ctx->libctx, 1003 kem_info->keytype, 1004 ctx->propq, 1005 pub, publen); 1006 } 1007 if (pubp == NULL) { 1008 /* can happen based on external input - buffer value may be garbage */ 1009 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1010 goto err; 1011 } 1012 /* 1013 * extract out the public key in encoded form so we 1014 * should be fine even if given compressed form 1015 */ 1016 lpub = OPENSSL_malloc(OSSL_HPKE_MAXSIZE); 1017 if (lpub == NULL) 1018 goto err; 1019 if (EVP_PKEY_get_octet_string_param(pubp, 1020 OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, 1021 lpub, OSSL_HPKE_MAXSIZE, &lpublen) 1022 != 1) { 1023 OPENSSL_free(lpub); 1024 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1025 goto err; 1026 } 1027 /* free up old value */ 1028 OPENSSL_free(ctx->authpub); 1029 ctx->authpub = lpub; 1030 ctx->authpublen = lpublen; 1031 erv = 1; 1032 1033 err: 1034 EVP_PKEY_free(pubp); 1035 return erv; 1036 } 1037 1038 int OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX *ctx, uint64_t *seq) 1039 { 1040 if (ctx == NULL || seq == NULL) { 1041 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER); 1042 return 0; 1043 } 1044 *seq = ctx->seq; 1045 return 1; 1046 } 1047 1048 int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX *ctx, uint64_t seq) 1049 { 1050 if (ctx == NULL) { 1051 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER); 1052 return 0; 1053 } 1054 /* 1055 * We disallow senders from doing this as it's dangerous 1056 * Receivers are ok to use this, as no harm should ensue 1057 * if they go wrong. 1058 */ 1059 if (ctx->role == OSSL_HPKE_ROLE_SENDER) { 1060 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1061 return 0; 1062 } 1063 ctx->seq = seq; 1064 return 1; 1065 } 1066 1067 int OSSL_HPKE_encap(OSSL_HPKE_CTX *ctx, 1068 unsigned char *enc, size_t *enclen, 1069 const unsigned char *pub, size_t publen, 1070 const unsigned char *info, size_t infolen) 1071 { 1072 int erv = 1; 1073 size_t minenc = 0; 1074 1075 if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0 1076 || pub == NULL || publen == 0) { 1077 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1078 return 0; 1079 } 1080 if (ctx->role != OSSL_HPKE_ROLE_SENDER) { 1081 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1082 return 0; 1083 } 1084 if (infolen > OSSL_HPKE_MAX_INFOLEN) { 1085 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1086 return 0; 1087 } 1088 if (infolen > 0 && info == NULL) { 1089 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1090 return 0; 1091 } 1092 minenc = OSSL_HPKE_get_public_encap_size(ctx->suite); 1093 if (minenc == 0 || minenc > *enclen) { 1094 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1095 return 0; 1096 } 1097 if (ctx->shared_secret != NULL) { 1098 /* only allow one encap per OSSL_HPKE_CTX */ 1099 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1100 return 0; 1101 } 1102 if (hpke_encap(ctx, enc, enclen, pub, publen) != 1) { 1103 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1104 return 0; 1105 } 1106 /* 1107 * note that the info is not part of the context as it 1108 * only needs to be used once here so doesn't need to 1109 * be stored 1110 */ 1111 erv = hpke_do_middle(ctx, info, infolen); 1112 return erv; 1113 } 1114 1115 int OSSL_HPKE_decap(OSSL_HPKE_CTX *ctx, 1116 const unsigned char *enc, size_t enclen, 1117 EVP_PKEY *recippriv, 1118 const unsigned char *info, size_t infolen) 1119 { 1120 int erv = 1; 1121 size_t minenc = 0; 1122 1123 if (ctx == NULL || enc == NULL || enclen == 0 || recippriv == NULL) { 1124 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1125 return 0; 1126 } 1127 if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) { 1128 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1129 return 0; 1130 } 1131 if (infolen > OSSL_HPKE_MAX_INFOLEN) { 1132 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1133 return 0; 1134 } 1135 if (infolen > 0 && info == NULL) { 1136 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1137 return 0; 1138 } 1139 minenc = OSSL_HPKE_get_public_encap_size(ctx->suite); 1140 if (minenc == 0 || minenc > enclen) { 1141 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1142 return 0; 1143 } 1144 if (ctx->shared_secret != NULL) { 1145 /* only allow one encap per OSSL_HPKE_CTX */ 1146 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1147 return 0; 1148 } 1149 erv = hpke_decap(ctx, enc, enclen, recippriv); 1150 if (erv != 1) { 1151 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1152 return 0; 1153 } 1154 /* 1155 * note that the info is not part of the context as it 1156 * only needs to be used once here so doesn't need to 1157 * be stored 1158 */ 1159 erv = hpke_do_middle(ctx, info, infolen); 1160 return erv; 1161 } 1162 1163 int OSSL_HPKE_seal(OSSL_HPKE_CTX *ctx, 1164 unsigned char *ct, size_t *ctlen, 1165 const unsigned char *aad, size_t aadlen, 1166 const unsigned char *pt, size_t ptlen) 1167 { 1168 unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN]; 1169 size_t seqlen = 0; 1170 1171 if (ctx == NULL || ct == NULL || ctlen == NULL || *ctlen == 0 1172 || pt == NULL || ptlen == 0) { 1173 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1174 return 0; 1175 } 1176 if (ctx->role != OSSL_HPKE_ROLE_SENDER) { 1177 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1178 return 0; 1179 } 1180 if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */ 1181 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1182 return 0; 1183 } 1184 if (ctx->key == NULL || ctx->nonce == NULL) { 1185 /* need to have done an encap first, info can be NULL */ 1186 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1187 return 0; 1188 } 1189 seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf)); 1190 if (seqlen == 0) { 1191 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1192 return 0; 1193 } 1194 if (hpke_aead_enc(ctx, seqbuf, aad, aadlen, pt, ptlen, ct, ctlen) != 1) { 1195 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1196 OPENSSL_cleanse(seqbuf, sizeof(seqbuf)); 1197 return 0; 1198 } else { 1199 ctx->seq++; 1200 } 1201 OPENSSL_cleanse(seqbuf, sizeof(seqbuf)); 1202 return 1; 1203 } 1204 1205 int OSSL_HPKE_open(OSSL_HPKE_CTX *ctx, 1206 unsigned char *pt, size_t *ptlen, 1207 const unsigned char *aad, size_t aadlen, 1208 const unsigned char *ct, size_t ctlen) 1209 { 1210 unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN]; 1211 size_t seqlen = 0; 1212 1213 if (ctx == NULL || pt == NULL || ptlen == NULL || *ptlen == 0 1214 || ct == NULL || ctlen == 0) { 1215 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1216 return 0; 1217 } 1218 if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) { 1219 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1220 return 0; 1221 } 1222 if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */ 1223 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1224 return 0; 1225 } 1226 if (ctx->key == NULL || ctx->nonce == NULL) { 1227 /* need to have done an encap first, info can be NULL */ 1228 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1229 return 0; 1230 } 1231 seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf)); 1232 if (seqlen == 0) { 1233 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1234 return 0; 1235 } 1236 if (hpke_aead_dec(ctx, seqbuf, aad, aadlen, ct, ctlen, pt, ptlen) != 1) { 1237 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1238 OPENSSL_cleanse(seqbuf, sizeof(seqbuf)); 1239 return 0; 1240 } 1241 ctx->seq++; 1242 OPENSSL_cleanse(seqbuf, sizeof(seqbuf)); 1243 return 1; 1244 } 1245 1246 int OSSL_HPKE_export(OSSL_HPKE_CTX *ctx, 1247 unsigned char *secret, size_t secretlen, 1248 const unsigned char *label, size_t labellen) 1249 { 1250 int erv = 0; 1251 EVP_KDF_CTX *kctx = NULL; 1252 unsigned char suitebuf[6]; 1253 const char *mdname = NULL; 1254 const OSSL_HPKE_KDF_INFO *kdf_info = NULL; 1255 1256 if (ctx == NULL || secret == NULL || secretlen == 0) { 1257 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1258 return 0; 1259 } 1260 if (labellen > OSSL_HPKE_MAX_PARMLEN) { 1261 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1262 return 0; 1263 } 1264 if (labellen > 0 && label == NULL) { 1265 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1266 return 0; 1267 } 1268 if (ctx->exportersec == NULL) { 1269 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); 1270 return 0; 1271 } 1272 kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id); 1273 if (kdf_info == NULL) { 1274 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1275 return 0; 1276 } 1277 mdname = kdf_info->mdname; 1278 kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq); 1279 if (kctx == NULL) { 1280 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1281 return 0; 1282 } 1283 /* full suiteid as per RFC9180 sec 5.3 */ 1284 suitebuf[0] = ctx->suite.kem_id / 256; 1285 suitebuf[1] = ctx->suite.kem_id % 256; 1286 suitebuf[2] = ctx->suite.kdf_id / 256; 1287 suitebuf[3] = ctx->suite.kdf_id % 256; 1288 suitebuf[4] = ctx->suite.aead_id / 256; 1289 suitebuf[5] = ctx->suite.aead_id % 256; 1290 erv = ossl_hpke_labeled_expand(kctx, secret, secretlen, 1291 ctx->exportersec, ctx->exporterseclen, 1292 OSSL_HPKE_SEC51LABEL, 1293 suitebuf, sizeof(suitebuf), 1294 OSSL_HPKE_EXP_SEC_LABEL, 1295 label, labellen); 1296 EVP_KDF_CTX_free(kctx); 1297 if (erv != 1) 1298 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1299 return erv; 1300 } 1301 1302 int OSSL_HPKE_keygen(OSSL_HPKE_SUITE suite, 1303 unsigned char *pub, size_t *publen, EVP_PKEY **priv, 1304 const unsigned char *ikm, size_t ikmlen, 1305 OSSL_LIB_CTX *libctx, const char *propq) 1306 { 1307 int erv = 0; /* Our error return value - 1 is success */ 1308 EVP_PKEY_CTX *pctx = NULL; 1309 EVP_PKEY *skR = NULL; 1310 const OSSL_HPKE_KEM_INFO *kem_info = NULL; 1311 OSSL_PARAM params[3], *p = params; 1312 1313 if (pub == NULL || publen == NULL || *publen == 0 || priv == NULL) { 1314 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1315 return 0; 1316 } 1317 if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1) { 1318 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1319 return 0; 1320 } 1321 if ((ikmlen > 0 && ikm == NULL) 1322 || (ikmlen == 0 && ikm != NULL) 1323 || ikmlen > OSSL_HPKE_MAX_PARMLEN) { 1324 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1325 return 0; 1326 } 1327 1328 if (hpke_kem_id_nist_curve(suite.kem_id) == 1) { 1329 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, 1330 (char *)kem_info->groupname, 0); 1331 pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq); 1332 } else { 1333 pctx = EVP_PKEY_CTX_new_from_name(libctx, kem_info->keytype, propq); 1334 } 1335 if (pctx == NULL 1336 || EVP_PKEY_keygen_init(pctx) <= 0) { 1337 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1338 goto err; 1339 } 1340 if (ikm != NULL) 1341 *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM, 1342 (char *)ikm, ikmlen); 1343 *p = OSSL_PARAM_construct_end(); 1344 if (EVP_PKEY_CTX_set_params(pctx, params) <= 0) { 1345 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1346 goto err; 1347 } 1348 if (EVP_PKEY_generate(pctx, &skR) <= 0) { 1349 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1350 goto err; 1351 } 1352 EVP_PKEY_CTX_free(pctx); 1353 pctx = NULL; 1354 if (EVP_PKEY_get_octet_string_param(skR, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, 1355 pub, *publen, publen) 1356 != 1) { 1357 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1358 goto err; 1359 } 1360 *priv = skR; 1361 erv = 1; 1362 1363 err: 1364 if (erv != 1) 1365 EVP_PKEY_free(skR); 1366 EVP_PKEY_CTX_free(pctx); 1367 return erv; 1368 } 1369 1370 int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite) 1371 { 1372 return hpke_suite_check(suite, NULL, NULL, NULL); 1373 } 1374 1375 int OSSL_HPKE_get_grease_value(const OSSL_HPKE_SUITE *suite_in, 1376 OSSL_HPKE_SUITE *suite, 1377 unsigned char *enc, size_t *enclen, 1378 unsigned char *ct, size_t ctlen, 1379 OSSL_LIB_CTX *libctx, const char *propq) 1380 { 1381 OSSL_HPKE_SUITE chosen; 1382 size_t plen = 0; 1383 const OSSL_HPKE_KEM_INFO *kem_info = NULL; 1384 const OSSL_HPKE_AEAD_INFO *aead_info = NULL; 1385 EVP_PKEY *fakepriv = NULL; 1386 1387 if (enc == NULL || enclen == 0 1388 || ct == NULL || ctlen == 0 || suite == NULL) { 1389 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT); 1390 return 0; 1391 } 1392 if (suite_in == NULL) { 1393 /* choose a random suite */ 1394 if (hpke_random_suite(libctx, propq, &chosen) != 1) { 1395 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1396 goto err; 1397 } 1398 } else { 1399 chosen = *suite_in; 1400 } 1401 if (hpke_suite_check(chosen, &kem_info, NULL, &aead_info) != 1) { 1402 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1403 goto err; 1404 } 1405 *suite = chosen; 1406 /* make sure room for tag and one plaintext octet */ 1407 if (aead_info->taglen >= ctlen) { 1408 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1409 goto err; 1410 } 1411 /* publen */ 1412 plen = kem_info->Npk; 1413 if (plen > *enclen) { 1414 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1415 goto err; 1416 } 1417 /* 1418 * In order for our enc to look good for sure, we generate and then 1419 * delete a real key for that curve - bit OTT but it ensures we do 1420 * get the encoding right (e.g. 0x04 as 1st octet for NIST curves in 1421 * uncompressed form) and that the value really does map to a point on 1422 * the relevant curve. 1423 */ 1424 if (OSSL_HPKE_keygen(chosen, enc, enclen, &fakepriv, NULL, 0, 1425 libctx, propq) 1426 != 1) { 1427 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1428 goto err; 1429 } 1430 EVP_PKEY_free(fakepriv); 1431 if (RAND_bytes_ex(libctx, ct, ctlen, 0) <= 0) { 1432 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); 1433 goto err; 1434 } 1435 return 1; 1436 err: 1437 return 0; 1438 } 1439 1440 int OSSL_HPKE_str2suite(const char *str, OSSL_HPKE_SUITE *suite) 1441 { 1442 return ossl_hpke_str2suite(str, suite); 1443 } 1444 1445 size_t OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite, size_t clearlen) 1446 { 1447 size_t enclen = 0; 1448 size_t cipherlen = 0; 1449 1450 if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1) 1451 return 0; 1452 return cipherlen; 1453 } 1454 1455 size_t OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite) 1456 { 1457 size_t enclen = 0; 1458 size_t cipherlen = 0; 1459 size_t clearlen = 16; 1460 1461 if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1) 1462 return 0; 1463 return enclen; 1464 } 1465 1466 size_t OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite) 1467 { 1468 const OSSL_HPKE_KEM_INFO *kem_info = NULL; 1469 1470 if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1) 1471 return 0; 1472 if (kem_info == NULL) 1473 return 0; 1474 1475 return kem_info->Nsk; 1476 } 1477