2009-06-22 17 views
8

Sto ottenendo due diversi hash dello stesso documento xml quando direttamente canonicalizzo qualche xml rispetto a quando eseguo una firma digitale su di esso che esegue anche lo stesso algoritmo di canonicalizzazione su xml prima di eseguirne l'hashing? Ho capito che la canonicalizzazione della firma digitale include i caratteri della nuova riga '\ n' e la spaziatura dei caratteri quando canonicalizza e l'algoritmo diretto no.L'algoritmo XML Canonicalization fornisce due risultati di differenza quando viene richiamato direttamente rispetto a quando viene chiamato come parte di una firma digitale xml?

Anche se i caratteri della nuova riga + spazi non sono nella specifica di canonizzazione? Sto specificatamente guardando questa versione http://www.w3.org/TR/2001/REC-xml-c14n-20010315

Qualcuno sa cosa sta succedendo? Ho incluso il documento XML e entrambe le implementazioni del codice in modo che tu possa vedere.

Questo mi sta davvero sconcertando e mi piacerebbe sapere perché, mi manca qualcosa di ovvio?

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

Il codice canonica diretta

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

La firma digitale XML codice

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

Qualsiasi idea sarebbe grande! A proposito, è tutto il codice C#.

Grazie in anticipo

Jon

risposta

7

Il modo in cui XML Sig gestisce gli spazi è, a mio parere rotto. Non è certamente conforme a ciò che la maggior parte delle persone che pensano correttamente chiamerebbe canonicalizzazione. Cambiare gli spazi vuoti non dovrebbe non influenzare il digest, ma in xmlsig, lo fa.

Una possibile soluzione è passare il documento attraverso una routine di canonicalizer prima di passarlo al codice di generazione della firma. Ciò dovrebbe rendere le cose molto più prevedibili.

This article potrebbe aiutare a chiarire le cose.

+0

Ahh, quindi il problema non è con l'algoritmo C14n stesso la specifica della firma xml-digital specifica lo spazio bianco e i caratteri della nuova riga da conservare mentre si canonicalizza il documento? Questo è un trabocchetto di cui non ero a conoscenza. Proverò il tuo suggerimento su canonocalizzare l'xml prima di passarlo a un firmatario. Questa è sicuramente la logica a ritroso, tuttavia, il W3c ha impiegato tutto il tempo a elaborare una specifica per ottenere un documento XML in una forma canonica e quindi contraddirsi nelle specifiche della firma digitale xml? Sembra molto strano. Sai per quale motivo? Grazie per il vostro aiuto! – Jon

0

Sembra che nel secondo pezzo di codice che hanno

xmlDoc.PreserveWhitespace = true; 

mentre nel primo non lo fai.

A quanto ho capito, la specifica di canonicalizzazione chiede di preservare lo spazio tra gli elementi, quindi suggerisco di includere questa linea in entrambi.