Commit 2506f1fc32 for openssl.org
commit 2506f1fc323b567b0e48a13b6069c7778077e55e
Author: Hamzah Yamani <hamzah.yamani125@gmail.com>
Date: Tue Oct 6 17:49:56 2026 -0400
test: migrate test_aes_siv_ctx_enc_retval from evp_extra_test.c to evp_aead_test.c
Move test_aes_siv_ctx_enc_retval() out of test/evp_extra_test.c into
test/evp_aead_test.c, rename it to test_evp_aead_enc_retval() and run
it over aead_list instead of only AES-128-SIV.
The check is that after a completed encrypt, a further
EVP_EncryptUpdate() on the same context is rejected,
and the EVP_EncryptFinal_ex() that follows fails as well,
instead of reporting the earlier success. GCM, OCB and ASCON mark
the context finished. SIV stores the result of the last operation,
so a rejected Update makes the following Final fail.
CCM, GCM-SIV and ChaCha20-Poly1305 are skipped: Final currently succeeds
after the rejected Update, and what it should do is not settled yet.
ChaCha20-Poly1305 reports the same mode as ASCON, so it is matched
by name.
Key and IV are sized from the resolved cipher parameters, the context
is set up with EVP_EncryptInit_ex2(), and the tag is fetched after Final
with OSSL_PARAM.
Assisted-by: Claude:claude-sonnet-5
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Merge-date: Mon Oct 12 13:15:18 2026
Merged-from: https://github.com/openssl/openssl/pull/33135
diff --git a/test/evp_aead_test.c b/test/evp_aead_test.c
index a032cb0024..244da453ae 100644
--- a/test/evp_aead_test.c
+++ b/test/evp_aead_test.c
@@ -770,6 +770,70 @@ err:
return testresult;
}
+/*
+ * After a completed encrypt, a further Update on the same context must be
+ * rejected, and the Final that follows must fail as well instead of reporting
+ * the earlier success.
+ *
+ * How a cipher gets there differs: GCM, OCB and ASCON mark the context
+ * finished, while SIV does its single crypto operation inside the payload
+ * Update and lets any later failed operation overwrite the stored result.
+ *
+ * CCM, GCM-SIV and ChaCha20-Poly1305 are skipped: Final currently succeeds
+ * after the rejected Update, and what it should do is not settled yet.
+ */
+static int test_evp_aead_enc_retval(int idx)
+{
+ const AEAD_DATA *info = &aead_list[idx];
+ EVP_CIPHER_CTX *enc_ctx = NULL;
+ OSSL_PARAM tagparams[2];
+
+ unsigned char key[EVP_MAX_KEY_LENGTH] = { 0 };
+ unsigned char iv[EVP_MAX_IV_LENGTH] = { 0 };
+ unsigned char tag[EVPTEST_TAG_LEN_MAX] = { 0 };
+
+ static const unsigned char in[] = "input";
+ unsigned char ct[sizeof(in) + EVP_MAX_BLOCK_LENGTH] = { 0 };
+
+ int i = 0, len = 0, ret = 0;
+
+ if (info->mode == EVP_CIPH_CCM_MODE
+ || info->mode == EVP_CIPH_GCM_SIV_MODE
+ || EVP_CIPHER_is_a(info->ciph, "ChaCha20-Poly1305"))
+ return 1;
+
+ for (i = 0; i < info->keylen; i++)
+ key[i] = (unsigned char)(0xA0 + i);
+ for (i = 0; i < info->ivlen; i++)
+ iv[i] = (unsigned char)(0xB0 + i);
+
+ tagparams[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG,
+ tag, info->taglen);
+ tagparams[1] = OSSL_PARAM_construct_end();
+
+ if (!TEST_ptr(enc_ctx = EVP_CIPHER_CTX_new())
+ || !TEST_true(EVP_EncryptInit_ex2(enc_ctx, info->ciph, key, iv, NULL))
+ || !TEST_true(EVP_EncryptUpdate(enc_ctx, ct, &len, in, sizeof(in)))
+ || !TEST_true(EVP_EncryptFinal_ex(enc_ctx, ct + len, &len))
+ || !TEST_true(EVP_CIPHER_CTX_get_params(enc_ctx, tagparams))) {
+ TEST_info("%s: encrypt", info->name);
+ goto err;
+ }
+
+ /* Encryption is fine, provoke error by repeating it on the same context */
+ if (!TEST_false(EVP_EncryptUpdate(enc_ctx, ct, &len, in, sizeof(in)))
+ || !TEST_false(EVP_EncryptFinal_ex(enc_ctx, ct + len, &len))) {
+ TEST_info("%s: encrypt Update, Final after Final", info->name);
+ goto err;
+ }
+
+ ret = 1;
+err:
+ ERR_clear_error();
+ EVP_CIPHER_CTX_free(enc_ctx);
+ return ret;
+}
+
int setup_tests(void)
{
int i = 0;
@@ -789,6 +853,7 @@ int setup_tests(void)
ADD_ALL_TESTS(test_evp_aead_finished_ctx, aead_list_n);
ADD_ALL_TESTS(test_evp_aead_get_tag_pairwise, aead_list_n);
ADD_ALL_TESTS(test_evp_final_no_tag, aead_list_n);
+ ADD_ALL_TESTS(test_evp_aead_enc_retval, aead_list_n);
return 1;
}
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index 81467dd9a0..3771cb46bb 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -8265,42 +8265,6 @@ err:
return ret;
}
-static int test_aes_siv_ctx_enc_retval(void)
-{
- unsigned char key[32] = { 7 };
- unsigned char in[6] = "input";
- unsigned char ct[6] = { 0 };
-
- unsigned char tagbuf[16];
- int len, ret = 0;
- EVP_CIPHER_CTX *enc_ctx = NULL;
-
- EVP_CIPHER *cipher = EVP_CIPHER_fetch(NULL, "AES-128-SIV", NULL);
-
- if (cipher == NULL)
- return TEST_skip("AES-128-SIV cipher is not available");
-
- enc_ctx = EVP_CIPHER_CTX_new();
- if (!TEST_ptr(enc_ctx)
- || !TEST_true(EVP_EncryptInit_ex(enc_ctx, cipher, NULL, key, NULL))
- || !TEST_true(EVP_EncryptUpdate(enc_ctx, ct, &len, in, sizeof(in)))
- || !TEST_true(EVP_CIPHER_CTX_ctrl(enc_ctx, EVP_CTRL_AEAD_GET_TAG, sizeof(tagbuf), tagbuf))
- || !TEST_true(EVP_EncryptFinal_ex(enc_ctx, ct + len, &len)))
- goto err;
-
- /*
- * Encryption is fine, provoke error by repeating encrypt on same context. */
- if (!TEST_false(EVP_EncryptUpdate(enc_ctx, ct, &len, in, sizeof(in)))
- || !TEST_false(EVP_EncryptFinal_ex(enc_ctx, ct + len, &len)))
- goto err;
-
- ret = 1;
-err:
- EVP_CIPHER_CTX_free(enc_ctx);
- EVP_CIPHER_free(cipher);
- return ret;
-}
-
static int test_invalid_ctx_for_digest(void)
{
int ret;
@@ -9912,7 +9876,6 @@ int setup_tests(void)
ADD_TEST(test_aes_gcm_siv_empty_data);
ADD_TEST(test_aes_siv_ctx_reuse);
ADD_TEST(test_aes_siv_ctx_dec_retval);
- ADD_TEST(test_aes_siv_ctx_enc_retval);
ADD_TEST(test_invalid_ctx_for_digest);