2012-02-08 63 views
5

Tengo un programa ejecutándose en C# que aplica una firma XMLSignature a un documento xml. Tengo los mismos documentos XML en ambos casos (C# y Java), pero no obtengo los mismos valores de resumen y firma. Sé que los resultados de mi programa C son correctos, pero no los consigo correctamente en Java.DigestValue en XMLSignature en Java es diferente de C#

Aquí el código C#:

 public void SignXml(XmlDocument xmlDoc, RSA Key) 
     { 
      // Check arguments. 
      if (xmlDoc == null) 
       throw new ArgumentException("xmlDoc"); 
      if (Key == null) 
       throw new ArgumentException("Key"); 

      // Create a SignedXml object. 
      SignedXml signedXml = new SignedXml(xmlDoc); 

      // Add the key to the SignedXml document. 
      signedXml.SigningKey = Key; 

      // Create a reference to be signed. 
      Reference reference = new Reference(); 
      reference.Uri = ""; 

      // Add an enveloped transformation to the reference. 
      XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(); 
      reference.AddTransform(env); 

      // Add the reference to the SignedXml object. 
      signedXml.AddReference(reference); 

      KeyInfo ki = new KeyInfo(); 
      KeyInfoX509Data clause = new KeyInfoX509Data(); 
      clause.AddCertificate(x509_2); 
      clause.AddIssuerSerial(x509_2.Issuer, x509_2.GetSerialNumberString()); 
      ki.AddClause(clause); 
      signedXml.KeyInfo = ki; 

      // Compute the signature. 
      signedXml.ComputeSignature(); 

      // Get the XML representation of the signature and save 
      // it to an XmlElement object. 
      XmlElement xmlDigitalSignature = signedXml.GetXml(); 

      //xmlDoc.Save("antes_firma.xml"); 
      // Append the element to the XML document. 
      xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); 


     } 

El código Java es la siguiente:

DOMSignContext dsc = new DOMSignContext (pk, doc.getDocumentElement()); 
      XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 

      Reference ref = fac.newReference ("", fac.newDigestMethod(DigestMethod.SHA1, null), 
         Collections.singletonList 
         (fac.newTransform(Transform.ENVELOPED, 
         (TransformParameterSpec) null)), null, null); 

      SignedInfo si = fac.newSignedInfo 
         (fac.newCanonicalizationMethod 
         (CanonicalizationMethod.INCLUSIVE, 
          (C14NMethodParameterSpec) null), 
         fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
         Collections.singletonList(ref)); 

      KeyInfoFactory kif = fac.getKeyInfoFactory(); 
      X509IssuerSerial issuerSerial = kif.newX509IssuerSerial(cert2.getIssuerDN().getName(), cert.getSerialNumber()); 
      List x509Content = new ArrayList(); 
      x509Content.add(issuerSerial); 
      x509Content.add(cert2); 
      X509Data xd = kif.newX509Data(x509Content); 
      KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd)); 

      XMLSignature signature = fac.newXMLSignature(si, ki); 

      signature.sign(dsc); 

Con el mismo documento XML, el certificado y la clave privada que estoy recibiendo los siguientes valores Digest en cada uno :

  • Java: EZTMZuMvR9D0WSUgbT2AdFYTBh4=

  • C#: EsJDdWiUMIOaQp9CC26wQWA6kJ0=

¿Por qué sucede esto?

+0

¿Estás seguro de que el código C# usa un algoritmo de resumen SHA-1? –

+0

Sí, porque en el XML resultante obtengo lo siguiente: ' EsJDdWiUMIOaQp9CC26wQWA6kJ0 =' – user1084509

Respuesta

1

No sé por qué sucede esto, pero la solución a este problema fue convertir el Documento a Cadena y luego al Documento de nuevo y al hacerlo obtuve los valores de firma y resumen esperados.

TransformerFactory transfac = TransformerFactory.newInstance(); 
      Transformer trans = transfac.newTransformer(); 


      //CREAR STRING DEL ARBOL XML 
      StringWriter sw = new StringWriter(); 
      StreamResult result = new StreamResult(sw); 
      DOMSource source = new DOMSource(doc); 
      trans.transform(source, result); 
      String xmlString = sw.toString(); 
      System.out.println(xmlString); 

      dbfac = DocumentBuilderFactory.newInstance(); 
      dbfac.setNamespaceAware(true); 
      doc = dbfac.newDocumentBuilder().parse(new InputSource(new StringReader(xmlString))); 
+0

Probablemente tiene que ver con la forma en que se organiza el XML una vez que se convierte en una cadena. –

+0

Eso funcionó para mí parcialmente. Si solo firmo el archivo una vez, su hack hace el trabajo. Pero si necesito firmar el archivo en tres partes diferentes, por ejemplo, los resúmenes de Java salen mal y no se validarán en una aplicación de C#. ¿Has visto esto? – Andre

3

sólo para añadir lo que hice para solucionar este problema:

String thisLine = ""; 
String xmlString = ""; 
BufferedReader br = new BufferedReader(new FileReader(xmlFile)); 
while ((thisLine = br.readLine()) != null) { 
    xmlString = xmlString + thisLine.trim(); 
} 
br.close(); 

ByteArrayInputStream xmlStream = new ByteArrayInputStream(xmlString.getBytes()); 
xmlDocument = docBuilder.parse(xmlStream); 

Por lo tanto, antes de calcular resumen y firma, es necesario quitar espacios en blanco y CRLF al cargar XML desde un archivo. De lo contrario, la firma y el resumen en comparación con el resultado de .Net serían diferentes.

0

Debe canonicalizar el xml antes de calcular el resumen y la firma. para los códigos C#.

XmlDsigC14NTransform canonicalization = new XmlDsigC14NTransform(); reference.AddTransform (canonicalización);

+1

La caninicalización no elimina los espacios en blanco. Ver http://www.w3.org/TR/2001/REC-xml-c14n-20010315 –

Cuestiones relacionadas