Commit 146688ff37 for openssl.org

commit 146688ff377f38d4ef21e608a6f95a4dc47065c6
Author: Trust-Worthy <jondeveloper0@gmail.com>
Date:   Wed Sep 9 14:36:41 2026 -0400

    AEAD SIV mode: zero-length message fix when no payload seen

    When no payload update is made, the single SIV pass never runs and
    the final fails. Run the pass over an empty payload in the final
    instead. RFC 5297 permits an empty plaintext.

    Assisted-by: Claude:claude-sonnet-5
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    Merge-date: Tue Sep 29 18:45:51 2026
    Merged-from: https://github.com/openssl/openssl/pull/32803

diff --git a/crypto/modes/siv128.c b/crypto/modes/siv128.c
index 456c1ae663..dea95be7aa 100644
--- a/crypto/modes/siv128.c
+++ b/crypto/modes/siv128.c
@@ -94,6 +94,9 @@ __owur static ossl_inline int siv128_do_s2v_p(SIV128_CONTEXT *ctx, SIV_BLOCK *ou
     EVP_MAC_CTX *mac_ctx;
     int ret = 0;

+    if (len > 0 && (in == NULL || out == NULL))
+        return 0;
+
     mac_ctx = EVP_MAC_CTX_dup(ctx->mac_ctx_init);
     if (mac_ctx == NULL)
         return 0;
@@ -107,7 +110,8 @@ __owur static ossl_inline int siv128_do_s2v_p(SIV128_CONTEXT *ctx, SIV_BLOCK *ou
             goto err;
     } else {
         memset(&t, 0, sizeof(t));
-        memcpy(&t, in, len);
+        if (len > 0)
+            memcpy(&t, in, len);
         t.byte[len] = 0x80;
         siv128_dbl(&ctx->d);
         siv128_xorblock(&t, &ctx->d);
diff --git a/providers/implementations/ciphers/cipher_aes_siv_hw.c b/providers/implementations/ciphers/cipher_aes_siv_hw.c
index a1db52ade6..50d5e861fa 100644
--- a/providers/implementations/ciphers/cipher_aes_siv_hw.c
+++ b/providers/implementations/ciphers/cipher_aes_siv_hw.c
@@ -111,8 +111,20 @@ static int aes_siv_cipher(void *vctx, unsigned char *out,
     SIV128_CONTEXT *sctx = &ctx->siv;

     /* EncryptFinal or DecryptFinal */
-    if (in == NULL)
+    if (in == NULL) {
+        /*
+         * no payload update was seen: the EVP layer never forwards a
+         * zero-length update, so run the single crypto operation on an
+         * empty payload here -- RFC 5297 permits an empty plaintext
+         */
+        if (sctx->final_ret == -1 && sctx->crypto_ok == 1) {
+            if (ctx->enc)
+                ossl_siv128_encrypt(sctx, NULL, out, 0);
+            else
+                ossl_siv128_decrypt(sctx, NULL, out, 0);
+        }
         return ossl_siv128_finish(sctx) == 0;
+    }

     /* Deal with associated data */
     if (out == NULL)