Skip to main content

Notifications

Announcements

No record found.

Finance | Project Operations, Human Resources, ...
Answered

Problem signing XML that would later be use in a D365FO project

Posted on by 148

Hi,

I'm building code in C# that later I will integrate it in a D365FO project. This code needs to sign an XMLDocument with a valid certificate I have and then later I have to send it to a web service. The problem is that when I get to this line: signedXml.ComputeSignature(); There is an error message that says that the algorithm use is not valid. The algorithm that I use is RSA-SHA256 and I already checked with windows certificates and indeed that algorithm is part of the certificate properties.

Here is the full code (I hid some of the urls and file info):

using System;
using System.Text;
using System.Xml;
using Console = System.Console;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;


namespace FirmaElectronica
{
    class Program
    {
        static void Main(string[] args)
        {
            // Definimos los parámetros de la petición
            string urlServicio = "https://url.com";
            string archivoXML = "C:\\Users\\...\\file.xml";
            string claveAcceso = "0000000000000000000000000000000000000000000000000";
            string rutaArchivoConfiguracion = "C:\\Users\\....\\file.txt";
            string clave = "";

            // Método para guardar clave en la variable
            if (File.Exists(rutaArchivoConfiguracion))
            {
                string[] lineas = File.ReadAllLines(rutaArchivoConfiguracion);

                foreach (string linea in lineas)
                {
                    if (linea.StartsWith("clave="))
                    {
                        clave = linea.Substring(6);
                        break;
                    }
                }
            }

            if (string.IsNullOrEmpty(clave))
            {
                throw new Exception("No se encontró la clave en el archivo de configuración.");
            }

            // Leemos el archivo XML
            string xml = System.IO.File.ReadAllText(archivoXML, Encoding.UTF8);

            // Convertimos la cadena a un objeto XmlDocument
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);

            // Leemos el certificado desde el archivo .p12 y proporcionamos la clave
            X509Certificate2 certificate = new X509Certificate2("C:\\Users\\....\\file.p12", clave, X509KeyStorageFlags.Exportable);

            // Creamos el objeto SignedXml y lo configuramos
            SignedXml signedXml = new SignedXml(xmlDoc);
            signedXml.SigningKey = certificate.PrivateKey;
            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;

            // Creamos una referencia al objeto SignedXml
            Reference reference = new Reference();
            reference.Uri = "";

            // Agregamos el transform para la referencia
            XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
            reference.AddTransform(env);

            // Agregamos la referencia al objeto SignedXml
            signedXml.AddReference(reference);

            // Creamos el objeto KeyInfo y lo configuramos
            KeyInfo keyInfo = new KeyInfo();
            keyInfo.AddClause(new KeyInfoX509Data(certificate));

            // Agregamos el objeto KeyInfo al objeto SignedXml
            signedXml.KeyInfo = keyInfo;

            // Especificamos el algoritmo de firma
            signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA256Url;

            // Firmamos el XML
            signedXml.ComputeSignature(); //HERE IT STOPS

            // Obtenemos la representación del XML firmado como objeto XmlElement
            XmlElement xmlDigitalSignature = signedXml.GetXml();

            // Agregamos el elemento firmado al XML original
            xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));

            // Convertimos el XML firmado a cadena
            string xmlFirmado = xmlDoc.OuterXml;

            // Armamos el cuerpo del mensaje SOAP
            string cuerpoMensaje = ""  
                                    ""  
                                    ""  
                                        ""  
                                            ""   claveAcceso   ""  
                                            ""   xmlFirmado   ""  
                                        ""  
                                    ""  
                                "";


            // Creamos la petición HTTP
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlServicio);
            request.Method = "POST";
            request.ContentType = "text/xml;charset=UTF-8";
            request.Headers.Add("SOAPAction", "");

            // Establecemos el tamaño del contenido que se va a enviar en la petición
            request.ContentLength = cuerpoMensaje.Length;

            // Escribimos el cuerpo del mensaje SOAP en el stream de la petición
            using (Stream stream = request.GetRequestStream())
            {
                using (StreamWriter sw = new StreamWriter(stream))
                {
                    sw.Write(cuerpoMensaje);
                }
            }

            // Obtenemos la respuesta del servicio web
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                // Leemos la respuesta
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    string responseXml = reader.ReadToEnd();

                    // Parseamos la respuesta como XML
                    XmlDocument xmlDocResponse = new XmlDocument();
                    xmlDocResponse.LoadXml(responseXml);

                    // Extraemos el estado de la autorización
                    string estado = xmlDocResponse.GetElementsByTagName("estado")[0].InnerText;

                    if (estado == "AUTORIZADO")
                    {
                        // El comprobante fue autorizado
                        Console.WriteLine("El comprobante fue autorizado");
                    }
                    else
                    {
                        // El comprobante fue rechazado o está en proceso
                        Console.WriteLine("El comprobante fue rechazado o está en proceso");
                    }
                }
            }
        }
    }
}



Thanks in advance.

  • Anton Venter Profile Picture
    Anton Venter 18,748 Super User 2024 Season 2 on at
    RE: Problem signing XML that would later be use in a D365FO project

    You are welcome :-)

  • Daniel Mora Profile Picture
    Daniel Mora 148 on at
    RE: Problem signing XML that would later be use in a D365FO project

    Thanks Anton, I just had to change signedXml.SigningKey = certificate.PrivateKey; for signedXml.SigningKey = certificate.GetRSAPrivateKey(); because it seems is this way for .Net 4.7.1 and above.

  • Verified answer
    Anton Venter Profile Picture
    Anton Venter 18,748 Super User 2024 Season 2 on at
    RE: Problem signing XML that would later be use in a D365FO project

    Have a look at this article, it says SHA-256 isn't supported by X509Certificate2 and the article describes the same error as you "invalid algorithm used"

    https://stackoverflow.com/questions/29005876/signedxml-compute-signature-with-sha256

  • Daniel Mora Profile Picture
    Daniel Mora 148 on at
    RE: Problem signing XML that would later be use in a D365FO project

    Main message:

    System.Security.Cryptography.CryptographicException: 'Specified algorithm is invalid.

    Full details:

    System.Security.Cryptography.CryptographicException

     HResult=0x80090008

     Message = Specified algorithm is invalid.

     Origin = mscorlib

    Stack trace:

      at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)

      at System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash, Int32 cbHash, ObjectHandleOnStack retSignature)

      at System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash)

      at System.Security.Cryptography.RSACryptoServiceProvider.SignHash(Byte[] rgbHash, Int32 calgHash)

      at System.Security.Cryptography.RSAPKCS1SignatureFormatter.CreateSignature(Byte[] rgbHash)

      at System.Security.Cryptography.AsymmetricSignatureFormatter.CreateSignature(HashAlgorithm hash)

      at System.Security.Cryptography.Xml.SignedXml.ComputeSignature()

      at FirmaElectronica.Program.Main(String[] args) in C:\Users\......\Program.cs:line 85

  • Martin Dráb Profile Picture
    Martin Dráb 229,443 Most Valuable Professional on at
    RE: Problem signing XML that would later be use in a D365FO project

    What is the type of the exception and the exact error message?

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

November Spotlight Star - Khushbu Rajvi

Congratulations to a top community star!

Forum Structure Changes Complete!

🔔 Be sure to subscribe to the new forums you are interested in to stay up to date! 🔔

Dynamics 365 Community Platform update – Oct 28

Welcome to the next edition of the Community Platform Update. This is a status …

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 290,961 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 229,443 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Product updates

Dynamics 365 release plans