Fix typos found by codespell
[openssl.git] / crypto / hpke / hpke.c
1 /*
2  * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3  *
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
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
23 /** default buffer size for keys and internal buffers we use */
24 #define OSSL_HPKE_MAXSIZE 512
25
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";
45
46 /**
47  * @brief sender or receiver context
48  */
49 struct ossl_hpke_ctx_st
50 {
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 */
64     size_t keylen;
65     unsigned char *nonce; /* aead base nonce */
66     size_t noncelen;
67     unsigned char *exportersec; /* exporter secret */
68     size_t exporterseclen;
69     char *pskid; /* PSK stuff */
70     unsigned char *psk;
71     size_t psklen;
72     EVP_PKEY *authpriv; /* sender's authentication private key */
73     unsigned char *authpub; /* auth public key */
74     size_t authpublen;
75     unsigned char *ikme; /* IKM for sender deterministic key gen */
76     size_t ikmelen;
77 };
78
79 /**
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
83  */
84 static int hpke_kem_id_nist_curve(uint16_t kem_id)
85 {
86     const OSSL_HPKE_KEM_INFO *kem_info;
87
88     kem_info = ossl_HPKE_KEM_INFO_find_id(kem_id);
89     return kem_info != NULL && kem_info->groupname != NULL;
90 }
91
92 /**
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
100  *
101  * Note that this could be a useful function to make public in
102  * future, but would likely require a name change.
103  */
104 static EVP_PKEY *evp_pkey_new_raw_nist_public_key(OSSL_LIB_CTX *libctx,
105                                                   const char *propq,
106                                                   const char *gname,
107                                                   const unsigned char *buf,
108                                                   size_t buflen)
109 {
110     OSSL_PARAM params[2];
111     EVP_PKEY *ret = NULL;
112     EVP_PKEY_CTX *cctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
113
114     params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
115                                                  (char *)gname, 0);
116     params[1] = OSSL_PARAM_construct_end();
117     if (cctx == NULL
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);
123         EVP_PKEY_free(ret);
124         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
125         return NULL;
126     }
127     EVP_PKEY_CTX_free(cctx);
128     return ret;
129 }
130
131 /**
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
142  */
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)
147 {
148     int erv = 0;
149     EVP_CIPHER_CTX *ctx = NULL;
150     int len = 0;
151     size_t taglen;
152
153     taglen = hctx->aead_info->taglen;
154     if (ctlen <= taglen || *ptlen < ctlen - taglen) {
155         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
156         return 0;
157     }
158     /* Create and initialise the context */
159     if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
160         return 0;
161
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);
165         goto err;
166     }
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);
170         goto err;
171     }
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);
175         goto err;
176     }
177     /* Provide AAD. */
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);
181             goto err;
182         }
183     }
184     if (EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen - taglen) != 1) {
185         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
186         goto err;
187     }
188     *ptlen = len;
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);
192         goto err;
193     }
194     /* Finalise decryption.  */
195     if (EVP_DecryptFinal_ex(ctx, pt + len, &len) <= 0) {
196         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
197         goto err;
198     }
199     erv = 1;
200
201 err:
202     if (erv != 1)
203         OPENSSL_cleanse(pt, *ptlen);
204     EVP_CIPHER_CTX_free(ctx);
205     return erv;
206 }
207
208 /**
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
219  */
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)
224 {
225     int erv = 0;
226     EVP_CIPHER_CTX *ctx = NULL;
227     int len;
228     size_t taglen = 0;
229     unsigned char tag[16];
230
231     taglen = hctx->aead_info->taglen;
232     if (*ctlen <= taglen || ptlen > *ctlen - taglen) {
233         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
234         return 0;
235     }
236     /* Create and initialise the context */
237     if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
238         return 0;
239
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);
243         goto err;
244     }
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);
248         goto err;
249     }
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);
253         goto err;
254     }
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);
259             goto err;
260         }
261     }
262     if (EVP_EncryptUpdate(ctx, ct, &len, pt, ptlen) != 1) {
263         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
264         goto err;
265     }
266     *ctlen = len;
267     /* Finalise the encryption. */
268     if (EVP_EncryptFinal_ex(ctx, ct + len, &len) != 1) {
269         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
270         goto err;
271     }
272     *ctlen += len;
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);
276         goto err;
277     }
278     memcpy(ct + *ctlen, tag, taglen);
279     *ctlen += taglen;
280     erv = 1;
281
282 err:
283     if (erv != 1)
284         OPENSSL_cleanse(ct, *ctlen);
285     EVP_CIPHER_CTX_free(ctx);
286     return erv;
287 }
288
289 /**
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
293  */
294 static int hpke_mode_check(unsigned int mode)
295 {
296     switch (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:
301         break;
302     default:
303         return 0;
304     }
305     return 1;
306 }
307
308 /**
309  * @brief check if a suite is supported locally
310  * @param suite is the suite to check
311  * @return 1 for good, 0 otherwise
312  */
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)
317 {
318     const OSSL_HPKE_KEM_INFO *kem_info_;
319     const OSSL_HPKE_KDF_INFO *kdf_info_;
320     const OSSL_HPKE_AEAD_INFO *aead_info_;
321
322     /* check KEM, KDF and AEAD are supported here */
323     if ((kem_info_ = ossl_HPKE_KEM_INFO_find_id(suite.kem_id)) == NULL)
324         return 0;
325     if ((kdf_info_ = ossl_HPKE_KDF_INFO_find_id(suite.kdf_id)) == NULL)
326         return 0;
327     if ((aead_info_ = ossl_HPKE_AEAD_INFO_find_id(suite.aead_id)) == NULL)
328         return 0;
329
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_;
336
337     return 1;
338 }
339
340 /*
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
346  */
347 static int hpke_random_suite(OSSL_LIB_CTX *libctx,
348                              const char *propq,
349                              OSSL_HPKE_SUITE *suite)
350 {
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;
354
355     /* random kem, kdf and aead */
356     kem_info = ossl_HPKE_KEM_INFO_find_random(libctx);
357     if (kem_info == NULL)
358         return 0;
359     suite->kem_id = kem_info->kem_id;
360     kdf_info = ossl_HPKE_KDF_INFO_find_random(libctx);
361     if (kdf_info == NULL)
362         return 0;
363     suite->kdf_id = kdf_info->kdf_id;
364     aead_info = ossl_HPKE_AEAD_INFO_find_random(libctx);
365     if (aead_info == NULL)
366         return 0;
367     suite->aead_id = aead_info->aead_id;
368     return 1;
369 }
370
371 /*
372  * @brief tell the caller how big the ciphertext will be
373  *
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.
379  *
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().
383  *
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
389  */
390 static int hpke_expansion(OSSL_HPKE_SUITE suite,
391                           size_t *enclen,
392                           size_t clearlen,
393                           size_t *cipherlen)
394 {
395     const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
396     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
397
398     if (cipherlen == NULL || enclen == NULL) {
399         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
400         return 0;
401     }
402     if (hpke_suite_check(suite, &kem_info, NULL, &aead_info) != 1) {
403         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
404         return 0;
405     }
406     *cipherlen = clearlen + aead_info->taglen;
407     *enclen = kem_info->Nenc;
408     return 1;
409 }
410
411 /*
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
417  */
418 static size_t hpke_seqnonce2buf(OSSL_HPKE_CTX *ctx,
419                                 unsigned char *buf, size_t blen)
420 {
421     size_t i;
422     uint64_t seq_copy;
423
424     if (ctx == NULL || blen < sizeof(seq_copy) || blen != ctx->noncelen)
425         return 0;
426     seq_copy = ctx->seq;
427     memset(buf, 0, blen);
428     for (i = 0; i < sizeof(seq_copy); i++) {
429         buf[blen - i - 1] = seq_copy & 0xff;
430         seq_copy >>= 8;
431     }
432     for (i = 0; i < blen; i++)
433         buf[i] ^= ctx->nonce[i];
434     return blen;
435 }
436
437 /*
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
445  */
446 static int hpke_encap(OSSL_HPKE_CTX *ctx, unsigned char *enc, size_t *enclen,
447                       const unsigned char *pub, size_t publen)
448 {
449     int erv = 0;
450     OSSL_PARAM params[3], *p = params;
451     size_t lsslen = 0;
452     EVP_PKEY_CTX *pctx = NULL;
453     EVP_PKEY *pkR = NULL;
454     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
455
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);
459         return 0;
460     }
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);
464         return 0;
465     }
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);
469         return 0;
470     }
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,
473                                                kem_info->groupname,
474                                                pub, publen);
475     } else {
476         pkR = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
477                                              kem_info->keytype,
478                                              ctx->propq, pub, publen);
479     }
480     if (pkR == NULL) {
481         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
482         goto err;
483     }
484     pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkR, ctx->propq);
485     if (pctx == NULL) {
486         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
487         goto err;
488     }
489     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
490                                             OSSL_KEM_PARAM_OPERATION_DHKEM,
491                                             0);
492     if (ctx->ikme != NULL) {
493         *p++ = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME,
494                                                  ctx->ikme, ctx->ikmelen);
495     }
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,
500                                            params) != 1) {
501             ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
502             goto err;
503         }
504     } else {
505         if (EVP_PKEY_encapsulate_init(pctx, params) != 1) {
506             ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
507             goto err;
508         }
509     }
510     if (EVP_PKEY_encapsulate(pctx, NULL, enclen, NULL, &lsslen) != 1) {
511         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
512         goto err;
513     }
514     ctx->shared_secret = OPENSSL_malloc(lsslen);
515     if (ctx->shared_secret == NULL)
516         goto err;
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);
524         goto err;
525     }
526     erv = 1;
527
528 err:
529     EVP_PKEY_CTX_free(pctx);
530     EVP_PKEY_free(pkR);
531     return erv;
532 }
533
534 /*
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
541  */
542 static int hpke_decap(OSSL_HPKE_CTX *ctx,
543                       const unsigned char *enc, size_t enclen,
544                       EVP_PKEY *priv)
545 {
546     int erv = 0;
547     EVP_PKEY_CTX *pctx = NULL;
548     EVP_PKEY *spub = NULL;
549     OSSL_PARAM params[2], *p = params;
550     size_t lsslen = 0;
551
552     if (ctx == NULL || enc == NULL || enclen == 0 || priv == NULL) {
553         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
554         return 0;
555     }
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);
559         return 0;
560     }
561     pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, priv, ctx->propq);
562     if (pctx == NULL) {
563         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
564         goto err;
565     }
566     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
567                                             OSSL_KEM_PARAM_OPERATION_DHKEM,
568                                             0);
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;
573
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);
577             goto err;
578         }
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,
581                                                     kem_info->groupname,
582                                                     ctx->authpub,
583                                                     ctx->authpublen);
584         } else {
585             spub = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
586                                                   kem_info->keytype,
587                                                   ctx->propq,
588                                                   ctx->authpub,
589                                                   ctx->authpublen);
590         }
591         if (spub == NULL) {
592             ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
593             goto err;
594         }
595         if (EVP_PKEY_auth_decapsulate_init(pctx, spub, params) != 1) {
596             ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
597             goto err;
598         }
599     } else {
600         if (EVP_PKEY_decapsulate_init(pctx, params) != 1) {
601             ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
602             goto err;
603         }
604     }
605     if (EVP_PKEY_decapsulate(pctx, NULL, &lsslen, enc, enclen) != 1) {
606         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
607         goto err;
608     }
609     ctx->shared_secret = OPENSSL_malloc(lsslen);
610     if (ctx->shared_secret == NULL)
611         goto err;
612     if (EVP_PKEY_decapsulate(pctx, ctx->shared_secret, &lsslen,
613                              enc, enclen) != 1) {
614         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
615         goto err;
616     }
617     ctx->shared_secretlen = lsslen;
618     erv = 1;
619
620 err:
621     EVP_PKEY_CTX_free(pctx);
622     EVP_PKEY_free(spub);
623     if (erv == 0) {
624         OPENSSL_free(ctx->shared_secret);
625         ctx->shared_secret = NULL;
626         ctx->shared_secretlen = 0;
627     }
628     return erv;
629 }
630
631 /*
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
637  *
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
641  */
642 static int hpke_do_middle(OSSL_HPKE_CTX *ctx,
643                           const unsigned char *info, size_t infolen)
644 {
645     int erv = 0;
646     size_t ks_contextlen = OSSL_HPKE_MAXSIZE;
647     unsigned char ks_context[OSSL_HPKE_MAXSIZE];
648     size_t halflen = 0;
649     size_t pskidlen = 0;
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;
659
660     /* only let this be done once */
661     if (ctx->exportersec != NULL) {
662         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
663         return 0;
664     }
665     if (ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id) == NULL) {
666         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
667         return 0;
668     }
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);
672         return 0;
673     }
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);
677         return 0;
678     }
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);
687         return 0;
688     }
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);
694             return 0;
695         }
696     }
697     kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
698     if (kctx == NULL) {
699         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
700         return 0;
701     }
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);
716         goto err;
717     }
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);
724         goto err;
725     }
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);
735         goto err;
736     }
737     secretlen = kdf_info->Nh;
738     if (secretlen > OSSL_HPKE_MAXSIZE) {
739         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
740         goto err;
741     }
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);
749         goto err;
750     }
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)
756             goto err;
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);
763             goto err;
764         }
765         ctx->keylen = aead_info->Nk;
766         ctx->key = OPENSSL_malloc(ctx->keylen);
767         if (ctx->key == NULL)
768             goto err;
769         if (ossl_hpke_labeled_expand(kctx, ctx->key, ctx->keylen,
770                                      secret, secretlen, OSSL_HPKE_SEC51LABEL,
771                                      suitebuf, sizeof(suitebuf),
772                                      OSSL_HPKE_KEY_LABEL,
773                                      ks_context, ks_contextlen) != 1) {
774             ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
775             goto err;
776         }
777     }
778     ctx->exporterseclen = kdf_info->Nh;
779     ctx->exportersec = OPENSSL_malloc(ctx->exporterseclen);
780     if (ctx->exportersec == NULL)
781         goto err;
782     if (ossl_hpke_labeled_expand(kctx, ctx->exportersec, ctx->exporterseclen,
783                                  secret, secretlen, OSSL_HPKE_SEC51LABEL,
784                                  suitebuf, sizeof(suitebuf),
785                                  OSSL_HPKE_EXP_LABEL,
786                                  ks_context, ks_contextlen) != 1) {
787         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
788         goto err;
789     }
790     erv = 1;
791
792 err:
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);
797     return erv;
798 }
799
800 /*
801  * externally visible functions from below here, API documentation is
802  * in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication
803  */
804
805 OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role,
806                                  OSSL_LIB_CTX *libctx, const char *propq)
807 {
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;
812
813     if (hpke_mode_check(mode) != 1) {
814         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
815         return NULL;
816     }
817     if (hpke_suite_check(suite, &kem_info, &kdf_info, &aead_info) != 1) {
818         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
819         return NULL;
820     }
821     if (role != OSSL_HPKE_ROLE_SENDER && role != OSSL_HPKE_ROLE_RECEIVER) {
822         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
823         return 0;
824     }
825     ctx = OPENSSL_zalloc(sizeof(*ctx));
826     if (ctx == NULL)
827         return NULL;
828     ctx->libctx = libctx;
829     if (propq != NULL) {
830         ctx->propq = OPENSSL_strdup(propq);
831         if (ctx->propq == NULL)
832             goto err;
833     }
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);
838             goto err;
839         }
840     }
841     ctx->role = role;
842     ctx->mode = mode;
843     ctx->suite = suite;
844     ctx->kem_info = kem_info;
845     ctx->kdf_info = kdf_info;
846     ctx->aead_info = aead_info;
847     return ctx;
848
849  err:
850     EVP_CIPHER_free(ctx->aead_ciph);
851     OPENSSL_free(ctx);
852     return NULL;
853 }
854
855 void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX *ctx)
856 {
857     if (ctx == NULL)
858         return;
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);
870
871     OPENSSL_free(ctx);
872     return;
873 }
874
875 int OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX *ctx,
876                            const char *pskid,
877                            const unsigned char *psk, size_t psklen)
878 {
879     if (ctx == NULL || pskid == NULL || psk == NULL || psklen == 0) {
880         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
881         return 0;
882     }
883     if (psklen > OSSL_HPKE_MAX_PARMLEN) {
884         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
885         return 0;
886     }
887     if (strlen(pskid) > OSSL_HPKE_MAX_PARMLEN) {
888         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
889         return 0;
890     }
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);
894         return 0;
895     }
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)
900         return 0;
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);
906         ctx->psk = NULL;
907         ctx->psklen = 0;
908         return 0;
909     }
910     return 1;
911 }
912
913 int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX *ctx,
914                             const unsigned char *ikme, size_t ikmelen)
915 {
916     if (ctx == NULL || ikme == NULL) {
917         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
918         return 0;
919     }
920     if (ikmelen == 0 || ikmelen > OSSL_HPKE_MAX_PARMLEN) {
921         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
922         return 0;
923     }
924     if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
925         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
926         return 0;
927     }
928     OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
929     ctx->ikme = OPENSSL_memdup(ikme, ikmelen);
930     if (ctx->ikme == NULL)
931         return 0;
932     ctx->ikmelen = ikmelen;
933     return 1;
934 }
935
936 int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX *ctx, EVP_PKEY *priv)
937 {
938     if (ctx == NULL || priv == NULL) {
939         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
940         return 0;
941     }
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);
945         return 0;
946     }
947     if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
948         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
949         return 0;
950     }
951     EVP_PKEY_free(ctx->authpriv);
952     ctx->authpriv = EVP_PKEY_dup(priv);
953     if (ctx->authpriv == NULL)
954         return 0;
955     return 1;
956 }
957
958 int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX *ctx,
959                                const unsigned char *pub, size_t publen)
960 {
961     int erv = 0;
962     EVP_PKEY *pubp = NULL;
963     unsigned char *lpub = NULL;
964     size_t lpublen = 0;
965     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
966
967     if (ctx == NULL || pub == NULL || publen == 0) {
968         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
969         return 0;
970     }
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);
974         return 0;
975     }
976     if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
977         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
978         return 0;
979     }
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)
983         return 0;
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,
986                                                 kem_info->groupname,
987                                                 pub, publen);
988     } else {
989         pubp = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
990                                               kem_info->keytype,
991                                               ctx->propq,
992                                               pub, publen);
993     }
994     if (pubp == NULL) {
995         /* can happen based on external input - buffer value may be garbage */
996         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
997         goto err;
998     }
999     /*
1000      * extract out the public key in encoded form so we
1001      * should be fine even if given compressed form
1002      */
1003     lpub = OPENSSL_malloc(OSSL_HPKE_MAXSIZE);
1004     if (lpub == NULL)
1005         goto err;
1006     if (EVP_PKEY_get_octet_string_param(pubp,
1007                                         OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
1008                                         lpub, OSSL_HPKE_MAXSIZE, &lpublen)
1009         != 1) {
1010         OPENSSL_free(lpub);
1011         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1012         goto err;
1013     }
1014     /* free up old value */
1015     OPENSSL_free(ctx->authpub);
1016     ctx->authpub = lpub;
1017     ctx->authpublen = lpublen;
1018     erv = 1;
1019
1020 err:
1021     EVP_PKEY_free(pubp);
1022     return erv;
1023 }
1024
1025 int OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX *ctx, uint64_t *seq)
1026 {
1027     if (ctx == NULL || seq == NULL) {
1028         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1029         return 0;
1030     }
1031     *seq = ctx->seq;
1032     return 1;
1033 }
1034
1035 int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX *ctx, uint64_t seq)
1036 {
1037     if (ctx == NULL) {
1038         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1039         return 0;
1040     }
1041     /*
1042      * We disallow senders from doing this as it's dangerous
1043      * Receivers are ok to use this, as no harm should ensue
1044      * if they go wrong.
1045      */
1046     if (ctx->role == OSSL_HPKE_ROLE_SENDER) {
1047         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1048         return 0;
1049     }
1050     ctx->seq = seq;
1051     return 1;
1052 }
1053
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)
1058 {
1059     int erv = 1;
1060
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);
1064         return 0;
1065     }
1066     if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
1067         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1068         return 0;
1069     }
1070     if (infolen > OSSL_HPKE_MAX_INFOLEN) {
1071         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1072         return 0;
1073     }
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);
1077         return 0;
1078     }
1079     if (hpke_encap(ctx, enc, enclen, pub, publen) != 1) {
1080         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1081         return 0;
1082     }
1083     /*
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
1086      * be stored
1087      */
1088     erv = hpke_do_middle(ctx, info, infolen);
1089     return erv;
1090 }
1091
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)
1096 {
1097     int erv = 1;
1098
1099     if (ctx == NULL || enc == NULL || enclen == 0 || recippriv == NULL) {
1100         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1101         return 0;
1102     }
1103     if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
1104         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1105         return 0;
1106     }
1107     if (infolen > OSSL_HPKE_MAX_INFOLEN) {
1108         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1109         return 0;
1110     }
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);
1114         return 0;
1115     }
1116     erv = hpke_decap(ctx, enc, enclen, recippriv);
1117     if (erv != 1) {
1118         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1119         return 0;
1120     }
1121     /*
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
1124      * be stored
1125      */
1126     erv = hpke_do_middle(ctx, info, infolen);
1127     return erv;
1128 }
1129
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)
1134 {
1135     unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
1136     size_t seqlen = 0;
1137
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);
1141         return 0;
1142     }
1143     if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
1144         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1145         return 0;
1146     }
1147     if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
1148         ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1149         return 0;
1150     }
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);
1154         return 0;
1155     }
1156     seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
1157     if (seqlen == 0) {
1158         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1159         return 0;
1160     }
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));
1164         return 0;
1165     } else {
1166         ctx->seq++;
1167     }
1168     OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1169     return 1;
1170 }
1171
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)
1176 {
1177     unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
1178     size_t seqlen = 0;
1179
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);
1183         return 0;
1184     }
1185     if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
1186         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1187         return 0;
1188     }
1189     if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
1190         ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1191         return 0;
1192     }
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);
1196         return 0;
1197     }
1198     seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
1199     if (seqlen == 0) {
1200         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1201         return 0;
1202     }
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));
1206         return 0;
1207     }
1208     ctx->seq++;
1209     OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1210     return 1;
1211 }
1212
1213 int OSSL_HPKE_export(OSSL_HPKE_CTX *ctx,
1214                      unsigned char *secret, size_t secretlen,
1215                      const unsigned char *label, size_t labellen)
1216 {
1217     int erv = 0;
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;
1222
1223     if (ctx == NULL) {
1224         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1225         return 0;
1226     }
1227     if (labellen > OSSL_HPKE_MAX_PARMLEN) {
1228         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1229         return 0;
1230     }
1231     if (ctx->exportersec == NULL) {
1232         ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1233         return 0;
1234     }
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);
1238         return 0;
1239     }
1240     mdname = kdf_info->mdname;
1241     kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
1242     if (kctx == NULL) {
1243         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1244         return 0;
1245     }
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,
1258                                    label, labellen);
1259     EVP_KDF_CTX_free(kctx);
1260     if (erv != 1)
1261         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1262     return erv;
1263 }
1264
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)
1269 {
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;
1275
1276     if (pub == NULL || publen == NULL || *publen == 0 || priv == NULL) {
1277         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1278         return 0;
1279     }
1280     if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1) {
1281         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1282         return 0;
1283     }
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);
1288         return 0;
1289     }
1290
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);
1295     } else {
1296         pctx = EVP_PKEY_CTX_new_from_name(libctx, kem_info->keytype, propq);
1297     }
1298     if (pctx == NULL
1299         || EVP_PKEY_keygen_init(pctx) <= 0) {
1300         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1301         goto err;
1302     }
1303     if (ikm != NULL)
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);
1309         goto err;
1310     }
1311     if (EVP_PKEY_generate(pctx, &skR) <= 0) {
1312         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1313         goto err;
1314     }
1315     EVP_PKEY_CTX_free(pctx);
1316     pctx = NULL;
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);
1320         goto err;
1321     }
1322     *priv = skR;
1323     erv = 1;
1324
1325 err:
1326     if (erv != 1)
1327         EVP_PKEY_free(skR);
1328     EVP_PKEY_CTX_free(pctx);
1329     return erv;
1330 }
1331
1332 int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite)
1333 {
1334     return hpke_suite_check(suite, NULL, NULL, NULL);
1335 }
1336
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)
1342 {
1343     OSSL_HPKE_SUITE chosen;
1344     size_t plen = 0;
1345     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1346     const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
1347     EVP_PKEY *fakepriv = NULL;
1348
1349     if (enc == NULL || enclen == 0
1350         || ct == NULL || ctlen == 0 || suite == NULL) {
1351         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1352         return 0;
1353     }
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);
1358             goto err;
1359         }
1360     } else {
1361         chosen = *suite_in;
1362     }
1363     if (hpke_suite_check(chosen, &kem_info, NULL, &aead_info) != 1) {
1364         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1365         goto err;
1366     }
1367     *suite = chosen;
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);
1371         goto err;
1372     }
1373     /* publen */
1374     plen = kem_info->Npk;
1375     if (plen > *enclen) {
1376         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1377         goto err;
1378     }
1379     /*
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.
1385      */
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);
1389         goto err;
1390     }
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);
1394         goto err;
1395     }
1396     return 1;
1397 err:
1398     return 0;
1399 }
1400
1401 int OSSL_HPKE_str2suite(const char *str, OSSL_HPKE_SUITE *suite)
1402 {
1403     return ossl_hpke_str2suite(str, suite);
1404 }
1405
1406 size_t OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite, size_t clearlen)
1407 {
1408     size_t enclen = 0;
1409     size_t cipherlen = 0;
1410
1411     if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
1412         return 0;
1413     return cipherlen;
1414 }
1415
1416 size_t OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite)
1417 {
1418     size_t enclen = 0;
1419     size_t cipherlen = 0;
1420     size_t clearlen = 16;
1421
1422     if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
1423         return 0;
1424     return enclen;
1425 }
1426
1427 size_t OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite)
1428 {
1429     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1430
1431     if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1)
1432         return 0;
1433     if (kem_info == NULL)
1434         return 0;
1435
1436     return kem_info->Nsk;
1437 }