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

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


The following commit(s) were added to refs/heads/master by this push:
     new 7626a1a44 Put a max bound on Derived Key offset + length (#669)
7626a1a44 is described below

commit 7626a1a44b0180ac3518c01db0c18f69d7335b73
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Fri Sep 4 07:15:18 2026 +0100

    Put a max bound on Derived Key offset + length (#669)
---
 .../wss4j/common/derivedKey/DerivedKeyUtils.java   | 26 +++++++++
 .../common/derivedKey/DerivedKeyUtilsTest.java     | 63 ++++++++++++++++++++++
 .../input/DerivedKeyTokenInputHandler.java         | 22 +++++++-
 3 files changed, 109 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 08fe625ee..7d72270c4 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
@@ -33,6 +33,18 @@ public final class DerivedKeyUtils {
      */
     public static final int MINIMUM_DERIVED_KEY_LENGTH = 16;
 
+    /**
+     * The maximum length in bytes of a derived key. wsc:Length and wsc:Offset 
are
+     * attacker-controlled message content, and the P_SHA-1 derivation 
allocates
+     * offset+length bytes and performs one HMAC operation per 20 output bytes.
+     */
+    public static final int MAXIMUM_DERIVED_KEY_LENGTH = 512;
+
+    /**
+     * The maximum value in bytes of the wsc:Offset of a derived key.
+     */
+    public static final int MAXIMUM_DERIVED_KEY_OFFSET = 4096;
+
     private DerivedKeyUtils() {
         // complete
     }
@@ -71,6 +83,20 @@ public final class DerivedKeyUtils {
                     + " byte(s) is less than the minimum allowed ("
                     + MINIMUM_DERIVED_KEY_LENGTH + " bytes)"});
         }
+        if (keyLength > MAXIMUM_DERIVED_KEY_LENGTH) {
+            throw new 
WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY,
+                "unsupportedKeyId",
+                new Object[] {"Requested derived key length of " + keyLength
+                    + " bytes exceeds the maximum allowed ("
+                    + MAXIMUM_DERIVED_KEY_LENGTH + " bytes)"});
+        }
+        if (offset < 0 || offset > MAXIMUM_DERIVED_KEY_OFFSET) {
+            throw new 
WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY,
+                "unsupportedKeyId",
+                new Object[] {"Requested derived key offset of " + offset
+                    + " bytes is outside the allowed range [0, "
+                    + MAXIMUM_DERIVED_KEY_OFFSET + "]"});
+        }
         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
index bf50941bd..ba353d688 100644
--- 
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
@@ -55,6 +55,69 @@ class DerivedKeyUtilsTest {
         Assertions.assertEquals(DerivedKeyUtils.MINIMUM_DERIVED_KEY_LENGTH, 
key.length);
     }
 
+    @Test
+    void rejectsDerivedKeyLengthAboveMaximum() {
+        WSSecurityException exception = 
Assertions.assertThrows(WSSecurityException.class,
+            () -> DerivedKeyUtils.deriveKey(
+                ConversationConstants.DerivationAlgorithm.P_SHA_1,
+                null,
+                DerivedKeyUtils.MAXIMUM_DERIVED_KEY_LENGTH + 1,
+                SECRET,
+                NONCE,
+                0));
+
+        
Assertions.assertEquals(WSSecurityException.ErrorCode.INVALID_SECURITY, 
exception.getErrorCode());
+    }
+
+    @Test
+    void rejectsDerivedKeyOffsetOutsideMaximum() {
+        WSSecurityException exception = 
Assertions.assertThrows(WSSecurityException.class,
+            () -> DerivedKeyUtils.deriveKey(
+                ConversationConstants.DerivationAlgorithm.P_SHA_1,
+                null,
+                DerivedKeyUtils.MINIMUM_DERIVED_KEY_LENGTH,
+                SECRET,
+                NONCE,
+                DerivedKeyUtils.MAXIMUM_DERIVED_KEY_OFFSET + 1));
+
+        
Assertions.assertEquals(WSSecurityException.ErrorCode.INVALID_SECURITY, 
exception.getErrorCode());
+    }
+
+    @Test
+    void rejectsNegativeDerivedKeyOffset() {
+        WSSecurityException exception = 
Assertions.assertThrows(WSSecurityException.class,
+            () -> DerivedKeyUtils.deriveKey(
+                ConversationConstants.DerivationAlgorithm.P_SHA_1,
+                null,
+                DerivedKeyUtils.MINIMUM_DERIVED_KEY_LENGTH,
+                SECRET,
+                NONCE,
+                -1));
+
+        
Assertions.assertEquals(WSSecurityException.ErrorCode.INVALID_SECURITY, 
exception.getErrorCode());
+    }
+
+    @Test
+    void acceptsNonDefaultDerivedKeyLengthAndOffset() throws Exception {
+        byte[] key = DerivedKeyUtils.deriveKey(
+            ConversationConstants.DerivationAlgorithm.P_SHA_1,
+            null,
+            24,
+            SECRET,
+            NONCE,
+            32);
+        byte[] keyWithDefaultOffset = DerivedKeyUtils.deriveKey(
+            ConversationConstants.DerivationAlgorithm.P_SHA_1,
+            null,
+            24,
+            SECRET,
+            NONCE,
+            0);
+
+        Assertions.assertEquals(24, key.length);
+        Assertions.assertFalse(java.util.Arrays.equals(keyWithDefaultOffset, 
key));
+    }
+
     @Test
     void preservesDefaultDerivedKeyLength() throws Exception {
         byte[] key = DerivedKeyUtils.deriveKey(
diff --git 
a/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/DerivedKeyTokenInputHandler.java
 
b/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/DerivedKeyTokenInputHandler.java
index 71c4822e4..ccbce361e 100644
--- 
a/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/DerivedKeyTokenInputHandler.java
+++ 
b/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/DerivedKeyTokenInputHandler.java
@@ -18,6 +18,7 @@
  */
 package org.apache.wss4j.stax.impl.processor.input;
 
+import java.math.BigInteger;
 import java.security.Key;
 import java.util.Deque;
 import java.util.List;
@@ -133,10 +134,12 @@ public class DerivedKeyTokenInputHandler extends 
AbstractInputSecurityHeaderHand
                         byte[] keyBytes = DerivedKeyUtils.deriveKey(
                                 derivedKeyAlgorithm,
                                 derivedKeyTokenType.getLabel(),
-                                derivedKeyTokenType.getLength().intValue(),
+                                
getDerivedKeyParameter(derivedKeyTokenType.getLength(),
+                                                       
DerivedKeyUtils.MAXIMUM_DERIVED_KEY_LENGTH, "length"),
                                 secret,
                                 nonce,
-                                derivedKeyTokenType.getOffset().intValue()
+                                
getDerivedKeyParameter(derivedKeyTokenType.getOffset(),
+                                                       
DerivedKeyUtils.MAXIMUM_DERIVED_KEY_OFFSET, "offset")
                         );
                         XMLSecurityConstants.AlgorithmUsage 
derivedKeyAlgorithmUsage;
                         if (WSSConstants.Enc.equals(algorithmUsage)) {
@@ -183,4 +186,19 @@ public class DerivedKeyTokenInputHandler extends 
AbstractInputSecurityHeaderHand
         
derivedKeyTokenSecurityEvent.setCorrelationID(derivedKeyTokenType.getId());
         
inputProcessorChain.getSecurityContext().registerSecurityEvent(derivedKeyTokenSecurityEvent);
     }
+
+    static int getDerivedKeyParameter(BigInteger value, int maximum, String 
name) throws WSSecurityException {
+        if (value == null) {
+            throw new 
WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY,
+                "unsupportedKeyId",
+                new Object[] {"Missing derived key " + name});
+        }
+        if (value.signum() < 0 || value.compareTo(BigInteger.valueOf(maximum)) 
> 0) {
+            throw new 
WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY,
+                "unsupportedKeyId",
+                new Object[] {"Requested derived key " + name + " of " + value
+                    + " bytes is outside the allowed range [0, " + maximum + 
"]"});
+        }
+        return value.intValue();
+    }
 }

Reply via email to