xref: /openssl/crypto/hpke/hpke.c (revision 8ff6edb9)
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->propq);
845     OPENSSL_free(ctx);
846     return NULL;
847 }
848 
OSSL_HPKE_CTX_free(OSSL_HPKE_CTX * ctx)849 void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX *ctx)
850 {
851     if (ctx == NULL)
852         return;
853     EVP_CIPHER_free(ctx->aead_ciph);
854     OPENSSL_free(ctx->propq);
855     OPENSSL_clear_free(ctx->exportersec, ctx->exporterseclen);
856     OPENSSL_free(ctx->pskid);
857     OPENSSL_clear_free(ctx->psk, ctx->psklen);
858     OPENSSL_clear_free(ctx->key, ctx->keylen);
859     OPENSSL_clear_free(ctx->nonce, ctx->noncelen);
860     OPENSSL_clear_free(ctx->shared_secret, ctx->shared_secretlen);
861     OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
862     EVP_PKEY_free(ctx->authpriv);
863     OPENSSL_free(ctx->authpub);
864 
865     OPENSSL_free(ctx);
866     return;
867 }
868 
OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX * ctx,const char * pskid,const unsigned char * psk,size_t psklen)869 int OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX *ctx,
870                            const char *pskid,
871                            const unsigned char *psk, size_t psklen)
872 {
873     if (ctx == NULL || pskid == NULL || psk == NULL || psklen == 0) {
874         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
875         return 0;
876     }
877     if (psklen > OSSL_HPKE_MAX_PARMLEN) {
878         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
879         return 0;
880     }
881     if (psklen < OSSL_HPKE_MIN_PSKLEN) {
882         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
883         return 0;
884     }
885     if (strlen(pskid) > OSSL_HPKE_MAX_PARMLEN) {
886         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
887         return 0;
888     }
889     if (strlen(pskid) == 0) {
890         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
891         return 0;
892     }
893     if (ctx->mode != OSSL_HPKE_MODE_PSK
894         && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
895         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
896         return 0;
897     }
898     /* free previous values if any */
899     OPENSSL_clear_free(ctx->psk, ctx->psklen);
900     ctx->psk = OPENSSL_memdup(psk, psklen);
901     if (ctx->psk == NULL)
902         return 0;
903     ctx->psklen = psklen;
904     OPENSSL_free(ctx->pskid);
905     ctx->pskid = OPENSSL_strdup(pskid);
906     if (ctx->pskid == NULL) {
907         OPENSSL_clear_free(ctx->psk, ctx->psklen);
908         ctx->psk = NULL;
909         ctx->psklen = 0;
910         return 0;
911     }
912     return 1;
913 }
914 
OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX * ctx,const unsigned char * ikme,size_t ikmelen)915 int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX *ctx,
916                             const unsigned char *ikme, size_t ikmelen)
917 {
918     if (ctx == NULL || ikme == NULL) {
919         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
920         return 0;
921     }
922     if (ikmelen == 0 || ikmelen > OSSL_HPKE_MAX_PARMLEN) {
923         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
924         return 0;
925     }
926     if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
927         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
928         return 0;
929     }
930     OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
931     ctx->ikme = OPENSSL_memdup(ikme, ikmelen);
932     if (ctx->ikme == NULL)
933         return 0;
934     ctx->ikmelen = ikmelen;
935     return 1;
936 }
937 
OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX * ctx,EVP_PKEY * priv)938 int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX *ctx, EVP_PKEY *priv)
939 {
940     if (ctx == NULL || priv == NULL) {
941         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
942         return 0;
943     }
944     if (ctx->mode != OSSL_HPKE_MODE_AUTH
945         && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
946         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
947         return 0;
948     }
949     if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
950         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
951         return 0;
952     }
953     EVP_PKEY_free(ctx->authpriv);
954     ctx->authpriv = EVP_PKEY_dup(priv);
955     if (ctx->authpriv == NULL)
956         return 0;
957     return 1;
958 }
959 
OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX * ctx,const unsigned char * pub,size_t publen)960 int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX *ctx,
961                                const unsigned char *pub, size_t publen)
962 {
963     int erv = 0;
964     EVP_PKEY *pubp = NULL;
965     unsigned char *lpub = NULL;
966     size_t lpublen = 0;
967     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
968 
969     if (ctx == NULL || pub == NULL || publen == 0) {
970         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
971         return 0;
972     }
973     if (ctx->mode != OSSL_HPKE_MODE_AUTH
974         && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
975         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
976         return 0;
977     }
978     if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
979         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
980         return 0;
981     }
982     /* check the value seems like a good public key for this kem */
983     kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
984     if (kem_info == NULL)
985         return 0;
986     if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
987         pubp = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
988                                                 kem_info->groupname,
989                                                 pub, publen);
990     } else {
991         pubp = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
992                                               kem_info->keytype,
993                                               ctx->propq,
994                                               pub, publen);
995     }
996     if (pubp == NULL) {
997         /* can happen based on external input - buffer value may be garbage */
998         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
999         goto err;
1000     }
1001     /*
1002      * extract out the public key in encoded form so we
1003      * should be fine even if given compressed form
1004      */
1005     lpub = OPENSSL_malloc(OSSL_HPKE_MAXSIZE);
1006     if (lpub == NULL)
1007         goto err;
1008     if (EVP_PKEY_get_octet_string_param(pubp,
1009                                         OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
1010                                         lpub, OSSL_HPKE_MAXSIZE, &lpublen)
1011         != 1) {
1012         OPENSSL_free(lpub);
1013         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1014         goto err;
1015     }
1016     /* free up old value */
1017     OPENSSL_free(ctx->authpub);
1018     ctx->authpub = lpub;
1019     ctx->authpublen = lpublen;
1020     erv = 1;
1021 
1022 err:
1023     EVP_PKEY_free(pubp);
1024     return erv;
1025 }
1026 
OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX * ctx,uint64_t * seq)1027 int OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX *ctx, uint64_t *seq)
1028 {
1029     if (ctx == NULL || seq == NULL) {
1030         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1031         return 0;
1032     }
1033     *seq = ctx->seq;
1034     return 1;
1035 }
1036 
OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX * ctx,uint64_t seq)1037 int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX *ctx, uint64_t seq)
1038 {
1039     if (ctx == NULL) {
1040         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1041         return 0;
1042     }
1043     /*
1044      * We disallow senders from doing this as it's dangerous
1045      * Receivers are ok to use this, as no harm should ensue
1046      * if they go wrong.
1047      */
1048     if (ctx->role == OSSL_HPKE_ROLE_SENDER) {
1049         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1050         return 0;
1051     }
1052     ctx->seq = seq;
1053     return 1;
1054 }
1055 
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)1056 int OSSL_HPKE_encap(OSSL_HPKE_CTX *ctx,
1057                     unsigned char *enc, size_t *enclen,
1058                     const unsigned char *pub, size_t publen,
1059                     const unsigned char *info, size_t infolen)
1060 {
1061     int erv = 1;
1062     size_t minenc = 0;
1063 
1064     if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0
1065         || pub == NULL || publen == 0) {
1066         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1067         return 0;
1068     }
1069     if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
1070         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1071         return 0;
1072     }
1073     if (infolen > OSSL_HPKE_MAX_INFOLEN) {
1074         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1075         return 0;
1076     }
1077     if (infolen > 0 && info == NULL) {
1078         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1079         return 0;
1080     }
1081     minenc = OSSL_HPKE_get_public_encap_size(ctx->suite);
1082     if (minenc == 0 || minenc > *enclen) {
1083         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1084         return 0;
1085     }
1086     if (ctx->shared_secret != NULL) {
1087         /* only allow one encap per OSSL_HPKE_CTX */
1088         ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1089         return 0;
1090     }
1091     if (hpke_encap(ctx, enc, enclen, pub, publen) != 1) {
1092         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1093         return 0;
1094     }
1095     /*
1096      * note that the info is not part of the context as it
1097      * only needs to be used once here so doesn't need to
1098      * be stored
1099      */
1100     erv = hpke_do_middle(ctx, info, infolen);
1101     return erv;
1102 }
1103 
OSSL_HPKE_decap(OSSL_HPKE_CTX * ctx,const unsigned char * enc,size_t enclen,EVP_PKEY * recippriv,const unsigned char * info,size_t infolen)1104 int OSSL_HPKE_decap(OSSL_HPKE_CTX *ctx,
1105                     const unsigned char *enc, size_t enclen,
1106                     EVP_PKEY *recippriv,
1107                     const unsigned char *info, size_t infolen)
1108 {
1109     int erv = 1;
1110     size_t minenc = 0;
1111 
1112     if (ctx == NULL || enc == NULL || enclen == 0 || recippriv == NULL) {
1113         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1114         return 0;
1115     }
1116     if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
1117         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1118         return 0;
1119     }
1120     if (infolen > OSSL_HPKE_MAX_INFOLEN) {
1121         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1122         return 0;
1123     }
1124     if (infolen > 0 && info == NULL) {
1125         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1126         return 0;
1127     }
1128     minenc = OSSL_HPKE_get_public_encap_size(ctx->suite);
1129     if (minenc == 0 || minenc > enclen) {
1130         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1131         return 0;
1132     }
1133     if (ctx->shared_secret != NULL) {
1134         /* only allow one encap per OSSL_HPKE_CTX */
1135         ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1136         return 0;
1137     }
1138     erv = hpke_decap(ctx, enc, enclen, recippriv);
1139     if (erv != 1) {
1140         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1141         return 0;
1142     }
1143     /*
1144      * note that the info is not part of the context as it
1145      * only needs to be used once here so doesn't need to
1146      * be stored
1147      */
1148     erv = hpke_do_middle(ctx, info, infolen);
1149     return erv;
1150 }
1151 
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)1152 int OSSL_HPKE_seal(OSSL_HPKE_CTX *ctx,
1153                    unsigned char *ct, size_t *ctlen,
1154                    const unsigned char *aad, size_t aadlen,
1155                    const unsigned char *pt, size_t ptlen)
1156 {
1157     unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
1158     size_t seqlen = 0;
1159 
1160     if (ctx == NULL || ct == NULL || ctlen == NULL || *ctlen == 0
1161         || pt == NULL || ptlen == 0) {
1162         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1163         return 0;
1164     }
1165     if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
1166         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1167         return 0;
1168     }
1169     if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
1170         ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1171         return 0;
1172     }
1173     if (ctx->key == NULL || ctx->nonce == NULL) {
1174         /* need to have done an encap first, info can be NULL */
1175         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1176         return 0;
1177     }
1178     seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
1179     if (seqlen == 0) {
1180         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1181         return 0;
1182     }
1183     if (hpke_aead_enc(ctx, seqbuf, aad, aadlen, pt, ptlen, ct, ctlen) != 1) {
1184         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1185         OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1186         return 0;
1187     } else {
1188         ctx->seq++;
1189     }
1190     OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1191     return 1;
1192 }
1193 
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)1194 int OSSL_HPKE_open(OSSL_HPKE_CTX *ctx,
1195                    unsigned char *pt, size_t *ptlen,
1196                    const unsigned char *aad, size_t aadlen,
1197                    const unsigned char *ct, size_t ctlen)
1198 {
1199     unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
1200     size_t seqlen = 0;
1201 
1202     if (ctx == NULL || pt == NULL || ptlen == NULL || *ptlen == 0
1203         || ct == NULL || ctlen == 0) {
1204         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1205         return 0;
1206     }
1207     if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
1208         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1209         return 0;
1210     }
1211     if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
1212         ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1213         return 0;
1214     }
1215     if (ctx->key == NULL || ctx->nonce == NULL) {
1216         /* need to have done an encap first, info can be NULL */
1217         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1218         return 0;
1219     }
1220     seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
1221     if (seqlen == 0) {
1222         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1223         return 0;
1224     }
1225     if (hpke_aead_dec(ctx, seqbuf, aad, aadlen, ct, ctlen, pt, ptlen) != 1) {
1226         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1227         OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1228         return 0;
1229     }
1230     ctx->seq++;
1231     OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1232     return 1;
1233 }
1234 
OSSL_HPKE_export(OSSL_HPKE_CTX * ctx,unsigned char * secret,size_t secretlen,const unsigned char * label,size_t labellen)1235 int OSSL_HPKE_export(OSSL_HPKE_CTX *ctx,
1236                      unsigned char *secret, size_t secretlen,
1237                      const unsigned char *label, size_t labellen)
1238 {
1239     int erv = 0;
1240     EVP_KDF_CTX *kctx = NULL;
1241     unsigned char suitebuf[6];
1242     const char *mdname = NULL;
1243     const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
1244 
1245     if (ctx == NULL || secret == NULL || secretlen == 0) {
1246         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1247         return 0;
1248     }
1249     if (labellen > OSSL_HPKE_MAX_PARMLEN) {
1250         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1251         return 0;
1252     }
1253     if (labellen > 0 && label == NULL) {
1254         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1255         return 0;
1256     }
1257     if (ctx->exportersec == NULL) {
1258         ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1259         return 0;
1260     }
1261     kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id);
1262     if (kdf_info == NULL) {
1263         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1264         return 0;
1265     }
1266     mdname = kdf_info->mdname;
1267     kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
1268     if (kctx == NULL) {
1269         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1270         return 0;
1271     }
1272     /* full suiteid as per RFC9180 sec 5.3 */
1273     suitebuf[0] = ctx->suite.kem_id / 256;
1274     suitebuf[1] = ctx->suite.kem_id % 256;
1275     suitebuf[2] = ctx->suite.kdf_id / 256;
1276     suitebuf[3] = ctx->suite.kdf_id % 256;
1277     suitebuf[4] = ctx->suite.aead_id / 256;
1278     suitebuf[5] = ctx->suite.aead_id % 256;
1279     erv = ossl_hpke_labeled_expand(kctx, secret, secretlen,
1280                                    ctx->exportersec, ctx->exporterseclen,
1281                                    OSSL_HPKE_SEC51LABEL,
1282                                    suitebuf, sizeof(suitebuf),
1283                                    OSSL_HPKE_EXP_SEC_LABEL,
1284                                    label, labellen);
1285     EVP_KDF_CTX_free(kctx);
1286     if (erv != 1)
1287         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1288     return erv;
1289 }
1290 
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)1291 int OSSL_HPKE_keygen(OSSL_HPKE_SUITE suite,
1292                      unsigned char *pub, size_t *publen, EVP_PKEY **priv,
1293                      const unsigned char *ikm, size_t ikmlen,
1294                      OSSL_LIB_CTX *libctx, const char *propq)
1295 {
1296     int erv = 0; /* Our error return value - 1 is success */
1297     EVP_PKEY_CTX *pctx = NULL;
1298     EVP_PKEY *skR = NULL;
1299     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1300     OSSL_PARAM params[3], *p = params;
1301 
1302     if (pub == NULL || publen == NULL || *publen == 0 || priv == NULL) {
1303         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1304         return 0;
1305     }
1306     if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1) {
1307         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1308         return 0;
1309     }
1310     if ((ikmlen > 0 && ikm == NULL)
1311         || (ikmlen == 0 && ikm != NULL)
1312         || ikmlen > OSSL_HPKE_MAX_PARMLEN) {
1313         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1314         return 0;
1315     }
1316 
1317     if (hpke_kem_id_nist_curve(suite.kem_id) == 1) {
1318         *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
1319                                                 (char *)kem_info->groupname, 0);
1320         pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
1321     } else {
1322         pctx = EVP_PKEY_CTX_new_from_name(libctx, kem_info->keytype, propq);
1323     }
1324     if (pctx == NULL
1325         || EVP_PKEY_keygen_init(pctx) <= 0) {
1326         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1327         goto err;
1328     }
1329     if (ikm != NULL)
1330         *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
1331                                                  (char *)ikm, ikmlen);
1332     *p = OSSL_PARAM_construct_end();
1333     if (EVP_PKEY_CTX_set_params(pctx, params) <= 0) {
1334         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1335         goto err;
1336     }
1337     if (EVP_PKEY_generate(pctx, &skR) <= 0) {
1338         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1339         goto err;
1340     }
1341     EVP_PKEY_CTX_free(pctx);
1342     pctx = NULL;
1343     if (EVP_PKEY_get_octet_string_param(skR, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
1344                                         pub, *publen, publen) != 1) {
1345         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1346         goto err;
1347     }
1348     *priv = skR;
1349     erv = 1;
1350 
1351 err:
1352     if (erv != 1)
1353         EVP_PKEY_free(skR);
1354     EVP_PKEY_CTX_free(pctx);
1355     return erv;
1356 }
1357 
OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite)1358 int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite)
1359 {
1360     return hpke_suite_check(suite, NULL, NULL, NULL);
1361 }
1362 
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)1363 int OSSL_HPKE_get_grease_value(const OSSL_HPKE_SUITE *suite_in,
1364                                OSSL_HPKE_SUITE *suite,
1365                                unsigned char *enc, size_t *enclen,
1366                                unsigned char *ct, size_t ctlen,
1367                                OSSL_LIB_CTX *libctx, const char *propq)
1368 {
1369     OSSL_HPKE_SUITE chosen;
1370     size_t plen = 0;
1371     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1372     const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
1373     EVP_PKEY *fakepriv = NULL;
1374 
1375     if (enc == NULL || enclen == 0
1376         || ct == NULL || ctlen == 0 || suite == NULL) {
1377         ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1378         return 0;
1379     }
1380     if (suite_in == NULL) {
1381         /* choose a random suite */
1382         if (hpke_random_suite(libctx, propq, &chosen) != 1) {
1383             ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1384             goto err;
1385         }
1386     } else {
1387         chosen = *suite_in;
1388     }
1389     if (hpke_suite_check(chosen, &kem_info, NULL, &aead_info) != 1) {
1390         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1391         goto err;
1392     }
1393     *suite = chosen;
1394     /* make sure room for tag and one plaintext octet */
1395     if (aead_info->taglen >= ctlen) {
1396         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1397         goto err;
1398     }
1399     /* publen */
1400     plen = kem_info->Npk;
1401     if (plen > *enclen) {
1402         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1403         goto err;
1404     }
1405     /*
1406      * In order for our enc to look good for sure, we generate and then
1407      * delete a real key for that curve - bit OTT but it ensures we do
1408      * get the encoding right (e.g. 0x04 as 1st octet for NIST curves in
1409      * uncompressed form) and that the value really does map to a point on
1410      * the relevant curve.
1411      */
1412     if (OSSL_HPKE_keygen(chosen, enc, enclen, &fakepriv, NULL, 0,
1413                          libctx, propq) != 1) {
1414         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1415         goto err;
1416     }
1417     EVP_PKEY_free(fakepriv);
1418     if (RAND_bytes_ex(libctx, ct, ctlen, 0) <= 0) {
1419         ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1420         goto err;
1421     }
1422     return 1;
1423 err:
1424     return 0;
1425 }
1426 
OSSL_HPKE_str2suite(const char * str,OSSL_HPKE_SUITE * suite)1427 int OSSL_HPKE_str2suite(const char *str, OSSL_HPKE_SUITE *suite)
1428 {
1429     return ossl_hpke_str2suite(str, suite);
1430 }
1431 
OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite,size_t clearlen)1432 size_t OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite, size_t clearlen)
1433 {
1434     size_t enclen = 0;
1435     size_t cipherlen = 0;
1436 
1437     if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
1438         return 0;
1439     return cipherlen;
1440 }
1441 
OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite)1442 size_t OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite)
1443 {
1444     size_t enclen = 0;
1445     size_t cipherlen = 0;
1446     size_t clearlen = 16;
1447 
1448     if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
1449         return 0;
1450     return enclen;
1451 }
1452 
OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite)1453 size_t OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite)
1454 {
1455     const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1456 
1457     if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1)
1458         return 0;
1459     if (kem_info == NULL)
1460         return 0;
1461 
1462     return kem_info->Nsk;
1463 }
1464