title: How to verify digital XML signature
body: <p>I want to verify that the document was not be modified in any way.</p>
  
  <p>From a Java web service, I receive the following Soap response with a digital <strong>XML signature</strong>:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"&gt;&lt;SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"&gt;  
  &lt;wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" SOAP-ENV:mustUnderstand="1"&gt;
  &lt;wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="CertId-38670273"&gt;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&lt;/wsse:BinarySecurityToken&gt;&lt;ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&gt;
  &lt;ds:SignedInfo&gt;
  &lt;ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
  &lt;ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/&gt;
  &lt;ds:Reference URI="#id-32516734"&gt;
  &lt;ds:Transforms&gt;
  &lt;ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
  &lt;/ds:Transforms&gt;
  &lt;ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
  &lt;ds:DigestValue&gt;Rx5L4j8kF5RVYnC+spUCdvhh5N0=&lt;/ds:DigestValue&gt;
  &lt;/ds:Reference&gt;
  &lt;ds:Reference URI="#id-7716709"&gt;
  &lt;ds:Transforms&gt;
  &lt;ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&gt;
  &lt;/ds:Transforms&gt;
  &lt;ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&gt;
  &lt;ds:DigestValue&gt;fFr2j5DoKTgpEvX1Se7gTC55bWM=&lt;/ds:DigestValue&gt;
  &lt;/ds:Reference&gt;
  &lt;/ds:SignedInfo&gt;
  &lt;ds:SignatureValue&gt;
  jG1BaGgNbbk9JCc3R6JsJKY56p++f0+8RM2aL6TGOXS34NAGv48Sp3iAHEAuUt9+JV6w3VDAcFct
  no3nCEISa0P4dVWTlPQJue3GVTWnnlcXao95tjukh9o8lIU7vZGgYHBUZLU+jgS6ZcaUlNW4KFUl
  AdrPxR5DmJcFyGEtRY2yclqYhnJdnUc+ZBu5eWbRZgbJzR4MgtGsEQcgtftFe2i0CvRbOSe4mt3T
  JQzbGY81ssFCnB44vitgjhVLfPd/08amSa5Xn8KRptbNatp2uq1iGXAifJLVup8T0yS0RzaqhCJg
  CaHRPFVKFN3WaJcqPZex75KBwSZMZaaJDZW7lQ==
  &lt;/ds:SignatureValue&gt;
  &lt;ds:KeyInfo Id="KeyId-16708261"&gt;
  &lt;wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-32258670"&gt;&lt;wsse:Reference URI="#CertId-38670273" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/&gt;&lt;/wsse:SecurityTokenReference&gt;
  &lt;/ds:KeyInfo&gt;
  &lt;/ds:Signature&gt;
  &lt;wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-32516734"&gt;&lt;wsu:Created&gt;2017-03-31T09:04:40.352Z&lt;/wsu:Created&gt;&lt;wsu:Expires&gt;2017-03-31T09:09:40.352Z&lt;/wsu:Expires&gt;&lt;/wsu:Timestamp&gt;&lt;/wsse:Security&gt;&lt;wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" SOAP-ENV:mustUnderstand="0"&gt;uuid:12b93a00-15f1-11e7-af6b-f16d80f418ae&lt;/wsa:MessageID&gt;&lt;wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" SOAP-ENV:mustUnderstand="0"&gt;http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous&lt;/wsa:To&gt;&lt;/SOAP-ENV:Header&gt;
  
  
  &lt;SOAP-ENV:Body xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-7716709"&gt;
  ...
   &lt;/SOAP-ENV:Body&gt;&lt;/Envelope&gt;
  </code></pre>
  
  <p>I've found an usefull example to verify the xml file on <a href="https://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.xmldsigexcc14ntransform.inclusivenamespacesprefixlist(v=vs.110).aspx" rel="nofollow noreferrer">MSDN</a>:</p>
  
  <pre><code>  ' Verify the signature of an XML file and return the result.
  Function VerifyXmlFile(ByVal Name As String) As [Boolean]
      ' Create a new XML document.
      Dim xmlDocument As New XmlDocument()
  
      ' Format using white spaces.
      xmlDocument.PreserveWhitespace = True
  
      ' Load the passed XML file into the document. 
      xmlDocument.Load(Name)
  
      ' Create a new SignedXml object and pass it
      ' the XML document class.
      Dim signedXml As New SignedXml(xmlDocument)
  
      ' Find the "Signature" node and create a new
      ' XmlNodeList object.
       Dim nodeList As XmlNodeList = xmlDocument.GetElementsByTagName("Signature", "http://www.w3.org/2000/09/xmldsig#")
  
      ' Load the signature node.
      signedXml.LoadXml(CType(nodeList(0), XmlElement))
  
      ' Check the signature and return the result.
      Return signedXml.CheckSignature()
  
  End Function
  </code></pre>
  
  <p>Unfortunately, the verification always returns false. I struggle to understand why it doesn't work.</p>
  
  <hr>
  
  <p><strong>UPDATE 1</strong> according to the proposals from <a href="https://stackoverflow.com/users/60761/henk-holterman">Henk Holterman </a> and <a href="https://stackoverflow.com/users/403671/simon-mourier">Simon Mourier</a>:</p>
  
  <pre><code> Function VerifyXmlFile(ByVal Name As String) As Boolean
  
      ' &lt;SOAP-ENV:Envelope ... &gt; ... &lt;/SOAP-ENV:Envelope&gt;
      Dim xDoc = XDocument.Load(Name)
  
      ' &lt;wsse:binarySecurityToken ... &gt; ... &lt;/wsse:binarySecurityToken&gt;
      Dim xBinarySecurityToken = xDoc.Root.Descendants().Skip(2).FirstOrDefault
  
      ' &lt;SOAP-ENV:Body ... &gt; ... &lt;/SOAP-ENV:Body&gt;
      Dim xBody = xDoc.Root.Elements().Skip(1).FirstOrDefault
      Dim signedXml = New SignedXml(ToXmlElement(xBody))
  
      Dim xmlDocument As New XmlDocument()
      xmlDocument.PreserveWhitespace = True
      xmlDocument.Load(Name)
  
      Dim nodeList = xmlDocument.GetElementsByTagName("Signature", "http://www.w3.org/2000/09/xmldsig#")
      signedXml.LoadXml(CType(nodeList(0), XmlElement))
  
      Dim byteCert = Encoding.UTF8.GetBytes(xBinarySecurityToken.Value)
      Dim cert = New X509Certificates.X509Certificate2(byteCert)
  
      Return signedXml.CheckSignature(cert, True)
  
  End Function
  
  Public Shared Function ToXmlElement(xElement As XElement) As XmlElement
      Dim xmlDoc = New XmlDocument() With {.PreserveWhitespace = True}
      xmlDoc.Load(xElement.CreateReader())
      Return xmlDoc.DocumentElement
  End Function
  </code></pre>
  
  <p>Resulted in a <strong>CryptographicException</strong> with the message "<strong>Malformed reference element</strong>" by calling the function <strong>CheckSignature()</strong>.</p>
  
  <hr>
  
  <p><strong>UPDATE 2 and SOLUTION</strong> according to the proposals from @SimonMourier and @lax1089</p>
  
  <pre><code>Private Function VerifyXmlfile(Name As String) As Boolean
      CryptoConfig.AddAlgorithm(GetType(MyXmlDsigC14NTransform), "http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
  
      Dim xmlDocument As New XmlDocument()
      xmlDocument.PreserveWhitespace = True
      xmlDocument.Load(Name)
      MyXmlDsigC14NTransform.document = xmlDocument
  
      Dim soapBody As XmlElement = xmlDocument.GetElementsByTagName("SOAP-ENV:Body")(0)
      Dim securityToken = xmlDocument.GetElementsByTagName("SOAP-ENV:Header")(0).FirstChild.NextSibling.FirstChild.NextSibling.InnerText
  
      Dim signedXml = New SignedXmlWithId(soapBody)
  
      Dim nodeList = xmlDocument.GetElementsByTagName("Signature", "http://www.w3.org/2000/09/xmldsig#")
      signedXml.LoadXml(CType(nodeList(0), XmlElement))
  
      Dim byteCert = Convert.FromBase64String(securityToken)
      Dim cert = New X509Certificates.X509Certificate2(byteCert)
  
      Return signedXml.CheckSignature(cert, True)
  
  End Function
  </code></pre>
  
  <p>A helper class stolen from <a href="https://stackoverflow.com/a/6467877">Dog Ears</a></p>
  
  <pre><code>Public Class SignedXmlWithId
  Inherits SignedXml
  
  Public Sub New(xml As XmlDocument)
      MyBase.New(xml)
  End Sub
  
  Public Sub New(xmlElement As XmlElement)
      MyBase.New(xmlElement)
  End Sub
  
  Public Overrides Function GetIdElement(doc As XmlDocument, id As String) As XmlElement
      ' check to see if it's a standard ID reference
      Dim idElem As XmlElement = MyBase.GetIdElement(doc, id)
  
      If idElem Is Nothing Then
          Dim nsManager As New XmlNamespaceManager(doc.NameTable)
          nsManager.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")
  
          idElem = TryCast(doc.SelectSingleNode((Convert.ToString("//*[@wsu:Id=""") &amp; id) + """]", nsManager), XmlElement)
      End If
  
      Return idElem
  End Function
  
  End Class
  </code></pre>
  
  <p>Credits to <a href="https://stackoverflow.com/questions/43939085/how-to-verify-digital-xml-signature#comment75157884_43939085">@SimonMourier</a> and <a href="https://stackoverflow.com/a/27257036/4033690">@CarlosLopez-MSFT</a></p>