Commit 854def489a for openssl.org

commit 854def489afd256d5fabf5344312b66b6fc63c68
Author: Milan Broz <gmazyland@gmail.com>
Date:   Thu May 7 08:34:53 2026 +0200

    test: add test for IV reuse in AEAD providers

    After EVP_EncryptFinal, AEAD providers (GCM, OCB, Chacha20-Poly1305)
    transition to IV_STATE_FINISHED to prevent IV reuse.

    No encryption should be possible in such state.

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Paul Dale <paul.dale@oracle.com>
    MergeDate: Tue May 12 05:14:10 2026
    (Merged from https://github.com/openssl/openssl/pull/31104)

diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index c178c6b63a..f4bfeae2a1 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -6463,6 +6463,59 @@ err:
     return res;
 }

+static const char *iv_state_ciphers[] = {
+    "AES-256-GCM",
+#ifndef OPENSSL_NO_OCB
+    "AES-256-OCB",
+#endif
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+    "ChaCha20-Poly1305",
+#endif
+};
+
+/* Negative test for IV_STATE_FINISHED (avoid IV reuse) */
+static int test_iv_reuse(int idx)
+{
+    int outlen;
+    int res = 0;
+    unsigned char outbuf[64];
+    EVP_CIPHER_CTX *ctx = NULL;
+    EVP_CIPHER *ciph = NULL;
+
+    if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()))
+        goto err;
+
+    if (!TEST_ptr(ciph = EVP_CIPHER_fetch(testctx, iv_state_ciphers[idx],
+                      testpropq)))
+        goto err;
+
+    /* Use the cipher: Init, Update, Final. */
+    if (!TEST_true(EVP_EncryptInit_ex2(ctx, ciph, kGCMDefaultKey,
+            iGCMDefaultIV, NULL)))
+        goto err;
+    if (!TEST_true(EVP_EncryptUpdate(ctx, outbuf, &outlen, gcmDefaultPlaintext,
+            sizeof(gcmDefaultPlaintext))))
+        goto err;
+    if (!TEST_true(EVP_EncryptFinal_ex(ctx, outbuf, &outlen)))
+        goto err;
+
+    /* Without IV change, EncryptUpdate must be rejected */
+    ERR_set_mark();
+    if (!TEST_false(EVP_EncryptUpdate(ctx, outbuf, &outlen,
+            gcmDefaultPlaintext,
+            sizeof(gcmDefaultPlaintext)))) {
+        ERR_clear_last_mark();
+        goto err;
+    }
+    ERR_pop_to_mark();
+
+    res = 1;
+err:
+    EVP_CIPHER_CTX_free(ctx);
+    EVP_CIPHER_free(ciph);
+    return res;
+}
+
 static const char *keylen_change_ciphers[] = {
 #ifndef OPENSSL_NO_BF
     "BF-ECB",
@@ -7960,6 +8013,7 @@ int setup_tests(void)
     ADD_ALL_TESTS(test_evp_final_no_tag, OSSL_NELEM(evp_final_no_tag));

     ADD_ALL_TESTS(test_ivlen_change, OSSL_NELEM(ivlen_change_ciphers));
+    ADD_ALL_TESTS(test_iv_reuse, OSSL_NELEM(iv_state_ciphers));
     if (OSSL_NELEM(keylen_change_ciphers) - 1 > 0)
         ADD_ALL_TESTS(test_keylen_change, OSSL_NELEM(keylen_change_ciphers) - 1);