Commit ce58c02c5b for openssl.org

commit ce58c02c5ba30efc0d020bb79a38d8a0b679cbea
Author: Daniel Kubec <kubec@openssl.foundation>
Date:   Sat Oct 31 19:16:53 2026 +0100

    AES-GCM-SIV: no-op on zero-length update and clear stale AAD on reuse

    The default-provider AES-GCM-SIV implementation treated a zero-length
    AAD update as a reset: aes_gcm_siv_aad() freed the AAD accumulated
    so far, cleared its length, and returned success.  This meant
    that an application passing AAD in multiple chunks, of which some
    might have zero length, would have the previous AAD chunks effectively
    unauthenticated.  Remove the AAD reset logic for zero-length updates.

    Also, on context reinitialization, the AAD was not reset, which meant
    that any AAD accumulated from the previous context usage were also
    included in the AAD of the new message.  This applied
    to a reinitialization with a new key or nonce, as well as
    to a reinitialization without either after a completed operation, which
    restarts the operation under the same key and nonce.  Reset the AAD
    reset in both cases.  A parameters-only reinitialization before
    the payload still keeps the AAD accumulated so far.

    Fixes: CVE-2026-88823
    Fixes: 0113ec8460a9 "Implement AES-GCM-SIV (RFC8452)"
    Co-authored-by: Mounir IDRASSI <mounir.idrassi@amcrypto.jp>
    Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Reviewed-by: Norbert Pocs <norbertp@openssl.org>
    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Merge-date: Wed Nov  4 12:15:48 2026
    Merged-from: https://github.com/openssl/openssl/pull/33456

diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv.c b/providers/implementations/ciphers/cipher_aes_gcm_siv.c
index 371caddb1d..aecaa7d8b7 100644
--- a/providers/implementations/ciphers/cipher_aes_gcm_siv.c
+++ b/providers/implementations/ciphers/cipher_aes_gcm_siv.c
@@ -100,6 +100,16 @@ static int ossl_aes_gcm_siv_init(void *vctx, const unsigned char *key, size_t ke

     ctx->enc = enc;

+    /*
+     * Clear AAD when starting a new message or restarting after payload
+     * processing. Preserve pending AAD during parameter adjustments.
+     */
+    if (key != NULL || iv != NULL || ctx->used_enc || ctx->used_dec) {
+        OPENSSL_clear_free(ctx->aad, ctx->aad_len);
+        ctx->aad = NULL;
+        ctx->aad_len = 0;
+    }
+
     if (key != NULL) {
         if (keylen != ctx->key_len) {
             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c b/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c
index d387973894..d38c508bb9 100644
--- a/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c
+++ b/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c
@@ -115,13 +115,8 @@ static int aes_gcm_siv_aad(PROV_AES_GCM_SIV_CTX *ctx,
     uint8_t *ptr;
     uint64_t len64;

-    /* length of 0 resets the AAD */
-    if (len == 0) {
-        OPENSSL_free(ctx->aad);
-        ctx->aad = NULL;
-        ctx->aad_len = 0;
+    if (len == 0)
         return 1;
-    }
     to_alloc = UP16(ctx->aad_len + len);
     /* need to check the size of the AAD per RFC8452 */
     len64 = to_alloc;