Hi all,
Today I'm posting a sample which signs an XML with or without a certificate (PFX file) and verifies the signature, all that with .NET and its SignedXml class. I won't include in the sample the code that VS designer includes when I add the textboxes and buttons used in the code. I don't think that's needed to understand the code.
<SAMPLE>
Imports System.Xml Imports System.Security Imports System.Security.Cryptography Imports System.Security.Cryptography.Xml Imports System.Security.Cryptography.X509Certificates Public Class Form1 Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code " ... #End Region Private Sub SignButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SignButton.Click ' Generate a signing key. ' Dim Key As New RSACryptoServiceProvider ' Create a new XML document. ' Dim doc As New XmlDocument ' Format using white spaces. ' doc.PreserveWhitespace = True ' Load the passed XML. ' doc.Load(TextBox2.Text) ' Create a SignedXml object. ' Dim signedXml As New SignedXml(doc) ' Add the key to the SignedXml document. ' signedXml.SigningKey = Key ' Create a reference to be signed. ' Dim reference As New Reference reference.Uri = "" ' Add a transformation to the reference. ' Dim trns As XmlDsigC14NTransform = New XmlDsigC14NTransform reference.AddTransform(trns) ' Add an enveloped transformation to the reference. ' Dim env As New XmlDsigEnvelopedSignatureTransform reference.AddTransform(env) ' Add the reference to the SignedXml object. ' signedXml.AddReference(reference) ' Add an RSAKeyValue KeyInfo (optional; helps recipient find key to validate). ' Dim keyInfo As New KeyInfo keyInfo.AddClause(New RSAKeyValue(CType(Key, RSA))) signedXml.KeyInfo = keyInfo ' Compute the signature. ' signedXml.ComputeSignature() ' Get the XML representation of the signature and save ' it to an XmlElement object. ' Dim xmlDigitalSignature As XmlElement = signedXml.GetXml() ' Append the element to the XML document. ' doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, True)) If TypeOf doc.FirstChild Is XmlDeclaration Then doc.RemoveChild(doc.FirstChild) End If ' Show the signature ' ToVerifyTextBox.Text = doc.OuterXml End Sub Private Sub SignWithCerButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SignWithCerButton.Click ' Variables ' Dim bResult As Boolean = False Dim pCertContext As IntPtr = IntPtr.Zero Dim key As RSA = Nothing Dim doc As XmlDocument = Nothing Dim signedXml As SignedXml = Nothing Dim reference As Reference = Nothing Dim trns As XmlDsigC14NTransform = Nothing Dim env As XmlDsigEnvelopedSignatureTransform = Nothing Dim keyInfo As KeyInfo = Nothing Dim xmlDigitalSignature As XmlElement = Nothing Dim cert As X509Certificate2 = Nothing Dim pass As SecureString = Nothing ' Generate a signing key from the subject certificate. ' pass = New SecureString() pass.AppendChar("p") pass.AppendChar("a") pass.AppendChar("s") pass.AppendChar("s") pass.AppendChar("w") pass.AppendChar("o") pass.AppendChar("r") pass.AppendChar("d") cert = New X509Certificate2(TextBox1.Text, pass) key = cert.PrivateKey ' Create a new XML document. ' doc = New XmlDocument ' Format using white spaces. ' doc.PreserveWhitespace = True ' Load the passed XML. ' doc.Load(TextBox2.Text) ' Create a SignedXml object. ' signedXml = New SignedXml(doc) ' Add the key to the SignedXml document. ' signedXml.SigningKey = key ' Create a reference to be signed. ' reference = New Reference reference.Uri = "" ' Add a transformation to the reference. ' trns = New XmlDsigC14NTransform reference.AddTransform(trns) ' Add an enveloped transformation to the reference. ' env = New XmlDsigEnvelopedSignatureTransform reference.AddTransform(env) ' Add the reference to the SignedXml object. ' signedXml.AddReference(reference) ' Add an RSAKeyValue KeyInfo (optional; helps recipient find key to validate). ' 'keyInfo = New KeyInfo 'keyInfo.AddClause(New RSAKeyValue(CType(Key, RSA))) 'signedXml.KeyInfo = keyInfo ' Create a new KeyInfo object. ' keyInfo = New KeyInfo() ' Load the certificate into a KeyInfoX509Data object ' and add it to the KeyInfo object. keyInfo.AddClause(New KeyInfoX509Data(cert)) ' Add the KeyInfo object to the SignedXml object. signedXml.KeyInfo = keyInfo ' Compute the signature. ' signedXml.ComputeSignature() ' Get the XML representation of the signature and save ' it to an XmlElement object. ' xmlDigitalSignature = signedXml.GetXml() ' Append the element to the XML document. ' doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, True)) If TypeOf doc.FirstChild Is XmlDeclaration Then doc.RemoveChild(doc.FirstChild) End If ' Show the signature ' ToVerifyTextBox.Text = doc.OuterXml End Sub Private Sub VerifyButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles VerifyButton.Click ' 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.LoadXml(ToVerifyTextBox.Text) ' 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 show the result. ' If signedXml.CheckSignature() Then MessageBox.Show("Signature verified!") Else MessageBox.Show("Invalid signature!!!") End If End Sub End Class
</SAMPLE>
I hope this helps.
Cheers,
Alex (Alejandro Campos Magencio)
OH! Very good , I want it . Thanks :D
Hi,
What i need to sign the same doc multiple times & then try to verify the same ? How would that work ?
I tired to simply add one more signature to the signing part with a new key & try to get the same from the next node for verification.
In this case the first signature fails but the second one passes. Any clue if wot im doing is right ?
Thanks for helping me on the way with my project!
I've written a class for signing and verifying XML with C# .NET 1.1 using CAPICOM: http://blog.sallarp.com/2009/03/verify-xml-signatures-with-net-1-using-capicom/
Thank you very much for you post. I found it very useful.
Hello,
Hope you are still reading this. I really enjoyed the example. Got a question tough. How can I retrieve the X509Certificate from the signedXMl document ? I want to check also the attached certificate, not only the signature. I tried with GetElementsByTagName("X509Certificate"). This results in a nodelist of 1 element, but how to cast this or convert this to a X509Certificate object ? I want to match this to a list of allowed issuers.
If you have any idea on this, please help me out.
Best regards,
Ronald
Sorry, I have no free time to attend this kind of requests. If you open a case with Microsoft Technical Support, we may be able to assist.
Regards,
Alex