VYPR
Moderate severityNVD Advisory· Published Jan 21, 2015· Updated May 6, 2026

CVE-2014-8152

CVE-2014-8152

Description

Apache Santuario XML Security for Java 2.0.x before 2.0.3 allows remote attackers to bypass the streaming XML signature protection mechanism via a crafted XML document.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.santuario:xmlsecMaven
>= 2.0.0, < 2.0.32.0.3

Affected products

4
  • cpe:2.3:a:apache:santuario_xml_security_for_java:2.0.0:*:*:*:*:*:*:*+ 2 more
    • cpe:2.3:a:apache:santuario_xml_security_for_java:2.0.0:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:santuario_xml_security_for_java:2.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:apache:santuario_xml_security_for_java:2.0.2:*:*:*:*:*:*:*
  • ghsa-coords
    Range: >= 2.0.0, < 2.0.3

Patches

1
55857fd4cdfd

more signature verification tests

https://github.com/apache/santuario-javaMarc GigerOct 26, 2014via ghsa
4 files changed · +288 2
  • src/main/java/org/apache/xml/security/stax/ext/InputProcessorChain.java+15 0 modified
    @@ -72,6 +72,7 @@ public interface InputProcessorChain extends ProcessorChain {
         /**
          * Create a new SubChain. The XMLEvents will be only be processed from the given InputProcessor to the end.
          * All earlier InputProcessors don't get these events. In other words the chain will be splitted in two parts.
    +     * The associated DocumentContext will be cloned.
          *
          * @param inputProcessor The InputProcessor position the XMLEvents should be processed over this SubChain.
          * @return A new InputProcessorChain
    @@ -80,6 +81,20 @@ public interface InputProcessorChain extends ProcessorChain {
          */
         InputProcessorChain createSubChain(InputProcessor inputProcessor) throws XMLStreamException, XMLSecurityException;
     
    +    /**
    +     * Create a new SubChain. The XMLEvents will be only be processed from the given InputProcessor to the end.
    +     * All earlier InputProcessors don't get these events. In other words the chain will be splitted in two parts.
    +     *
    +     * The parameter clone controls if the associated DocumentContext should be cloned or reference the existing one.
    +     *
    +     * @param inputProcessor The InputProcessor position the XMLEvents should be processed over this SubChain.
    +     * @param clone if true the associated DocumentContext will be cloned otherwise the DocumentContext will be referenced.
    +     * @return A new InputProcessorChain
    +     * @throws XMLStreamException   thrown when a streaming error occurs
    +     * @throws XMLSecurityException thrown when a Security failure occurs
    +     */
    +    InputProcessorChain createSubChain(InputProcessor inputProcessor, boolean clone) throws XMLStreamException, XMLSecurityException;
    +
         /**
          * Requests the next security header XMLEvent from the next processor in the chain.
          *
    
  • src/main/java/org/apache/xml/security/stax/impl/InputProcessorChainImpl.java+7 1 modified
    @@ -200,9 +200,15 @@ public void doFinal() throws XMLStreamException, XMLSecurityException {
     
         @Override
         public InputProcessorChain createSubChain(InputProcessor inputProcessor) throws XMLStreamException, XMLSecurityException {
    +        return createSubChain(inputProcessor, true);
    +    }
    +
    +    @Override
    +    public InputProcessorChain createSubChain(InputProcessor inputProcessor, boolean clone) throws XMLStreamException, XMLSecurityException {
             InputProcessorChainImpl inputProcessorChain;
             try {
    -            inputProcessorChain = new InputProcessorChainImpl(inboundSecurityContext, documentContext.clone(),
    +            final DocumentContextImpl docContext = clone ? documentContext.clone() : documentContext;
    +            inputProcessorChain = new InputProcessorChainImpl(inboundSecurityContext, docContext,
                         inputProcessors.indexOf(inputProcessor) + 1, new ArrayList<InputProcessor>(this.inputProcessors));
             } catch (CloneNotSupportedException e) {
                 throw new XMLSecurityException(e);
    
  • src/main/java/org/apache/xml/security/stax/impl/processor/input/XMLSecurityInputProcessor.java+5 1 modified
    @@ -138,11 +138,15 @@ public XMLSecEvent processNextEvent(InputProcessorChain inputProcessorChain)
                         inputProcessorChain.addProcessor(internalReplayProcessor);
     
                         //...and let the SignatureVerificationProcessor process the buffered events (enveloped signature).
    -                    InputProcessorChain subInputProcessorChain = inputProcessorChain.createSubChain(this);
    +                    InputProcessorChain subInputProcessorChain = inputProcessorChain.createSubChain(this, false);
                         while (!xmlSecEventList.isEmpty()) {
                             subInputProcessorChain.reset();
                             subInputProcessorChain.processEvent();
                         }
    +
    +                    // copy all processor back to main chain for finalization
    +                    inputProcessorChain.getProcessors().clear();
    +                    inputProcessorChain.getProcessors().addAll(subInputProcessorChain.getProcessors());
                     }
                     break;
             }
    
  • src/test/java/org/apache/xml/security/test/stax/signature/SignatureVerificationTest.java+261 0 modified
    @@ -63,6 +63,7 @@
     import org.junit.Before;
     import org.junit.Test;
     import org.w3c.dom.Document;
    +import org.w3c.dom.Element;
     
     /**
      * A set of test-cases for Signature verification.
    @@ -1420,4 +1421,264 @@ public void testCustomC14nAlgo() throws Exception {
     
             StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader);
         }
    +
    +    @Test
    +    public void testPartialSignedDocumentTampered_ContentFirst() throws Exception {
    +        // Read in plaintext document
    +        InputStream sourceDocument =
    +                this.getClass().getClassLoader().getResourceAsStream(
    +                        "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml");
    +        DocumentBuilder builder = XMLUtils.createDocumentBuilder(false);
    +        Document document = builder.parse(sourceDocument);
    +
    +        // Set up the Key
    +        KeyStore keyStore = KeyStore.getInstance("jks");
    +        keyStore.load(
    +                this.getClass().getClassLoader().getResource("transmitter.jks").openStream(),
    +                "default".toCharArray()
    +        );
    +        Key key = keyStore.getKey("transmitter", "default".toCharArray());
    +        X509Certificate cert = (X509Certificate)keyStore.getCertificate("transmitter");
    +
    +        // Sign using DOM
    +        List<String> localNames = new ArrayList<String>();
    +        localNames.add("PaymentInfo");
    +        XMLSignature sig = signUsingDOM(
    +                "http://www.w3.org/2000/09/xmldsig#rsa-sha1", document, localNames, key
    +        );
    +
    +        // Add KeyInfo
    +        sig.addKeyInfo(cert);
    +
    +        // Now modify the context of PaymentInfo
    +        Element paymentInfoElement =
    +                (Element)document.getElementsByTagNameNS("urn:example:po", "BillingAddress").item(0);
    +        paymentInfoElement.setTextContent("Dig PLC, 1 First Ave, Dublin 1, US");
    +
    +        // Convert Document to a Stream Reader
    +        javax.xml.transform.Transformer transformer = transformerFactory.newTransformer();
    +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    +        transformer.transform(new DOMSource(document), new StreamResult(baos));
    +        final XMLStreamReader xmlStreamReader =
    +                xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray()));
    +
    +        // Verify signature
    +        XMLSecurityProperties properties = new XMLSecurityProperties();
    +        InboundXMLSec inboundXMLSec = XMLSec.getInboundWSSec(properties);
    +        TestSecurityEventListener securityEventListener = new TestSecurityEventListener();
    +        XMLStreamReader securityStreamReader =
    +                inboundXMLSec.processInMessage(xmlStreamReader, null, securityEventListener);
    +
    +        try {
    +            StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader);
    +            fail("Failure expected on a modified document");
    +        } catch (XMLStreamException ex) {
    +            Assert.assertTrue(ex.getMessage().contains("Invalid digest of reference"));
    +        }
    +    }
    +
    +    @Test
    +    public void testPartialSignedDocumentTampered_SignatureFirst() throws Exception {
    +        // Read in plaintext document
    +        InputStream sourceDocument =
    +                this.getClass().getClassLoader().getResourceAsStream(
    +                        "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml");
    +        DocumentBuilder builder = XMLUtils.createDocumentBuilder(false);
    +        Document document = builder.parse(sourceDocument);
    +
    +        // Set up the Key
    +        KeyStore keyStore = KeyStore.getInstance("jks");
    +        keyStore.load(
    +                this.getClass().getClassLoader().getResource("transmitter.jks").openStream(),
    +                "default".toCharArray()
    +        );
    +        Key key = keyStore.getKey("transmitter", "default".toCharArray());
    +        X509Certificate cert = (X509Certificate)keyStore.getCertificate("transmitter");
    +
    +        // Sign using DOM
    +        List<String> localNames = new ArrayList<String>();
    +        localNames.add("PaymentInfo");
    +        XMLSignature sig = signUsingDOM(
    +                "http://www.w3.org/2000/09/xmldsig#rsa-sha1", document, localNames, key
    +        );
    +
    +        // Add KeyInfo
    +        sig.addKeyInfo(cert);
    +
    +        // Now modify the context of PaymentInfo
    +        Element paymentInfoElement =
    +                (Element)document.getElementsByTagNameNS("urn:example:po", "BillingAddress").item(0);
    +        paymentInfoElement.setTextContent("Dig PLC, 1 First Ave, Dublin 1, US");
    +
    +        //move signature below root element
    +        Element sigElement = (Element)document.getElementsByTagNameNS(
    +                XMLSecurityConstants.TAG_dsig_Signature.getNamespaceURI(),
    +                XMLSecurityConstants.TAG_dsig_Signature.getLocalPart()).item(0);
    +        document.getDocumentElement().insertBefore(sigElement,
    +                XMLUtils.getNextElement(document.getDocumentElement().getFirstChild()));
    +
    +        // Convert Document to a Stream Reader
    +        javax.xml.transform.Transformer transformer = transformerFactory.newTransformer();
    +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    +        transformer.transform(new DOMSource(document), new StreamResult(baos));
    +        final XMLStreamReader xmlStreamReader =
    +                xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray()));
    +
    +        // Verify signature
    +        XMLSecurityProperties properties = new XMLSecurityProperties();
    +        InboundXMLSec inboundXMLSec = XMLSec.getInboundWSSec(properties);
    +        TestSecurityEventListener securityEventListener = new TestSecurityEventListener();
    +        XMLStreamReader securityStreamReader =
    +                inboundXMLSec.processInMessage(xmlStreamReader, null, securityEventListener);
    +
    +        try {
    +            StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader);
    +            fail("Failure expected on a modified document");
    +        } catch (XMLStreamException ex) {
    +            Assert.assertTrue(ex.getMessage().contains("Invalid digest of reference"));
    +        }
    +    }
    +
    +    @Test
    +    public void testEnvelopedSignatureTampered_ContentFirst() throws Exception {
    +        // Read in plaintext document
    +        InputStream sourceDocument =
    +                this.getClass().getClassLoader().getResourceAsStream(
    +                        "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml");
    +        DocumentBuilder builder = XMLUtils.createDocumentBuilder(false);
    +        Document document = builder.parse(sourceDocument);
    +
    +        // Set up the Key
    +        KeyStore keyStore = KeyStore.getInstance("jks");
    +        keyStore.load(
    +                this.getClass().getClassLoader().getResource("transmitter.jks").openStream(),
    +                "default".toCharArray()
    +        );
    +        Key key = keyStore.getKey("transmitter", "default".toCharArray());
    +        X509Certificate cert = (X509Certificate)keyStore.getCertificate("transmitter");
    +
    +        // Sign using DOM
    +        List<String> localNames = new ArrayList<String>();
    +
    +        ReferenceInfo referenceInfo = new ReferenceInfo(
    +                "",
    +                new String[]{
    +                        "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
    +                        "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
    +                },
    +                "http://www.w3.org/2000/09/xmldsig#sha1",
    +                false
    +        );
    +
    +        List<ReferenceInfo> referenceInfos = new ArrayList<ReferenceInfo>();
    +        referenceInfos.add(referenceInfo);
    +
    +        XMLSignature sig = signUsingDOM(
    +                "http://www.w3.org/2000/09/xmldsig#rsa-sha1", document, localNames, key, referenceInfos
    +        );
    +
    +        // Add KeyInfo
    +        sig.addKeyInfo(cert);
    +
    +        // Now modify the context of PaymentInfo
    +        Element paymentInfoElement =
    +                (Element)document.getElementsByTagNameNS("urn:example:po", "BillingAddress").item(0);
    +        paymentInfoElement.setTextContent("Dig PLC, 1 First Ave, Dublin 1, US");
    +
    +        // Convert Document to a Stream Reader
    +        javax.xml.transform.Transformer transformer = transformerFactory.newTransformer();
    +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    +        transformer.transform(new DOMSource(document), new StreamResult(baos));
    +        final XMLStreamReader xmlStreamReader =
    +                xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray()));
    +
    +        // Verify signature
    +        XMLSecurityProperties properties = new XMLSecurityProperties();
    +        InboundXMLSec inboundXMLSec = XMLSec.getInboundWSSec(properties);
    +        TestSecurityEventListener securityEventListener = new TestSecurityEventListener();
    +        XMLStreamReader securityStreamReader =
    +                inboundXMLSec.processInMessage(xmlStreamReader, null, securityEventListener);
    +
    +        try {
    +            final Document res = StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader);
    +            fail("Failure expected on a modified document");
    +        } catch (XMLStreamException ex) {
    +            Assert.assertTrue(ex.getMessage().contains("Invalid digest of reference"));
    +        }
    +    }
    +
    +    @Test
    +    public void testEnvelopedSignatureTampered_SignatureFirst() throws Exception {
    +        // Read in plaintext document
    +        InputStream sourceDocument =
    +                this.getClass().getClassLoader().getResourceAsStream(
    +                        "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml");
    +        DocumentBuilder builder = XMLUtils.createDocumentBuilder(false);
    +        Document document = builder.parse(sourceDocument);
    +
    +        // Set up the Key
    +        KeyStore keyStore = KeyStore.getInstance("jks");
    +        keyStore.load(
    +                this.getClass().getClassLoader().getResource("transmitter.jks").openStream(),
    +                "default".toCharArray()
    +        );
    +        Key key = keyStore.getKey("transmitter", "default".toCharArray());
    +        X509Certificate cert = (X509Certificate)keyStore.getCertificate("transmitter");
    +
    +        // Sign using DOM
    +        List<String> localNames = new ArrayList<String>();
    +
    +        ReferenceInfo referenceInfo = new ReferenceInfo(
    +                "",
    +                new String[]{
    +                        "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
    +                        "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
    +                },
    +                "http://www.w3.org/2000/09/xmldsig#sha1",
    +                false
    +        );
    +
    +        List<ReferenceInfo> referenceInfos = new ArrayList<ReferenceInfo>();
    +        referenceInfos.add(referenceInfo);
    +
    +        XMLSignature sig = signUsingDOM(
    +                "http://www.w3.org/2000/09/xmldsig#rsa-sha1", document, localNames, key, referenceInfos
    +        );
    +
    +        // Add KeyInfo
    +        sig.addKeyInfo(cert);
    +
    +        // Now modify the context of PaymentInfo
    +        Element paymentInfoElement =
    +                (Element)document.getElementsByTagNameNS("urn:example:po", "BillingAddress").item(0);
    +        paymentInfoElement.setTextContent("Dig PLC, 1 First Ave, Dublin 1, US");
    +
    +        //move signature below root element
    +        Element sigElement = (Element)document.getElementsByTagNameNS(
    +                XMLSecurityConstants.TAG_dsig_Signature.getNamespaceURI(),
    +                XMLSecurityConstants.TAG_dsig_Signature.getLocalPart()).item(0);
    +        document.getDocumentElement().insertBefore(sigElement,
    +                XMLUtils.getNextElement(document.getDocumentElement().getFirstChild()));
    +
    +        // Convert Document to a Stream Reader
    +        javax.xml.transform.Transformer transformer = transformerFactory.newTransformer();
    +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    +        transformer.transform(new DOMSource(document), new StreamResult(baos));
    +        final XMLStreamReader xmlStreamReader =
    +                xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray()));
    +
    +        // Verify signature
    +        XMLSecurityProperties properties = new XMLSecurityProperties();
    +        InboundXMLSec inboundXMLSec = XMLSec.getInboundWSSec(properties);
    +        TestSecurityEventListener securityEventListener = new TestSecurityEventListener();
    +        XMLStreamReader securityStreamReader =
    +                inboundXMLSec.processInMessage(xmlStreamReader, null, securityEventListener);
    +
    +        try {
    +            final Document res = StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader);
    +            fail("Failure expected on a modified document");
    +        } catch (XMLStreamException ex) {
    +            Assert.assertTrue(ex.getMessage().contains("Invalid digest of reference"));
    +        }
    +    }
     }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

13

News mentions

0

No linked articles in our index yet.