An Always Valid XML Signature

XML Signatures are powerful, but also a bit tricky to get right. Here’s a challenge: I have a signature that will validate, even though the contents of the XML document are altered.

This is the “magic” signature that validates regardless of what XML document it is placed in.

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
  </SignedInfo>
  <SignatureValue>ZlSHRu+tG6bVTPxyKvp2PcNqg+lVmBSB2TnzABa2eJZiFcIBtD4/0dhT8Mhr+TbcpzGTbPgMFOx1JmZzfQVzbcMUJfnU674C368VlULAnRa3Avqb+MNJWdAIT8cgdB1yJyZbtuChww13e2CMhikW+xZhaZFzD11KTKqiR+7DRcd+k026w7y6JYy/XgUkS3y1MzuUFO0Uk+tIKI2ik/iLH0XvO0TFO+5uLoz3VaVYj4BIgwFZlYFE/y36EVTeVC4fW7bxPiLdKfZNMin2ZpOusgr/Lyp+J5NQBUOV1FklGsHJbFLN7GJcaUBwnmAib8yReVmAIjsEWBRhB5b6TLojbw==</SignatureValue>
  <KeyInfo>
     <X509Data>
        <X509Certificate>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</X509Certificate>
     </X509Data>
  </KeyInfo>
</Signature>

I’ve made a small test program where I try it out.

var signature = "<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><SignedInfo><CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\" /><SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\" /></SignedInfo><SignatureValue>ZlSHRu+tG6bVTPxyKvp2PcNqg+lVmBSB2TnzABa2eJZiFcIBtD4/0dhT8Mhr+TbcpzGTbPgMFOx1JmZzfQVzbcMUJfnU674C368VlULAnRa3Avqb+MNJWdAIT8cgdB1yJyZbtuChww13e2CMhikW+xZhaZFzD11KTKqiR+7DRcd+k026w7y6JYy/XgUkS3y1MzuUFO0Uk+tIKI2ik/iLH0XvO0TFO+5uLoz3VaVYj4BIgwFZlYFE/y36EVTeVC4fW7bxPiLdKfZNMin2ZpOusgr/Lyp+J5NQBUOV1FklGsHJbFLN7GJcaUBwnmAib8yReVmAIjsEWBRhB5b6TLojbw==</SignatureValue><KeyInfo><X509Data><X509Certificate>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</X509Certificate></X509Data></KeyInfo></Signature>";
 
var xml = new[] 
{
  $"<a>{signature}</a>",
  $"<x><b>green</b>{signature}<c>Red</c></x>"
};
 
foreach (var x in xml)
{
  var xmlDoc = new XmlDocument();
  xmlDoc.LoadXml(x);
 
  var signedXml = new SignedXml(xmlDoc);
  var signatureNode = xmlDoc.DocumentElement["Signature", SignedXml.XmlDsigNamespaceUrl];
  signedXml.LoadXml((XmlElement)signatureNode);
 
  Console.WriteLine("Signature of xml with root <"
    + xmlDoc.DocumentElement.LocalName
    + "> validation result: "
    + signedXml.CheckSignature());
}

Running it gives the following output:

Signature of xml with root <a> validation result: True
Signature of xml with root <x> validation result: True

Please try yourself by adding more xml examples to the array, or altering the existing. As long as you don’t add prefixed xml namespaces it should validate until 24th of April 2016 which is the expiration date on the certificate I used.

A signature is used to ensure integrity of the XML. It is used in security solutions such as SAML2 to ensure that the XML has not been tampered with. But, in this example the XML can be changed arbitrarily and still validate. How come? I’ll show why in a follow up post.

Leave a comment

Your email address will not be published. Required fields are marked *

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