我有一个Java应用程序,可以通过.NET服务器进行签入以获取许可。许可服务器以签名的xml响应。对于某些消息,Java应用程序无法验证签名,但是对于其他消息,它可以正常工作。
这里是一条可以毫无问题地验证的消息(格式化并替换了敏感数据):
<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>
这里是验证失败的消息(格式化):
<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>
在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));
}
Java中的验证码(jboss
为假):
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());
}
}
任何想法为何对某些消息都无法正常签名而对其他消息却失败?我尝试对文档进行不同的编码,并发送第二个消息而不带';角色,行为无差异。
编辑:我还尝试以几种不同的方式构建服务器返回的HttpContent,以防在构建StringContent时某些空白格式发生更改。
在签名后从消息节点中删除了一些白色的新行。我不太清楚为什么,所以我只是在没有新行的情况下构建消息。