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