Error Singed XML SOAP

luis E. alvarez G 1 Reputation point
2020-06-24T17:08:44.863+00:00

Good morning dear, I have an application in c #, which generates an xml document and must be sent by signed SOAP to the government entity, this entity gives a pdf indicating how it should look, try the SOAPUI program and it is sent correctly, the problem is In my application, my signed SOAP is very similar to SOAPUI, but it is not sent, it gives me an error 500, here is my code

XML SOAPUI
10550-sendtestfe.xml

XML APP C#
10519-sendtestfe2.xml

My code

       private void button1_Click(object sender, EventArgs e)  
        {  
            try  
            {  
                string c_GUID = Guid.NewGuid().ToString().Replace("-", "");  
                // Generate a signing key.  
                string rutaCer = $@"{Application.StartupPath}\Certificado.p12";  
                //X509Certificate2 cert = new X509Certificate2(ConvertirCertificadoEnBytes(rutaCer), "Certificado123.", X509KeyStorageFlags.Exportable);  
                X509Certificate2 cert = new X509Certificate2(rutaCer, "Certificado123.", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);  
  
                //RSACryptoServiceProvider Key = GetCertificateKey(cert);  
  
                // Create an XML file to sign.  
                CreateSomeXml("Example.xml", cert, c_GUID);  
                Console.WriteLine("New XML file created.");  
  
                // Sign the XML that was just created and save it in a   
                // new file.  
                SignXmlFile("Example.xml", "signedExample.xml", cert, c_GUID);  
                Console.WriteLine("XML file signed.");  
  
                // Verify the signature of the signed XML.  
                Console.WriteLine("Verifying signature...");  
                bool result = VerifyXmlFile("SignedExample.xml", cert);  
  
                // Display the results of the signature verification to   
                // the console.  
                if (result)  
                {  
                    Console.ForegroundColor = ConsoleColor.Green;  
                    Console.WriteLine("The XML signature is valid.");  
                }  
                else  
                {  
                    Console.ForegroundColor = ConsoleColor.Red;  
                    Console.WriteLine("The XML signature is not valid.");  
                    MessageBox.Show("The XML signature is not valid.");  
                }  
            }  
            catch (CryptographicException ex)  
            {  
                Console.ForegroundColor = ConsoleColor.Yellow;  
                Console.WriteLine(ex.Message);  
            }  
        }  

        public static void CreateSomeXml(string FileName, X509Certificate2 cert, string c_GUID)  
        {  
            // Create a new XmlDocument object.  
            XmlDocument document = new XmlDocument();  
            document.PreserveWhitespace = true;  
            string binarySecToken = Convert.ToBase64String(cert.RawData);  
            //@"<?xml version=""1.0"" encoding=""utf-8""?>"  
            document.LoadXml(@"<?xml version=""1.0""?>" +  
                             @"<soap:Envelope xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"" xmlns:wcf=""http://wcf.dian.colombia"">" +  
                             @"  <soap:Header xmlns:wsa=""http://www.w3.org/2005/08/addressing"">" +  
                             @"    <wsse:Security xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"" xmlns:wsu=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"">" +  
                             @"      <wsu:Timestamp wsu:Id=""TS-C417959476FF26245815906820173826"">" +  
                             @"        <wsu:Created>{0}</wsu:Created>" +  
                             @"        <wsu:Expires>{1}</wsu:Expires>" +  
                             @"      </wsu:Timestamp>" +  
                            $@"      <wsse:BinarySecurityToken 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=""X509-{c_GUID}4"">{binarySecToken}</wsse:BinarySecurityToken>" +  
                             @"    </wsse:Security>" +  
                             @"    <wsa:Action>http://wcf.dian.colombia/IWcfDianCustomerServices/SendTestSetAsync</wsa:Action>" +  
                            $@"    <wsa:To wsu:Id=""id-{c_GUID}4"" xmlns:wsu=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"">https://vpfe-hab.dian.gov.co/WcfDianCustomerServices.svc</wsa:To>" +  
                              "  </soap:Header>" +  
                              "  <soap:Body>" +  
                              "    <wcf:SendTestSetAsync>" +  
                              "      <wcf:fileName>{2}</wcf:fileName>" +  
                              "      <wcf:contentFile>{3}</wcf:contentFile>" +  
                              "      <wcf:testSetId>{4}</wcf:testSetId>" +  
                              "    </wcf:SendTestSetAsync>" +  
                              "  </soap:Body>" +  
                              "</soap:Envelope>");  
  
            // Save the XML document to the file name specified.  
            using (XmlTextWriter xmltw = new XmlTextWriter(FileName, new UTF8Encoding(false)))  
            {  
                document.WriteTo(xmltw);  
                xmltw.Close();  
            }  
        }  
  
        public static RSACryptoServiceProvider GetCertificateKey(X509Certificate2 cert)  
        {  
            //System.Windows.Forms.MessageBox.Show("GetCertificateKey");  
  
            RSACryptoServiceProvider rsaKey = null;  
  
            if (cert == null)  
            {  
                //System.Windows.Forms.MessageBox.Show("Couldn't get the certificate");  
                return null;  
            }  
            if (cert.HasPrivateKey)  
            {  
                //System.Windows.Forms.MessageBox.Show("certificate has private key");  
                //throw new Exception(System.Security.Principal.WindowsIdentity.GetCurrent().Name);  
                rsaKey = (RSACryptoServiceProvider)cert.PrivateKey;  
                //System.Windows.Forms.MessageBox.Show("rsaKey cert");  
            }  
            else  
            {  
                //System.Windows.Forms.MessageBox.Show("certificate hasn't private key");  
                throw new Exception("The certificate doesn't include the private key, it's mandatory to sign the message.");  
            }  
  
            return rsaKey;  
        }  
  
        // Sign an XML file and save the signature in a new file. This method does not    
        // save the public key within the XML file.  This file cannot be verified unless    
        // the verifying code has the key with which it was signed.  
        public static void SignXmlFile(string FileName, string SignedFileName, X509Certificate2 cert, string c_GUID)  
        {  
            if (!cert.HasPrivateKey)  
                return; // Nothing to do.  
            CryptoConfig.AddAlgorithm(typeof(RsaPkcs1Sha256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");  
  
            //var cspParams = new CspParameters(24) { KeyContainerName = "XML_DISG_RSA_KEY" };  
            var exportedKeyMaterial = cert.PrivateKey.ToXmlString( /* includePrivateParameters = */ true);  
            var Key = new RSACryptoServiceProvider(new CspParameters(24 /* PROV_RSA_AES */));  
            Key.PersistKeyInCsp = false;  
            Key.FromXmlString(exportedKeyMaterial);  
            //RSACryptoServiceProvider Key = //new RSACryptoServiceProvider(cspParams);//= GetCertificateKey(cert);  
  
            // Create a new XML document.  
            XmlDsigDocument doc = new XmlDsigDocument();  
            //doc.PreserveWhitespace = true;  
            // Load the passed XML file using its name.  
            doc.Load(new XmlTextReader(FileName));  
  
            // Create a SignedXml object.  
            CustomSignedXml signedXml = new CustomSignedXml(doc);  
            //PrefixedSignedXML signedXml = new PrefixedSignedXML(doc);  
  
            // Add the key to the SignedXml document.   
            signedXml.SigningKey = Key;  
  
            // CAntonio, generate a unique ID to identify the components  
            // Generate a unique ID to identify the components  
            // i.e. const string c_BodyID = "id-B14BFCA57E84D4B67C146427915604219";  
  
            string toId = $"id-{c_GUID}4";  
            string signatureID = $"SIG-{c_GUID}1";  
            string keyInfoID = $"KI-{c_GUID}2";  
            string securityTokenReferenceID = $"STR-{c_GUID}3";  
            string STRX509DataID = $"X509-{c_GUID}4";  
  
            // Find body  
            XPathNavigator docNav = doc.CreateNavigator();  
            XmlNamespaceManager nSpMgr = new XmlNamespaceManager(doc.NameTable);  
            nSpMgr.AddNamespace("soap", CustomSignedXml.xmlSoapEnvelopeUrl);  
            nSpMgr.AddNamespace("wsu", CustomSignedXml.xmlOasisWSSSecurityUtilUrl);  
  
            // Set Signature ID (Add Id Attribute to the Signature Node)  
            signedXml.Signature.Id = signatureID;  
  
            // Specify a canonicalization method.  
            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;  
            signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";  
  
            // Set the InclusiveNamespacesPrefixList property.  
            XmlDsigExcC14NTransform canMethod = (XmlDsigExcC14NTransform)signedXml.SignedInfo.CanonicalizationMethodObject;  
            canMethod.InclusiveNamespacesPrefixList = "wsa soap wcf";  
  
            // Create a reference to be signed.  
            Reference reference = new Reference();  
            reference.Uri = "#" + toId;   // Nust match the part that is required to be signed.  
                                          // Add an enveloped transformation to the reference.  
                                          //reference.AddTransform(canMethod);  
            reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";  
  
            XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();  
            env.InclusiveNamespacesPrefixList = "soap wcf";  // sch, schn are part of the body schema.  
            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.Id = keyInfoID;  
            XmlElement x = doc.CreateElement("wsse", "SecurityTokenReference", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");  
            x.SetAttribute("Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", securityTokenReferenceID);  
            XmlElement y = doc.CreateElement("wsse", "Reference", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");  
            y.SetAttribute("URI", $"#{STRX509DataID}");  
            y.SetAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");  
            x.AppendChild(y);  
            var keyInfoData = new KeyInfoNode(x);  
            keyInfo.AddClause(keyInfoData);  
            signedXml.KeyInfo = keyInfo;  
  
            // Compute the signature.  
            signedXml.ComputeSignature(); // "ds" namespace on SignedInfo breaks signature !!!  
  
            // Get the XML representation of the signature and save  
            // it to an XmlElement object.  
            XmlElement xmlDigitalSignature = signedXml.GetXml(); // "ds" namespace on SignedInfo breaks signature !!!  
            signedXml.SignedInfo.References.Clear();  
            // Append the element to the XML document, within <wsse:Security/> node.  
            XPathNavigator headerNode = docNav.SelectSingleNode("soap:Envelope/soap:Header", nSpMgr);  
            if (headerNode != null)  
            {  
                nSpMgr.AddNamespace("wsse", CustomSignedXml.xmlOasisWSSSecurityExtUrl);  
                nSpMgr.AddNamespace("wsse", CustomSignedXml.xmlOasisWSSSecurityExtUrl);  
  
                XPathNavigator secNode = headerNode.SelectSingleNode("wsse:Security", nSpMgr);  
  
                if (secNode != null)  
                {  
                    // Once on security node, append the Signature element  
                    XPathNavigator navSignature = xmlDigitalSignature.CreateNavigator();  
                    secNode.AppendChild(navSignature);  
                }  
            }  
            else  
            {  
                //System.Windows.Forms.MessageBox.Show("wsse:Security not found");  
                // !!! throw new Exception("Header node doesn't found");  
                doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));  
            }  
  
            // Save the signed XML document to a file specified  
            // using the passed string.  
            using (XmlTextWriter xmltw = new XmlTextWriter(SignedFileName, new UTF8Encoding(false)))  
            {  
                doc.WriteTo(xmltw);  
                xmltw.Close();  
            }  
        }  
  
  
        // Verify the signature of an XML file against an asymetric   
        // algorithm and return the result.  
        public static Boolean VerifyXmlFile(String Name, X509Certificate2 cert)  
        {  
            // Create a new XML document.  
            XmlDocument xmlDocument = new XmlDocument();  
  
            // Load the passed XML file into the document.   
            xmlDocument.Load(Name);  
  
            // Create a new SignedXml object and pass it  
            // the XML document class.  
            CustomSignedXml signedXml = new CustomSignedXml(xmlDocument);  
  
            // Find the "Signature" node and create a new  
            // XmlNodeList object.  
            XmlElement signatureElement = null;  
            XmlNodeList nodeList = xmlDocument.GetElementsByTagName("ds:Signature");  
            // If not found, search with namespace  
            if ((nodeList == null) || (nodeList.Count == 0))  
            {  
                // Search with namespace  
                nodeList = xmlDocument.GetElementsByTagName("ds:Signature", SignedXml.XmlDsigNamespaceUrl);  
            }  
  
            if ((nodeList != null) && (nodeList.Count > 0))  
            {  
                signatureElement = (XmlElement)nodeList[0];  
            }  
            else  
            {  
                // Signature not found  
                return false;  
            }  
  
            // Load the signature node.  
            signedXml.LoadXml(signatureElement);  
  
            // Check the signature and return the result.  
            return signedXml.CheckSignature(cert, true);  
        }  
  
        public static byte[] ConvertirCertificadoEnBytes(string pathCertificado)  
        {  
            byte[] certificadoBytes = System.IO.File.ReadAllBytes(pathCertificado);  
            return certificadoBytes;  
        }  

Class RsaPkcs1Sha256SignatureDescription

using System;  
using System.Security.Cryptography;  
  
namespace FirmaSoap  
{  
    public sealed class RsaPkcs1Sha256SignatureDescription : SignatureDescription  
    {  
        /// <summary>  
        /// This type of CSP has SHA256 support  
        /// </summary>  
        private const int PROV_RSA_AES = 24;  
  
        public RsaPkcs1Sha256SignatureDescription()  
        {  
            KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;  
            DigestAlgorithm = typeof(SHA256Cng).FullName;  
            FormatterAlgorithm = typeof(RSAPKCS1SignatureFormatter).FullName;  
            DeformatterAlgorithm = typeof(RSAPKCS1SignatureDeformatter).FullName;  
        }  
  
        /// <summary>  
        /// Adds support for sha256RSA XML signatures.  
        /// </summary>  
        public static void RegisterForSignedXml()  
        {  
            CryptoConfig.AddAlgorithm(  
                typeof(RsaPkcs1Sha256SignatureDescription),  
                "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");  
        }  
  
        public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)  
        {  
            if (key == null) throw new ArgumentNullException("key");  
  
            key = GetSha2CompatibleKey(key);  
  
            var signatureDeformatter = new RSAPKCS1SignatureDeformatter(key);  
            signatureDeformatter.SetHashAlgorithm("SHA256");  
            return signatureDeformatter;  
        }  
  
        public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)  
        {  
            if (key == null) throw new ArgumentNullException("key");  
  
            key = GetSha2CompatibleKey(key);  
  
            var signatureFormatter = new RSAPKCS1SignatureFormatter(key);  
            signatureFormatter.SetHashAlgorithm("SHA256");  
            return signatureFormatter;  
        }  
  
        // Some certificates are generated without SHA2 support, this method recreates the CSP for them.  
        // See https://stackoverflow.com/a/11223454/280778  
        // WIF handles this case internally if no sha256RSA support is installed globally.  
        private static AsymmetricAlgorithm GetSha2CompatibleKey(AsymmetricAlgorithm key)  
        {  
            var csp = key as RSACryptoServiceProvider;  
            if (csp == null || csp.CspKeyContainerInfo.ProviderType == PROV_RSA_AES)  
                return key;  
  
            var newKey = new RSACryptoServiceProvider(new CspParameters(PROV_RSA_AES));  
            newKey.ImportParameters(csp.ExportParameters(true));  
            return newKey;  
        }  
    }  
}  

Class XmlDsigDocument

using System;
using System.Collections.Generic;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Xml;

namespace FirmaSoap
{
class XmlDsigDocument : XmlDocument
{
// Constants
public const string XmlDsigNamespacePrefix = "ds";

    /// <summary>  
    /// Override CreateElement function as it is extensively used by SignedXml  
    /// </summary>  
    /// <param name="prefix"></param>  
    /// <param name="localName"></param>  
    /// <param name="namespaceURI"></param>  
    /// <returns></returns>  
    public override XmlElement CreateElement(string prefix, string localName, string namespaceURI)  
    {  
        // CAntonio. If this is a Digital signature security element, add the prefix.   
        if (string.IsNullOrEmpty(prefix))  
        {  
            // !!! Note: If you comment this line, you'll get a valid signed file! (but without ds prefix)  
            // !!! Note: If you uncomment this line, you'll get an invalid signed file! (with ds prefix within 'Signature' object)  
            //prefix = GetPrefix(namespaceURI);  

            // The only way to get a valid signed file is to prevent 'Prefix' on 'SignedInfo' and descendants.  
            List<string> SignedInfoAndDescendants = new List<string>();  
            SignedInfoAndDescendants.Add("SignedInfo");  
            SignedInfoAndDescendants.Add("CanonicalizationMethod");  
            SignedInfoAndDescendants.Add("InclusiveNamespaces");  
            SignedInfoAndDescendants.Add("SignatureMethod");  
            SignedInfoAndDescendants.Add("Reference");  
            SignedInfoAndDescendants.Add("Transforms");  
            SignedInfoAndDescendants.Add("Transform");  
            SignedInfoAndDescendants.Add("InclusiveNamespaces");  
            SignedInfoAndDescendants.Add("DigestMethod");  
            SignedInfoAndDescendants.Add("DigestValue");  
            //if (!SignedInfoAndDescendants.Contains(localName))  
            //{  
                prefix = GetPrefix(namespaceURI);  
            //}  
        }  

        return base.CreateElement(prefix, localName, namespaceURI);  
    }  

    /// <summary>  
    /// Set the prefix to this and all its descendants.  
    /// </summary>  
    /// <param name="prefix"></param>  
    /// <param name="node"></param>  
    /// <returns></returns>  
    public static XmlNode SetPrefix(string prefix, XmlNode node)  
    {  
        foreach (XmlNode n in node.ChildNodes)  
        {  
            SetPrefix(prefix, n);  
        }  
        if (node.NamespaceURI == "http://www.w3.org/2001/10/xml-exc-c14n#")  
            node.Prefix = "ec";  
        else if ((node.NamespaceURI == CustomSignedXml.XmlDsigNamespaceUrl) || (string.IsNullOrEmpty(node.Prefix)))  
            node.Prefix = prefix;  

        return node;  
    }  

    /// <summary>  
    /// Select the standar prefix for the namespaceURI provided  
    /// </summary>  
    /// <param name="namespaceURI"></param>  
    /// <returns></returns>  
    public static string GetPrefix(string namespaceURI)  
    {  
        if (namespaceURI == "http://www.w3.org/2001/10/xml-exc-c14n#")  
            return "ec";  
        else if (namespaceURI == CustomSignedXml.XmlDsigNamespaceUrl)  
            return "ds";  

        return string.Empty;  
    }  
}  

}

Class CustomSignedXml

namespace FirmaSoap
{
using System;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Reflection;

//  Subclass System.Security.Cryptography.Xml.SignedXml to handle situations  
//  where the signed XML element has an attribute named id instead of Id.  

// Public Class SignedXML : System.Security.Cryptography.Xml.SignedXml  
public class CustomSignedXml : SignedXml  
{  
    public CustomSignedXml()  
        : base()  
    {  
    }  

    public CustomSignedXml(XmlDocument doc)  
        : base(doc)  
    {  
    }  

    public CustomSignedXml(XmlElement elem)  
        : base(elem)  
    {  
    }  

    // Summary:  
    //     Represents the Uniform Resource Identifier (URI) for the soap envelope description  
    //     transformation. This field is constant.  
    public const string xmlSoapEnvelopeUrl = "http://www.w3.org/2003/05/soap-envelope";  

    // Summary:  
    //     Represents the Uniform Resource Identifier (URI) for the soap security description  
    //     transformation. This field is constant.  
    public const string xmlSoapSecurityUrl = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";  

    // Summary:  
    //     Represents the Uniform Resource Identifier (URI) for the wss utility namespace  
    //     transformation. This field is constant.  
    public const string xmlOasisWSSSecurityUtilUrl = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";  

    // Summary:  
    //     Represents the Uniform Resource Identifier (URI) for the wss extension namespace  
    //     transformation. This field is constant.  
    public const string xmlOasisWSSSecurityExtUrl =   "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";  

    // This function expands the overriden GetIdElement method of the  
    // base SignedXML class to search for attribute "id" in addition to  
    // the default "Id" attribute.  
    public override XmlElement GetIdElement(XmlDocument document, string idValue)  
    {  
        if (document == null)  
            return null;  

        // Get the element with idValue  
        XmlElement elem = document.GetElementById(idValue);  
        if (elem != null)  
            return elem;  

        // Make a list of the possible id's since it is case sensitive.  
        string[] arraySearchIDs = { "id", "Id", "ID", "wsu:id", "wsu:Id", "wsu:ID", "WSU:id", "WSU:Id", "WSU:ID" };  

        // search with namespace wsu  
        // http://stackoverflow.com/questions/5099156/malformed-reference-element-when-adding-a-reference-based-on-an-id-attribute-w  
        XmlNamespaceManager nsManager = new XmlNamespaceManager(document.NameTable);  
        nsManager.AddNamespace("wsu", CustomSignedXml.xmlOasisWSSSecurityUtilUrl);  
        foreach (string idLabel in arraySearchIDs)  
        {  
            // Get the element with idValue, try all combinations in array  
            string xpathId = "//*[@" + idLabel + "=\"" + idValue + "\"]";  
            elem = document.SelectSingleNode(xpathId, nsManager) as XmlElement;  
            if (elem != null)  
                return elem;  
        }  

        return elem;  
    }  
}  

}

Not Monitored
Not Monitored
Tag not monitored by Microsoft.
37,671 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Anonymous
    2020-06-24T17:19:38.09+00:00

    C# is not currently supported here on QnA. They're actively answering questions in dedicated forums here.
    https://social.msdn.microsoft.com/Forums/en-US/home?forum=csharpgeneral

    --please don't forget to Accept as answer if the reply is helpful--


    Regards, Dave Patrick ....
    Microsoft Certified Professional
    Microsoft MVP [Windows Server] Datacenter Management

    Disclaimer: This posting is provided "AS IS" with no warranties or guarantees, and confers no rights.

    0 comments No comments