From 52d23c86a54adab5ee9f80e48b242b52c4cc2347 Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertp@openssl.org>
Date: Thu, 8 Jan 2026 15:04:54 +0100
Subject: [PATCH] Fix OCB AES-NI/HW stream path unauthenticated/unencrypted
 trailing bytes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When ctx->stream (e.g., AES‑NI or ARMv8 CE) is available, the fast path
encrypts/decrypts full blocks but does not advance in/out pointers. The
tail-handling code then operates on the base pointers, effectively reprocessing
the beginning of the buffer while leaving the actual trailing bytes
unencrypted (encryption) or using the wrong plaintext (decryption). The
authentication checksum excludes the true tail.

CVE-2025-69418

Fixes: https://github.com/openssl/srt/issues/58

Signed-off-by: Norbert Pocs <norbertp@openssl.org>

Reviewed-by: Saša Nedvědický <sashan@openssl.org>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
MergeDate: Mon Jan 26 19:48:35 2026
(cherry picked from commit be9375d5d45dfaf897b56ef148a0b58402491fcb)

Reference:https://github.com/openssl/openssl/commit/52d23c86a54adab5ee9f80e48b242b52c4cc2347
Conflict:Context adaptation

---
 crypto/modes/ocb128.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/crypto/modes/ocb128.c b/crypto/modes/ocb128.c
index 9d2d3a2278..2194a89232 100644
--- a/crypto/modes/ocb128.c
+++ b/crypto/modes/ocb128.c
@@ -341,7 +341,7 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
 
     if (num_blocks && all_num_blocks == (size_t)all_num_blocks
         && ctx->stream != NULL) {
-        size_t max_idx = 0, top = (size_t)all_num_blocks;
+        size_t max_idx = 0, top = (size_t)all_num_blocks, processed_bytes = 0;
 
         /*
          * See how many L_{i} entries we need to process data at hand
@@ -355,6 +355,9 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
         ctx->stream(in, out, num_blocks, ctx->keyenc,
                     (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c,
                     (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c);
+        processed_bytes = num_blocks * 16;
+        in += processed_bytes;
+        out += processed_bytes;
     } else {
         /* Loop through all full blocks to be encrypted */
         for (i = ctx->sess.blocks_processed + 1; i <= all_num_blocks; i++) {
@@ -433,7 +436,7 @@ int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
 
     if (num_blocks && all_num_blocks == (size_t)all_num_blocks
         && ctx->stream != NULL) {
-        size_t max_idx = 0, top = (size_t)all_num_blocks;
+        size_t max_idx = 0, top = (size_t)all_num_blocks, processed_bytes = 0;
 
         /*
          * See how many L_{i} entries we need to process data at hand
@@ -447,6 +450,9 @@ int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
         ctx->stream(in, out, num_blocks, ctx->keydec,
                     (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c,
                     (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c);
+        processed_bytes = num_blocks * 16;
+        in += processed_bytes;
+        out += processed_bytes;
     } else {
         OCB_BLOCK tmp;
 
-- 
2.33.0