Reputation: 1902
I have a program running in C# which applies an XMLSignature to an xml document. I have the same XML documents in both cases (C# and Java), but I am not getting the same digest and signature values. I know that the results from my C program are correct, but I dont get to get them correctly in Java.
Here the C# code:
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));
}
The Java code is the following:
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);
With the same xml document, certificate and private key I am getting the following Digest Values in each one:
Java: EZTMZuMvR9D0WSUgbT2AdFYTBh4=
C#: EsJDdWiUMIOaQp9CC26wQWA6kJ0=
Why does this happen?
Upvotes: 5
Views: 6732
Reputation: 1
You should canonicalize the xml before calculate digest and signature. for the C# codes.
XmlDsigC14NTransform canonicalization = new XmlDsigC14NTransform(); reference.AddTransform(canonicalization);
Upvotes: 0
Reputation: 175
Just to add what I did to solve this problem:
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);
So, before computing digest and signature, you need to strip whitespace and CRLF when loading xml from file. Otherwise, signature and digest compared to .Net result would be different.
Upvotes: 3
Reputation: 1902
I dont know why this happens, but the solution to this problem was converting the Document to String and then to Document again and by doing that I got the expected digest and signature values.
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)));
Upvotes: 3