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

coheigea pushed a commit to branch 2_4_x-fixes
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git


The following commit(s) were added to refs/heads/2_4_x-fixes by this push:
     new 8ae3c1248 Put a lower bound of 16 bytes on minimum derived key length 
(#667)
8ae3c1248 is described below

commit 8ae3c1248d84f3a3f685a3def8eeb2e4e5aee579
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Thu Sep 3 16:27:09 2026 +0100

    Put a lower bound of 16 bytes on minimum derived key length (#667)
---
 .../wss4j/common/derivedKey/DerivedKeyUtils.java   | 16 +++++
 .../common/derivedKey/DerivedKeyUtilsTest.java     | 70 ++++++++++++++++++++++
 .../output/DerivedKeyTokenOutputProcessor.java     |  6 +-
 3 files changed, 90 insertions(+), 2 deletions(-)

diff --git 
a/ws-security-common/src/main/java/org/apache/wss4j/common/derivedKey/DerivedKeyUtils.java
 
b/ws-security-common/src/main/java/org/apache/wss4j/common/derivedKey/DerivedKeyUtils.java
index 4d1c88929..08fe625ee 100644
--- 
a/ws-security-common/src/main/java/org/apache/wss4j/common/derivedKey/DerivedKeyUtils.java
+++ 
b/ws-security-common/src/main/java/org/apache/wss4j/common/derivedKey/DerivedKeyUtils.java
@@ -24,6 +24,15 @@ import org.apache.wss4j.common.ext.WSSecurityException;
 
 public final class DerivedKeyUtils {
 
+    /**
+     * The minimum length in bytes of a derived key (128 bits). The wsc:Length 
value is
+     * attacker-controlled message content: a shorter derived key (e.g. 
Length=1) reduces
+     * an HMAC signature key to a trivially brute-forceable keyspace. No 
standard
+     * WS-SecurityPolicy algorithm suite derives keys shorter than 128 bits, 
so this is
+     * enforced as a hard engine-level floor, independent of any configured 
AlgorithmSuite.
+     */
+    public static final int MINIMUM_DERIVED_KEY_LENGTH = 16;
+
     private DerivedKeyUtils() {
         // complete
     }
@@ -55,6 +64,13 @@ public final class DerivedKeyUtils {
         if (keyLength <= 0) {
             keyLength = 32L;
         }
+        if (keyLength < MINIMUM_DERIVED_KEY_LENGTH) {
+            throw new 
WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY,
+                "unsupportedKeyId",
+                new Object[] {"Requested derived key length of " + keyLength
+                    + " byte(s) is less than the minimum allowed ("
+                    + MINIMUM_DERIVED_KEY_LENGTH + " bytes)"});
+        }
         return algo.createKey(secret, seed, offset, keyLength);
     }
 }
diff --git 
a/ws-security-common/src/test/java/org/apache/wss4j/common/derivedKey/DerivedKeyUtilsTest.java
 
b/ws-security-common/src/test/java/org/apache/wss4j/common/derivedKey/DerivedKeyUtilsTest.java
new file mode 100644
index 000000000..bf50941bd
--- /dev/null
+++ 
b/ws-security-common/src/test/java/org/apache/wss4j/common/derivedKey/DerivedKeyUtilsTest.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.wss4j.common.derivedKey;
+
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class DerivedKeyUtilsTest {
+
+    private static final byte[] SECRET = 
"0123456789abcdef".getBytes(java.nio.charset.StandardCharsets.UTF_8);
+    private static final byte[] NONCE = 
"abcdefghijklmnop".getBytes(java.nio.charset.StandardCharsets.UTF_8);
+
+    @Test
+    void rejectsPositiveDerivedKeyLengthsBelowMinimum() {
+        WSSecurityException exception = 
Assertions.assertThrows(WSSecurityException.class,
+            () -> DerivedKeyUtils.deriveKey(
+                ConversationConstants.DerivationAlgorithm.P_SHA_1,
+                null,
+                DerivedKeyUtils.MINIMUM_DERIVED_KEY_LENGTH - 1,
+                SECRET,
+                NONCE,
+                0));
+
+        
Assertions.assertEquals(WSSecurityException.ErrorCode.INVALID_SECURITY, 
exception.getErrorCode());
+    }
+
+    @Test
+    void acceptsMinimumDerivedKeyLength() throws Exception {
+        byte[] key = DerivedKeyUtils.deriveKey(
+            ConversationConstants.DerivationAlgorithm.P_SHA_1,
+            null,
+            DerivedKeyUtils.MINIMUM_DERIVED_KEY_LENGTH,
+            SECRET,
+            NONCE,
+            0);
+
+        Assertions.assertEquals(DerivedKeyUtils.MINIMUM_DERIVED_KEY_LENGTH, 
key.length);
+    }
+
+    @Test
+    void preservesDefaultDerivedKeyLength() throws Exception {
+        byte[] key = DerivedKeyUtils.deriveKey(
+            ConversationConstants.DerivationAlgorithm.P_SHA_1,
+            null,
+            0,
+            SECRET,
+            NONCE,
+            0);
+
+        Assertions.assertEquals(32, key.length);
+    }
+}
diff --git 
a/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/DerivedKeyTokenOutputProcessor.java
 
b/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/DerivedKeyTokenOutputProcessor.java
index 94cbb1842..08b4bd610 100644
--- 
a/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/DerivedKeyTokenOutputProcessor.java
+++ 
b/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/output/DerivedKeyTokenOutputProcessor.java
@@ -88,7 +88,8 @@ public class DerivedKeyTokenOutputProcessor extends 
AbstractOutputProcessor {
                 } else {
                     length = 
JCEAlgorithmMapper.getKeyLengthFromURI(getSecurityProperties().getSignatureAlgorithm())
 / 8;
                     if (length == 0) {
-                        length = 
KeyUtils.getKeyLength(getSecurityProperties().getSignatureAlgorithm()) / 8;
+                        // KeyUtils.getKeyLength already returns a length in 
bytes
+                        length = 
KeyUtils.getKeyLength(getSecurityProperties().getSignatureAlgorithm());
                     }
                 }
             } else if 
(WSSConstants.ENCRYPTION_WITH_DERIVED_KEY.equals(action)) {
@@ -97,7 +98,8 @@ public class DerivedKeyTokenOutputProcessor extends 
AbstractOutputProcessor {
                 } else {
                     length = 
JCEAlgorithmMapper.getKeyLengthFromURI(getSecurityProperties().getEncryptionSymAlgorithm())
 / 8;
                     if (length == 0) {
-                        length = 
KeyUtils.getKeyLength(getSecurityProperties().getEncryptionSymAlgorithm()) / 8;
+                        // KeyUtils.getKeyLength already returns a length in 
bytes
+                        length = 
KeyUtils.getKeyLength(getSecurityProperties().getEncryptionSymAlgorithm());
                     }
                 }
             }

Reply via email to