prevent HPKE sender setting seq unwisely

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19840)
This commit is contained in:
Stephen Farrell 2022-12-07 21:36:46 +00:00 committed by Tomas Mraz
parent fc93335760
commit cae72eefc3
4 changed files with 199 additions and 50 deletions

View File

@ -56,6 +56,7 @@ struct ossl_hpke_ctx_st
const OSSL_HPKE_KDF_INFO *kdf_info;
const OSSL_HPKE_AEAD_INFO *aead_info;
EVP_CIPHER *aead_ciph;
int role; /* sender(0) or receiver(1) */
uint64_t seq; /* aead sequence number */
unsigned char *shared_secret; /* KEM output, zz */
size_t shared_secretlen;
@ -801,7 +802,7 @@ err:
* in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication
*/
OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite,
OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role,
OSSL_LIB_CTX *libctx, const char *propq)
{
OSSL_HPKE_CTX *ctx = NULL;
@ -817,6 +818,10 @@ OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite,
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return NULL;
}
if (role != OSSL_HPKE_ROLE_SENDER && role != OSSL_HPKE_ROLE_RECEIVER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
@ -833,6 +838,7 @@ OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite,
goto err;
}
}
ctx->role = role;
ctx->mode = mode;
ctx->suite = suite;
ctx->kem_info = kem_info;
@ -915,6 +921,10 @@ int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX *ctx,
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
ctx->ikme = OPENSSL_memdup(ikme, ikmelen);
if (ctx->ikme == NULL)
@ -934,6 +944,10 @@ int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX *ctx, EVP_PKEY *priv)
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
EVP_PKEY_free(ctx->authpriv);
ctx->authpriv = EVP_PKEY_dup(priv);
if (ctx->authpriv == NULL)
@ -959,6 +973,10 @@ int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX *ctx,
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
/* check the value seems like a good public key for this kem */
kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
if (kem_info == NULL)
@ -1020,6 +1038,15 @@ int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX *ctx, uint64_t seq)
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
/*
* We disallow senders from doing this as it's dangerous
* Receivers are ok to use this, as no harm should ensue
* if they go wrong.
*/
if (ctx->role == OSSL_HPKE_ROLE_SENDER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
ctx->seq = seq;
return 1;
}
@ -1036,6 +1063,10 @@ int OSSL_HPKE_encap(OSSL_HPKE_CTX *ctx,
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (infolen > OSSL_HPKE_MAX_INFOLEN) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
@ -1069,6 +1100,10 @@ int OSSL_HPKE_decap(OSSL_HPKE_CTX *ctx,
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (infolen > OSSL_HPKE_MAX_INFOLEN) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
@ -1105,6 +1140,10 @@ int OSSL_HPKE_seal(OSSL_HPKE_CTX *ctx,
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
@ -1143,6 +1182,10 @@ int OSSL_HPKE_open(OSSL_HPKE_CTX *ctx,
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;

View File

@ -24,7 +24,7 @@ OSSL_HPKE_CTX_get_seq, OSSL_HPKE_CTX_set_seq
uint16_t aead_id;
} OSSL_HPKE_SUITE;
OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite,
OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role,
OSSL_LIB_CTX *libctx, const char *propq);
void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX *ctx);
@ -182,8 +182,35 @@ supplied before the encapsulation/decapsulation operation will work.
=back
For further information related to authentication see L</Pre-Shared Key HPKE modes>
and L</Sender-authenticated HPKE Modes>.
For further information related to authentication see L</Pre-Shared Key HPKE
modes> and L</Sender-authenticated HPKE Modes>.
=head2 HPKE Roles
HPKE contexts have a role - either sender or receiver. This is used
to control which functions can be called and so that senders do not
re-use a key and nonce with different plaintexts.
OSSL_HPKE_CTX_free(), OSSL_HPKE_export(), OSSL_HPKE_CTX_set1_psk(),
and OSSL_HPKE_CTX_get_seq() can be called regardless of role.
=over 4
=item B<OSSL_HPKE_ROLE_SENDER>, 0
An I<OSSL_HPKE_CTX> with this role can be used with
OSSL_HPKE_encap(), OSSL_HPKE_seal(), OSSL_HPKE_CTX_set1_ikme() and
OSSL_HPKE_CTX_set1_authpriv().
=item B<OSSL_HPKE_ROLE_RECEIVER>, 1
An I<OSSL_HPKE_CTX> with this role can be used with OSSL_HPKE_decap(),
OSSL_HPKE_open(), OSSL_HPKE_CTX_set1_authpub() and OSSL_HPKE_CTX_set_seq().
=back
Calling a function with an incorrect role set on I<OSSL_HPKE_CTX> will result
in an error.
=head2 Parameter Size Limits
@ -202,13 +229,14 @@ for the I<infolen> parameter.
=head2 Context Construct/Free
OSSL_HPKE_CTX_new() creates a B<OSSL_HPKE_CTX> context object used for subsequent
HPKE operations, given a I<mode> (See L</HPKE Modes>) and
I<suite> (see L</OSSL_HPKE_SUITE Identifiers>). The I<libctx> and I<propq>
are used when fetching algorithms from providers and may be set to NULL.
OSSL_HPKE_CTX_new() creates a B<OSSL_HPKE_CTX> context object used for
subsequent HPKE operations, given a I<mode> (See L</HPKE Modes>), I<suite> (see
L</OSSL_HPKE_SUITE Identifiers>) and a I<role> (see L</HPKE Roles>). The
I<libctx> and I<propq> are used when fetching algorithms from providers and may
be set to NULL.
OSSL_HPKE_CTX_free() frees the I<ctx> B<OSSL_HPKE_CTX> that was created previously
by a call to OSSL_HPKE_CTX_new().
OSSL_HPKE_CTX_free() frees the I<ctx> B<OSSL_HPKE_CTX> that was created
previously by a call to OSSL_HPKE_CTX_new().
=head2 Sender APIs
@ -363,13 +391,14 @@ or values that leak.
Some protocols may have to deal with packet loss while still being able to
decrypt arriving packets later. We provide a way to set the increment used for
the nonce to the next subsequent call to OSSL_HPKE_seal() or OSSL_HPKE_open().
The OSSL_HPKE_CTX_set_seq() API can be used for such purposes with the I<seq>
parameter value resetting the internal nonce to be used for the next call.
the nonce to the next subsequent call to OSSL_HPKE_open() (but not to
OSSL_HPKE_seal() as explained below). The OSSL_HPKE_CTX_set_seq() API can be
used for such purposes with the I<seq> parameter value resetting the internal
nonce increment to be used for the next call.
A baseline nonce value is established based on the encapsulation or
decapsulation operation and is then incremented by 1 for each call to seal or
open. (In other words, the I<seq> is a zero-based counter.)
open. (In other words, the first I<seq> increment defaults to zero.)
If a caller needs to determine how many calls to seal or open have been made
the OSSL_HPKE_CTX_get_seq() API can be used to retrieve the increment (in the
@ -377,18 +406,18 @@ I<seq> output) that will be used in the next call to seal or open. That would
return 0 before the first call a sender made to OSSL_HPKE_seal() and 1 after
that first call.
Note that re-use of the same nonce and key with different plaintexts would
be very dangerous and could lead to loss of confidentiality and integrity.
We therefore only support application control over I<seq> for decryption
(i.e. OSSL_HPKE_open()) operations.
For compatibility with other implementations these I<seq> increments are
represented as I<uint64_t>.
Note that re-use of the same nonce and key with different plaintexts is very
dangerous and can lead to loss of confidentiality. Applications therefore need
to exercise extreme caution in using these APIs and would be better off avoiding
them entirely.
=head2 Protocol Convenience Functions
Additional convenience APIs allow the caller to access internal details of
local HPKE support and/or algorithms, such as parmameter lengths.
local HPKE support and/or algorithms, such as parameter lengths.
OSSL_HPKE_suite_check() checks if a specific B<OSSL_HPKE_SUITE> I<suite>
is supported locally.
@ -483,7 +512,9 @@ This example demonstrates a minimal round-trip using HPKE.
goto err;
/* sender's actions - encrypt data using the receivers public key */
if ((sctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite, NULL, NULL)) == NULL)
if ((sctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_SENDER,
NULL, NULL)) == NULL)
goto err;
if (OSSL_HPKE_encap(sctx, enc, &enclen, pub, publen, info, infolen) != 1)
goto err;
@ -491,7 +522,9 @@ This example demonstrates a minimal round-trip using HPKE.
goto err;
/* receiver's actions - decrypt data using the recievers private key */
if ((rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite, NULL, NULL)) == NULL)
if ((rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_RECEIVER,
NULL, NULL)) == NULL)
goto err;
if (OSSL_HPKE_decap(rctx, enc, enclen, priv, info, infolen) != 1)
goto err;

View File

@ -65,6 +65,13 @@
# define OSSL_HPKE_AEADSTR_CP "chacha20-poly1305" /* AEAD id 3 */
# define OSSL_HPKE_AEADSTR_EXP "exporter" /* AEAD id 0xff */
/*
* Roles for use in creating an OSSL_HPKE_CTX, most
* important use of this is to control nonce re-use.
*/
# define OSSL_HPKE_ROLE_SENDER 0
# define OSSL_HPKE_ROLE_RECEIVER 1
typedef struct {
uint16_t kem_id; /* Key Encapsulation Method id */
uint16_t kdf_id; /* Key Derivation Function id */
@ -84,7 +91,7 @@ typedef struct {
typedef struct ossl_hpke_ctx_st OSSL_HPKE_CTX;
OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite,
OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role,
OSSL_LIB_CTX *libctx, const char *propq);
void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX *ctx);

View File

@ -123,6 +123,7 @@ static int do_testhpke(const TEST_BASEDATA *base,
if (!TEST_true(cmpkey(privE, base->expected_pkEm, base->expected_pkEmlen)))
goto end;
if (!TEST_ptr(sealctx = OSSL_HPKE_CTX_new(base->mode, base->suite,
OSSL_HPKE_ROLE_SENDER,
libctx, propq)))
goto end;
if (!TEST_true(OSSL_HPKE_CTX_set1_ikme(sealctx, base->ikmE, base->ikmElen)))
@ -172,6 +173,7 @@ static int do_testhpke(const TEST_BASEDATA *base,
goto end;
}
if (!TEST_ptr(openctx = OSSL_HPKE_CTX_new(base->mode, base->suite,
OSSL_HPKE_ROLE_RECEIVER,
libctx, propq)))
goto end;
if (base->mode == OSSL_HPKE_MODE_PSK
@ -913,7 +915,6 @@ static int test_hpke_modes_suites(void)
OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
size_t plainlen = OSSL_HPKE_TSTSIZE;
unsigned char plain[OSSL_HPKE_TSTSIZE];
uint64_t startseq = 0;
OSSL_HPKE_CTX *rctx = NULL;
OSSL_HPKE_CTX *ctx = NULL;
@ -995,6 +996,7 @@ static int test_hpke_modes_suites(void)
NULL, 0, testctx, NULL)))
overallresult = 0;
if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_SENDER,
testctx, NULL)))
overallresult = 0;
if (hpke_mode == OSSL_HPKE_MODE_PSK
@ -1009,15 +1011,6 @@ static int test_hpke_modes_suites(void)
authpriv)))
overallresult = 0;
}
if (COIN_IS_HEADS) {
if (!TEST_int_eq(1, RAND_bytes_ex(testctx,
(unsigned char *) &startseq,
sizeof(startseq), 0))
|| !TEST_true(OSSL_HPKE_CTX_set_seq(ctx, startseq)))
overallresult = 0;
} else {
startseq = 0;
}
if (!TEST_true(OSSL_HPKE_encap(ctx, senderpub,
&senderpublen,
pub, publen,
@ -1037,9 +1030,10 @@ static int test_hpke_modes_suites(void)
overallresult = 0;
OSSL_HPKE_CTX_free(ctx);
memset(clear, 0, clearlen);
if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode,
hpke_suite,
testctx, NULL)))
rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_RECEIVER,
testctx, NULL);
if (!TEST_ptr(rctx))
overallresult = 0;
if (hpke_mode == OSSL_HPKE_MODE_PSK
|| hpke_mode == OSSL_HPKE_MODE_PSKAUTH) {
@ -1063,10 +1057,6 @@ static int test_hpke_modes_suites(void)
authpublen)))
overallresult = 0;
}
if (startseq != 0) {
if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, startseq)))
overallresult = 0;
}
if (!TEST_true(OSSL_HPKE_decap(rctx, senderpub,
senderpublen, privp,
infop, infolen)))
@ -1142,6 +1132,7 @@ static int test_hpke_export(void)
NULL, 0, testctx, NULL)))
goto end;
if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_SENDER,
testctx, NULL)))
goto end;
/* a few error cases 1st */
@ -1168,6 +1159,7 @@ static int test_hpke_export(void)
if (!TEST_mem_eq(exp, sizeof(exp), exp2, sizeof(exp2)))
goto end;
if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_RECEIVER,
testctx, NULL)))
goto end;
if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
@ -1403,6 +1395,7 @@ static int test_hpke_oddcalls(void)
/* a psk context with no psk => encap fail */
if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_PSK, hpke_suite,
OSSL_HPKE_ROLE_SENDER,
testctx, NULL)))
goto end;
/* set bad length psk */
@ -1422,14 +1415,17 @@ static int test_hpke_oddcalls(void)
/* bad suite */
if (!TEST_ptr_null(ctx = OSSL_HPKE_CTX_new(hpke_mode, bad_suite,
OSSL_HPKE_ROLE_SENDER,
testctx, NULL)))
goto end;
/* bad mode */
if (!TEST_ptr_null(ctx = OSSL_HPKE_CTX_new(bad_mode, hpke_suite,
OSSL_HPKE_ROLE_SENDER,
testctx, NULL)))
goto end;
/* make good ctx */
if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_SENDER,
testctx, NULL)))
goto end;
/* too long ikm */
@ -1472,17 +1468,7 @@ static int test_hpke_oddcalls(void)
if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
plain, plainlen)))
goto end;
/* the sequence ought not have been incremented, so good to start over */
plainlen = sizeof(plain);
/* seq wrap around test */
if (!TEST_true(OSSL_HPKE_CTX_set_seq(ctx, -1)))
goto end;
if (!TEST_false(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
plain, plainlen)))
goto end;
/* reset seq */
if (!TEST_true(OSSL_HPKE_CTX_set_seq(ctx, 0)))
goto end;
/* working seal */
if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
plain, plainlen)))
@ -1491,6 +1477,7 @@ static int test_hpke_oddcalls(void)
/* receiver side */
/* decap fail with psk mode but no psk set */
if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_PSK, hpke_suite,
OSSL_HPKE_ROLE_RECEIVER,
testctx, NULL)))
goto end;
if (!TEST_false(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
@ -1500,6 +1487,7 @@ static int test_hpke_oddcalls(void)
/* back good calls for base mode */
if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_RECEIVER,
testctx, NULL)))
goto end;
/* open before decap */
@ -1815,6 +1803,7 @@ static int test_hpke_compressed(void)
NULL, 0, testctx, NULL)))
goto end;
if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_SENDER,
testctx, NULL)))
goto end;
if (!TEST_true(OSSL_HPKE_CTX_set1_authpriv(ctx, authpriv)))
@ -1827,6 +1816,7 @@ static int test_hpke_compressed(void)
/* receiver side providing compressed form of auth public */
if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_RECEIVER,
testctx, NULL)))
goto end;
if (!TEST_true(OSSL_HPKE_CTX_set1_authpub(rctx, authpub, authpublen)))
@ -1846,6 +1836,81 @@ end:
return erv;
}
/*
* Test that nonce reuse calls are prevented as we expect
*/
static int test_hpke_noncereuse(void)
{
int erv = 0;
EVP_PKEY *privp = NULL;
unsigned char pub[OSSL_HPKE_TSTSIZE];
size_t publen = sizeof(pub);
int hpke_mode = OSSL_HPKE_MODE_BASE;
OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
OSSL_HPKE_CTX *ctx = NULL;
OSSL_HPKE_CTX *rctx = NULL;
unsigned char plain[] = "quick brown fox";
size_t plainlen = sizeof(plain);
unsigned char enc[OSSL_HPKE_TSTSIZE];
size_t enclen = sizeof(enc);
unsigned char cipher[OSSL_HPKE_TSTSIZE];
size_t cipherlen = sizeof(cipher);
unsigned char clear[OSSL_HPKE_TSTSIZE];
size_t clearlen = sizeof(clear);
uint64_t seq = 0xbad1dea;
/* sender side is not allowed set seq once some crypto done */
if (!TEST_true(OSSL_HPKE_keygen(hpke_suite, pub, &publen, &privp,
NULL, 0, testctx, NULL)))
goto end;
if (!TEST_ptr(ctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_SENDER,
testctx, NULL)))
goto end;
/* set seq will fail before any crypto done */
if (!TEST_false(OSSL_HPKE_CTX_set_seq(ctx, seq)))
goto end;
if (!TEST_true(OSSL_HPKE_encap(ctx, enc, &enclen, pub, publen, NULL, 0)))
goto end;
/* set seq will also fail after some crypto done */
if (!TEST_false(OSSL_HPKE_CTX_set_seq(ctx, seq + 1)))
goto end;
if (!TEST_true(OSSL_HPKE_seal(ctx, cipher, &cipherlen, NULL, 0,
plain, plainlen)))
goto end;
/* receiver side is allowed control seq */
if (!TEST_ptr(rctx = OSSL_HPKE_CTX_new(hpke_mode, hpke_suite,
OSSL_HPKE_ROLE_RECEIVER,
testctx, NULL)))
goto end;
/* set seq will work before any crypto done */
if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, seq)))
goto end;
if (!TEST_true(OSSL_HPKE_decap(rctx, enc, enclen, privp, NULL, 0)))
goto end;
/* set seq will work for receivers even after crypto done */
if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, seq)))
goto end;
/* but that value isn't good so decap will fail */
if (!TEST_false(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
cipher, cipherlen)))
goto end;
/* reset seq to correct value and _open() should work */
if (!TEST_true(OSSL_HPKE_CTX_set_seq(rctx, 0)))
goto end;
if (!TEST_true(OSSL_HPKE_open(rctx, clear, &clearlen, NULL, 0,
cipher, cipherlen)))
goto end;
erv = 1;
end:
EVP_PKEY_free(privp);
OSSL_HPKE_CTX_free(ctx);
OSSL_HPKE_CTX_free(rctx);
return erv;
}
typedef enum OPTION_choice {
OPT_ERR = -1,
OPT_EOF = 0,
@ -1894,6 +1959,7 @@ int setup_tests(void)
ADD_TEST(test_hpke_random_suites);
ADD_TEST(test_hpke_oddcalls);
ADD_TEST(test_hpke_compressed);
ADD_TEST(test_hpke_noncereuse);
return 1;
}