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