2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
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
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"
23 /** default buffer size for keys and internal buffers we use */
24 #define OSSL_HPKE_MAXSIZE 512
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";
47 * @brief sender or receiver context
49 struct ossl_hpke_ctx_st
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 */
60 unsigned char *nonce
; /* aead base nonce */
62 unsigned char *exportersec
; /* exporter secret */
63 size_t exporterseclen
;
64 char *pskid
; /* PSK stuff */
67 EVP_PKEY
*authpriv
; /* sender's authentication private key */
68 unsigned char *authpub
; /* auth public key */
70 unsigned char *ikme
; /* IKM for sender deterministic key gen */
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
79 static int hpke_kem_id_nist_curve(uint16_t kem_id
)
81 const OSSL_HPKE_KEM_INFO
*kem_info
;
83 kem_info
= ossl_HPKE_KEM_INFO_find_id(kem_id
);
84 return kem_info
!= NULL
&& kem_info
->groupname
!= NULL
;
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
96 * Note that this could be a useful function to make public in
97 * future, but would likely require a name change.
99 static EVP_PKEY
*evp_pkey_new_raw_nist_public_key(OSSL_LIB_CTX
*libctx
,
102 const unsigned char *buf
,
105 OSSL_PARAM params
[2];
106 EVP_PKEY
*ret
= NULL
;
107 EVP_PKEY_CTX
*cctx
= EVP_PKEY_CTX_new_from_name(libctx
, "EC", propq
);
109 params
[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME
,
111 params
[1] = OSSL_PARAM_construct_end();
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
);
119 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
122 EVP_PKEY_CTX_free(cctx
);
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
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
)
152 EVP_CIPHER_CTX
*ctx
= NULL
;
155 EVP_CIPHER
*enc
= NULL
;
156 const OSSL_HPKE_AEAD_INFO
*aead_info
= NULL
;
158 if (pt
== NULL
|| ptlen
== NULL
) {
159 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
167 taglen
= aead_info
->taglen
;
168 if (ctlen
<= taglen
|| *ptlen
< ctlen
- taglen
) {
169 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
172 /* Create and initialise the context */
173 if ((ctx
= EVP_CIPHER_CTX_new()) == NULL
) {
174 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
177 /* Initialise the encryption operation */
178 enc
= EVP_CIPHER_fetch(libctx
, aead_info
->name
, propq
);
180 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
183 if (EVP_DecryptInit_ex(ctx
, enc
, NULL
, NULL
, NULL
) != 1) {
184 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
187 EVP_CIPHER_free(enc
);
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
);
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
);
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
);
205 if (EVP_DecryptUpdate(ctx
, pt
, &len
, ct
, ctlen
- taglen
) != 1) {
206 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
215 /* Finalise decryption. */
216 if (EVP_DecryptFinal_ex(ctx
, pt
+ len
, &len
) <= 0) {
217 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
224 OPENSSL_cleanse(pt
, *ptlen
);
225 EVP_CIPHER_CTX_free(ctx
);
226 EVP_CIPHER_free(enc
);
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
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
)
256 EVP_CIPHER_CTX
*ctx
= NULL
;
259 const OSSL_HPKE_AEAD_INFO
*aead_info
= NULL
;
260 EVP_CIPHER
*enc
= NULL
;
261 unsigned char tag
[16];
263 if (ct
== NULL
|| ctlen
== NULL
) {
264 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
272 taglen
= aead_info
->taglen
;
273 if (*ctlen
<= taglen
|| ptlen
> *ctlen
- taglen
) {
274 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
277 /* Create and initialise the context */
278 if ((ctx
= EVP_CIPHER_CTX_new()) == NULL
) {
279 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
282 /* Initialise the encryption operation. */
283 enc
= EVP_CIPHER_fetch(libctx
, aead_info
->name
, propq
);
285 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
288 if (EVP_EncryptInit_ex(ctx
, enc
, NULL
, NULL
, NULL
) != 1) {
289 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
292 EVP_CIPHER_free(enc
);
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
);
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
);
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
);
310 if (EVP_EncryptUpdate(ctx
, ct
, &len
, pt
, ptlen
) != 1) {
311 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
315 /* Finalise the encryption. */
316 if (EVP_EncryptFinal_ex(ctx
, ct
+ len
, &len
) != 1) {
317 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
326 memcpy(ct
+ *ctlen
, tag
, taglen
);
332 OPENSSL_cleanse(ct
, *ctlen
);
333 EVP_CIPHER_CTX_free(ctx
);
334 EVP_CIPHER_free(enc
);
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
343 static int hpke_mode_check(unsigned int 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
:
358 * @brief check if a suite is supported locally
359 * @param suite is the suite to check
360 * @return 1 for good, 0 otherwise
362 static int hpke_suite_check(OSSL_HPKE_SUITE suite
)
364 /* check KEM, KDF and AEAD are supported here */
365 if (ossl_HPKE_KEM_INFO_find_id(suite
.kem_id
) == NULL
)
367 if (ossl_HPKE_KDF_INFO_find_id(suite
.kdf_id
) == NULL
)
369 if (ossl_HPKE_AEAD_INFO_find_id(suite
.aead_id
) == NULL
)
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
381 static int hpke_random_suite(OSSL_LIB_CTX
*libctx
,
383 OSSL_HPKE_SUITE
*suite
)
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
;
389 /* random kem, kdf and aead */
390 kem_info
= ossl_HPKE_KEM_INFO_find_random(libctx
);
391 if (kem_info
== NULL
)
393 suite
->kem_id
= kem_info
->kem_id
;
394 kdf_info
= ossl_HPKE_KDF_INFO_find_random(libctx
);
395 if (kdf_info
== NULL
)
397 suite
->kdf_id
= kdf_info
->kdf_id
;
398 aead_info
= ossl_HPKE_AEAD_INFO_find_random(libctx
);
399 if (aead_info
== NULL
)
401 suite
->aead_id
= aead_info
->aead_id
;
406 * @brief tell the caller how big the ciphertext will be
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.
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().
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
424 static int hpke_expansion(OSSL_HPKE_SUITE suite
,
429 const OSSL_HPKE_AEAD_INFO
*aead_info
= NULL
;
430 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
432 if (cipherlen
== NULL
|| enclen
== NULL
) {
433 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
436 if (hpke_suite_check(suite
) != 1) {
437 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
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
);
451 *enclen
= kem_info
->Nenc
;
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
462 static size_t hpke_seqnonce2buf(OSSL_HPKE_CTX
*ctx
,
463 unsigned char *buf
, size_t blen
)
468 if (ctx
== NULL
|| blen
< sizeof(seq_copy
) || blen
!= ctx
->noncelen
)
471 memset(buf
, 0, blen
);
472 for (i
= 0; i
< sizeof(seq_copy
); i
++) {
473 buf
[blen
- i
- 1] = seq_copy
& 0xff;
476 for (i
= 0; i
< blen
; i
++)
477 buf
[i
] ^= ctx
->nonce
[i
];
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
490 static int hpke_encap(OSSL_HPKE_CTX
*ctx
, unsigned char *enc
, size_t *enclen
,
491 const unsigned char *pub
, size_t publen
)
494 OSSL_PARAM params
[3], *p
= params
;
496 EVP_PKEY_CTX
*pctx
= NULL
;
497 EVP_PKEY
*pkR
= NULL
;
498 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
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
);
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
);
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
);
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
,
520 pkR
= EVP_PKEY_new_raw_public_key_ex(ctx
->libctx
,
522 ctx
->propq
, pub
, publen
);
525 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
528 pctx
= EVP_PKEY_CTX_new_from_pkey(ctx
->libctx
, pkR
, ctx
->propq
);
530 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
533 *p
++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION
,
534 OSSL_KEM_PARAM_OPERATION_DHKEM
,
536 if (ctx
->ikme
!= NULL
) {
537 *p
++ = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME
,
538 ctx
->ikme
, ctx
->ikmelen
);
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
,
545 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
549 if (EVP_PKEY_encapsulate_init(pctx
, params
) != 1) {
550 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
554 if (EVP_PKEY_encapsulate(pctx
, NULL
, enclen
, NULL
, &lsslen
) != 1) {
555 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
558 ctx
->shared_secret
= OPENSSL_malloc(lsslen
);
559 if (ctx
->shared_secret
== NULL
)
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
);
573 EVP_PKEY_CTX_free(pctx
);
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
586 static int hpke_decap(OSSL_HPKE_CTX
*ctx
,
587 const unsigned char *enc
, size_t enclen
,
591 EVP_PKEY_CTX
*pctx
= NULL
;
592 EVP_PKEY
*spub
= NULL
;
593 OSSL_PARAM params
[2], *p
= params
;
596 if (ctx
== NULL
|| enc
== NULL
|| enclen
== 0 || priv
== NULL
) {
597 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
605 pctx
= EVP_PKEY_CTX_new_from_pkey(ctx
->libctx
, priv
, ctx
->propq
);
607 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
610 *p
++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION
,
611 OSSL_KEM_PARAM_OPERATION_DHKEM
,
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
;
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
);
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
,
629 spub
= EVP_PKEY_new_raw_public_key_ex(ctx
->libctx
,
636 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
639 if (EVP_PKEY_auth_decapsulate_init(pctx
, spub
, params
) != 1) {
640 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
644 if (EVP_PKEY_decapsulate_init(pctx
, params
) != 1) {
645 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
649 if (EVP_PKEY_decapsulate(pctx
, NULL
, &lsslen
, enc
, enclen
) != 1) {
650 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
653 ctx
->shared_secret
= OPENSSL_malloc(lsslen
);
654 if (ctx
->shared_secret
== NULL
)
656 if (EVP_PKEY_decapsulate(pctx
, ctx
->shared_secret
, &lsslen
,
658 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
661 ctx
->shared_secretlen
= lsslen
;
665 EVP_PKEY_CTX_free(pctx
);
668 OPENSSL_free(ctx
->shared_secret
);
669 ctx
->shared_secret
= NULL
;
670 ctx
->shared_secretlen
= 0;
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
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
686 static int hpke_do_middle(OSSL_HPKE_CTX
*ctx
,
687 const unsigned char *info
, size_t infolen
)
690 size_t ks_contextlen
= OSSL_HPKE_MAXSIZE
;
691 unsigned char ks_context
[OSSL_HPKE_MAXSIZE
];
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
;
704 /* only let this be done once */
705 if (ctx
->exportersec
!= NULL
) {
706 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
709 if (ossl_HPKE_KEM_INFO_find_id(ctx
->suite
.kem_id
) == NULL
) {
710 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
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
);
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
);
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
);
741 kctx
= ossl_kdf_ctx_create("HKDF", mdname
, ctx
->libctx
, ctx
->propq
);
743 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
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
);
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
);
781 secretlen
= kdf_info
->Nh
;
782 if (secretlen
> OSSL_HPKE_MAXSIZE
) {
783 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
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
)
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
);
809 ctx
->keylen
= aead_info
->Nk
;
810 ctx
->key
= OPENSSL_malloc(ctx
->keylen
);
811 if (ctx
->key
== NULL
)
813 if (ossl_hpke_labeled_expand(kctx
, ctx
->key
, ctx
->keylen
,
814 secret
, secretlen
, OSSL_HPKE_SEC51LABEL
,
815 suitebuf
, sizeof(suitebuf
),
817 ks_context
, ks_contextlen
) != 1) {
818 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
822 ctx
->exporterseclen
= kdf_info
->Nh
;
823 ctx
->exportersec
= OPENSSL_malloc(ctx
->exporterseclen
);
824 if (ctx
->exportersec
== NULL
)
826 if (ossl_hpke_labeled_expand(kctx
, ctx
->exportersec
, ctx
->exporterseclen
,
827 secret
, secretlen
, OSSL_HPKE_SEC51LABEL
,
828 suitebuf
, sizeof(suitebuf
),
830 ks_context
, ks_contextlen
) != 1) {
831 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
845 * externally visible functions from below here, API documentation is
846 * in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication
849 OSSL_HPKE_CTX
*OSSL_HPKE_CTX_new(int mode
, OSSL_HPKE_SUITE suite
,
850 OSSL_LIB_CTX
*libctx
, const char *propq
)
852 OSSL_HPKE_CTX
*ctx
= NULL
;
854 if (hpke_mode_check(mode
) != 1) {
855 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
858 if (hpke_suite_check(suite
) != 1) {
859 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
862 ctx
= OPENSSL_zalloc(sizeof(*ctx
));
865 ctx
->libctx
= libctx
;
867 ctx
->propq
= OPENSSL_strdup(propq
);
868 if (ctx
->propq
== NULL
) {
878 void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX
*ctx
)
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
);
897 int OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX
*ctx
,
899 const unsigned char *psk
, size_t psklen
)
901 if (ctx
== NULL
|| pskid
== NULL
|| psk
== NULL
|| psklen
== 0) {
902 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
905 if (psklen
> OSSL_HPKE_MAX_PARMLEN
) {
906 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
909 if (strlen(pskid
) > OSSL_HPKE_MAX_PARMLEN
) {
910 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
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
)
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
);
935 int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX
*ctx
,
936 const unsigned char *ikme
, size_t ikmelen
)
938 if (ctx
== NULL
|| ikme
== NULL
) {
939 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
942 if (ikmelen
== 0 || ikmelen
> OSSL_HPKE_MAX_PARMLEN
) {
943 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
946 OPENSSL_clear_free(ctx
->ikme
, ctx
->ikmelen
);
947 ctx
->ikme
= OPENSSL_memdup(ikme
, ikmelen
);
948 if (ctx
->ikme
== NULL
)
950 ctx
->ikmelen
= ikmelen
;
954 int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX
*ctx
, EVP_PKEY
*priv
)
956 if (ctx
== NULL
|| priv
== NULL
) {
957 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
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
);
965 EVP_PKEY_free(ctx
->authpriv
);
966 ctx
->authpriv
= EVP_PKEY_dup(priv
);
967 if (ctx
->authpriv
== NULL
)
972 int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX
*ctx
,
973 const unsigned char *pub
, size_t publen
)
976 EVP_PKEY
*pubp
= NULL
;
977 unsigned char *lpub
= NULL
;
979 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
981 if (ctx
== NULL
|| pub
== NULL
|| publen
== 0) {
982 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
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
);
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
)
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
,
999 pubp
= EVP_PKEY_new_raw_public_key_ex(ctx
->libctx
,
1005 /* can happen based on external input - buffer value may be garbage */
1006 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1010 * extract out the public key in encoded form so we
1011 * should be fine even if given compressed form
1013 lpub
= OPENSSL_malloc(OSSL_HPKE_MAXSIZE
);
1016 if (EVP_PKEY_get_octet_string_param(pubp
,
1017 OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY
,
1018 lpub
, OSSL_HPKE_MAXSIZE
, &lpublen
)
1021 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
1024 /* free up old value */
1025 OPENSSL_free(ctx
->authpub
);
1026 ctx
->authpub
= lpub
;
1027 ctx
->authpublen
= lpublen
;
1031 EVP_PKEY_free(pubp
);
1035 int OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX
*ctx
, uint64_t *seq
)
1037 if (ctx
== NULL
|| seq
== NULL
) {
1038 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
1045 int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX
*ctx
, uint64_t seq
)
1048 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
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
)
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
);
1067 if (infolen
> OSSL_HPKE_MAX_INFOLEN
) {
1068 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
1076 if (hpke_encap(ctx
, enc
, enclen
, pub
, publen
) != 1) {
1077 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
1085 erv
= hpke_do_middle(ctx
, info
, infolen
);
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
)
1096 if (ctx
== NULL
|| enc
== NULL
|| enclen
== 0 || recippriv
== NULL
) {
1097 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
1100 if (infolen
> OSSL_HPKE_MAX_INFOLEN
) {
1101 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
1109 erv
= hpke_decap(ctx
, enc
, enclen
, recippriv
);
1111 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
1119 erv
= hpke_do_middle(ctx
, info
, infolen
);
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
)
1128 unsigned char seqbuf
[OSSL_HPKE_MAX_NONCELEN
];
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
);
1136 if ((ctx
->seq
+ 1) == 0) { /* wrap around imminent !!! */
1137 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED
);
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
);
1145 seqlen
= hpke_seqnonce2buf(ctx
, seqbuf
, sizeof(seqbuf
));
1147 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
));
1159 OPENSSL_cleanse(seqbuf
, sizeof(seqbuf
));
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
)
1168 unsigned char seqbuf
[OSSL_HPKE_MAX_NONCELEN
];
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
);
1176 if ((ctx
->seq
+ 1) == 0) { /* wrap around imminent !!! */
1177 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED
);
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
);
1185 seqlen
= hpke_seqnonce2buf(ctx
, seqbuf
, sizeof(seqbuf
));
1187 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
));
1198 OPENSSL_cleanse(seqbuf
, sizeof(seqbuf
));
1202 int OSSL_HPKE_export(OSSL_HPKE_CTX
*ctx
,
1203 unsigned char *secret
, size_t secretlen
,
1204 const unsigned char *label
, size_t labellen
)
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
;
1213 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
1216 if (labellen
> OSSL_HPKE_MAX_PARMLEN
) {
1217 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
1220 if (ctx
->exportersec
== NULL
) {
1221 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED
);
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
);
1229 mdname
= kdf_info
->mdname
;
1230 kctx
= ossl_kdf_ctx_create("HKDF", mdname
, ctx
->libctx
, ctx
->propq
);
1232 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
,
1248 EVP_KDF_CTX_free(kctx
);
1250 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
)
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
;
1265 if (pub
== NULL
|| publen
== NULL
|| *publen
== 0 || priv
== NULL
) {
1266 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
1269 if (hpke_suite_check(suite
) != 1) {
1270 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_INVALID_ARGUMENT
);
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
);
1280 kem_info
= ossl_HPKE_KEM_INFO_find_id(suite
.kem_id
);
1281 if (kem_info
== NULL
)
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
);
1288 pctx
= EVP_PKEY_CTX_new_from_name(libctx
, kem_info
->keytype
, propq
);
1291 || EVP_PKEY_keygen_init(pctx
) <= 0) {
1292 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
1303 if (EVP_PKEY_generate(pctx
, &skR
) <= 0) {
1304 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
1307 EVP_PKEY_CTX_free(pctx
);
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
);
1320 EVP_PKEY_CTX_free(pctx
);
1324 int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite
)
1326 return hpke_suite_check(suite
);
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
,
1337 OSSL_HPKE_SUITE chosen
;
1339 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
1340 const OSSL_HPKE_AEAD_INFO
*aead_info
= NULL
;
1341 EVP_PKEY
*fakepriv
= NULL
;
1343 if (enc
== NULL
|| enclen
== 0
1344 || ct
== NULL
|| ctlen
== 0 || suite
== NULL
) {
1345 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_PASSED_NULL_PARAMETER
);
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
);
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
);
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
);
1367 if (hpke_suite_check(chosen
) != 1) {
1368 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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
);
1378 plen
= kem_info
->Npk
;
1379 if (plen
> *enclen
) {
1380 ERR_raise(ERR_LIB_CRYPTO
, ERR_R_INTERNAL_ERROR
);
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.
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
);
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
);
1405 int OSSL_HPKE_str2suite(const char *str
, OSSL_HPKE_SUITE
*suite
)
1407 return ossl_hpke_str2suite(str
, suite
);
1410 size_t OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite
, size_t clearlen
)
1413 size_t cipherlen
= 0;
1415 if (hpke_expansion(suite
, &enclen
, clearlen
, &cipherlen
) != 1)
1420 size_t OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite
)
1423 size_t cipherlen
= 0;
1424 size_t clearlen
= 16;
1426 if (hpke_expansion(suite
, &enclen
, clearlen
, &cipherlen
) != 1)
1431 size_t OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite
)
1433 const OSSL_HPKE_KEM_INFO
*kem_info
= NULL
;
1435 if (hpke_suite_check(suite
) != 1)
1437 kem_info
= ossl_HPKE_KEM_INFO_find_id(suite
.kem_id
);
1438 return kem_info
->Nsk
;