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

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


The following commit(s) were added to refs/heads/3_0_x-fixes by this push:
     new fae5e611f EncryptedHeader child confusion causing wrong 
protected-header selection (#687)
fae5e611f is described below

commit fae5e611f626b5fec3a729eed50ac00d2d3bc24b
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Fri Sep 11 11:31:12 2026 +0100

    EncryptedHeader child confusion causing wrong protected-header selection 
(#687)
---
 .../org/apache/wss4j/dom/util/EncryptionUtils.java | 23 ++++++++++-
 .../apache/wss4j/dom/message/EncryptionTest.java   | 48 ++++++++++++++++++++++
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git 
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/util/EncryptionUtils.java 
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/util/EncryptionUtils.java
index f01f07a1b..9240f725f 100644
--- 
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/util/EncryptionUtils.java
+++ 
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/util/EncryptionUtils.java
@@ -90,6 +90,12 @@ public final class EncryptionUtils {
             while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
                 child = child.getNextSibling();
             }
+            if (child == null || !"EncryptedData".equals(child.getLocalName())
+                || !WSConstants.ENC_NS.equals(child.getNamespaceURI())) {
+                throw new WSSecurityException(
+                    WSSecurityException.ErrorCode.INVALID_SECURITY, "dataRef",
+                    new Object[] {dataRefURI});
+            }
             return (Element)child;
         }
         return encryptedDataElement;
@@ -218,7 +224,22 @@ public final class EncryptionUtils {
             || parent.getLocalName().equals(WSConstants.ENCRYPED_ASSERTION_LN)
             && parent.getNamespaceURI().equals(WSConstants.SAML2_NS)) {
 
-            Node decryptedHeader = parent.getFirstChild();
+            // The decrypted node sits where the EncryptedData was, which is 
not necessarily
+            // the wrapper's first child - anything else there was never 
encrypted.
+            Node decryptedHeader = decryptedNode;
+            if (decryptedHeader == null) {
+                if (content) {
+                    decryptedHeader = encData;
+                } else if (previousSibling == null) {
+                    decryptedHeader = parent.getFirstChild();
+                } else {
+                    decryptedHeader = previousSibling.getNextSibling();
+                }
+            }
+            if (decryptedHeader == null || Node.ELEMENT_NODE != 
decryptedHeader.getNodeType()) {
+                throw new 
WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK);
+            }
+
             Node soapHeader = parent.getParentNode();
             soapHeader.replaceChild(decryptedHeader, parent);
 
diff --git 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/EncryptionTest.java
 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/EncryptionTest.java
index 6e44a441b..1bbaa6fd0 100644
--- 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/EncryptionTest.java
+++ 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/EncryptionTest.java
@@ -62,6 +62,7 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.CsvSource;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -92,6 +93,53 @@ public class EncryptionTest {
         crypto = CryptoFactory.getInstance("wss40.properties");
     }
 
+    @Test
+    public void testEncryptedHeaderWithUnencryptedFirstChild() throws 
Exception {
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader(doc);
+        secHeader.insertSecurityHeader();
+        Element soapHeader = (Element)doc.getElementsByTagNameNS(
+            WSConstants.URI_SOAP11_ENV, "Header").item(0);
+        Element header = doc.createElementNS("urn:test", "test:header");
+        header.setAttributeNS(WSConstants.XMLNS_NS, "xmlns:test", "urn:test");
+        soapHeader.appendChild(header);
+
+        WSSecEncrypt builder = new WSSecEncrypt(secHeader);
+        builder.setUserInfo("wss40");
+        builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
+        builder.getParts().add(new WSEncryptionPart("header", "urn:test", 
"Header"));
+
+        Document encryptedDoc = builder.build(crypto, key);
+        Element encryptedHeader = (Element)encryptedDoc.getElementsByTagNameNS(
+            WSConstants.WSSE11_NS, WSConstants.ENCRYPTED_HEADER).item(0);
+        Node encryptedData = encryptedHeader.getFirstChild();
+        while (encryptedData != null && encryptedData.getNodeType() != 
Node.ELEMENT_NODE) {
+            encryptedData = encryptedData.getNextSibling();
+        }
+        Element unencryptedHeader = encryptedDoc.createElementNS(
+            "urn:attacker", "attacker:header");
+        unencryptedHeader.setAttributeNS(
+            WSConstants.XMLNS_NS, "xmlns:attacker", "urn:attacker");
+        encryptedHeader.insertBefore(unencryptedHeader, encryptedData);
+
+        WSHandlerResult results = secEngine.processSecurityHeader(
+            encryptedDoc, null, keystoreCallbackHandler, crypto);
+
+        Element promotedHeader = (Element)encryptedDoc.getElementsByTagNameNS(
+            "urn:test", "header").item(0);
+        assertNotNull(promotedHeader);
+        assertEquals("urn:test", promotedHeader.getNamespaceURI());
+        assertEquals("header", promotedHeader.getLocalName());
+        assertEquals(0, encryptedDoc.getElementsByTagNameNS(
+            "urn:attacker", "header").getLength());
+
+        @SuppressWarnings("unchecked")
+        java.util.List<WSDataRef> dataRefs = 
(java.util.List<WSDataRef>)results.getActionResults()
+            
.get(WSConstants.ENCR).get(0).get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
+        assertEquals(1, dataRefs.size());
+        assertEquals(promotedHeader, dataRefs.get(0).getProtectedElement());
+    }
+
     /**
      * Setup method
      *

Reply via email to