Skip to content

Instantly share code, notes, and snippets.

@ewoutkramer
Last active January 3, 2016 03:39
Show Gist options
  • Save ewoutkramer/8403698 to your computer and use it in GitHub Desktop.
Save ewoutkramer/8403698 to your computer and use it in GitHub Desktop.
Code from Furore's Spark FHIR server that is used to validate incoming signed xml data
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace Spark.Service
{
// This code contains parts of the code found at
// http://www.wiktorzychla.com/2012/12/interoperable-xml-digital-signatures-c_20.html
public class XmlSignatureHelper
{
public static bool VerifySignature(string xml)
{
if (xml == null) throw new ArgumentNullException("xml");
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(xml);
// If there's no signature => return that we are "valid"
XmlNode signatureNode = findSignatureElement(doc);
if (signatureNode == null) return true;
SignedXml signedXml = new SignedXml(doc);
signedXml.LoadXml((XmlElement)signatureNode);
//var x509Certificates = signedXml.KeyInfo.OfType<KeyInfoX509Data>();
//var certificate = x509Certificates.SelectMany(cert => cert.Certificates.Cast<X509Certificate2>()).FirstOrDefault();
//if (certificate == null) throw new InvalidOperationException("Signature does not contain a X509 certificate public key to verify the signature");
//return signedXml.CheckSignature(certificate, true);
return signedXml.CheckSignature();
}
private static XmlNode findSignatureElement(XmlDocument doc)
{
var signatureElements = doc.DocumentElement.GetElementsByTagName("Signature", "http://www.w3.org/2000/09/xmldsig#");
if (signatureElements.Count == 1)
return signatureElements[0];
else if (signatureElements.Count == 0)
return null;
else
throw new InvalidOperationException("Document has multiple xmldsig Signature elements");
}
public static bool IsSigned(string xml)
{
if (xml == null) throw new ArgumentNullException("xml");
var doc = new XmlDocument();
doc.LoadXml(xml);
return findSignatureElement(doc) != null;
}
public static string Sign(string xml, X509Certificate2 certificate)
{
if (xml == null) throw new ArgumentNullException("xml");
if (certificate == null) throw new ArgumentNullException("certificate");
if (!certificate.HasPrivateKey) throw new ArgumentException("certificate", "Certificate should have a private key");
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(xml);
SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = certificate.PrivateKey;
// Attach certificate KeyInfo
KeyInfoX509Data keyInfoData = new KeyInfoX509Data(certificate);
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(keyInfoData);
signedXml.KeyInfo = keyInfo;
// Attach transforms
var reference = new Reference("");
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform(includeComments: false));
reference.AddTransform(new XmlDsigExcC14NTransform(includeComments: false));
signedXml.AddReference(reference);
// Compute signature
signedXml.ComputeSignature();
var signatureElement = signedXml.GetXml();
// Add signature to bundle
doc.DocumentElement.AppendChild(doc.ImportNode(signatureElement, true));
return doc.OuterXml;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment