XML canonização algoritmo dá dois resultados diferença quando chamado diretamente do que quando chamado como parte de uma assinatura digital XML?

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

Pergunta

Estou recebendo dois hashes diferentes do mesmo documento XML quando eu canonizar diretamente alguns xml que quando eu executar uma assinatura digital nele que também executa a mesma canonização algoririth no xml antes de hash-lo? Eu trabalhei para fora que a canonização assinatura digital inclui os caracteres de nova linha '\ n' e caracteres de espaçamento quando Canonicalização eo algoritmo direto não.

Incluindo os novos caracteres de linha + espaços não está na especificação de canonização embora? Eu estou olhando especificamente esta versão http://www.w3.org / TR / 2001 / REC-XML-C14N-20010315

Alguém sabe o que está acontecendo? Eu incluí o doc xml e ambas as implementações do código para que você possa ver.

Este é realmente intrigante mim e eu gostaria de saber por que, estou faltando algo óbvio?

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

O código de canonização direto

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;
        }
    }
}

O código de assinatura 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;
    }
}

Qualquer ideia seria ótimo! É todo o código C # pelo caminho.

Agradecemos antecipadamente

Jon

Foi útil?

Solução

A forma como XML Sig alças espaço em branco é, na minha opinião quebrado. Certamente não é compatível com o que a maioria das pessoas que pensam direito chamaria de canonização. Alterar o espaço em branco deve não afetar a digest, mas em xmlsig, ele faz.

Uma solução possível é passar o documento através de uma rotina canonicalizer antes de passá-lo para o código de geração de assinatura. Isso deve tornar as coisas muito mais previsível.

Este artigo ajuda poder esclarecer as coisas.

Outras dicas

Parece que em sua segunda parte do código que você tem

xmlDoc.PreserveWhitespace = true;

enquanto que no primeiro você não.

Pelo que entendi, a especificação canonicalisation pede para preservar o espaço em branco entre os elementos, então eu sugiro que você incluir esta linha em ambos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top