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);