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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]