Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sign only specific part of XML

I am trying to do some XML Signature by signing only parts of the xml however after much searching I have not been able to find a solution.

I am using java to sign an XML using Xpath2 transform and EXCLUSIVE canonicalization. If I have the following XML

<?xml version="1.0" encoding="UTF-8"?>
<msg xmlns="http://someaddress/ad/m1" xmlns:ns1="http://someotheraddres/ad/m2" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">
<header>
    <id>wsfrwerwerwer</id>
    <name>addr</name>
    <somenode>
        <trace>ND</trace>
    </somenode>
</header>
<payload><ns0:addr xmlns:ns0="http://someaddres/ad/m3"><ns2:data xmlns:ns2="http://someaddres/ad/m3">
            <ns2:name>somevalue</ns2:name>
            <ns2:value>354</ns2:value>
        </ns2:data>
    </ns0:addr>
</payload>
</msg>

And sign it, I get the following output (Real data replaced with dummy)

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<msg xmlns="http://someaddress/ad/m1" xmlns:ns1="http://someotheraddres/ad/m2" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">
<header>
    <id>wsfrwerwerwer</id>
    <name>addr</name>
    <somenode>
        <trace>ND</trace>
    </somenode>
</header>
<payload>
    <ns0:addr xmlns:ns0="http://someaddres/ad/m3">
        <ns2:data xmlns:ns2="http://someaddres/ad/m3">
            <ns2:name>somevalue</ns2:name>
            <ns2:value>354</ns2:value>
        </ns2:data>
    </ns0:addr>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <Reference URI="">
                <Transforms>
                    <Transform Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
                        <XPath xmlns="http://www.w3.org/2002/06/xmldsig-filter2" xmlns:ns0="http://someaddres/ad/m3" Filter="intersect">//*[local-name()='addr']/*</XPath>
                    </Transform>
                </Transforms>
                <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <DigestValue>sdlfjdeklsdfngf</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>femhjgklnlkl</SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>swerwerwrwerwerwe</X509Certificate>
            </X509Data>
        </KeyInfo>
    </Signature>
</payload>
</msg>

If I validate the signature, everything is fine however the issue here is that right after this I perform an XSLT in the XML which perform some changes to some elements but not the signed element (ns0:addr) which is left intact. Even though I explicitly say that only the "addr" element should be signed, if I try to perform changes to any of its parents (payload, msg or addr), it then fails the signature when (according to my understanding) it should not. If I perform changes to other elements such as anything inside header, the signature is still valid.

I have tested the XPath expression (//*[local-name()='addr']/*) and it selects the correct data to be signed (ns2:data) but it seems to be taking also all elements leading to it starting from the root element (msg, addr).

I have also tried to use different transforms such as UNION but that does not work at all.

Does anybody know what the issue might be? Is there any way, in Java, to see exactly what is being signed when signing the XML for debugging purposes?

EDIT:

The xslt run later will be doing things like moving namespaces from the ns0:addr element to the root element (msg) and also it will be changing the main element name and namespace from msg to newmsg (and a different default namespace) but leaving the signed data (ns2:data) intact.

The code used to sign it is more or less the code mentioned here http://docs.oracle.com/javase/7/docs/technotes/guides/security/xmldsig/XMLDigitalSignature.html

Except instead of a ENVELOPED transform I am using an XPATH2 transform:

Map<String, String> namespaceMap = new HashMap<String, String>(0);
namespaceMap.put("ns0", "http://someaddres/ad/m3");
XPathType xPathType = new XPathType(xPathParameters, Filter.INTERSECT, namespaceMap);
List<XPathType> xPathList = new ArrayList<XPathType>(0);
xPathList.add(xPathType)
XPathFilter2ParameterSpec xPathFilter2ParameterSpec = new XPathFilter2ParameterSpec(xPathList);
transform = fac.newTransform(CanonicalizationMethod.XPATH2, xPathFilter2ParameterSpec);

And also instead of ENVELOPED I am using EXCLUSIVE

canonicalisationMethod = fac.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null);

EDIT2:

I have managed to enable finer debugging of the xml signing process and got the following:

FINER: Pre-digested input: 21-Sep-2012 10:51:39 org.jcp.xml.dsig.internal.DigesterOutputStream write FINER: <ns2:data xmlns="http://someaddress/ad/m1" xmlns:ns0="http://someaddres/ad/m3" xmlns:ns1="http://someotheraddres/ad/m2" xmlns:ns2="http://someaddres/ad/m3"> <ns2:name>somevalue</ns2:name> <ns2:value>354</ns2:value> </ns2:data>

It seems to be signing the correct data however it is also adding some extra namespaces to the signature which makes me wonder if that is the issue since those namspaces are taken from the parent elements.

Anybody know how to make it not get all extra namespaces added?

like image 621
Alexandre Thenorio Avatar asked Sep 20 '12 12:09

Alexandre Thenorio


People also ask

What is digital signature in XML?

An XML digital signature (XML DSIG) is an electronic, encrypted, stamp of authentication on digital information such as messages. The digital signature confirms that the information originated from the signer and was not altered in transmission.

What is signature value in XML?

The <SignatureValue> element is a subelement of the <Signature> element. Use the SignatureValue property to retrieve the value of the XML digital signature. This property is automatically populated when you make a successful call to the ComputeSignature method.


1 Answers

After much fighting with XML Signatures I finally arrived at an acceptable solution (though not ideal).

As it turns out an Exclusive canonicalization is not enough. You need to also add an Exclusive transform after all other transformers. Following the code snippets I wrote above:

List<Transform> transforms = new ArrayList<Transform>()
transforms.add(transform)
fac.newTransform(CanonicalizationMethod.EXCLUSIVE, (TransformParameterSpec) null)

This will make it so that any other namespaces outside of the signed elements will not be taken into account (though it has the added effect that inserting namespace(s) inside the signed element is allowed).

Also it seems that any element in the xpath to the signed element will be taken into account so if you have the following xpath /root/A/B it will sign tag B however you will not be able to change the tag name of either A or root elements.

This can be overcome by using an xpath with less elements in it such as //B.

I believe it may be possible to overcome this issue too though so far I have not been able to.

like image 84
Alexandre Thenorio Avatar answered Sep 29 '22 02:09

Alexandre Thenorio