This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/9.0.x by this push:
     new 4aae5a86ad Switch strong ETag generation from SHA-1 to SHA-256
4aae5a86ad is described below

commit 4aae5a86adb9c5f1c61375de40736b1080d9e9fd
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Sep 2 17:00:43 2025 +0100

    Switch strong ETag generation from SHA-1 to SHA-256
---
 java/org/apache/catalina/webresources/AbstractResource.java    |  4 ++--
 java/org/apache/catalina/webresources/CachedResource.java      |  2 +-
 .../apache/tomcat/util/security/ConcurrentMessageDigest.java   | 10 ++++++++++
 .../catalina/servlets/TestDefaultServletIfMatchRequests.java   |  4 ++--
 .../catalina/servlets/TestDefaultServletRangeRequests.java     |  4 ++--
 test/org/apache/catalina/servlets/TestWebdavServlet.java       |  8 ++++++--
 webapps/docs/changelog.xml                                     | 10 ++++++++++
 7 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/java/org/apache/catalina/webresources/AbstractResource.java 
b/java/org/apache/catalina/webresources/AbstractResource.java
index 83109274ad..bfc543a52e 100644
--- a/java/org/apache/catalina/webresources/AbstractResource.java
+++ b/java/org/apache/catalina/webresources/AbstractResource.java
@@ -90,7 +90,7 @@ public abstract class AbstractResource implements WebResource 
{
                         if (contentLength <= 16 * 1024) {
                             byte[] buf = getContent();
                             if (buf != null) {
-                                buf = ConcurrentMessageDigest.digest("SHA-1", 
buf);
+                                buf = 
ConcurrentMessageDigest.digestSHA256(buf);
                                 strongETag = "\"" + HexUtils.toHexString(buf) 
+ "\"";
                             } else {
                                 strongETag = getETag();
@@ -98,7 +98,7 @@ public abstract class AbstractResource implements WebResource 
{
                         } else {
                             byte[] buf = new byte[4096];
                             try (InputStream is = getInputStream()) {
-                                MessageDigest digest = 
MessageDigest.getInstance("SHA-1");
+                                MessageDigest digest = 
MessageDigest.getInstance("SHA-256");
                                 while (true) {
                                     int n = is.read(buf);
                                     if (n <= 0) {
diff --git a/java/org/apache/catalina/webresources/CachedResource.java 
b/java/org/apache/catalina/webresources/CachedResource.java
index 72bd60e967..872bfc1db8 100644
--- a/java/org/apache/catalina/webresources/CachedResource.java
+++ b/java/org/apache/catalina/webresources/CachedResource.java
@@ -295,7 +295,7 @@ public class CachedResource implements WebResource {
         if (cachedStrongETag == null) {
             byte[] buf = getContent();
             if (buf != null) {
-                buf = ConcurrentMessageDigest.digest("SHA-1", buf);
+                buf = ConcurrentMessageDigest.digestSHA256(buf);
                 cachedStrongETag = "\"" + HexUtils.toHexString(buf) + "\"";
             } else {
                 cachedStrongETag = webResource.getStrongETag();
diff --git a/java/org/apache/tomcat/util/security/ConcurrentMessageDigest.java 
b/java/org/apache/tomcat/util/security/ConcurrentMessageDigest.java
index 9404f55044..b4d9cf3f67 100644
--- a/java/org/apache/tomcat/util/security/ConcurrentMessageDigest.java
+++ b/java/org/apache/tomcat/util/security/ConcurrentMessageDigest.java
@@ -38,6 +38,7 @@ public class ConcurrentMessageDigest {
 
     private static final String MD5 = "MD5";
     private static final String SHA1 = "SHA-1";
+    private static final String SHA256 = "SHA-256";
 
     private static final Map<String,Queue<MessageDigest>> queues = new 
ConcurrentHashMap<>();
 
@@ -58,6 +59,11 @@ public class ConcurrentMessageDigest {
         } catch (NoSuchAlgorithmException e) {
             throw new 
IllegalArgumentException(sm.getString("concurrentMessageDigest.noDigest"), e);
         }
+        try {
+            init(SHA256);
+        } catch (NoSuchAlgorithmException e) {
+            throw new 
IllegalArgumentException(sm.getString("concurrentMessageDigest.noDigest"), e);
+        }
     }
 
     public static byte[] digestMD5(byte[]... input) {
@@ -68,6 +74,10 @@ public class ConcurrentMessageDigest {
         return digest(SHA1, input);
     }
 
+    public static byte[] digestSHA256(byte[]... input) {
+        return digest(SHA256, input);
+    }
+
     public static byte[] digest(String algorithm, byte[]... input) {
         return digest(algorithm, 1, input);
     }
diff --git 
a/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java 
b/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java
index 1df310e6b0..bcfa359388 100644
--- a/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java
+++ b/test/org/apache/catalina/servlets/TestDefaultServletIfMatchRequests.java
@@ -19,7 +19,6 @@ package org.apache.catalina.servlets;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.security.MessageDigest;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -40,6 +39,7 @@ import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.catalina.util.IOTools;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.HexUtils;
+import org.apache.tomcat.util.security.ConcurrentMessageDigest;
 
 @RunWith(Parameterized.class)
 public class TestDefaultServletIfMatchRequests extends TomcatBaseTest {
@@ -62,7 +62,7 @@ public class TestDefaultServletIfMatchRequests extends 
TomcatBaseTest {
         try (FileInputStream is = new FileInputStream(index)) {
             ByteArrayOutputStream os = new ByteArrayOutputStream();
             IOTools.flow(is, os);
-            resourceETagStrong = "\"" + 
HexUtils.toHexString(MessageDigest.getInstance("SHA-1").digest(os.toByteArray()))
 + "\"";
+            resourceETagStrong = "\"" + 
HexUtils.toHexString(ConcurrentMessageDigest.digestSHA256(os.toByteArray())) + 
"\"";
         } catch (Exception e) {
         }
         resourceETagWeak = "W/" + "\"" + index.length() + "-" + 
index.lastModified() + "\"";
diff --git 
a/test/org/apache/catalina/servlets/TestDefaultServletRangeRequests.java 
b/test/org/apache/catalina/servlets/TestDefaultServletRangeRequests.java
index e59534b5f9..60b1aec9bf 100644
--- a/test/org/apache/catalina/servlets/TestDefaultServletRangeRequests.java
+++ b/test/org/apache/catalina/servlets/TestDefaultServletRangeRequests.java
@@ -19,7 +19,6 @@ package org.apache.catalina.servlets;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.security.MessageDigest;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -40,6 +39,7 @@ import org.apache.catalina.util.IOTools;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.HexUtils;
 import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.security.ConcurrentMessageDigest;
 
 @RunWith(Parameterized.class)
 public class TestDefaultServletRangeRequests extends TomcatBaseTest {
@@ -58,7 +58,7 @@ public class TestDefaultServletRangeRequests extends 
TomcatBaseTest {
         try (FileInputStream is = new FileInputStream(index)) {
             ByteArrayOutputStream os = new ByteArrayOutputStream();
             IOTools.flow(is, os);
-            strongETag = "\"" + 
HexUtils.toHexString(MessageDigest.getInstance("SHA-1").digest(os.toByteArray()))
 + "\"";
+            strongETag = "\"" + 
HexUtils.toHexString(ConcurrentMessageDigest.digestSHA256(os.toByteArray())) + 
"\"";
         } catch (Exception e) {
         }
 
diff --git a/test/org/apache/catalina/servlets/TestWebdavServlet.java 
b/test/org/apache/catalina/servlets/TestWebdavServlet.java
index 0cd5e51ffb..233b4f8538 100644
--- a/test/org/apache/catalina/servlets/TestWebdavServlet.java
+++ b/test/org/apache/catalina/servlets/TestWebdavServlet.java
@@ -851,8 +851,12 @@ public class TestWebdavServlet extends TomcatBaseTest {
         
Assert.assertFalse(client.getResponseBody().contains("/myfolder/file4.txt"));
         Assert.assertTrue(client.getResponseBody().contains("/file7.txt"));
         Assert.assertTrue(client.getResponseBody().contains("Second-"));
-        
Assert.assertTrue(client.getResponseBody().contains("d1dc021f456864e84f9a37b7a6f51c51301128a0"));
-        
Assert.assertTrue(client.getResponseBody().contains("f3390fe2e5546dac3d1968970df1a222a3a39c00"));
+        // SHA-256 hash for "FOOBAR...FOOBAR" (repeats 3000 times)
+        Assert.assertTrue(client.getResponseBody().contains(
+                
"bb94e8d310800b24310036b168aa5a946e27f9572b3d99f956f3a3ed2e7d3045"));
+        // SHA-256 hash for "FOOBAR"
+        Assert.assertTrue(client.getResponseBody().contains(
+                
"24c422e681f1c1bd08286c7aaf5d23a5f088dcdb0b219806b3a9e579244f00c5"));
         String timeoutValue = 
client.getResponseBody().substring(client.getResponseBody().indexOf("Second-"));
         timeoutValue = timeoutValue.substring("Second-".length(), 
timeoutValue.indexOf('<'));
         Assert.assertTrue(Integer.valueOf(timeoutValue).intValue() <= 20);
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index ebf80f71dc..a98091bf09 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -105,6 +105,16 @@
   issues do not "pop up" wrt. others).
 -->
 <section name="Tomcat 9.0.110 (remm)" rtext="in development">
+  <subsection name="Catlaina">
+    <changelog>
+      <update>
+        Change the digest used to calculate strong ETags (if enabled) for the
+        default Servlet from SHA-1 to SHA-256 to align with the recommendation
+        in RFC 9110 that hash functions used to generate strong ETags should be
+        collision resistant. (markt)
+      </update>
+    </changelog>
+  </subsection>
   <subsection name="Coyote">
     <changelog>
       <update>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to