2 * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
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
10 /* An OpenSSL-based HPKE implementation of RFC9180 */
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"
24 /* default buffer size for keys and internal buffers we use */
25 #define OSSL_HPKE_MAXSIZE 512
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";
46 * @brief sender or receiver context
48 struct ossl_hpke_ctx_st
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 */
64 unsigned char *nonce
; /* aead base nonce */
66 unsigned char *exportersec
; /* exporter secret */
67 size_t exporterseclen
;
68 char *pskid
; /* PSK stuff */
71 EVP_PKEY
*authpriv
; /* sender's authentication private key */
72 unsigned char *authpub
; /* auth public key */
74 unsigned char *ikme
; /* IKM for sender deterministic key gen */
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
83 static int hpke_kem_id_nist_curve(uint16_t kem_id
)
85 const OSSL_HPKE_KEM_INFO
*kem_info
;
87 kem_info
= ossl_HPKE_KEM_INFO_find_id(kem_id
);
88 return kem_info
!= NULL
&& kem_info
->groupname
!= NULL
;
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
100 * Note that this could be a useful function to make public in
101 * future, but would likely require a name change.
103 static EVP_PKEY
*evp_pkey_new_raw_nist_public_key(OSSL_LIB_CTX
*libctx
,
106 const unsigned char *buf
,
109 OSSL_PARAM params
[2];
110 EVP_PKEY
*ret
= NULL
;
111 EVP_PKEY_CTX
*cctx
= EVP_PKEY_CTX_new_from_name(libctx
, "EC", propq
);
113 params
[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME
,
115 params
[1] = OSSL_PARAM_construct_end();
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
);
123 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
126 EVP_PKEY_CTX_free(cctx
);
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
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
)
148 EVP_CIPHER_CTX
*ctx
= NULL
;
152 taglen
= hctx
->aead_info
->taglen
;
153 if (ctlen
<= taglen
|| *ptlen
< ctlen
- taglen
) {
154 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
157 /* Create and initialise the context */
158 if ((ctx
= EVP_CIPHER_CTX_new()) == NULL
)
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
);
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
);
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
);
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
);
182 if (EVP_DecryptUpdate(ctx
, pt
, &len
, ct
, ctlen
- taglen
) != 1) {
183 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
192 /* Finalise decryption. */
193 if (EVP_DecryptFinal_ex(ctx
, pt
+ len
, &len
) <= 0) {
194 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
201 OPENSSL_cleanse(pt
, *ptlen
);
202 EVP_CIPHER_CTX_free(ctx
);
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
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
)
224 EVP_CIPHER_CTX
*ctx
= NULL
;
227 unsigned char tag
[EVP_MAX_AEAD_TAG_LENGTH
];
229 taglen
= hctx
->aead_info
->taglen
;
230 if (*ctlen
<= taglen
|| ptlen
> *ctlen
- taglen
) {
231 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
234 if (!ossl_assert(taglen
<= sizeof(tag
))) {
235 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
238 /* Create and initialise the context */
239 if ((ctx
= EVP_CIPHER_CTX_new()) == NULL
)
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
);
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
);
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
);
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
);
263 if (EVP_EncryptUpdate(ctx
, ct
, &len
, pt
, ptlen
) != 1) {
264 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
268 /* Finalise the encryption. */
269 if (EVP_EncryptFinal_ex(ctx
, ct
+ len
, &len
) != 1) {
270 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
279 memcpy(ct
+ *ctlen
, tag
, taglen
);
285 OPENSSL_cleanse(ct
, *ctlen
);
286 EVP_CIPHER_CTX_free(ctx
);
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
295 static int hpke_mode_check(unsigned int 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
:
310 * @brief check if a suite is supported locally
311 * @param suite is the suite to check
312 * @return 1 for good, 0 otherwise
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
)
319 const OSSL_HPKE_KEM_INFO
*kem_info_
;
320 const OSSL_HPKE_KDF_INFO
*kdf_info_
;
321 const OSSL_HPKE_AEAD_INFO
*aead_info_
;
323 /* check KEM, KDF and AEAD are supported here */
324 if ((kem_info_
= ossl_HPKE_KEM_INFO_find_id(suite
.kem_id
)) == NULL
)
326 if ((kdf_info_
= ossl_HPKE_KDF_INFO_find_id(suite
.kdf_id
)) == NULL
)
328 if ((aead_info_
= ossl_HPKE_AEAD_INFO_find_id(suite
.aead_id
)) == NULL
)
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_
;
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
348 static int hpke_random_suite(OSSL_LIB_CTX
*libctx
,
350 OSSL_HPKE_SUITE
*suite
)
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
;
356 /* random kem, kdf and aead */
357 kem_info
= ossl_HPKE_KEM_INFO_find_random(libctx
);
358 if (kem_info
== NULL
)
360 suite
->kem_id
= kem_info
->kem_id
;
361 kdf_info
= ossl_HPKE_KDF_INFO_find_random(libctx
);
362 if (kdf_info
== NULL
)
364 suite
->kdf_id
= kdf_info
->kdf_id
;
365 aead_info
= ossl_HPKE_AEAD_INFO_find_random(libctx
);
366 if (aead_info
== NULL
)
368 suite
->aead_id
= aead_info
->aead_id
;
373 * @brief tell the caller how big the ciphertext will be
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.
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().
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
391 static int hpke_expansion(OSSL_HPKE_SUITE suite
,
396 const OSSL_HPKE_AEAD_INFO
*aead_info
= NULL
;
397 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
399 if (cipherlen
== NULL
|| enclen
== NULL
) {
400 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
403 if (hpke_suite_check(suite
, &kem_info
, NULL
, &aead_info
) != 1) {
404 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
407 *cipherlen
= clearlen
+ aead_info
->taglen
;
408 *enclen
= kem_info
->Nenc
;
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
419 static size_t hpke_seqnonce2buf(OSSL_HPKE_CTX
*ctx
,
420 unsigned char *buf
, size_t blen
)
425 if (ctx
== NULL
|| blen
< sizeof(seq_copy
) || blen
!= ctx
->noncelen
)
428 memset(buf
, 0, blen
);
429 for (i
= 0; i
< sizeof(seq_copy
); i
++) {
430 buf
[blen
- i
- 1] = seq_copy
& 0xff;
433 for (i
= 0; i
< blen
; i
++)
434 buf
[i
] ^= ctx
->nonce
[i
];
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
447 static int hpke_encap(OSSL_HPKE_CTX
*ctx
, unsigned char *enc
, size_t *enclen
,
448 const unsigned char *pub
, size_t publen
)
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
;
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
);
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
);
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
);
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
,
477 pkR
= EVP_PKEY_new_raw_public_key_ex(ctx
->libctx
,
479 ctx
->propq
, pub
, publen
);
482 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
485 pctx
= EVP_PKEY_CTX_new_from_pkey(ctx
->libctx
, pkR
, ctx
->propq
);
487 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
490 *p
++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION
,
491 OSSL_KEM_PARAM_OPERATION_DHKEM
,
493 if (ctx
->ikme
!= NULL
) {
494 *p
++ = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME
,
495 ctx
->ikme
, ctx
->ikmelen
);
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
,
502 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
506 if (EVP_PKEY_encapsulate_init(pctx
, params
) != 1) {
507 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
512 if (EVP_PKEY_encapsulate(pctx
, NULL
, &lenclen
, NULL
, &lsslen
) != 1) {
513 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
516 if (lenclen
> *enclen
) {
517 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
520 ctx
->shared_secret
= OPENSSL_malloc(lsslen
);
521 if (ctx
->shared_secret
== NULL
)
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
);
535 EVP_PKEY_CTX_free(pctx
);
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
548 static int hpke_decap(OSSL_HPKE_CTX
*ctx
,
549 const unsigned char *enc
, size_t enclen
,
553 EVP_PKEY_CTX
*pctx
= NULL
;
554 EVP_PKEY
*spub
= NULL
;
555 OSSL_PARAM params
[2], *p
= params
;
558 if (ctx
== NULL
|| enc
== NULL
|| enclen
== 0 || priv
== NULL
) {
559 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
567 pctx
= EVP_PKEY_CTX_new_from_pkey(ctx
->libctx
, priv
, ctx
->propq
);
569 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
572 *p
++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION
,
573 OSSL_KEM_PARAM_OPERATION_DHKEM
,
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
;
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
);
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
,
591 spub
= EVP_PKEY_new_raw_public_key_ex(ctx
->libctx
,
598 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
601 if (EVP_PKEY_auth_decapsulate_init(pctx
, spub
, params
) != 1) {
602 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
606 if (EVP_PKEY_decapsulate_init(pctx
, params
) != 1) {
607 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
611 if (EVP_PKEY_decapsulate(pctx
, NULL
, &lsslen
, enc
, enclen
) != 1) {
612 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
615 ctx
->shared_secret
= OPENSSL_malloc(lsslen
);
616 if (ctx
->shared_secret
== NULL
)
618 if (EVP_PKEY_decapsulate(pctx
, ctx
->shared_secret
, &lsslen
,
620 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
623 ctx
->shared_secretlen
= lsslen
;
627 EVP_PKEY_CTX_free(pctx
);
630 OPENSSL_free(ctx
->shared_secret
);
631 ctx
->shared_secret
= NULL
;
632 ctx
->shared_secretlen
= 0;
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
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
648 static int hpke_do_middle(OSSL_HPKE_CTX
*ctx
,
649 const unsigned char *info
, size_t infolen
)
652 size_t ks_contextlen
= OSSL_HPKE_MAXSIZE
;
653 unsigned char ks_context
[OSSL_HPKE_MAXSIZE
];
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
;
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
);
669 if (ossl_HPKE_KEM_INFO_find_id(ctx
->suite
.kem_id
) == NULL
) {
670 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
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
);
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
);
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
);
701 kctx
= ossl_kdf_ctx_create("HKDF", mdname
, ctx
->libctx
, ctx
->propq
);
703 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
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
);
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
);
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
);
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
)
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
);
760 ctx
->keylen
= aead_info
->Nk
;
761 ctx
->key
= OPENSSL_malloc(ctx
->keylen
);
762 if (ctx
->key
== NULL
)
764 if (ossl_hpke_labeled_expand(kctx
, ctx
->key
, ctx
->keylen
,
765 secret
, secretlen
, OSSL_HPKE_SEC51LABEL
,
766 suitebuf
, sizeof(suitebuf
),
768 ks_context
, ks_contextlen
) != 1) {
769 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
773 ctx
->exporterseclen
= kdf_info
->Nh
;
774 ctx
->exportersec
= OPENSSL_malloc(ctx
->exporterseclen
);
775 if (ctx
->exportersec
== NULL
)
777 if (ossl_hpke_labeled_expand(kctx
, ctx
->exportersec
, ctx
->exporterseclen
,
778 secret
, secretlen
, OSSL_HPKE_SEC51LABEL
,
779 suitebuf
, sizeof(suitebuf
),
781 ks_context
, ks_contextlen
) != 1) {
782 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
788 OPENSSL_cleanse(ks_context
, OSSL_HPKE_MAXSIZE
);
789 OPENSSL_cleanse(secret
, OSSL_HPKE_MAXSIZE
);
790 EVP_KDF_CTX_free(kctx
);
795 * externally visible functions from below here, API documentation is
796 * in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication
799 OSSL_HPKE_CTX
*OSSL_HPKE_CTX_new(int mode
, OSSL_HPKE_SUITE suite
, int role
,
800 OSSL_LIB_CTX
*libctx
, const char *propq
)
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
;
807 if (hpke_mode_check(mode
) != 1) {
808 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
811 if (hpke_suite_check(suite
, &kem_info
, &kdf_info
, &aead_info
) != 1) {
812 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
815 if (role
!= OSSL_HPKE_ROLE_SENDER
&& role
!= OSSL_HPKE_ROLE_RECEIVER
) {
816 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
819 ctx
= OPENSSL_zalloc(sizeof(*ctx
));
822 ctx
->libctx
= libctx
;
824 ctx
->propq
= OPENSSL_strdup(propq
);
825 if (ctx
->propq
== NULL
)
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
);
838 ctx
->kem_info
= kem_info
;
839 ctx
->kdf_info
= kdf_info
;
840 ctx
->aead_info
= aead_info
;
844 EVP_CIPHER_free(ctx
->aead_ciph
);
849 void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX
*ctx
)
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
);
869 int OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX
*ctx
,
871 const unsigned char *psk
, size_t psklen
)
873 if (ctx
== NULL
|| pskid
== NULL
|| psk
== NULL
|| psklen
== 0) {
874 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
877 if (psklen
> OSSL_HPKE_MAX_PARMLEN
) {
878 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
881 if (psklen
< OSSL_HPKE_MIN_PSKLEN
) {
882 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
885 if (strlen(pskid
) > OSSL_HPKE_MAX_PARMLEN
) {
886 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
889 if (strlen(pskid
) == 0) {
890 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
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
)
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
);
915 int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX
*ctx
,
916 const unsigned char *ikme
, size_t ikmelen
)
918 if (ctx
== NULL
|| ikme
== NULL
) {
919 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
922 if (ikmelen
== 0 || ikmelen
> OSSL_HPKE_MAX_PARMLEN
) {
923 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
926 if (ctx
->role
!= OSSL_HPKE_ROLE_SENDER
) {
927 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
930 OPENSSL_clear_free(ctx
->ikme
, ctx
->ikmelen
);
931 ctx
->ikme
= OPENSSL_memdup(ikme
, ikmelen
);
932 if (ctx
->ikme
== NULL
)
934 ctx
->ikmelen
= ikmelen
;
938 int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX
*ctx
, EVP_PKEY
*priv
)
940 if (ctx
== NULL
|| priv
== NULL
) {
941 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
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
);
949 if (ctx
->role
!= OSSL_HPKE_ROLE_SENDER
) {
950 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
953 EVP_PKEY_free(ctx
->authpriv
);
954 ctx
->authpriv
= EVP_PKEY_dup(priv
);
955 if (ctx
->authpriv
== NULL
)
960 int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX
*ctx
,
961 const unsigned char *pub
, size_t publen
)
964 EVP_PKEY
*pubp
= NULL
;
965 unsigned char *lpub
= NULL
;
967 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
969 if (ctx
== NULL
|| pub
== NULL
|| publen
== 0) {
970 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
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
);
978 if (ctx
->role
!= OSSL_HPKE_ROLE_RECEIVER
) {
979 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
)
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
,
991 pubp
= EVP_PKEY_new_raw_public_key_ex(ctx
->libctx
,
997 /* can happen based on external input - buffer value may be garbage */
998 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1002 * extract out the public key in encoded form so we
1003 * should be fine even if given compressed form
1005 lpub
= OPENSSL_malloc(OSSL_HPKE_MAXSIZE
);
1008 if (EVP_PKEY_get_octet_string_param(pubp
,
1009 OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY
,
1010 lpub
, OSSL_HPKE_MAXSIZE
, &lpublen
)
1013 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
1016 /* free up old value */
1017 OPENSSL_free(ctx
->authpub
);
1018 ctx
->authpub
= lpub
;
1019 ctx
->authpublen
= lpublen
;
1023 EVP_PKEY_free(pubp
);
1027 int OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX
*ctx
, uint64_t *seq
)
1029 if (ctx
== NULL
|| seq
== NULL
) {
1030 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
1037 int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX
*ctx
, uint64_t seq
)
1040 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
1044 * We disallow senders from doing this as it's dangerous
1045 * Receivers are ok to use this, as no harm should ensue
1048 if (ctx
->role
== OSSL_HPKE_ROLE_SENDER
) {
1049 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
)
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
);
1069 if (ctx
->role
!= OSSL_HPKE_ROLE_SENDER
) {
1070 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1073 if (infolen
> OSSL_HPKE_MAX_INFOLEN
) {
1074 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1077 if (infolen
> 0 && info
== NULL
) {
1078 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
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
);
1091 if (hpke_encap(ctx
, enc
, enclen
, pub
, publen
) != 1) {
1092 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
1100 erv
= hpke_do_middle(ctx
, info
, infolen
);
1104 int OSSL_HPKE_decap(OSSL_HPKE_CTX
*ctx
,
1105 const unsigned char *enc
, size_t enclen
,
1106 EVP_PKEY
*recippriv
,
1107 const unsigned char *info
, size_t infolen
)
1112 if (ctx
== NULL
|| enc
== NULL
|| enclen
== 0 || recippriv
== NULL
) {
1113 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1116 if (ctx
->role
!= OSSL_HPKE_ROLE_RECEIVER
) {
1117 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1120 if (infolen
> OSSL_HPKE_MAX_INFOLEN
) {
1121 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1124 if (infolen
> 0 && info
== NULL
) {
1125 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
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
);
1138 erv
= hpke_decap(ctx
, enc
, enclen
, recippriv
);
1140 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
1148 erv
= hpke_do_middle(ctx
, info
, infolen
);
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
)
1157 unsigned char seqbuf
[OSSL_HPKE_MAX_NONCELEN
];
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
);
1165 if (ctx
->role
!= OSSL_HPKE_ROLE_SENDER
) {
1166 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1169 if ((ctx
->seq
+ 1) == 0) { /* wrap around imminent !!! */
1170 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED
);
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
);
1178 seqlen
= hpke_seqnonce2buf(ctx
, seqbuf
, sizeof(seqbuf
));
1180 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
));
1190 OPENSSL_cleanse(seqbuf
, sizeof(seqbuf
));
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
)
1199 unsigned char seqbuf
[OSSL_HPKE_MAX_NONCELEN
];
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
);
1207 if (ctx
->role
!= OSSL_HPKE_ROLE_RECEIVER
) {
1208 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1211 if ((ctx
->seq
+ 1) == 0) { /* wrap around imminent !!! */
1212 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED
);
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
);
1220 seqlen
= hpke_seqnonce2buf(ctx
, seqbuf
, sizeof(seqbuf
));
1222 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
));
1231 OPENSSL_cleanse(seqbuf
, sizeof(seqbuf
));
1235 int OSSL_HPKE_export(OSSL_HPKE_CTX
*ctx
,
1236 unsigned char *secret
, size_t secretlen
,
1237 const unsigned char *label
, size_t labellen
)
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
;
1245 if (ctx
== NULL
|| secret
== NULL
|| secretlen
== 0) {
1246 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1249 if (labellen
> OSSL_HPKE_MAX_PARMLEN
) {
1250 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1253 if (labellen
> 0 && label
== NULL
) {
1254 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1257 if (ctx
->exportersec
== NULL
) {
1258 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED
);
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
);
1266 mdname
= kdf_info
->mdname
;
1267 kctx
= ossl_kdf_ctx_create("HKDF", mdname
, ctx
->libctx
, ctx
->propq
);
1269 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
,
1285 EVP_KDF_CTX_free(kctx
);
1287 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
)
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
;
1302 if (pub
== NULL
|| publen
== NULL
|| *publen
== 0 || priv
== NULL
) {
1303 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1306 if (hpke_suite_check(suite
, &kem_info
, NULL
, NULL
) != 1) {
1307 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
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
);
1322 pctx
= EVP_PKEY_CTX_new_from_name(libctx
, kem_info
->keytype
, propq
);
1325 || EVP_PKEY_keygen_init(pctx
) <= 0) {
1326 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
1337 if (EVP_PKEY_generate(pctx
, &skR
) <= 0) {
1338 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
1341 EVP_PKEY_CTX_free(pctx
);
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
);
1354 EVP_PKEY_CTX_free(pctx
);
1358 int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite
)
1360 return hpke_suite_check(suite
, NULL
, NULL
, NULL
);
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
)
1369 OSSL_HPKE_SUITE chosen
;
1371 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
1372 const OSSL_HPKE_AEAD_INFO
*aead_info
= NULL
;
1373 EVP_PKEY
*fakepriv
= NULL
;
1375 if (enc
== NULL
|| enclen
== 0
1376 || ct
== NULL
|| ctlen
== 0 || suite
== NULL
) {
1377 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
1389 if (hpke_suite_check(chosen
, &kem_info
, NULL
, &aead_info
) != 1) {
1390 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
1400 plen
= kem_info
->Npk
;
1401 if (plen
> *enclen
) {
1402 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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.
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
);
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
);
1427 int OSSL_HPKE_str2suite(const char *str
, OSSL_HPKE_SUITE
*suite
)
1429 return ossl_hpke_str2suite(str
, suite
);
1432 size_t OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite
, size_t clearlen
)
1435 size_t cipherlen
= 0;
1437 if (hpke_expansion(suite
, &enclen
, clearlen
, &cipherlen
) != 1)
1442 size_t OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite
)
1445 size_t cipherlen
= 0;
1446 size_t clearlen
= 16;
1448 if (hpke_expansion(suite
, &enclen
, clearlen
, &cipherlen
) != 1)
1453 size_t OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite
)
1455 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
1457 if (hpke_suite_check(suite
, &kem_info
, NULL
, NULL
) != 1)
1459 if (kem_info
== NULL
)
1462 return kem_info
->Nsk
;