mirror of
https://github.com/openssl/openssl.git
synced 2025-03-31 20:10:45 +08:00
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:
parent
fc93335760
commit
cae72eefc3
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
120
test/hpke_test.c
120
test/hpke_test.c
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user