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

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-rampart.git

commit 07701083cf6984de90d83a3a6c826ad71c7b2f70
Author: Robert Lazarski <[email protected]>
AuthorDate: Wed Jun 10 07:46:05 2026 -1000

    RAMPART-44 / RAMPART-252: enforce the policy algorithm suite on inbound 
messages
    
    Rampart did not check that the algorithms actually used in an incoming 
message
    matched the policy's algorithm suite, so a peer could downgrade to weaker
    signature / digest / canonicalization / encryption / key-wrap algorithms 
and the
    message would still be accepted (RAMPART-44).
    
    RampartEngine now builds a WSS4J AlgorithmSuite from the policy's 
AlgorithmSuite
    and sets it on the RequestData (applyAlgorithmSuite), so WSS4J rejects a 
message
    whose algorithms are not those the policy mandates. Only the policy-defined
    categories are constrained; unspecified categories and the key-length 
bounds keep
    WSS4J's defaults, so legitimate messages are unaffected (verified across the
    Basic128/Basic256/TripleDes-RSA15, SAML and SecureConversation integration
    scenarios and the nine policy samples).
    
    This implements the algorithm-validation half of RAMPART-252, which 
supersedes
    RAMPART-44. The other half of RAMPART-252 (SAML issued-token referencelist
    processing) depended on WSS4J's WSS-206, which was never applied upstream, 
and is
    out of scope here.
    
    RampartTest case 34 (asymmetric client against a symmetric service) is now
    rejected by algorithm-suite enforcement - on the key-wrap algorithm - during
    security-header processing rather than by the older certificate-presence
    heuristic. The negative test is relaxed to assert that the request is 
rejected
    rather than matching the previous specific message. Note: WSS4J's
    AlgorithmSuiteValidator raises a terse "INVALID_SECURITY" fault for a suite
    violation; surfacing a clearer message is a possible follow-up.
    
    Verified with a full clean -Papache-release verify on JDK 25.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
 .../java/org/apache/rampart/RampartEngine.java     | 50 ++++++++++++++++++++++
 .../test/java/org/apache/rampart/RampartTest.java  | 10 ++++-
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git 
a/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java 
b/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java
index 540fdf1a..c8897f17 100644
--- a/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java
+++ b/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java
@@ -234,6 +234,11 @@ public class RampartEngine {
             requestData.setEncodePasswords(false); // default
        }
 
+        // RAMPART-44 / RAMPART-252: constrain the algorithms accepted on the 
incoming
+        // message to those permitted by the policy's algorithm suite, so a 
peer cannot
+        // downgrade to weaker algorithms than the policy requires.
+        applyAlgorithmSuite(requestData, rpd);
+
         ValidatorData data = new ValidatorData(rmd);
 
                SOAPHeader header = 
rmd.getMsgContext().getEnvelope().getHeader();
@@ -418,6 +423,51 @@ public class RampartEngine {
                return results;
        }
 
+    /**
+     * Builds a WSS4J algorithm suite from the policy's algorithm suite and 
sets it on
+     * the request data, so WSS4J rejects an incoming message whose signature, 
digest,
+     * canonicalization, encryption or key-wrap algorithm is not the one the 
policy
+     * mandates (RAMPART-44 / RAMPART-252). Categories that are not populated 
are left
+     * unrestricted by WSS4J; the symmetric/asymmetric key-length bounds keep 
WSS4J's
+     * sensible defaults. SAML assertion algorithms are validated separately 
and are
+     * intentionally left untouched here.
+     */
+    private void applyAlgorithmSuite(RequestData requestData, 
RampartPolicyData rpd) {
+        org.apache.ws.secpolicy.model.AlgorithmSuite policySuite = 
rpd.getAlgorithmSuite();
+        if (policySuite == null) {
+            return;
+        }
+
+        org.apache.wss4j.common.crypto.AlgorithmSuite wss4jSuite =
+                new org.apache.wss4j.common.crypto.AlgorithmSuite();
+
+        addAlgorithm(policySuite.getAsymmetricSignature(), wss4jSuite, 
AlgorithmKind.SIGNATURE);
+        addAlgorithm(policySuite.getSymmetricSignature(), wss4jSuite, 
AlgorithmKind.SIGNATURE);
+        addAlgorithm(policySuite.getDigest(), wss4jSuite, 
AlgorithmKind.DIGEST);
+        addAlgorithm(policySuite.getInclusiveC14n(), wss4jSuite, 
AlgorithmKind.C14N);
+        addAlgorithm(policySuite.getEncryption(), wss4jSuite, 
AlgorithmKind.ENCRYPTION);
+        addAlgorithm(policySuite.getSymmetricKeyWrap(), wss4jSuite, 
AlgorithmKind.KEY_WRAP);
+        addAlgorithm(policySuite.getAsymmetricKeyWrap(), wss4jSuite, 
AlgorithmKind.KEY_WRAP);
+
+        requestData.setAlgorithmSuite(wss4jSuite);
+    }
+
+    private enum AlgorithmKind { SIGNATURE, DIGEST, C14N, ENCRYPTION, KEY_WRAP 
}
+
+    private void addAlgorithm(String algorithm, 
org.apache.wss4j.common.crypto.AlgorithmSuite suite,
+            AlgorithmKind kind) {
+        if (algorithm == null || algorithm.length() == 0) {
+            return;
+        }
+        switch (kind) {
+            case SIGNATURE:  suite.addSignatureMethod(algorithm); break;
+            case DIGEST:     suite.addDigestAlgorithm(algorithm); break;
+            case C14N:       suite.addC14nAlgorithm(algorithm); break;
+            case ENCRYPTION: suite.addEncryptionMethod(algorithm); break;
+            case KEY_WRAP:   suite.addKeyWrapAlgorithm(algorithm); break;
+        }
+    }
+
     private WSHandlerResult processSecurityHeaderWithRSA15(RampartMessageData 
rmd, SOAPHeaderBlock secHeader, WSSecurityEngine engine,
                Crypto signatureCrypto, Crypto decCrypto, TokenCallbackHandler 
tokenCallbackHandler,
                RequestData requestData) 
diff --git 
a/modules/rampart-integration/src/test/java/org/apache/rampart/RampartTest.java 
b/modules/rampart-integration/src/test/java/org/apache/rampart/RampartTest.java
index 246d40f6..4f6c103f 100644
--- 
a/modules/rampart-integration/src/test/java/org/apache/rampart/RampartTest.java
+++ 
b/modules/rampart-integration/src/test/java/org/apache/rampart/RampartTest.java
@@ -18,6 +18,7 @@ package org.apache.rampart;
 
 import static org.apache.axis2.integration.TestConstants.TESTING_PATH;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
 import org.apache.axiom.om.OMAbstractFactory;
@@ -145,7 +146,14 @@ public class RampartTest {
                         if (i == 28) {
                             
assertEquals(resources.getString("encryptionMissing"), axisFault.getMessage());
                         } else if (i == 34) {
-                            
assertEquals(resources.getString("invalidSignatureAlgo"), 
axisFault.getMessage());
+                            // RAMPART-44 / RAMPART-252: an asymmetric-binding 
message sent to a
+                            // symmetric-binding service uses algorithms (here 
the key-wrap algorithm)
+                            // that the service's algorithm suite does not 
permit. It is now rejected by
+                            // algorithm-suite enforcement during 
security-header processing rather than
+                            // by the older certificate-presence heuristic, so 
assert that the request was
+                            // rejected rather than matching a specific 
message.
+                            assertNotNull("Case 34 (binding/algorithm 
mismatch) must be rejected",
+                                    axisFault.getMessage());
                         }
 
                     }

Reply via email to