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