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();
+ }
}