El algoritmo de canonización XML ofrece dos resultados diferentes cuando se llama directamente que cuando se llama como parte de una firma digital xml.

StackOverflow https://stackoverflow.com/questions/1026432

Pregunta

Recibo dos hashes diferentes del mismo documento xml cuando canonicalizo directamente algunos xml que cuando realizo una firma digital en él que también realiza el mismo algoritmo de canonicalización en el xml antes de hacerlo. Me di cuenta de que la canonicalización de la firma digital incluye los nuevos caracteres de línea '\ n' y los caracteres de espaciado cuando se canoniza y el algoritmo directo no.

¿Incluir los nuevos caracteres de línea + espacios no está en la especificación de canonicalización? Estoy mirando específicamente esta versión http://www.w3.org / TR / 2001 / REC-xml-c14n-20010315

¿Alguien sabe lo que está pasando? He incluido el documento xml y ambas implementaciones del código para que pueda ver.

Esto realmente me está desconcertando y me gustaría saber por qué, ¿me estoy perdiendo algo obvio?

<root>
  <child1>some text</child1>
  <child2 attr="1" />
</root>

El código de canonicalización directa

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography;
using System.IO;
using System.ComponentModel;

namespace XML_SignatureGenerator
{
    class XML_C14N
    {
        private String _filename;
        private Boolean isCommented = false;
        private XmlDocument xmlDoc = null;

        public XML_C14N(String filename)
        {
            _filename = filename;
            xmlDoc = new XmlDocument();
            xmlDoc.Load(_filename);
        }

        //implement this spec http://www.w3.org/TR/2001/REC-xml-c14n-20010315
        public String XML_Canonalize(System.Windows.Forms.RichTextBox tb)
        {
            //create c14n instance and load in xml file
            XmlDsigC14NTransform c14n = new XmlDsigC14NTransform(isCommented);

            c14n.LoadInput(xmlDoc);

            //get canonalised stream
            Stream s1 = (Stream)c14n.GetOutput(typeof(Stream));
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            Byte[] output = sha1.ComputeHash(s1);

            tb.Text = Convert.ToBase64String(output);

            //create new xmldocument and save
            String newFilename = _filename.Substring(0, _filename.Length - 4) + "C14N.xml";
            XmlDocument xmldoc2 = new XmlDocument();
            xmldoc2.Load(s1);
            xmldoc2.Save(newFilename);

            return newFilename;
        }

        public void set_isCommented(Boolean value)
        {
            isCommented = value;
        }

        public Boolean get_isCommented()
        {
            return isCommented;
        }
    }
}

El código de firma digital xml

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

namespace XML_SignatureGenerator
{
class xmlSignature
    {
        public xmlSignature(String filename)
        {
            _filename = filename;
        }

        public Boolean SignXML()
        {
            RSACryptoServiceProvider rsa =  new RSACryptoServiceProvider();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.PreserveWhitespace = true;
            String fname = _filename; //"C:\\SigTest.xml";
            xmlDoc.Load(fname);

            SignedXml xmlSig = new SignedXml(xmlDoc);
            xmlSig.SigningKey = rsa;

            Reference reference = new Reference();
            reference.Uri = "";

            XmlDsigC14NTransform env = new XmlDsigC14NTransform(false);
            reference.AddTransform(env);

            xmlSig.AddReference(reference);
            xmlSig.ComputeSignature();

            XmlElement xmlDigitalSignature = xmlSig.GetXml();
            xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));

            xmlDoc.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/SignedXML.xml");

            return true;
        }
        private String _filename;
    }
}

¡Cualquier idea sería genial! Por cierto, todo es código C #.

Gracias de antemano

Jon

¿Fue útil?

Solución

La forma en que XML Sig maneja los espacios en blanco es, en mi opinión, rota. Ciertamente no cumple con lo que la mayoría de las personas que piensan correctamente llamarían canonicalización. Cambiar el espacio en blanco debería no afectar el resumen, pero en xmlsig, sí.

Una posible solución alternativa es pasar el documento a través de una rutina de canonicalizador antes de pasarlo al código de generación de firma. Eso debería hacer las cosas mucho más predecibles.

Este artículo podría ayudar aclarar cosas.

Otros consejos

Parece que en tu segundo código tienes

xmlDoc.PreserveWhitespace = true;

mientras que en el primero no.

Según tengo entendido, la especificación de canonicalización solicita preservar el espacio en blanco entre los elementos, por lo que le sugiero que incluya esta línea en ambos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top