Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Commit

Permalink
more signature verification tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Marc Giger committed Oct 26, 2014
1 parent 5b197b8 commit 55857fd
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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"));
}
}
}

0 comments on commit 55857fd

Please sign in to comment.