diff options
author | Stephen Farrell <stephen.farrell@cs.tcd.ie> | 2022-12-07 21:36:46 +0000 |
---|---|---|
committer | Tomas Mraz <tomas@openssl.org> | 2022-12-08 10:59:03 +0100 |
commit | cae72eefc3fbdd2f7a1a065f237bf3943619bca2 (patch) | |
tree | cba00a2de71c008076d5ed7f3afaecd370422444 | |
parent | fc93335760686ad7cf3633d457caf18b0ac83ea2 (diff) | |
download | openssl-new-cae72eefc3fbdd2f7a1a065f237bf3943619bca2.tar.gz |
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)
-rw-r--r-- | crypto/hpke/hpke.c | 45 | ||||
-rw-r--r-- | doc/man3/OSSL_HPKE_CTX_new.pod | 75 | ||||
-rw-r--r-- | include/openssl/hpke.h | 9 | ||||
-rw-r--r-- | test/hpke_test.c | 120 |
4 files changed, 199 insertions, 50 deletions
diff --git a/crypto/hpke/hpke.c b/crypto/hpke/hpke.c index a106366a75..12a12ad8fc 100644 --- a/crypto/hpke/hpke.c +++ b/crypto/hpke/hpke.c @@ -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; diff --git a/doc/man3/OSSL_HPKE_CTX_new.pod b/doc/man3/OSSL_HPKE_CTX_new.pod index 1e0b118e84..50ad2895d8 100644 --- a/doc/man3/OSSL_HPKE_CTX_new.pod +++ b/doc/man3/OSSL_HPKE_CTX_new.pod @@ -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; diff --git a/include/openssl/hpke.h b/include/openssl/hpke.h index d38c3e3703..7b1419e66c 100644 --- a/include/openssl/hpke.h +++ b/include/openssl/hpke.h @@ -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); diff --git a/test/hpke_test.c b/test/hpke_test.c index 0a718869d2..fc2f80857f 100644 --- a/test/hpke_test.c +++ b/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; } |