* lib/sha3.c (sha3_read_ctx): When using OpenSSL, don’t update the
internal context; we’re supposed to read it, not write it.
Instead, clone it and update the clone.
* tests/test-sha3-224-buffer.c:
* tests/test-sha3-256-buffer.c:
* tests/test-sha3-384-buffer.c:
* tests/test-sha3-512-buffer.c:
(check): Test for the bug.
---
 ChangeLog                    | 10 ++++++++++
 lib/sha3.c                   | 17 +++++++++++++++--
 tests/test-sha3-224-buffer.c |  8 ++++++--
 tests/test-sha3-256-buffer.c |  8 ++++++--
 tests/test-sha3-384-buffer.c |  8 ++++++--
 tests/test-sha3-512-buffer.c |  8 ++++++--
 6 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9750ee1e80..18c2dd56d7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2026-02-22  Paul Eggert  <[email protected]>
 
+       crypto/sha3: fix sha3_read_ctx reset bug
+       * lib/sha3.c (sha3_read_ctx): When using OpenSSL, don’t update the
+       internal context; we’re supposed to read it, not write it.
+       Instead, clone it and update the clone.
+       * tests/test-sha3-224-buffer.c:
+       * tests/test-sha3-256-buffer.c:
+       * tests/test-sha3-384-buffer.c:
+       * tests/test-sha3-512-buffer.c:
+       (check): Test for the bug.
+
        crypto/sha3: EVP_MD_CTX_create → EVP_MD_CTX_new
        * lib/sha3.c (sha3_##SIZE##_init_ctx): Avoid deprecated macro name.
 
diff --git a/lib/sha3.c b/lib/sha3.c
index 2c3b932b91..ec893fc003 100644
--- a/lib/sha3.c
+++ b/lib/sha3.c
@@ -374,8 +374,21 @@ sha3_free_ctx (struct sha3_ctx *ctx)
 void *
 sha3_read_ctx (const struct sha3_ctx *ctx, void *resbuf)
 {
-  /* Assume any unprocessed bytes in ctx are not to be ignored.  */
-  return sha3_finish_ctx ((struct sha3_ctx *) ctx, resbuf);
+  void *result = NULL;
+  int err = ENOMEM;
+  EVP_MD_CTX *evp_ctx = EVP_MD_CTX_new ();
+  if (evp_ctx)
+    {
+      if (EVP_MD_CTX_copy_ex (evp_ctx, ctx->evp_ctx))
+        {
+          if (EVP_DigestFinal_ex (evp_ctx, resbuf, 0))
+            result = resbuf;
+          err = EINVAL;
+        }
+      EVP_MD_CTX_free (evp_ctx);
+    }
+  errno = err; /* OK to set errno even if successful.  */
+  return result;
 }
 
 void *
diff --git a/tests/test-sha3-224-buffer.c b/tests/test-sha3-224-buffer.c
index 3b6dd22bf8..33190be91b 100644
--- a/tests/test-sha3-224-buffer.c
+++ b/tests/test-sha3-224-buffer.c
@@ -74,11 +74,15 @@ check (char const *message, size_t len, char const *expect)
       sha3_224_init_ctx (&ctx);
       int part = SHA3_224_BLOCK_SIZE / 3;
       sha3_process_bytes (message, part, &ctx);
+      sha3_read_ctx (&ctx, buf);
       sha3_process_bytes (message + part, SHA3_224_BLOCK_SIZE - part, &ctx);
       char buf2[SHA3_224_DIGEST_SIZE];
       sha3_finish_ctx (&ctx, buf2);
-      failed |= mismatch (sha3_224_buffer (message, SHA3_224_BLOCK_SIZE, buf),
-                          buf2);
+      if (mismatch (sha3_224_buffer (message, SHA3_224_BLOCK_SIZE, buf), buf2))
+        {
+          failed = 1;
+          break;
+        }
       message += SHA3_224_BLOCK_SIZE;
       len -= SHA3_224_BLOCK_SIZE;
     }
diff --git a/tests/test-sha3-256-buffer.c b/tests/test-sha3-256-buffer.c
index ee97c95c21..4f03654c2b 100644
--- a/tests/test-sha3-256-buffer.c
+++ b/tests/test-sha3-256-buffer.c
@@ -75,11 +75,15 @@ check (char const *message, size_t len, char const *expect)
       sha3_256_init_ctx (&ctx);
       int part = SHA3_256_BLOCK_SIZE / 3;
       sha3_process_bytes (message, part, &ctx);
+      sha3_read_ctx (&ctx, buf);
       sha3_process_bytes (message + part, SHA3_256_BLOCK_SIZE - part, &ctx);
       char buf2[SHA3_256_DIGEST_SIZE];
       sha3_finish_ctx (&ctx, buf2);
-      failed |= mismatch (sha3_256_buffer (message, SHA3_256_BLOCK_SIZE, buf),
-                          buf2);
+      if (mismatch (sha3_256_buffer (message, SHA3_256_BLOCK_SIZE, buf), buf2))
+        {
+          failed = 1;
+          break;
+        }
       message += SHA3_256_BLOCK_SIZE;
       len -= SHA3_256_BLOCK_SIZE;
     }
diff --git a/tests/test-sha3-384-buffer.c b/tests/test-sha3-384-buffer.c
index 7452b138f9..c2cbd4f8d9 100644
--- a/tests/test-sha3-384-buffer.c
+++ b/tests/test-sha3-384-buffer.c
@@ -79,11 +79,15 @@ check (char const *message, size_t len, char const *expect)
       sha3_384_init_ctx (&ctx);
       int part = SHA3_384_BLOCK_SIZE / 3;
       sha3_process_bytes (message, part, &ctx);
+      sha3_read_ctx (&ctx, buf);
       sha3_process_bytes (message + part, SHA3_384_BLOCK_SIZE - part, &ctx);
       char buf2[SHA3_384_DIGEST_SIZE];
       sha3_finish_ctx (&ctx, buf2);
-      failed |= mismatch (sha3_384_buffer (message, SHA3_384_BLOCK_SIZE, buf),
-                          buf2);
+      if (mismatch (sha3_384_buffer (message, SHA3_384_BLOCK_SIZE, buf), buf2))
+        {
+          failed = 1;
+          break;
+        }
       message += SHA3_384_BLOCK_SIZE;
       len -= SHA3_384_BLOCK_SIZE;
     }
diff --git a/tests/test-sha3-512-buffer.c b/tests/test-sha3-512-buffer.c
index 303f75d61e..186cd2da00 100644
--- a/tests/test-sha3-512-buffer.c
+++ b/tests/test-sha3-512-buffer.c
@@ -83,11 +83,15 @@ check (char const *message, size_t len, char const *expect)
       sha3_512_init_ctx (&ctx);
       int part = SHA3_512_BLOCK_SIZE / 3;
       sha3_process_bytes (message, part, &ctx);
+      sha3_read_ctx (&ctx, buf);
       sha3_process_bytes (message + part, SHA3_512_BLOCK_SIZE - part, &ctx);
       char buf2[SHA3_512_DIGEST_SIZE];
       sha3_finish_ctx (&ctx, buf2);
-      failed |= mismatch (sha3_512_buffer (message, SHA3_512_BLOCK_SIZE, buf),
-                          buf2);
+      if (mismatch (sha3_512_buffer (message, SHA3_512_BLOCK_SIZE, buf), buf2))
+        {
+          failed = 1;
+          break;
+        }
       message += SHA3_512_BLOCK_SIZE;
       len -= SHA3_512_BLOCK_SIZE;
     }
-- 
2.51.0


Reply via email to