void CheckProperties(XmlDsigExcC14NWithCommentsTransform transform) { Assert.Equal("http://www.w3.org/2001/10/xml-exc-c14n#WithComments", transform.Algorithm); Type[] input = transform.InputTypes; Assert.Equal(3, input.Length); // check presence of every supported input types bool istream = false; bool ixmldoc = false; bool ixmlnl = false; foreach (Type t in input) { if (t == typeof(Stream)) { istream = true; } if (t == typeof(XmlDocument)) { ixmldoc = true; } if (t == typeof(XmlNodeList)) { ixmlnl = true; } } Assert.True(istream, "Input Stream"); Assert.True(ixmldoc, "Input XmlDocument"); Assert.True(ixmlnl, "Input XmlNodeList"); Type[] output = transform.OutputTypes; Assert.Equal(1, output.Length); Assert.Equal(typeof(Stream), output[0]); }
// Sign an XML file and save the signature in a new file. public static void SignXmlFile(string FileName, string SignedFileName, RSA Key) { // Create a new XML document. XmlDocument doc = new XmlDocument(); // Format the document to ignore white spaces. doc.PreserveWhitespace = false; // Load the passed XML file using it's name. doc.Load(new XmlTextReader(FileName)); // Create a SignedXml object. SignedXml signedXml = new SignedXml(doc); // Add the key to the SignedXml document. signedXml.SigningKey = Key; // Specify a canonicalization method. signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NWithCommentsTransformUrl; // Set the InclusiveNamespacesPrefixList property. XmlDsigExcC14NWithCommentsTransform canMethod = (XmlDsigExcC14NWithCommentsTransform)signedXml.SignedInfo.CanonicalizationMethodObject; canMethod.InclusiveNamespacesPrefixList = "Sign"; // Create a reference to be signed. Reference reference = new Reference(); reference.Uri = ""; // Add an enveloped transformation to the reference. XmlDsigEnvelopedSignatureTransform 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 keyInfo = new KeyInfo(); keyInfo.AddClause(new RSAKeyValue((RSA)Key)); signedXml.KeyInfo = keyInfo; // Compute the signature. signedXml.ComputeSignature(); // Get the XML representation of the signature and save // it to an XmlElement object. XmlElement xmlDigitalSignature = signedXml.GetXml(); // Append the element to the XML document. doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true)); if (doc.FirstChild is XmlDeclaration) { doc.RemoveChild(doc.FirstChild); } // Save the signed XML document to a file specified // using the passed string. XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false)); doc.WriteTo(xmltw); xmltw.Close(); }
/// <summary> /// Signs the specified xml document with the certificate found in /// the local machine matching the provided friendly name and /// referring to the specified target reference ID. /// </summary> /// <param name="certFriendlyName"> /// Friendly Name of the X509Certificate to be retrieved /// from the LocalMachine keystore and used to sign the xml document. /// Be sure to have appropriate permissions set on the keystore. /// </param> /// <param name="xmlDoc"> /// XML document to be signed. /// </param> /// <param name="targetReferenceId"> /// Reference element that will be specified as signed. /// </param> /// <param name="includePublicKey"> /// Flag to determine whether to include the public key in the /// signed xml. /// </param> /// <param name="serviceProviderInstance"> /// ServiceProvider instance for retreaving Signature transform /// and canonicalization method /// </param> public static void SignXml(string certFriendlyName, IXPathNavigable xmlDoc, string targetReferenceId, bool includePublicKey, ServiceProvider serviceProviderInstance) { if (string.IsNullOrEmpty(certFriendlyName)) { throw new Saml2Exception(Resources.SignedXmlInvalidCertFriendlyName); } if (xmlDoc == null) { throw new Saml2Exception(Resources.SignedXmlInvalidXml); } if (string.IsNullOrEmpty(targetReferenceId)) { throw new Saml2Exception(Resources.SignedXmlInvalidTargetRefId); } X509Certificate2 cert = FedletCertificateFactory.GetCertificateByFriendlyName(certFriendlyName); if (cert == null) { throw new Saml2Exception(Resources.SignedXmlCertNotFound); } XmlDocument xml = (XmlDocument)xmlDoc; SignedXml signedXml = new SignedXml(xml); signedXml.SigningKey = cert.PrivateKey; if (includePublicKey) { KeyInfo keyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509Data(cert)); signedXml.KeyInfo = keyInfo; } Reference reference = new Reference(); reference.Uri = "#" + targetReferenceId; //Read the transform type and canonicalization method from sp-extended.xml string transformType = serviceProviderInstance.SignatureTransformMethod; string canonicalizationMethodType = serviceProviderInstance.CanonicalizationMethod; Transform sigTransform; //Implement the gathered data switch (transformType) { case "XmlDsigExcC14NTransform": sigTransform = new XmlDsigExcC14NTransform(); break; case "XmlDsigExcC14NWithCommentsTransform": sigTransform = new XmlDsigExcC14NWithCommentsTransform(); break; default: sigTransform = new XmlDsigEnvelopedSignatureTransform(); break; } if (canonicalizationMethodType != null && (canonicalizationMethodType == SignedXml.XmlDsigExcC14NTransformUrl || canonicalizationMethodType == SignedXml.XmlDsigExcC14NWithCommentsTransformUrl)) { signedXml.Signature.SignedInfo.CanonicalizationMethod = canonicalizationMethodType; } reference.AddTransform(sigTransform); signedXml.AddReference(reference); signedXml.ComputeSignature(); XmlElement xmlSignature = signedXml.GetXml(); XmlNamespaceManager nsMgr = new XmlNamespaceManager(xml.NameTable); nsMgr.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); nsMgr.AddNamespace("saml", Saml2Constants.NamespaceSamlAssertion); nsMgr.AddNamespace("samlp", Saml2Constants.NamespaceSamlProtocol); XmlNode issuerNode = xml.DocumentElement.SelectSingleNode("saml:Issuer", nsMgr); if (issuerNode != null) { xml.DocumentElement.InsertAfter(xmlSignature, issuerNode); } else { // Insert as a child to the target reference id XmlNode targetNode = xml.DocumentElement.SelectSingleNode("//*[@ID='" + targetReferenceId + "']", nsMgr); targetNode.PrependChild(xmlSignature); } }
public static void ReaderWriter_C14N_DifferentReadersWriters() { int count = 0; var params1 = TestConfigHelper.GetTest("ReaderWriter_C14N_DifferentReadersWriters_ParamGroup1"); var params2 = TestConfigHelper.GetTest("ReaderWriter_C14N_DifferentReadersWriters_ParamGroup2"); var params3 = TestConfigHelper.GetTest("ReaderWriter_C14N_DifferentReadersWriters_ParamGroup3"); var params4 = TestConfigHelper.GetTest("ReaderWriter_C14N_DifferentReadersWriters_ParamGroup4"); Transform transform; MemoryStream canonicalStream; MemoryStream ms; Stream transformedOutput; byte[] outputFromSecurity; byte[] outputFromIndigo; //TestC14NInMultipleWriters foreach (var input in params1.Inputs) { foreach (var input2 in params2.Inputs) { foreach (var input3 in params3.Inputs) { count++; string rwTypeStr = input.Arguments[0].Value; ReaderWriterFactory.ReaderWriterType rwType = (ReaderWriterFactory.ReaderWriterType)Enum.Parse(typeof(ReaderWriterFactory.ReaderWriterType), rwTypeStr, true); Encoding encoding = Encoding.GetEncoding((string)input.Arguments[1].Value); string sampleXmlFileName = input2.Arguments[0].Value; bool mustSupportV14N = input.Arguments[2].Value == "true"; string baselineFileName = input2.Arguments[1].Value; bool testWithComments = input3.Arguments[0].Value == "true"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.PreserveWhitespace = true; if (testWithComments) { transform = new XmlDsigExcC14NWithCommentsTransform(); } else { transform = new XmlDsigExcC14NTransform(); } xmlDoc.Load(baselineFileName); transform.LoadInput(xmlDoc); transformedOutput = transform.GetOutput(typeof(Stream)) as Stream; outputFromSecurity = StreamToByteArray(transformedOutput); byte[] sampleXmlFileBytes = File.ReadAllBytes(sampleXmlFileName); ms = new MemoryStream(); XmlWriter w = ReaderWriterFactory.CreateXmlWriter(rwType, ms, encoding); canonicalStream = new MemoryStream(); XmlDictionaryWriter dicWriter = w as XmlDictionaryWriter; if (dicWriter == null) { dicWriter = XmlDictionaryWriter.CreateDictionaryWriter(w); } if (!dicWriter.CanCanonicalize) { Assert.False(mustSupportV14N, "Error, writer should support C14N, but it doesn't!"); continue; } dicWriter.WriteStartElement("MyRoot"); dicWriter.StartCanonicalization(canonicalStream, testWithComments, null); FileStream fs = File.OpenRead(sampleXmlFileName); XmlReader webdataReader = XmlReader.Create(fs); CopyXmlToWriter(webdataReader, dicWriter); dicWriter.EndCanonicalization(); dicWriter.WriteEndElement(); dicWriter.Flush(); webdataReader.Close(); fs.Close(); outputFromIndigo = canonicalStream.ToArray(); Helper.DumpToFile(outputFromSecurity); Helper.DumpToFile(outputFromIndigo); Assert.True(Enumerable.SequenceEqual(outputFromSecurity, outputFromIndigo), $"ReaderWriter_C14N_DifferentReadersWriters test variation #{count} failed"); } } } //TestC14NInReader foreach (var input in params4.Inputs) { count++; string sampleXmlFileName = input.Arguments[3].Value; string rwTypeStr = input.Arguments[0].Value; ReaderWriterFactory.ReaderWriterType rwType = (ReaderWriterFactory.ReaderWriterType)Enum.Parse(typeof(ReaderWriterFactory.ReaderWriterType), rwTypeStr, true); Encoding encoding = Encoding.GetEncoding((string)input.Arguments[1].Value); bool mustSupportV14N = input.Arguments[2].Value == "true"; string baselineFileName = "ReaderWriter_C14N_BaselineXML_OnlyLF.xml"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.PreserveWhitespace = true; transform = new XmlDsigExcC14NTransform(); xmlDoc.Load(baselineFileName); transform.LoadInput(xmlDoc); transformedOutput = transform.GetOutput(typeof(Stream)) as Stream; outputFromSecurity = StreamToByteArray(transformedOutput); byte[] sampleXmlFileBytes = File.ReadAllBytes(sampleXmlFileName); XmlReader r = ReaderWriterFactory.CreateXmlReader(rwType, sampleXmlFileBytes, encoding); XmlDictionaryReader dicReader = r as XmlDictionaryReader; if (dicReader == null) { dicReader = XmlDictionaryReader.CreateDictionaryReader(r); } canonicalStream = new MemoryStream(); if (!dicReader.CanCanonicalize) { Assert.False(mustSupportV14N, "Error, reader should support C14N, but it doesn't!"); continue; } dicReader.StartCanonicalization(canonicalStream, false, null); canonicalStream.Position = 0; string str = new StreamReader(canonicalStream).ReadToEnd(); canonicalStream.Position = 0; while (dicReader.Read()) { ; // simply read it all into the C14N writer } dicReader.EndCanonicalization(); dicReader.Close(); outputFromIndigo = canonicalStream.ToArray(); Helper.DumpToFile(outputFromSecurity); Helper.DumpToFile(outputFromIndigo); Assert.True(Enumerable.SequenceEqual(outputFromSecurity, outputFromIndigo), $"ReaderWriter_C14N_DifferentReadersWriters test variation #{count} failed"); } //TestC14NWriterWithManyAttributes int numberOfAttributes = 1000; int seed = (int)DateTime.Now.Ticks; Random rndGen = new Random(seed); StringBuilder sb = new StringBuilder(); sb.Append("<Root><Element"); int prefixIndex = 0; for (int i = 0; i < numberOfAttributes; i++) { string namespaceUri = null; string prefix = null; if ((rndGen.Next() % 5) == 0) { prefix = "p" + (prefixIndex++); namespaceUri = "http://namespace_" + i; } string localName = "attr" + i; string value = "attrValue" + i; if (prefix == null) { sb.Append($" {localName}=\"{value}\""); } else { sb.Append($" {prefix}:{localName}=\"{2}\" xmlns:{value}=\"{namespaceUri}\""); } } sb.Append(">Hello world</Element></Root>"); string xmlString = sb.ToString(); XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlString); ms = new MemoryStream(); XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(ms); canonicalStream = new MemoryStream(); writer.StartCanonicalization(canonicalStream, false, null); doc.WriteTo(writer); writer.Flush(); writer.EndCanonicalization(); outputFromIndigo = canonicalStream.ToArray(); byte[] nonCanonicalOutput = ms.ToArray(); XmlDsigExcC14NTransform transform2 = new XmlDsigExcC14NTransform(); transform2.LoadInput(doc); transformedOutput = transform2.GetOutput(typeof(Stream)) as Stream; outputFromSecurity = StreamToByteArray(transformedOutput); Helper.DumpToFile(outputFromSecurity); Helper.DumpToFile(outputFromIndigo); Helper.DumpToFile(nonCanonicalOutput); Assert.True(Enumerable.SequenceEqual(outputFromSecurity, outputFromIndigo), $"ReaderWriter_C14N_DifferentReadersWriters test variation #{count} failed"); count++; Assert.Equal(params1.Inputs.Count * params2.Inputs.Count * params3.Inputs.Count + params4.Inputs.Count + 1, count); }
/// <summary> /// Signs the specified xml document with the certificate found in /// the local machine matching the provided friendly name and /// referring to the specified target reference ID. /// </summary> /// <param name="certFriendlyName"> /// Friendly Name of the X509Certificate to be retrieved /// from the LocalMachine keystore and used to sign the xml document. /// Be sure to have appropriate permissions set on the keystore. /// </param> /// <param name="xmlDoc"> /// XML document to be signed. /// </param> /// <param name="targetReferenceId"> /// Reference element that will be specified as signed. /// </param> /// <param name="includePublicKey"> /// Flag to determine whether to include the public key in the /// signed xml. /// </param> /// <param name="signatureSigningAlgorithm"> /// The algorithm used to sign the xml. /// </param> /// <param name="digestAlgorithm"> /// The method used to create the message digest. /// </param> /// <param name="serviceProviderInstance"> /// ServiceProvider instance for retreaving Signature transform /// and canonicalization method /// </param> public static void SignXml(string certFriendlyName, IXPathNavigable xmlDoc, string targetReferenceId, bool includePublicKey, string signatureSigningAlgorithm, string digestAlgorithm, ServiceProvider serviceProviderInstance) { if (string.IsNullOrEmpty(certFriendlyName)) { throw new Saml2Exception(Resources.SignedXmlInvalidCertFriendlyName); } if (xmlDoc == null) { throw new Saml2Exception(Resources.SignedXmlInvalidXml); } if (string.IsNullOrEmpty(targetReferenceId)) { throw new Saml2Exception(Resources.SignedXmlInvalidTargetRefId); } X509Certificate2 cert = FedletCertificateFactory.GetCertificateByFriendlyName(certFriendlyName); if (cert == null) { throw new Saml2Exception(Resources.SignedXmlCertNotFound); } XmlDocument xml = (XmlDocument)xmlDoc; SignedXml signedXml = new SignedXml(xml); var cspParams = new CspParameters(24) { KeyContainerName = "XML_DISG_RSA_KEY" }; var key = new RSACryptoServiceProvider(cspParams); key.FromXmlString(cert.PrivateKey.ToXmlString(true)); signedXml.SigningKey = key; if (includePublicKey) { KeyInfo keyInfo = new KeyInfo(); keyInfo.AddClause(new KeyInfoX509Data(cert)); signedXml.KeyInfo = keyInfo; } Reference reference = new Reference(); reference.Uri = "#" + targetReferenceId; //Read the transform type, signature digest and canonicalization method from sp-extended.xml string transformType = serviceProviderInstance.SignatureTransformMethod; string canonicalizationMethodType = serviceProviderInstance.CanonicalizationMethod; Transform sigTransform; //Implement the gathered data switch (transformType) { case "XmlDsigExcC14NTransform": sigTransform = new XmlDsigExcC14NTransform(); break; case "XmlDsigExcC14NWithCommentsTransform": sigTransform = new XmlDsigExcC14NWithCommentsTransform(); break; default: sigTransform = new XmlDsigEnvelopedSignatureTransform(); break; } if (canonicalizationMethodType != null && (canonicalizationMethodType == SignedXml.XmlDsigExcC14NTransformUrl || canonicalizationMethodType == SignedXml.XmlDsigExcC14NWithCommentsTransformUrl)) { signedXml.Signature.SignedInfo.CanonicalizationMethod = canonicalizationMethodType; } reference.AddTransform(sigTransform); bool bIsUsingExtendedAlgorithms = false; if (!String.IsNullOrEmpty(digestAlgorithm)) { reference.DigestMethod = digestAlgorithm; if (!digestAlgorithm.ToLowerInvariant().Contains("xmldsig#sha1")) { bIsUsingExtendedAlgorithms = true; } } signedXml.AddReference(reference); if (!String.IsNullOrEmpty(signatureSigningAlgorithm)) { signedXml.SignedInfo.SignatureMethod = signatureSigningAlgorithm; if (!signatureSigningAlgorithm.ToLowerInvariant().Contains("-sha1")) { bIsUsingExtendedAlgorithms = true; } } if (bIsUsingExtendedAlgorithms && !FedletSignedSignatureSupportSingleton.IsInitialised) { throw new Saml2Exception(Resources.ExtendedAlgorithmsUnavailable); } signedXml.ComputeSignature(); XmlElement xmlSignature = signedXml.GetXml(); XmlNamespaceManager nsMgr = new XmlNamespaceManager(xml.NameTable); nsMgr.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); nsMgr.AddNamespace("saml", Saml2Constants.NamespaceSamlAssertion); nsMgr.AddNamespace("samlp", Saml2Constants.NamespaceSamlProtocol); XmlNode issuerNode = xml.DocumentElement.SelectSingleNode("saml:Issuer", nsMgr); if (issuerNode != null) { xml.DocumentElement.InsertAfter(xmlSignature, issuerNode); } else { // Insert as a child to the target reference id XmlNode targetNode = xml.DocumentElement.SelectSingleNode("//*[@ID='" + targetReferenceId + "']", nsMgr); targetNode.PrependChild(xmlSignature); } }