Filter #XML Documents using #XPATH2 Transforms for signature digests #banking #fintech

By | November 26, 2021

While working with XML Documents and trying to implement the XMLSignature I hit the issue of filtering what to sign from an XML.

The basic documentation of the from XML signature standard XML Signature Syntax and Processing Version 1.1 describes several methods that can be used to transform an XML to prepare it for signing.

After several days of trying I got “lucky” and found out how to do the filtering.

Lucky as this dog

See 6.6 Transform Algorithms for details.

Bellow I am going to mention the two most used.

Enveloped Signature Transform

This is the most basic and most used transform when you simply want to sign the whole document and embed the signature in the resulting document.

What the transform is doing is to tell the signing algorithm to calculate a digest on the whole XML and exclude from that any <Signature> tag and its content. As a result you can add one or more signatures without tempering with the digest.

The Java code is straight forward:

...
XMLSignatureFactory fac = getXMLSignatureFactory();
Transform trf = fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null);
...

XPath Filtering Transform

This is a more versatile transform that can do a micromanagement of what we want to sign from the XML. This allows us to have signature on messages that have parts that will to be modified my other 3rd party systems through which our messages pass.

The syntax is a bit strange but bellow there are several useful examples

Ignore the first/only Signature in digest calculation

...
Map<String, String> xpathNamespaceMap = new HashMap<String, String>();
xpathNamespaceMap.put("ds", "http://www.w3.org/2000/09/xmldsig#");
XMLSignatureFactory fac = getXMLSignatureFactory();
String expression = "/descendant::*[name()='ds:Signature'][1]";
XPathFilter2ParameterSpec xp2Spec = new XPathFilter2ParameterSpec(Collections.singletonList(new XPathType(expression, XPathType.Filter.SUBTRACT, xpathNamespaceMap)));
Transform trf = fac.newTransform(Transform.XPATH2, xp2Spec);
...

Ignore just the current signature in digest calculation, consider the existing signature

...
Map<String, String> xpathNamespaceMap = new HashMap<String, String>();
xpathNamespaceMap.put("ds", "http://www.w3.org/2000/09/xmldsig#");
XMLSignatureFactory fac = getXMLSignatureFactory();
String expression = "/descendant::*[name()='ds:Signature'][2]";
XPathFilter2ParameterSpec xp2Spec = new XPathFilter2ParameterSpec(Collections.singletonList(new XPathType(expression, XPathType.Filter.SUBTRACT, xpathNamespaceMap)));
Transform trf = fac.newTransform(Transform.XPATH2, xp2Spec);
...

Ignore all signatures in digest calculation (basically identical to Transform.ENVELOPED )

...
Map<String, String> xpathNamespaceMap = new HashMap<String, String>();
xpathNamespaceMap.put("ds", "http://www.w3.org/2000/09/xmldsig#");
XMLSignatureFactory fac = getXMLSignatureFactory();
String expression = expression = "/descendant::*[name()='ds:Signature']";
XPathFilter2ParameterSpec xp2Spec = new XPathFilter2ParameterSpec(Collections.singletonList(new XPathType(expression, XPathType.Filter.SUBTRACT, xpathNamespaceMap)));
Transform trf = fac.newTransform(Transform.XPATH2, xp2Spec);
...

Ignore a specific signature identified by a signature id.

For ex:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="BankSignature">
...
Map<String, String> xpathNamespaceMap = new HashMap<String, String>();
xpathNamespaceMap.put("ds", "http://www.w3.org/2000/09/xmldsig#");
XMLSignatureFactory fac = getXMLSignatureFactory();
String expression = expression = "/descendant::*[@id='BankSignature'][name()='ds:Signature']";
XPathFilter2ParameterSpec xp2Spec = new XPathFilter2ParameterSpec(Collections.singletonList(new XPathType(expression, XPathType.Filter.SUBTRACT, xpathNamespaceMap)));
Transform trf = fac.newTransform(Transform.XPATH2, xp2Spec);
...

Note:

The XPath2 filter expects that the expression returns a Node not a boolean as in the case of XPath. This was very confusing due to the fact that all the examples from the standard are given with XPath syntax.

A very good on-line tool to check the validity of your XPATH2 expressions is https://www.freeformatter.com/xpath-tester.html

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.