I have a java application that checks in with a .NET server for licensing purposes. The licensing server responds with signed xml. For some messages the Java application fails to validate the signature, but for others it works fine.
Here is a message that is able to be validated with no problem (formatted and replaced sensitive data):
<AuthorizeResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<LicenseKey>replaced actual data</LicenseKey>
<Message i:nil="true" />
<MessageGuid>67d5b7bd-33bd-467b-a3fc-842f0f4782e3</MessageGuid>
<Nonce>0</Nonce>
<Success>true</Success>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>QQL4nxJbna/VUR/b3caorWjHb0Q=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
nui/m6DvMBbKjncklq1/1Bo4Bzq8C1Z+dhL0c3YMM2wDdDMhC7ob201r3XnDijFcuhz8BomNbE2Br51Y9+R1wPq2JuQ0K8037f7WmQW5M1l+5Dvz9bFrK1oKExKudg9iRNv0iYcgMxY6x0m3tyQTC6KnH/uBtALbQeNLTti+ho4=
</SignatureValue>
</Signature>
</AuthorizeResponse>
Here is a message where validation fails (formatted):
<AuthorizeResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<LicenseKey i:nil="true" />
<Message>Already using license on max number of systems. Running on
systems:127.0.0.1;192.168.1.8;host.docker.internal;1127.0.0.1;192.168.1.8;host.docker.internal;2</Message>
<MessageGuid>7f5d0e32-6117-4204-85e1-dec5c57c053e</MessageGuid>
<Nonce>0</Nonce>
<Success>false</Success>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>JJ81DxbusvrVSCZUy/3nobs71FU=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>
aYhs9Vri70bSqsRcVyE8HpQgs0KIQQfmTgJiIv2QzP4Aa172T5ntiii0EU4CJn28N3tXSJK4wmbxZBOvZGnyYuBOv/5jWEFyeUuNAwmw/r+HdVKctBD0BRmSSq+fqQpMjlJmyT/3RL1S250KhCFB05NhvSxk0IbZUei/4RpWwcc=
</SignatureValue>
</Signature>
</AuthorizeResponse>
Signing code in C#:
public static void SignXmlDocument(string privateKey, XmlDocument xmlDoc)
{
SignedXml signedXml = new SignedXml(xmlDoc);
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();
rsaKey.FromXmlString(privateKey);
signedXml.SigningKey = rsaKey;
Reference reference = new Reference {Uri = ""};
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
signedXml.AddReference(reference);
signedXml.ComputeSignature();
XmlElement xmlDigitalSignature = signedXml.GetXml();
// ReSharper disable once PossibleNullReferenceException
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
}
Validation code in Java (jboss is false):
private static boolean verifyXmlFromStream(InputStream SignedXmlDocumentStream, boolean jboss)
{
try
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document sourceDoc = dbf.newDocumentBuilder().parse(SignedXmlDocumentStream);
NodeList nl = sourceDoc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nl.getLength() == 0)
throw new Exception("Cannot find Signature element");
XMLSignatureFactory factory = getSignatureFactory(jboss);
DOMValidateContext valContext = new DOMValidateContext(new KeyValueKeySelector(), nl.item(0));
XMLSignature signature = factory.unmarshalXMLSignature(valContext);
boolean coreValidity = signature.validate(valContext);
if (!coreValidity)
log.warn("Signature failed core validation!"); // error?
return coreValidity;
}
catch (Exception e)
{
log.error(e);
return false;
}
}
private static XMLSignatureFactory getSignatureFactory(boolean jboss)
throws ClassNotFoundException,
InstantiationException,
IllegalAccessException
{
if (jboss)
{
log.debug("Getting XML security provider using JBoss friendly method.");
return XMLSignatureFactory.getInstance("DOM");
}
else
{
String provider = System.getProperty("jsr105Provider",
"org.jcp.xml.dsig.internal.dom.XMLDSigRI");
return XMLSignatureFactory.getInstance("DOM",
(Provider)Class.forName(provider).newInstance());
}
}
Any idea why signing is working correctly for some messages and failing with others? I've tried encoding the document differently and sending the second message without the ';' character with no difference in behavior.
Edit: I've also tried building the HttpContent returned by my server in several different ways in case some white space formatting was changing when I built my StringContent.