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

coheigea pushed a commit to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 7cec2100b13ae53098c7e21321426410e560bcc9
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Tue Sep 1 08:27:49 2026 +0100

    Use a properly random source to generate digest client nonces (#3423)
    
    (cherry picked from commit b0196449b3561b29924b219ed331a8e85f237f73)
---
 .../apache/cxf/transport/http/auth/DigestAuthSupplier.java | 12 +++++++++++-
 .../cxf/transport/http/auth/DigestAuthSupplierTest.java    | 14 ++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git 
a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/DigestAuthSupplier.java
 
b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/DigestAuthSupplier.java
index b076ae3fd7b..6ab3931f90d 100644
--- 
a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/DigestAuthSupplier.java
+++ 
b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/DigestAuthSupplier.java
@@ -22,6 +22,7 @@ package org.apache.cxf.transport.http.auth;
 import java.net.URI;
 import java.nio.ByteBuffer;
 import java.security.MessageDigest;
+import java.security.SecureRandom;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -36,6 +37,7 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
  *
  */
 public class DigestAuthSupplier implements HttpAuthSupplier {
+    private static final SecureRandom CNONCE_GENERATOR = new SecureRandom();
 
     Map<URI, DigestInfo> authInfo = new ConcurrentHashMap<>();
 
@@ -107,8 +109,16 @@ public class DigestAuthSupplier implements 
HttpAuthSupplier {
         return authURI;
     }
 
+    /**
+     * Creates the client nonce. RFC 7616 relies on the cnonce being 
unpredictable so
+     * that a hostile or spoofed server controlling the challenge nonce cannot 
steer
+     * the client into computing a digest over fully attacker-chosen input; a
+     * timestamp is guessable and must not be used here.
+     */
     public String createCnonce() {
-        return Long.toString(System.currentTimeMillis());
+        byte[] bytes = new byte[16];
+        CNONCE_GENERATOR.nextBytes(bytes);
+        return StringUtils.toHexString(bytes);
     }
 
     class DigestInfo {
diff --git 
a/rt/transports/http/src/test/java/org/apache/cxf/transport/http/auth/DigestAuthSupplierTest.java
 
b/rt/transports/http/src/test/java/org/apache/cxf/transport/http/auth/DigestAuthSupplierTest.java
index 127b88b8856..81e20e4c878 100644
--- 
a/rt/transports/http/src/test/java/org/apache/cxf/transport/http/auth/DigestAuthSupplierTest.java
+++ 
b/rt/transports/http/src/test/java/org/apache/cxf/transport/http/auth/DigestAuthSupplierTest.java
@@ -29,6 +29,7 @@ import org.apache.cxf.message.MessageImpl;
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 public class DigestAuthSupplierTest {
@@ -92,6 +93,19 @@ public class DigestAuthSupplierTest {
         assertEquals(expectedParams, params);
     }
 
+    @Test
+    public void testCnonceIsUnpredictable() throws Exception {
+        DigestAuthSupplier authSupplier = new DigestAuthSupplier();
+        String cnonce1 = authSupplier.createCnonce();
+        String cnonce2 = authSupplier.createCnonce();
+        // 16 random bytes, hex encoded
+        assertEquals(32, cnonce1.length());
+        assertTrue(cnonce1.matches("[0-9a-fA-F]+"));
+        assertNotEquals(cnonce1, cnonce2);
+        // must not be an epoch-millis timestamp
+        assertNotEquals(Long.toString(System.currentTimeMillis()).length(), 
cnonce1.length());
+    }
+
     @Test
     public void testUrlEncodedUri() throws Exception {
         AuthorizationPolicy authPolicy = new AuthorizationPolicy();

Reply via email to