Commit f06ed969e9 for openssl.org

commit f06ed969e90e3325e4ebc2ab98a41c77e6245d63
Author: Billy Brumley <bbb@iki.fi>
Date:   Tue Oct 6 02:11:43 2026 -0400

    AEAD contexts must refuse to operate without a key

    A fresh context should fail to operate on plaintext or ciphertext
    in any meaningful way. This regression test checks that for every AEAD.

    Assisted-by: Claude:claude-fable-5-1
    Reviewed-by: Richard Levitte <levitte@openssl.foundation>
    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Merge-date: Sun Nov  8 21:43:09 2026
    Merged-from: https://github.com/openssl/openssl/pull/33116

diff --git a/test/evp_aead_test.c b/test/evp_aead_test.c
index be49ab918e..a6f17bb988 100644
--- a/test/evp_aead_test.c
+++ b/test/evp_aead_test.c
@@ -1131,6 +1131,52 @@ err:
     return testresult;
 }

+/*
+ * a fresh context without a key should fail to do anything meaningful
+ * with AAD, plaintext or ciphertext, and Final must not succeed either
+ */
+static int test_evp_aead_no_key(int idx)
+{
+    const AEAD_DATA *info = &aead_list[idx];
+    EVP_CIPHER_CTX *ctx_enc = NULL;
+    EVP_CIPHER_CTX *ctx_dec = NULL;
+
+    static const unsigned char msg[] = "no key regression";
+    static const unsigned char aad[] = "no key aad";
+    unsigned char out[sizeof(msg) + EVP_MAX_BLOCK_LENGTH] = { 0 };
+
+    int len = 0, testresult = 0;
+
+    if (!TEST_ptr(ctx_enc = EVP_CIPHER_CTX_new())
+        || !TEST_true(EVP_EncryptInit_ex2(ctx_enc, info->ciph, NULL, NULL, NULL))
+        || (info->mode == EVP_CIPH_CCM_MODE
+            && !TEST_false(EVP_EncryptUpdate(ctx_enc, NULL, &len, NULL, sizeof(msg))))
+        || !TEST_false(EVP_EncryptUpdate(ctx_enc, NULL, &len, aad, sizeof(aad)))
+        || !TEST_false(EVP_EncryptUpdate(ctx_enc, out, &len, msg, sizeof(msg)))
+        || !TEST_false(EVP_EncryptFinal_ex(ctx_enc, out, &len))) {
+        TEST_info("%s: encrypt without key", info->name);
+        goto err;
+    }
+
+    if (!TEST_ptr(ctx_dec = EVP_CIPHER_CTX_new())
+        || !TEST_true(EVP_DecryptInit_ex2(ctx_dec, info->ciph, NULL, NULL, NULL))
+        || (info->mode == EVP_CIPH_CCM_MODE
+            && !TEST_false(EVP_DecryptUpdate(ctx_dec, NULL, &len, NULL, sizeof(msg))))
+        || !TEST_false(EVP_DecryptUpdate(ctx_dec, NULL, &len, aad, sizeof(aad)))
+        || !TEST_false(EVP_DecryptUpdate(ctx_dec, out, &len, msg, sizeof(msg)))
+        || !TEST_false(EVP_DecryptFinal_ex(ctx_dec, out, &len))) {
+        TEST_info("%s: decrypt without key", info->name);
+        goto err;
+    }
+
+    testresult = 1;
+err:
+    ERR_clear_error();
+    EVP_CIPHER_CTX_free(ctx_enc);
+    EVP_CIPHER_CTX_free(ctx_dec);
+    return testresult;
+}
+
 int setup_tests(void)
 {
     size_t i = 0;
@@ -1149,6 +1195,7 @@ int setup_tests(void)
     ADD_ALL_TESTS(test_evp_oneshot_aead_zerolen, OSSL_NELEM(aead_list));
     ADD_ALL_TESTS(test_evp_aead_late_aad, OSSL_NELEM(aead_list));
     ADD_ALL_TESTS(test_evp_aead_finished_ctx, OSSL_NELEM(aead_list));
+    ADD_ALL_TESTS(test_evp_aead_no_key, OSSL_NELEM(aead_list));
     ADD_ALL_TESTS(test_evp_aead_get_tag_pairwise, OSSL_NELEM(aead_list));
     ADD_ALL_TESTS(test_evp_final_no_tag, OSSL_NELEM(aead_list));
     ADD_ALL_TESTS(test_evp_aead_enc_retval, OSSL_NELEM(aead_list));