]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/hpke/hpke.c
Copyright year updates
[thirdparty/openssl.git] / crypto / hpke / hpke.c
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 {
50 OSSL_LIB_CTX *libctx; /* library context */
51 char *propq; /* properties */
52 int mode; /* HPKE mode */
53 OSSL_HPKE_SUITE suite; /* suite */
54 const OSSL_HPKE_KEM_INFO *kem_info;
55 const OSSL_HPKE_KDF_INFO *kdf_info;
56 const OSSL_HPKE_AEAD_INFO *aead_info;
57 EVP_CIPHER *aead_ciph;
58 int role; /* sender(0) or receiver(1) */
59 uint64_t seq; /* aead sequence number */
60 unsigned char *shared_secret; /* KEM output, zz */
61 size_t shared_secretlen;
62 unsigned char *key; /* final aead key */
63 size_t keylen;
64 unsigned char *nonce; /* aead base nonce */
65 size_t noncelen;
66 unsigned char *exportersec; /* exporter secret */
67 size_t exporterseclen;
68 char *pskid; /* PSK stuff */
69 unsigned char *psk;
70 size_t psklen;
71 EVP_PKEY *authpriv; /* sender's authentication private key */
72 unsigned char *authpub; /* auth public key */
73 size_t authpublen;
74 unsigned char *ikme; /* IKM for sender deterministic key gen */
75 size_t ikmelen;
76 };
77
78 /**
79 * @brief check if KEM uses NIST curve or not
80 * @param kem_id is the externally supplied kem_id
81 * @return 1 for NIST curves, 0 for other
82 */
83 static int hpke_kem_id_nist_curve(uint16_t kem_id)
84 {
85 const OSSL_HPKE_KEM_INFO *kem_info;
86
87 kem_info = ossl_HPKE_KEM_INFO_find_id(kem_id);
88 return kem_info != NULL && kem_info->groupname != NULL;
89 }
90
91 /**
92 * @brief wrapper to import NIST curve public key as easily as x25519/x448
93 * @param libctx is the context to use
94 * @param propq is a properties string
95 * @param gname is the curve groupname
96 * @param buf is the binary buffer with the (uncompressed) public value
97 * @param buflen is the length of the private key buffer
98 * @return a working EVP_PKEY * or NULL
99 *
100 * Note that this could be a useful function to make public in
101 * future, but would likely require a name change.
102 */
103 static EVP_PKEY *evp_pkey_new_raw_nist_public_key(OSSL_LIB_CTX *libctx,
104 const char *propq,
105 const char *gname,
106 const unsigned char *buf,
107 size_t buflen)
108 {
109 OSSL_PARAM params[2];
110 EVP_PKEY *ret = NULL;
111 EVP_PKEY_CTX *cctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
112
113 params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
114 (char *)gname, 0);
115 params[1] = OSSL_PARAM_construct_end();
116 if (cctx == NULL
117 || EVP_PKEY_paramgen_init(cctx) <= 0
118 || EVP_PKEY_CTX_set_params(cctx, params) <= 0
119 || EVP_PKEY_paramgen(cctx, &ret) <= 0
120 || EVP_PKEY_set1_encoded_public_key(ret, buf, buflen) != 1) {
121 EVP_PKEY_CTX_free(cctx);
122 EVP_PKEY_free(ret);
123 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
124 return NULL;
125 }
126 EVP_PKEY_CTX_free(cctx);
127 return ret;
128 }
129
130 /**
131 * @brief do the AEAD decryption
132 * @param hctx is the context to use
133 * @param iv is the initialisation vector
134 * @param aad is the additional authenticated data
135 * @param aadlen is the length of the aad
136 * @param ct is the ciphertext buffer
137 * @param ctlen is the ciphertext length (including tag).
138 * @param pt is the output buffer
139 * @param ptlen input/output, better be big enough on input, exact on output
140 * @return 1 on success, 0 otherwise
141 */
142 static int hpke_aead_dec(OSSL_HPKE_CTX *hctx, const unsigned char *iv,
143 const unsigned char *aad, size_t aadlen,
144 const unsigned char *ct, size_t ctlen,
145 unsigned char *pt, size_t *ptlen)
146 {
147 int erv = 0;
148 EVP_CIPHER_CTX *ctx = NULL;
149 int len = 0;
150 size_t taglen;
151
152 taglen = hctx->aead_info->taglen;
153 if (ctlen <= taglen || *ptlen < ctlen - taglen) {
154 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
155 return 0;
156 }
157 /* Create and initialise the context */
158 if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
159 return 0;
160 /* Initialise the decryption operation. */
161 if (EVP_DecryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) {
162 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
163 goto err;
164 }
165 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
166 hctx->noncelen, NULL) != 1) {
167 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
168 goto err;
169 }
170 /* Initialise key and IV */
171 if (EVP_DecryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) {
172 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
173 goto err;
174 }
175 /* Provide AAD. */
176 if (aadlen != 0 && aad != NULL) {
177 if (EVP_DecryptUpdate(ctx, NULL, &len, aad, aadlen) != 1) {
178 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
179 goto err;
180 }
181 }
182 if (EVP_DecryptUpdate(ctx, pt, &len, ct, ctlen - taglen) != 1) {
183 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
184 goto err;
185 }
186 *ptlen = len;
187 if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
188 taglen, (void *)(ct + ctlen - taglen))) {
189 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
190 goto err;
191 }
192 /* Finalise decryption. */
193 if (EVP_DecryptFinal_ex(ctx, pt + len, &len) <= 0) {
194 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
195 goto err;
196 }
197 erv = 1;
198
199 err:
200 if (erv != 1)
201 OPENSSL_cleanse(pt, *ptlen);
202 EVP_CIPHER_CTX_free(ctx);
203 return erv;
204 }
205
206 /**
207 * @brief do AEAD encryption as per the RFC
208 * @param hctx is the context to use
209 * @param iv is the initialisation vector
210 * @param aad is the additional authenticated data
211 * @param aadlen is the length of the aad
212 * @param pt is the plaintext buffer
213 * @param ptlen is the length of pt
214 * @param ct is the output buffer
215 * @param ctlen input/output, needs space for tag on input, exact on output
216 * @return 1 for success, 0 otherwise
217 */
218 static int hpke_aead_enc(OSSL_HPKE_CTX *hctx, const unsigned char *iv,
219 const unsigned char *aad, size_t aadlen,
220 const unsigned char *pt, size_t ptlen,
221 unsigned char *ct, size_t *ctlen)
222 {
223 int erv = 0;
224 EVP_CIPHER_CTX *ctx = NULL;
225 int len;
226 size_t taglen = 0;
227 unsigned char tag[EVP_MAX_AEAD_TAG_LENGTH];
228
229 taglen = hctx->aead_info->taglen;
230 if (*ctlen <= taglen || ptlen > *ctlen - taglen) {
231 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
232 return 0;
233 }
234 if (!ossl_assert(taglen <= sizeof(tag))) {
235 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
236 return 0;
237 }
238 /* Create and initialise the context */
239 if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
240 return 0;
241 /* Initialise the encryption operation. */
242 if (EVP_EncryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) {
243 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
244 goto err;
245 }
246 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
247 hctx->noncelen, NULL) != 1) {
248 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
249 goto err;
250 }
251 /* Initialise key and IV */
252 if (EVP_EncryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) {
253 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
254 goto err;
255 }
256 /* Provide any AAD data. */
257 if (aadlen != 0 && aad != NULL) {
258 if (EVP_EncryptUpdate(ctx, NULL, &len, aad, aadlen) != 1) {
259 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
260 goto err;
261 }
262 }
263 if (EVP_EncryptUpdate(ctx, ct, &len, pt, ptlen) != 1) {
264 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
265 goto err;
266 }
267 *ctlen = len;
268 /* Finalise the encryption. */
269 if (EVP_EncryptFinal_ex(ctx, ct + len, &len) != 1) {
270 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
271 goto err;
272 }
273 *ctlen += len;
274 /* Get tag. Not a duplicate so needs to be added to the ciphertext */
275 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, tag) != 1) {
276 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
277 goto err;
278 }
279 memcpy(ct + *ctlen, tag, taglen);
280 *ctlen += taglen;
281 erv = 1;
282
283 err:
284 if (erv != 1)
285 OPENSSL_cleanse(ct, *ctlen);
286 EVP_CIPHER_CTX_free(ctx);
287 return erv;
288 }
289
290 /**
291 * @brief check mode is in-range and supported
292 * @param mode is the caller's chosen mode
293 * @return 1 for good mode, 0 otherwise
294 */
295 static int hpke_mode_check(unsigned int mode)
296 {
297 switch (mode) {
298 case OSSL_HPKE_MODE_BASE:
299 case OSSL_HPKE_MODE_PSK:
300 case OSSL_HPKE_MODE_AUTH:
301 case OSSL_HPKE_MODE_PSKAUTH:
302 break;
303 default:
304 return 0;
305 }
306 return 1;
307 }
308
309 /**
310 * @brief check if a suite is supported locally
311 * @param suite is the suite to check
312 * @return 1 for good, 0 otherwise
313 */
314 static int hpke_suite_check(OSSL_HPKE_SUITE suite,
315 const OSSL_HPKE_KEM_INFO **kem_info,
316 const OSSL_HPKE_KDF_INFO **kdf_info,
317 const OSSL_HPKE_AEAD_INFO **aead_info)
318 {
319 const OSSL_HPKE_KEM_INFO *kem_info_;
320 const OSSL_HPKE_KDF_INFO *kdf_info_;
321 const OSSL_HPKE_AEAD_INFO *aead_info_;
322
323 /* check KEM, KDF and AEAD are supported here */
324 if ((kem_info_ = ossl_HPKE_KEM_INFO_find_id(suite.kem_id)) == NULL)
325 return 0;
326 if ((kdf_info_ = ossl_HPKE_KDF_INFO_find_id(suite.kdf_id)) == NULL)
327 return 0;
328 if ((aead_info_ = ossl_HPKE_AEAD_INFO_find_id(suite.aead_id)) == NULL)
329 return 0;
330
331 if (kem_info != NULL)
332 *kem_info = kem_info_;
333 if (kdf_info != NULL)
334 *kdf_info = kdf_info_;
335 if (aead_info != NULL)
336 *aead_info = aead_info_;
337
338 return 1;
339 }
340
341 /*
342 * @brief randomly pick a suite
343 * @param libctx is the context to use
344 * @param propq is a properties string
345 * @param suite is the result
346 * @return 1 for success, 0 otherwise
347 */
348 static int hpke_random_suite(OSSL_LIB_CTX *libctx,
349 const char *propq,
350 OSSL_HPKE_SUITE *suite)
351 {
352 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
353 const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
354 const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
355
356 /* random kem, kdf and aead */
357 kem_info = ossl_HPKE_KEM_INFO_find_random(libctx);
358 if (kem_info == NULL)
359 return 0;
360 suite->kem_id = kem_info->kem_id;
361 kdf_info = ossl_HPKE_KDF_INFO_find_random(libctx);
362 if (kdf_info == NULL)
363 return 0;
364 suite->kdf_id = kdf_info->kdf_id;
365 aead_info = ossl_HPKE_AEAD_INFO_find_random(libctx);
366 if (aead_info == NULL)
367 return 0;
368 suite->aead_id = aead_info->aead_id;
369 return 1;
370 }
371
372 /*
373 * @brief tell the caller how big the ciphertext will be
374 *
375 * AEAD algorithms add a tag for data authentication.
376 * Those are almost always, but not always, 16 octets
377 * long, and who knows what will be true in the future.
378 * So this function allows a caller to find out how
379 * much data expansion they will see with a given suite.
380 *
381 * "enc" is the name used in RFC9180 for the encapsulated
382 * public value of the sender, who calls OSSL_HPKE_seal(),
383 * that is sent to the recipient, who calls OSSL_HPKE_open().
384 *
385 * @param suite is the suite to be used
386 * @param enclen points to what will be enc length
387 * @param clearlen is the length of plaintext
388 * @param cipherlen points to what will be ciphertext length (including tag)
389 * @return 1 for success, 0 otherwise
390 */
391 static int hpke_expansion(OSSL_HPKE_SUITE suite,
392 size_t *enclen,
393 size_t clearlen,
394 size_t *cipherlen)
395 {
396 const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
397 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
398
399 if (cipherlen == NULL || enclen == NULL) {
400 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
401 return 0;
402 }
403 if (hpke_suite_check(suite, &kem_info, NULL, &aead_info) != 1) {
404 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
405 return 0;
406 }
407 *cipherlen = clearlen + aead_info->taglen;
408 *enclen = kem_info->Nenc;
409 return 1;
410 }
411
412 /*
413 * @brief expand and XOR the 64-bit unsigned seq with (nonce) buffer
414 * @param ctx is the HPKE context
415 * @param buf is the buffer for the XOR'd seq and nonce
416 * @param blen is the size of buf
417 * @return 0 for error, otherwise blen
418 */
419 static size_t hpke_seqnonce2buf(OSSL_HPKE_CTX *ctx,
420 unsigned char *buf, size_t blen)
421 {
422 size_t i;
423 uint64_t seq_copy;
424
425 if (ctx == NULL || blen < sizeof(seq_copy) || blen != ctx->noncelen)
426 return 0;
427 seq_copy = ctx->seq;
428 memset(buf, 0, blen);
429 for (i = 0; i < sizeof(seq_copy); i++) {
430 buf[blen - i - 1] = seq_copy & 0xff;
431 seq_copy >>= 8;
432 }
433 for (i = 0; i < blen; i++)
434 buf[i] ^= ctx->nonce[i];
435 return blen;
436 }
437
438 /*
439 * @brief call the underlying KEM to encap
440 * @param ctx is the OSSL_HPKE_CTX
441 * @param enc is a buffer for the sender's ephemeral public value
442 * @param enclen is the size of enc on input, number of octets used on output
443 * @param pub is the recipient's public value
444 * @param publen is the length of pub
445 * @return 1 for success, 0 for error
446 */
447 static int hpke_encap(OSSL_HPKE_CTX *ctx, unsigned char *enc, size_t *enclen,
448 const unsigned char *pub, size_t publen)
449 {
450 int erv = 0;
451 OSSL_PARAM params[3], *p = params;
452 size_t lsslen = 0, lenclen = 0;
453 EVP_PKEY_CTX *pctx = NULL;
454 EVP_PKEY *pkR = NULL;
455 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
456
457 if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0
458 || pub == NULL || publen == 0) {
459 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
460 return 0;
461 }
462 if (ctx->shared_secret != NULL) {
463 /* only run the KEM once per OSSL_HPKE_CTX */
464 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
465 return 0;
466 }
467 kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
468 if (kem_info == NULL) {
469 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
470 return 0;
471 }
472 if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
473 pkR = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
474 kem_info->groupname,
475 pub, publen);
476 } else {
477 pkR = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
478 kem_info->keytype,
479 ctx->propq, pub, publen);
480 }
481 if (pkR == NULL) {
482 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
483 goto err;
484 }
485 pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkR, ctx->propq);
486 if (pctx == NULL) {
487 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
488 goto err;
489 }
490 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
491 OSSL_KEM_PARAM_OPERATION_DHKEM,
492 0);
493 if (ctx->ikme != NULL) {
494 *p++ = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME,
495 ctx->ikme, ctx->ikmelen);
496 }
497 *p = OSSL_PARAM_construct_end();
498 if (ctx->mode == OSSL_HPKE_MODE_AUTH
499 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
500 if (EVP_PKEY_auth_encapsulate_init(pctx, ctx->authpriv,
501 params) != 1) {
502 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
503 goto err;
504 }
505 } else {
506 if (EVP_PKEY_encapsulate_init(pctx, params) != 1) {
507 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
508 goto err;
509 }
510 }
511 lenclen = *enclen;
512 if (EVP_PKEY_encapsulate(pctx, NULL, &lenclen, NULL, &lsslen) != 1) {
513 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
514 goto err;
515 }
516 if (lenclen > *enclen) {
517 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
518 goto err;
519 }
520 ctx->shared_secret = OPENSSL_malloc(lsslen);
521 if (ctx->shared_secret == NULL)
522 goto err;
523 ctx->shared_secretlen = lsslen;
524 if (EVP_PKEY_encapsulate(pctx, enc, enclen, ctx->shared_secret,
525 &ctx->shared_secretlen) != 1) {
526 ctx->shared_secretlen = 0;
527 OPENSSL_free(ctx->shared_secret);
528 ctx->shared_secret = NULL;
529 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
530 goto err;
531 }
532 erv = 1;
533
534 err:
535 EVP_PKEY_CTX_free(pctx);
536 EVP_PKEY_free(pkR);
537 return erv;
538 }
539
540 /*
541 * @brief call the underlying KEM to decap
542 * @param ctx is the OSSL_HPKE_CTX
543 * @param enc is a buffer for the sender's ephemeral public value
544 * @param enclen is the length of enc
545 * @param priv is the recipient's private value
546 * @return 1 for success, 0 for error
547 */
548 static int hpke_decap(OSSL_HPKE_CTX *ctx,
549 const unsigned char *enc, size_t enclen,
550 EVP_PKEY *priv)
551 {
552 int erv = 0;
553 EVP_PKEY_CTX *pctx = NULL;
554 EVP_PKEY *spub = NULL;
555 OSSL_PARAM params[2], *p = params;
556 size_t lsslen = 0;
557
558 if (ctx == NULL || enc == NULL || enclen == 0 || priv == NULL) {
559 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
560 return 0;
561 }
562 if (ctx->shared_secret != NULL) {
563 /* only run the KEM once per OSSL_HPKE_CTX */
564 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
565 return 0;
566 }
567 pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, priv, ctx->propq);
568 if (pctx == NULL) {
569 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
570 goto err;
571 }
572 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
573 OSSL_KEM_PARAM_OPERATION_DHKEM,
574 0);
575 *p = OSSL_PARAM_construct_end();
576 if (ctx->mode == OSSL_HPKE_MODE_AUTH
577 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
578 const OSSL_HPKE_KEM_INFO *kem_info = NULL;
579
580 kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
581 if (kem_info == NULL) {
582 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
583 goto err;
584 }
585 if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
586 spub = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
587 kem_info->groupname,
588 ctx->authpub,
589 ctx->authpublen);
590 } else {
591 spub = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
592 kem_info->keytype,
593 ctx->propq,
594 ctx->authpub,
595 ctx->authpublen);
596 }
597 if (spub == NULL) {
598 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
599 goto err;
600 }
601 if (EVP_PKEY_auth_decapsulate_init(pctx, spub, params) != 1) {
602 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
603 goto err;
604 }
605 } else {
606 if (EVP_PKEY_decapsulate_init(pctx, params) != 1) {
607 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
608 goto err;
609 }
610 }
611 if (EVP_PKEY_decapsulate(pctx, NULL, &lsslen, enc, enclen) != 1) {
612 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
613 goto err;
614 }
615 ctx->shared_secret = OPENSSL_malloc(lsslen);
616 if (ctx->shared_secret == NULL)
617 goto err;
618 if (EVP_PKEY_decapsulate(pctx, ctx->shared_secret, &lsslen,
619 enc, enclen) != 1) {
620 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
621 goto err;
622 }
623 ctx->shared_secretlen = lsslen;
624 erv = 1;
625
626 err:
627 EVP_PKEY_CTX_free(pctx);
628 EVP_PKEY_free(spub);
629 if (erv == 0) {
630 OPENSSL_free(ctx->shared_secret);
631 ctx->shared_secret = NULL;
632 ctx->shared_secretlen = 0;
633 }
634 return erv;
635 }
636
637 /*
638 * @brief do "middle" of HPKE, between KEM and AEAD
639 * @param ctx is the OSSL_HPKE_CTX
640 * @param info is a buffer for the added binding information
641 * @param infolen is the length of info
642 * @return 0 for error, 1 for success
643 *
644 * This does all the HPKE extracts and expands as defined in RFC9180
645 * section 5.1, (badly termed there as a "key schedule") and sets the
646 * ctx fields for the shared_secret, nonce, key and exporter_secret
647 */
648 static int hpke_do_middle(OSSL_HPKE_CTX *ctx,
649 const unsigned char *info, size_t infolen)
650 {
651 int erv = 0;
652 size_t ks_contextlen = OSSL_HPKE_MAXSIZE;
653 unsigned char ks_context[OSSL_HPKE_MAXSIZE];
654 size_t halflen = 0;
655 size_t pskidlen = 0;
656 const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
657 const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
658 size_t secretlen = OSSL_HPKE_MAXSIZE;
659 unsigned char secret[OSSL_HPKE_MAXSIZE];
660 EVP_KDF_CTX *kctx = NULL;
661 unsigned char suitebuf[6];
662 const char *mdname = NULL;
663
664 /* only let this be done once */
665 if (ctx->exportersec != NULL) {
666 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
667 return 0;
668 }
669 if (ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id) == NULL) {
670 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
671 return 0;
672 }
673 aead_info = ossl_HPKE_AEAD_INFO_find_id(ctx->suite.aead_id);
674 if (aead_info == NULL) {
675 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
676 return 0;
677 }
678 kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id);
679 if (kdf_info == NULL) {
680 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
681 return 0;
682 }
683 mdname = kdf_info->mdname;
684 /* create key schedule context */
685 memset(ks_context, 0, sizeof(ks_context));
686 ks_context[0] = (unsigned char)(ctx->mode % 256);
687 ks_contextlen--; /* remaining space */
688 halflen = kdf_info->Nh;
689 if ((2 * halflen) > ks_contextlen) {
690 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
691 return 0;
692 }
693 /* check a psk was set if in that mode */
694 if (ctx->mode == OSSL_HPKE_MODE_PSK
695 || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
696 if (ctx->psk == NULL || ctx->psklen == 0 || ctx->pskid == NULL) {
697 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
698 return 0;
699 }
700 }
701 kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
702 if (kctx == NULL) {
703 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
704 return 0;
705 }
706 pskidlen = (ctx->psk == NULL ? 0 : strlen(ctx->pskid));
707 /* full suite details as per RFC9180 sec 5.1 */
708 suitebuf[0] = ctx->suite.kem_id / 256;
709 suitebuf[1] = ctx->suite.kem_id % 256;
710 suitebuf[2] = ctx->suite.kdf_id / 256;
711 suitebuf[3] = ctx->suite.kdf_id % 256;
712 suitebuf[4] = ctx->suite.aead_id / 256;
713 suitebuf[5] = ctx->suite.aead_id % 256;
714 /* Extract and Expand variously... */
715 if (ossl_hpke_labeled_extract(kctx, ks_context + 1, halflen,
716 NULL, 0, OSSL_HPKE_SEC51LABEL,
717 suitebuf, sizeof(suitebuf),
718 OSSL_HPKE_PSKIDHASH_LABEL,
719 (unsigned char *)ctx->pskid, pskidlen) != 1) {
720 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
721 goto err;
722 }
723 if (ossl_hpke_labeled_extract(kctx, ks_context + 1 + halflen, halflen,
724 NULL, 0, OSSL_HPKE_SEC51LABEL,
725 suitebuf, sizeof(suitebuf),
726 OSSL_HPKE_INFOHASH_LABEL,
727 (unsigned char *)info, infolen) != 1) {
728 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
729 goto err;
730 }
731 ks_contextlen = 1 + 2 * halflen;
732 secretlen = kdf_info->Nh;
733 if (secretlen > OSSL_HPKE_MAXSIZE) {
734 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
735 goto err;
736 }
737 if (ossl_hpke_labeled_extract(kctx, secret, secretlen,
738 ctx->shared_secret, ctx->shared_secretlen,
739 OSSL_HPKE_SEC51LABEL,
740 suitebuf, sizeof(suitebuf),
741 OSSL_HPKE_SECRET_LABEL,
742 ctx->psk, ctx->psklen) != 1) {
743 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
744 goto err;
745 }
746 if (ctx->suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) {
747 /* we only need nonce/key for non export AEADs */
748 ctx->noncelen = aead_info->Nn;
749 ctx->nonce = OPENSSL_malloc(ctx->noncelen);
750 if (ctx->nonce == NULL)
751 goto err;
752 if (ossl_hpke_labeled_expand(kctx, ctx->nonce, ctx->noncelen,
753 secret, secretlen, OSSL_HPKE_SEC51LABEL,
754 suitebuf, sizeof(suitebuf),
755 OSSL_HPKE_NONCE_LABEL,
756 ks_context, ks_contextlen) != 1) {
757 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
758 goto err;
759 }
760 ctx->keylen = aead_info->Nk;
761 ctx->key = OPENSSL_malloc(ctx->keylen);
762 if (ctx->key == NULL)
763 goto err;
764 if (ossl_hpke_labeled_expand(kctx, ctx->key, ctx->keylen,
765 secret, secretlen, OSSL_HPKE_SEC51LABEL,
766 suitebuf, sizeof(suitebuf),
767 OSSL_HPKE_KEY_LABEL,
768 ks_context, ks_contextlen) != 1) {
769 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
770 goto err;
771 }
772 }
773 ctx->exporterseclen = kdf_info->Nh;
774 ctx->exportersec = OPENSSL_malloc(ctx->exporterseclen);
775 if (ctx->exportersec == NULL)
776 goto err;
777 if (ossl_hpke_labeled_expand(kctx, ctx->exportersec, ctx->exporterseclen,
778 secret, secretlen, OSSL_HPKE_SEC51LABEL,
779 suitebuf, sizeof(suitebuf),
780 OSSL_HPKE_EXP_LABEL,
781 ks_context, ks_contextlen) != 1) {
782 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
783 goto err;
784 }
785 erv = 1;
786
787 err:
788 OPENSSL_cleanse(ks_context, OSSL_HPKE_MAXSIZE);
789 OPENSSL_cleanse(secret, OSSL_HPKE_MAXSIZE);
790 EVP_KDF_CTX_free(kctx);
791 return erv;
792 }
793
794 /*
795 * externally visible functions from below here, API documentation is
796 * in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication
797 */
798
799 OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role,
800 OSSL_LIB_CTX *libctx, const char *propq)
801 {
802 OSSL_HPKE_CTX *ctx = NULL;
803 const OSSL_HPKE_KEM_INFO *kem_info;
804 const OSSL_HPKE_KDF_INFO *kdf_info;
805 const OSSL_HPKE_AEAD_INFO *aead_info;
806
807 if (hpke_mode_check(mode) != 1) {
808 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
809 return NULL;
810 }
811 if (hpke_suite_check(suite, &kem_info, &kdf_info, &aead_info) != 1) {
812 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
813 return NULL;
814 }
815 if (role != OSSL_HPKE_ROLE_SENDER && role != OSSL_HPKE_ROLE_RECEIVER) {
816 ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
817 return 0;
818 }
819 ctx = OPENSSL_zalloc(sizeof(*ctx));
820 if (ctx == NULL)
821 return NULL;
822 ctx->libctx = libctx;
823 if (propq != NULL) {
824 ctx->propq = OPENSSL_strdup(propq);
825 if (ctx->propq == NULL)
826 goto err;
827 }
828 if (suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) {
829 ctx->aead_ciph = EVP_CIPHER_fetch(libctx, aead_info->name, propq);
830 if (ctx->aead_ciph == NULL) {
831 ERR_raise(ERR_LIB_CRYPTO, ERR_R_FETCH_FAILED);
832 goto err;
833 }
834 }
835 ctx->role = role;
836 ctx->mode = mode;
837 ctx->suite = suite;
838 ctx->kem_info = kem_info;
839 ctx->kdf_info = kdf_info;
840 ctx->aead_info = aead_info;
841 return ctx;
842
843 err:
844 EVP_CIPHER_free(ctx->aead_ciph);
845 OPENSSL_free(ctx);
846 return NULL;
847 }
848
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
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
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
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
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
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
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
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
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
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
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
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
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
1358 int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite)
1359 {
1360 return hpke_suite_check(suite, NULL, NULL, NULL);
1361 }
1362
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
1427 int OSSL_HPKE_str2suite(const char *str, OSSL_HPKE_SUITE *suite)
1428 {
1429 return ossl_hpke_str2suite(str, suite);
1430 }
1431
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
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
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 }