2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the OpenSSL license (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
10 /* An OpenSSL-based HPKE implementation of RFC9180 */
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"
23 /** default buffer size for keys and internal buffers we use */
24 #define OSSL_HPKE_MAXSIZE 512
26 /* Define HPKE labels from RFC9180 in hex for EBCDIC compatibility */
27 /* "HPKE" - "suite_id" label for section 5.1 */
28 static const char OSSL_HPKE_SEC51LABEL[] = "\x48\x50\x4b\x45";
29 /* "psk_id_hash" - in key_schedule_context */
30 static const char OSSL_HPKE_PSKIDHASH_LABEL[] = "\x70\x73\x6b\x5f\x69\x64\x5f\x68\x61\x73\x68";
31 /* "info_hash" - in key_schedule_context */
32 static const char OSSL_HPKE_INFOHASH_LABEL[] = "\x69\x6e\x66\x6f\x5f\x68\x61\x73\x68";
33 /* "base_nonce" - base nonce calc label */
34 static const char OSSL_HPKE_NONCE_LABEL[] = "\x62\x61\x73\x65\x5f\x6e\x6f\x6e\x63\x65";
35 /* "exp" - internal exporter secret generation label */
36 static const char OSSL_HPKE_EXP_LABEL[] = "\x65\x78\x70";
37 /* "sec" - external label for exporting secret */
38 static const char OSSL_HPKE_EXP_SEC_LABEL[] = "\x73\x65\x63";
39 /* "key" - label for use when generating key from shared secret */
40 static const char OSSL_HPKE_KEY_LABEL[] = "\x6b\x65\x79";
41 /* "psk_hash" - for hashing PSK */
42 static const char OSSL_HPKE_PSK_HASH_LABEL[] = "\x70\x73\x6b\x5f\x68\x61\x73\x68";
43 /* "secret" - for generating shared secret */
44 static const char OSSL_HPKE_SECRET_LABEL[] = "\x73\x65\x63\x72\x65\x74";
47 * @brief sender or receiver context
49 struct ossl_hpke_ctx_st
51 OSSL_LIB_CTX *libctx; /* library context */
52 char *propq; /* properties */
53 int mode; /* HPKE mode */
54 OSSL_HPKE_SUITE suite; /* suite */
55 const OSSL_HPKE_KEM_INFO *kem_info;
56 const OSSL_HPKE_KDF_INFO *kdf_info;
57 const OSSL_HPKE_AEAD_INFO *aead_info;
58 EVP_CIPHER *aead_ciph;
59 int role; /* sender(0) or receiver(1) */
60 uint64_t seq; /* aead sequence number */
61 unsigned char *shared_secret; /* KEM output, zz */
62 size_t shared_secretlen;
63 unsigned char *key; /* final aead key */
65 unsigned char *nonce; /* aead base nonce */
67 unsigned char *exportersec; /* exporter secret */
68 size_t exporterseclen;
69 char *pskid; /* PSK stuff */
72 EVP_PKEY *authpriv; /* sender's authentication private key */
73 unsigned char *authpub; /* auth public key */
75 unsigned char *ikme; /* IKM for sender deterministic key gen */
80 * @brief check if KEM uses NIST curve or not
81 * @param kem_id is the externally supplied kem_id
82 * @return 1 for NIST curves, 0 for other
84 static int hpke_kem_id_nist_curve(uint16_t kem_id)
86 const OSSL_HPKE_KEM_INFO *kem_info;
88 kem_info = ossl_HPKE_KEM_INFO_find_id(kem_id);
89 return kem_info != NULL && kem_info->groupname != NULL;
93 * @brief wrapper to import NIST curve public key as easily as x25519/x448
94 * @param libctx is the context to use
95 * @param propq is a properties string
96 * @param gname is the curve groupname
97 * @param buf is the binary buffer with the (uncompressed) public value
98 * @param buflen is the length of the private key buffer
99 * @return a working EVP_PKEY * or NULL
101 * Note that this could be a useful function to make public in
102 * future, but would likely require a name change.
104 static EVP_PKEY *evp_pkey_new_raw_nist_public_key(OSSL_LIB_CTX *libctx,
107 const unsigned char *buf,
110 OSSL_PARAM params[2];
111 EVP_PKEY *ret = NULL;
112 EVP_PKEY_CTX *cctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
114 params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
116 params[1] = OSSL_PARAM_construct_end();
118 || EVP_PKEY_paramgen_init(cctx) <= 0
119 || EVP_PKEY_CTX_set_params(cctx, params) <= 0
120 || EVP_PKEY_paramgen(cctx, &ret) <= 0
121 || EVP_PKEY_set1_encoded_public_key(ret, buf, buflen) != 1) {
122 EVP_PKEY_CTX_free(cctx);
124 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
127 EVP_PKEY_CTX_free(cctx);
132 * @brief do the AEAD decryption
133 * @param hctx is the context to use
134 * @param iv is the initialisation vector
135 * @param aad is the additional authenticated data
136 * @param aadlen is the length of the aad
137 * @param ct is the ciphertext buffer
138 * @param ctlen is the ciphertext length (including tag).
139 * @param pt is the output buffer
140 * @param ptlen input/output, better be big enough on input, exact on output
141 * @return 1 on success, 0 otherwise
143 static int hpke_aead_dec(OSSL_HPKE_CTX *hctx, const unsigned char *iv,
144 const unsigned char *aad, size_t aadlen,
145 const unsigned char *ct, size_t ctlen,
146 unsigned char *pt, size_t *ptlen)
149 EVP_CIPHER_CTX *ctx = NULL;
153 taglen = hctx->aead_info->taglen;
154 if (ctlen <= taglen || *ptlen < ctlen - taglen) {
155 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
158 /* Create and initialise the context */
159 if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
162 /* Initialise the decryption operation. */
163 if (EVP_DecryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) {
164 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
167 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
168 hctx->noncelen, NULL) != 1) {
169 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
172 /* Initialise key and IV */
173 if (EVP_DecryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) {
174 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
178 if (aadlen != 0 && aad != NULL) {
179 if (EVP_DecryptUpdate(ctx, NULL, &len, aad, aadlen) != 1) {
180 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
184 if (EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen - taglen) != 1) {
185 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
189 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
190 taglen, (void *)(ct + ctlen - taglen))) {
191 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
194 /* Finalise decryption. */
195 if (EVP_DecryptFinal_ex(ctx, pt + len, &len) <= 0) {
196 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
203 OPENSSL_cleanse(pt, *ptlen);
204 EVP_CIPHER_CTX_free(ctx);
209 * @brief do AEAD encryption as per the RFC
210 * @param hctx is the context to use
211 * @param iv is the initialisation vector
212 * @param aad is the additional authenticated data
213 * @param aadlen is the length of the aad
214 * @param pt is the plaintext buffer
215 * @param ptlen is the length of pt
216 * @param ct is the output buffer
217 * @param ctlen input/output, needs space for tag on input, exact on output
218 * @return 1 for success, 0 otherwise
220 static int hpke_aead_enc(OSSL_HPKE_CTX *hctx, const unsigned char *iv,
221 const unsigned char *aad, size_t aadlen,
222 const unsigned char *pt, size_t ptlen,
223 unsigned char *ct, size_t *ctlen)
226 EVP_CIPHER_CTX *ctx = NULL;
229 unsigned char tag[16];
231 taglen = hctx->aead_info->taglen;
232 if (*ctlen <= taglen || ptlen > *ctlen - taglen) {
233 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
236 /* Create and initialise the context */
237 if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
240 /* Initialise the encryption operation. */
241 if (EVP_EncryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) {
242 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
245 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
246 hctx->noncelen, NULL) != 1) {
247 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
250 /* Initialise key and IV */
251 if (EVP_EncryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) {
252 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
255 /* Provide any AAD data. */
256 if (aadlen != 0 && aad != NULL) {
257 if (EVP_EncryptUpdate(ctx, NULL, &len, aad, aadlen) != 1) {
258 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
262 if (EVP_EncryptUpdate(ctx, ct, &len, pt, ptlen) != 1) {
263 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
267 /* Finalise the encryption. */
268 if (EVP_EncryptFinal_ex(ctx, ct + len, &len) != 1) {
269 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
273 /* Get tag. Not a duplicate so needs to be added to the ciphertext */
274 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, tag) != 1) {
275 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
278 memcpy(ct + *ctlen, tag, taglen);
284 OPENSSL_cleanse(ct, *ctlen);
285 EVP_CIPHER_CTX_free(ctx);
290 * @brief check mode is in-range and supported
291 * @param mode is the caller's chosen mode
292 * @return 1 for good mode, 0 otherwise
294 static int hpke_mode_check(unsigned int mode)
297 case OSSL_HPKE_MODE_BASE:
298 case OSSL_HPKE_MODE_PSK:
299 case OSSL_HPKE_MODE_AUTH:
300 case OSSL_HPKE_MODE_PSKAUTH:
309 * @brief check if a suite is supported locally
310 * @param suite is the suite to check
311 * @return 1 for good, 0 otherwise
313 static int hpke_suite_check(OSSL_HPKE_SUITE suite,
314 const OSSL_HPKE_KEM_INFO **kem_info,
315 const OSSL_HPKE_KDF_INFO **kdf_info,
316 const OSSL_HPKE_AEAD_INFO **aead_info)
318 const OSSL_HPKE_KEM_INFO *kem_info_;
319 const OSSL_HPKE_KDF_INFO *kdf_info_;
320 const OSSL_HPKE_AEAD_INFO *aead_info_;
322 /* check KEM, KDF and AEAD are supported here */
323 if ((kem_info_ = ossl_HPKE_KEM_INFO_find_id(suite.kem_id)) == NULL)
325 if ((kdf_info_ = ossl_HPKE_KDF_INFO_find_id(suite.kdf_id)) == NULL)
327 if ((aead_info_ = ossl_HPKE_AEAD_INFO_find_id(suite.aead_id)) == NULL)
330 if (kem_info != NULL)
331 *kem_info = kem_info_;
332 if (kdf_info != NULL)
333 *kdf_info = kdf_info_;
334 if (aead_info != NULL)
335 *aead_info = aead_info_;
341 * @brief randomly pick a suite
342 * @param libctx is the context to use
343 * @param propq is a properties string
344 * @param suite is the result
345 * @return 1 for success, 0 otherwise
347 static int hpke_random_suite(OSSL_LIB_CTX *libctx,
349 OSSL_HPKE_SUITE *suite)
351 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
352 const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
353 const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
355 /* random kem, kdf and aead */
356 kem_info = ossl_HPKE_KEM_INFO_find_random(libctx);
357 if (kem_info == NULL)
359 suite->kem_id = kem_info->kem_id;
360 kdf_info = ossl_HPKE_KDF_INFO_find_random(libctx);
361 if (kdf_info == NULL)
363 suite->kdf_id = kdf_info->kdf_id;
364 aead_info = ossl_HPKE_AEAD_INFO_find_random(libctx);
365 if (aead_info == NULL)
367 suite->aead_id = aead_info->aead_id;
372 * @brief tell the caller how big the ciphertext will be
374 * AEAD algorithms add a tag for data authentication.
375 * Those are almost always, but not always, 16 octets
376 * long, and who knows what will be true in the future.
377 * So this function allows a caller to find out how
378 * much data expansion they will see with a given suite.
380 * "enc" is the name used in RFC9180 for the encapsulated
381 * public value of the sender, who calls OSSL_HPKE_seal(),
382 * that is sent to the recipient, who calls OSSL_HPKE_open().
384 * @param suite is the suite to be used
385 * @param enclen points to what will be enc length
386 * @param clearlen is the length of plaintext
387 * @param cipherlen points to what will be ciphertext length (including tag)
388 * @return 1 for success, 0 otherwise
390 static int hpke_expansion(OSSL_HPKE_SUITE suite,
395 const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
396 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
398 if (cipherlen == NULL || enclen == NULL) {
399 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
402 if (hpke_suite_check(suite, &kem_info, NULL, &aead_info) != 1) {
403 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
406 *cipherlen = clearlen + aead_info->taglen;
407 *enclen = kem_info->Nenc;
412 * @brief expand and XOR the 64-bit unsigned seq with (nonce) buffer
413 * @param ctx is the HPKE context
414 * @param buf is the buffer for the XOR'd seq and nonce
415 * @param blen is the size of buf
416 * @return 0 for error, otherwise blen
418 static size_t hpke_seqnonce2buf(OSSL_HPKE_CTX *ctx,
419 unsigned char *buf, size_t blen)
424 if (ctx == NULL || blen < sizeof(seq_copy) || blen != ctx->noncelen)
427 memset(buf, 0, blen);
428 for (i = 0; i < sizeof(seq_copy); i++) {
429 buf[blen - i - 1] = seq_copy & 0xff;
432 for (i = 0; i < blen; i++)
433 buf[i] ^= ctx->nonce[i];
438 * @brief call the underlying KEM to encap
439 * @param ctx is the OSSL_HPKE_CTX
440 * @param enc is a buffer for the sender's ephemeral public value
441 * @param enclen is the size of enc on input, number of octets used on output
442 * @param pub is the recipient's public value
443 * @param publen is the length of pub
444 * @return 1 for success, 0 for error
446 static int hpke_encap(OSSL_HPKE_CTX *ctx, unsigned char *enc, size_t *enclen,
447 const unsigned char *pub, size_t publen)
450 OSSL_PARAM params[3], *p = params;
452 EVP_PKEY_CTX *pctx = NULL;
453 EVP_PKEY *pkR = NULL;
454 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
456 if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0
457 || pub == NULL || publen == 0) {
458 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
461 if (ctx->shared_secret != NULL) {
462 /* only run the KEM once per OSSL_HPKE_CTX */
463 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
466 kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
467 if (kem_info == NULL) {
468 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
471 if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
472 pkR = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
476 pkR = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
478 ctx->propq, pub, publen);
481 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
484 pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkR, ctx->propq);
486 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
489 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
490 OSSL_KEM_PARAM_OPERATION_DHKEM,
492 if (ctx->ikme != NULL) {
493 *p++ = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME,
494 ctx->ikme, ctx->ikmelen);
496 *p = OSSL_PARAM_construct_end();
497 if (ctx->mode == OSSL_HPKE_MODE_AUTH
498 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
499 if (EVP_PKEY_auth_encapsulate_init(pctx, ctx->authpriv,
501 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
505 if (EVP_PKEY_encapsulate_init(pctx, params) != 1) {
506 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
510 if (EVP_PKEY_encapsulate(pctx, NULL, enclen, NULL, &lsslen) != 1) {
511 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
514 ctx->shared_secret = OPENSSL_malloc(lsslen);
515 if (ctx->shared_secret == NULL)
517 ctx->shared_secretlen = lsslen;
518 if (EVP_PKEY_encapsulate(pctx, enc, enclen, ctx->shared_secret,
519 &ctx->shared_secretlen) != 1) {
520 ctx->shared_secretlen = 0;
521 OPENSSL_free(ctx->shared_secret);
522 ctx->shared_secret = NULL;
523 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
529 EVP_PKEY_CTX_free(pctx);
535 * @brief call the underlying KEM to decap
536 * @param ctx is the OSSL_HPKE_CTX
537 * @param enc is a buffer for the sender's ephemeral public value
538 * @param enclen is the length of enc
539 * @param priv is the recipient's private value
540 * @return 1 for success, 0 for error
542 static int hpke_decap(OSSL_HPKE_CTX *ctx,
543 const unsigned char *enc, size_t enclen,
547 EVP_PKEY_CTX *pctx = NULL;
548 EVP_PKEY *spub = NULL;
549 OSSL_PARAM params[2], *p = params;
552 if (ctx == NULL || enc == NULL || enclen == 0 || priv == NULL) {
553 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
556 if (ctx->shared_secret != NULL) {
557 /* only run the KEM once per OSSL_HPKE_CTX */
558 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
561 pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, priv, ctx->propq);
563 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
566 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
567 OSSL_KEM_PARAM_OPERATION_DHKEM,
569 *p = OSSL_PARAM_construct_end();
570 if (ctx->mode == OSSL_HPKE_MODE_AUTH
571 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
572 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
574 kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
575 if (kem_info == NULL) {
576 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
579 if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
580 spub = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
585 spub = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
592 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
595 if (EVP_PKEY_auth_decapsulate_init(pctx, spub, params) != 1) {
596 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
600 if (EVP_PKEY_decapsulate_init(pctx, params) != 1) {
601 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
605 if (EVP_PKEY_decapsulate(pctx, NULL, &lsslen, enc, enclen) != 1) {
606 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
609 ctx->shared_secret = OPENSSL_malloc(lsslen);
610 if (ctx->shared_secret == NULL)
612 if (EVP_PKEY_decapsulate(pctx, ctx->shared_secret, &lsslen,
614 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
617 ctx->shared_secretlen = lsslen;
621 EVP_PKEY_CTX_free(pctx);
624 OPENSSL_free(ctx->shared_secret);
625 ctx->shared_secret = NULL;
626 ctx->shared_secretlen = 0;
632 * @brief do "middle" of HPKE, between KEM and AEAD
633 * @param ctx is the OSSL_HPKE_CTX
634 * @param info is a buffer for the added binding information
635 * @param infolen is the length of info
636 * @return 0 for error, 1 for success
638 * This does all the HPKE extracts and expands as defined in RFC9180
639 * section 5.1, (badly termed there as a "key schedule") and sets the
640 * ctx fields for the shared_secret, nonce, key and exporter_secret
642 static int hpke_do_middle(OSSL_HPKE_CTX *ctx,
643 const unsigned char *info, size_t infolen)
646 size_t ks_contextlen = OSSL_HPKE_MAXSIZE;
647 unsigned char ks_context[OSSL_HPKE_MAXSIZE];
650 size_t psk_hashlen = OSSL_HPKE_MAXSIZE;
651 unsigned char psk_hash[OSSL_HPKE_MAXSIZE];
652 const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
653 const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
654 size_t secretlen = OSSL_HPKE_MAXSIZE;
655 unsigned char secret[OSSL_HPKE_MAXSIZE];
656 EVP_KDF_CTX *kctx = NULL;
657 unsigned char suitebuf[6];
658 const char *mdname = NULL;
660 /* only let this be done once */
661 if (ctx->exportersec != NULL) {
662 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
665 if (ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id) == NULL) {
666 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
669 aead_info = ossl_HPKE_AEAD_INFO_find_id(ctx->suite.aead_id);
670 if (aead_info == NULL) {
671 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
674 kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id);
675 if (kdf_info == NULL) {
676 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
679 mdname = kdf_info->mdname;
680 /* create key schedule context */
681 memset(ks_context, 0, sizeof(ks_context));
682 ks_context[0] = (unsigned char)(ctx->mode % 256);
683 ks_contextlen--; /* remaining space */
684 halflen = kdf_info->Nh;
685 if ((2 * halflen) > ks_contextlen) {
686 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
689 /* check a psk was set if in that mode */
690 if (ctx->mode == OSSL_HPKE_MODE_PSK
691 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
692 if (ctx->psk == NULL || ctx->psklen == 0 || ctx->pskid == NULL) {
693 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
697 kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
699 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
702 pskidlen = (ctx->psk == NULL ? 0 : strlen(ctx->pskid));
703 /* full suite details as per RFC9180 sec 5.1 */
704 suitebuf[0] = ctx->suite.kem_id / 256;
705 suitebuf[1] = ctx->suite.kem_id % 256;
706 suitebuf[2] = ctx->suite.kdf_id / 256;
707 suitebuf[3] = ctx->suite.kdf_id % 256;
708 suitebuf[4] = ctx->suite.aead_id / 256;
709 suitebuf[5] = ctx->suite.aead_id % 256;
710 if (ossl_hpke_labeled_extract(kctx, ks_context + 1, halflen,
711 NULL, 0, OSSL_HPKE_SEC51LABEL,
712 suitebuf, sizeof(suitebuf),
713 OSSL_HPKE_PSKIDHASH_LABEL,
714 (unsigned char *)ctx->pskid, pskidlen) != 1) {
715 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
718 if (ossl_hpke_labeled_extract(kctx, ks_context + 1 + halflen, halflen,
719 NULL, 0, OSSL_HPKE_SEC51LABEL,
720 suitebuf, sizeof(suitebuf),
721 OSSL_HPKE_INFOHASH_LABEL,
722 (unsigned char *)info, infolen) != 1) {
723 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
726 ks_contextlen = 1 + 2 * halflen;
727 /* Extract and Expand variously... */
728 psk_hashlen = halflen;
729 if (ossl_hpke_labeled_extract(kctx, psk_hash, psk_hashlen,
730 NULL, 0, OSSL_HPKE_SEC51LABEL,
731 suitebuf, sizeof(suitebuf),
732 OSSL_HPKE_PSK_HASH_LABEL,
733 ctx->psk, ctx->psklen) != 1) {
734 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
737 secretlen = kdf_info->Nh;
738 if (secretlen > OSSL_HPKE_MAXSIZE) {
739 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
742 if (ossl_hpke_labeled_extract(kctx, secret, secretlen,
743 ctx->shared_secret, ctx->shared_secretlen,
744 OSSL_HPKE_SEC51LABEL,
745 suitebuf, sizeof(suitebuf),
746 OSSL_HPKE_SECRET_LABEL,
747 ctx->psk, ctx->psklen) != 1) {
748 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
751 if (ctx->suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) {
752 /* we only need nonce/key for non export AEADs */
753 ctx->noncelen = aead_info->Nn;
754 ctx->nonce = OPENSSL_malloc(ctx->noncelen);
755 if (ctx->nonce == NULL)
757 if (ossl_hpke_labeled_expand(kctx, ctx->nonce, ctx->noncelen,
758 secret, secretlen, OSSL_HPKE_SEC51LABEL,
759 suitebuf, sizeof(suitebuf),
760 OSSL_HPKE_NONCE_LABEL,
761 ks_context, ks_contextlen) != 1) {
762 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
765 ctx->keylen = aead_info->Nk;
766 ctx->key = OPENSSL_malloc(ctx->keylen);
767 if (ctx->key == NULL)
769 if (ossl_hpke_labeled_expand(kctx, ctx->key, ctx->keylen,
770 secret, secretlen, OSSL_HPKE_SEC51LABEL,
771 suitebuf, sizeof(suitebuf),
773 ks_context, ks_contextlen) != 1) {
774 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
778 ctx->exporterseclen = kdf_info->Nh;
779 ctx->exportersec = OPENSSL_malloc(ctx->exporterseclen);
780 if (ctx->exportersec == NULL)
782 if (ossl_hpke_labeled_expand(kctx, ctx->exportersec, ctx->exporterseclen,
783 secret, secretlen, OSSL_HPKE_SEC51LABEL,
784 suitebuf, sizeof(suitebuf),
786 ks_context, ks_contextlen) != 1) {
787 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
793 OPENSSL_cleanse(ks_context, OSSL_HPKE_MAXSIZE);
794 OPENSSL_cleanse(psk_hash, OSSL_HPKE_MAXSIZE);
795 OPENSSL_cleanse(secret, OSSL_HPKE_MAXSIZE);
796 EVP_KDF_CTX_free(kctx);
801 * externally visible functions from below here, API documentation is
802 * in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication
805 OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role,
806 OSSL_LIB_CTX *libctx, const char *propq)
808 OSSL_HPKE_CTX *ctx = NULL;
809 const OSSL_HPKE_KEM_INFO *kem_info;
810 const OSSL_HPKE_KDF_INFO *kdf_info;
811 const OSSL_HPKE_AEAD_INFO *aead_info;
813 if (hpke_mode_check(mode) != 1) {
814 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
817 if (hpke_suite_check(suite, &kem_info, &kdf_info, &aead_info) != 1) {
818 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
821 if (role != OSSL_HPKE_ROLE_SENDER && role != OSSL_HPKE_ROLE_RECEIVER) {
822 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
825 ctx = OPENSSL_zalloc(sizeof(*ctx));
828 ctx->libctx = libctx;
830 ctx->propq = OPENSSL_strdup(propq);
831 if (ctx->propq == NULL)
834 if (suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) {
835 ctx->aead_ciph = EVP_CIPHER_fetch(libctx, aead_info->name, propq);
836 if (ctx->aead_ciph == NULL) {
837 ERR_raise(ERR_LIB_CRYPTO, ERR_R_FETCH_FAILED);
844 ctx->kem_info = kem_info;
845 ctx->kdf_info = kdf_info;
846 ctx->aead_info = aead_info;
850 EVP_CIPHER_free(ctx->aead_ciph);
855 void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX *ctx)
859 EVP_CIPHER_free(ctx->aead_ciph);
860 OPENSSL_free(ctx->propq);
861 OPENSSL_clear_free(ctx->exportersec, ctx->exporterseclen);
862 OPENSSL_free(ctx->pskid);
863 OPENSSL_clear_free(ctx->psk, ctx->psklen);
864 OPENSSL_clear_free(ctx->key, ctx->keylen);
865 OPENSSL_clear_free(ctx->nonce, ctx->noncelen);
866 OPENSSL_clear_free(ctx->shared_secret, ctx->shared_secretlen);
867 OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
868 EVP_PKEY_free(ctx->authpriv);
869 OPENSSL_free(ctx->authpub);
875 int OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX *ctx,
877 const unsigned char *psk, size_t psklen)
879 if (ctx == NULL || pskid == NULL || psk == NULL || psklen == 0) {
880 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
883 if (psklen > OSSL_HPKE_MAX_PARMLEN) {
884 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
887 if (strlen(pskid) > OSSL_HPKE_MAX_PARMLEN) {
888 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
891 if (ctx->mode != OSSL_HPKE_MODE_PSK
892 && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
893 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
896 /* free previous values if any */
897 OPENSSL_clear_free(ctx->psk, ctx->psklen);
898 ctx->psk = OPENSSL_memdup(psk, psklen);
899 if (ctx->psk == NULL)
901 ctx->psklen = psklen;
902 OPENSSL_free(ctx->pskid);
903 ctx->pskid = OPENSSL_strdup(pskid);
904 if (ctx->pskid == NULL) {
905 OPENSSL_clear_free(ctx->psk, ctx->psklen);
913 int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX *ctx,
914 const unsigned char *ikme, size_t ikmelen)
916 if (ctx == NULL || ikme == NULL) {
917 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
920 if (ikmelen == 0 || ikmelen > OSSL_HPKE_MAX_PARMLEN) {
921 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
924 if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
925 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
928 OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
929 ctx->ikme = OPENSSL_memdup(ikme, ikmelen);
930 if (ctx->ikme == NULL)
932 ctx->ikmelen = ikmelen;
936 int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX *ctx, EVP_PKEY *priv)
938 if (ctx == NULL || priv == NULL) {
939 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
942 if (ctx->mode != OSSL_HPKE_MODE_AUTH
943 && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
944 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
947 if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
948 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
951 EVP_PKEY_free(ctx->authpriv);
952 ctx->authpriv = EVP_PKEY_dup(priv);
953 if (ctx->authpriv == NULL)
958 int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX *ctx,
959 const unsigned char *pub, size_t publen)
962 EVP_PKEY *pubp = NULL;
963 unsigned char *lpub = NULL;
965 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
967 if (ctx == NULL || pub == NULL || publen == 0) {
968 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
971 if (ctx->mode != OSSL_HPKE_MODE_AUTH
972 && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
973 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
976 if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
977 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
980 /* check the value seems like a good public key for this kem */
981 kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
982 if (kem_info == NULL)
984 if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
985 pubp = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
989 pubp = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
995 /* can happen based on external input - buffer value may be garbage */
996 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1000 * extract out the public key in encoded form so we
1001 * should be fine even if given compressed form
1003 lpub = OPENSSL_malloc(OSSL_HPKE_MAXSIZE);
1006 if (EVP_PKEY_get_octet_string_param(pubp,
1007 OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
1008 lpub, OSSL_HPKE_MAXSIZE, &lpublen)
1011 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1014 /* free up old value */
1015 OPENSSL_free(ctx->authpub);
1016 ctx->authpub = lpub;
1017 ctx->authpublen = lpublen;
1021 EVP_PKEY_free(pubp);
1025 int OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX *ctx, uint64_t *seq)
1027 if (ctx == NULL || seq == NULL) {
1028 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1035 int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX *ctx, uint64_t seq)
1038 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1042 * We disallow senders from doing this as it's dangerous
1043 * Receivers are ok to use this, as no harm should ensue
1046 if (ctx->role == OSSL_HPKE_ROLE_SENDER) {
1047 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1054 int OSSL_HPKE_encap(OSSL_HPKE_CTX *ctx,
1055 unsigned char *enc, size_t *enclen,
1056 const unsigned char *pub, size_t publen,
1057 const unsigned char *info, size_t infolen)
1061 if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0
1062 || pub == NULL || publen == 0) {
1063 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1066 if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
1067 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1070 if (infolen > OSSL_HPKE_MAX_INFOLEN) {
1071 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1074 if (ctx->shared_secret != NULL) {
1075 /* only allow one encap per OSSL_HPKE_CTX */
1076 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1079 if (hpke_encap(ctx, enc, enclen, pub, publen) != 1) {
1080 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1084 * note that the info is not part of the context as it
1085 * only needs to be used once here so doesn't need to
1088 erv = hpke_do_middle(ctx, info, infolen);
1092 int OSSL_HPKE_decap(OSSL_HPKE_CTX *ctx,
1093 const unsigned char *enc, size_t enclen,
1094 EVP_PKEY *recippriv,
1095 const unsigned char *info, size_t infolen)
1099 if (ctx == NULL || enc == NULL || enclen == 0 || recippriv == NULL) {
1100 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1103 if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
1104 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1107 if (infolen > OSSL_HPKE_MAX_INFOLEN) {
1108 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1111 if (ctx->shared_secret != NULL) {
1112 /* only allow one encap per OSSL_HPKE_CTX */
1113 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1116 erv = hpke_decap(ctx, enc, enclen, recippriv);
1118 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1122 * note that the info is not part of the context as it
1123 * only needs to be used once here so doesn't need to
1126 erv = hpke_do_middle(ctx, info, infolen);
1130 int OSSL_HPKE_seal(OSSL_HPKE_CTX *ctx,
1131 unsigned char *ct, size_t *ctlen,
1132 const unsigned char *aad, size_t aadlen,
1133 const unsigned char *pt, size_t ptlen)
1135 unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
1138 if (ctx == NULL || ct == NULL || ctlen == NULL || *ctlen == 0
1139 || pt == NULL || ptlen == 0) {
1140 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1143 if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
1144 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1147 if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
1148 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1151 if (ctx->key == NULL || ctx->nonce == NULL) {
1152 /* need to have done an encap first, info can be NULL */
1153 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1156 seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
1158 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1161 if (hpke_aead_enc(ctx, seqbuf, aad, aadlen, pt, ptlen, ct, ctlen) != 1) {
1162 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1163 OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1168 OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1172 int OSSL_HPKE_open(OSSL_HPKE_CTX *ctx,
1173 unsigned char *pt, size_t *ptlen,
1174 const unsigned char *aad, size_t aadlen,
1175 const unsigned char *ct, size_t ctlen)
1177 unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
1180 if (ctx == NULL || pt == NULL || ptlen == NULL || *ptlen == 0
1181 || ct == NULL || ctlen == 0) {
1182 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1185 if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
1186 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1189 if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
1190 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1193 if (ctx->key == NULL || ctx->nonce == NULL) {
1194 /* need to have done an encap first, info can be NULL */
1195 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1198 seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
1200 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1203 if (hpke_aead_dec(ctx, seqbuf, aad, aadlen, ct, ctlen, pt, ptlen) != 1) {
1204 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1205 OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1209 OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1213 int OSSL_HPKE_export(OSSL_HPKE_CTX *ctx,
1214 unsigned char *secret, size_t secretlen,
1215 const unsigned char *label, size_t labellen)
1218 EVP_KDF_CTX *kctx = NULL;
1219 unsigned char suitebuf[6];
1220 const char *mdname = NULL;
1221 const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
1224 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1227 if (labellen > OSSL_HPKE_MAX_PARMLEN) {
1228 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1231 if (ctx->exportersec == NULL) {
1232 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1235 kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id);
1236 if (kdf_info == NULL) {
1237 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1240 mdname = kdf_info->mdname;
1241 kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
1243 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1246 /* full suiteid as per RFC9180 sec 5.3 */
1247 suitebuf[0] = ctx->suite.kem_id / 256;
1248 suitebuf[1] = ctx->suite.kem_id % 256;
1249 suitebuf[2] = ctx->suite.kdf_id / 256;
1250 suitebuf[3] = ctx->suite.kdf_id % 256;
1251 suitebuf[4] = ctx->suite.aead_id / 256;
1252 suitebuf[5] = ctx->suite.aead_id % 256;
1253 erv = ossl_hpke_labeled_expand(kctx, secret, secretlen,
1254 ctx->exportersec, ctx->exporterseclen,
1255 OSSL_HPKE_SEC51LABEL,
1256 suitebuf, sizeof(suitebuf),
1257 OSSL_HPKE_EXP_SEC_LABEL,
1259 EVP_KDF_CTX_free(kctx);
1261 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1265 int OSSL_HPKE_keygen(OSSL_HPKE_SUITE suite,
1266 unsigned char *pub, size_t *publen, EVP_PKEY **priv,
1267 const unsigned char *ikm, size_t ikmlen,
1268 OSSL_LIB_CTX *libctx, const char *propq)
1270 int erv = 0; /* Our error return value - 1 is success */
1271 EVP_PKEY_CTX *pctx = NULL;
1272 EVP_PKEY *skR = NULL;
1273 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1274 OSSL_PARAM params[3], *p = params;
1276 if (pub == NULL || publen == NULL || *publen == 0 || priv == NULL) {
1277 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1280 if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1) {
1281 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1284 if ((ikmlen > 0 && ikm == NULL)
1285 || (ikmlen == 0 && ikm != NULL)
1286 || ikmlen > OSSL_HPKE_MAX_PARMLEN) {
1287 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1291 if (hpke_kem_id_nist_curve(suite.kem_id) == 1) {
1292 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
1293 (char *)kem_info->groupname, 0);
1294 pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
1296 pctx = EVP_PKEY_CTX_new_from_name(libctx, kem_info->keytype, propq);
1299 || EVP_PKEY_keygen_init(pctx) <= 0) {
1300 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1304 *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
1305 (char *)ikm, ikmlen);
1306 *p = OSSL_PARAM_construct_end();
1307 if (EVP_PKEY_CTX_set_params(pctx, params) <= 0) {
1308 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1311 if (EVP_PKEY_generate(pctx, &skR) <= 0) {
1312 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1315 EVP_PKEY_CTX_free(pctx);
1317 if (EVP_PKEY_get_octet_string_param(skR, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
1318 pub, *publen, publen) != 1) {
1319 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1328 EVP_PKEY_CTX_free(pctx);
1332 int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite)
1334 return hpke_suite_check(suite, NULL, NULL, NULL);
1337 int OSSL_HPKE_get_grease_value(const OSSL_HPKE_SUITE *suite_in,
1338 OSSL_HPKE_SUITE *suite,
1339 unsigned char *enc, size_t *enclen,
1340 unsigned char *ct, size_t ctlen,
1341 OSSL_LIB_CTX *libctx, const char *propq)
1343 OSSL_HPKE_SUITE chosen;
1345 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1346 const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
1347 EVP_PKEY *fakepriv = NULL;
1349 if (enc == NULL || enclen == 0
1350 || ct == NULL || ctlen == 0 || suite == NULL) {
1351 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1354 if (suite_in == NULL) {
1355 /* choose a random suite */
1356 if (hpke_random_suite(libctx, propq, &chosen) != 1) {
1357 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1363 if (hpke_suite_check(chosen, &kem_info, NULL, &aead_info) != 1) {
1364 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1368 /* make sure room for tag and one plaintext octet */
1369 if (aead_info->taglen >= ctlen) {
1370 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1374 plen = kem_info->Npk;
1375 if (plen > *enclen) {
1376 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1380 * In order for our enc to look good for sure, we generate and then
1381 * delete a real key for that curve - bit OTT but it ensures we do
1382 * get the encoding right (e.g. 0x04 as 1st octet for NIST curves in
1383 * uncompressed form) and that the value really does map to a point on
1384 * the relevant curve.
1386 if (OSSL_HPKE_keygen(chosen, enc, enclen, &fakepriv, NULL, 0,
1387 libctx, propq) != 1) {
1388 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1391 EVP_PKEY_free(fakepriv);
1392 if (RAND_bytes_ex(libctx, ct, ctlen, 0) <= 0) {
1393 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1401 int OSSL_HPKE_str2suite(const char *str, OSSL_HPKE_SUITE *suite)
1403 return ossl_hpke_str2suite(str, suite);
1406 size_t OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite, size_t clearlen)
1409 size_t cipherlen = 0;
1411 if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
1416 size_t OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite)
1419 size_t cipherlen = 0;
1420 size_t clearlen = 16;
1422 if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
1427 size_t OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite)
1429 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1431 if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1)
1433 if (kem_info == NULL)
1436 return kem_info->Nsk;