我有一个用XaDes签名的XML文档。签名文档有两个带有URI的引用,一个带有空URI。当我验证签名时,出现NULL引用异常错误。
线程“主”中的异常javax.xml.crypto.dsig.XMLSignatureException:javax.xml.crypto.URIReferenceException:com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException:找不到URI null和Base null的解析器
这是我的签名XML
<Sgntr>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#_d36d665d-470b-429b-921c-f9381d2fc5f9">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>IybO1FjRmQn3IbvTrmrxCr1VqUw=</ds:DigestValue>
</ds:Reference>
<ds:Reference Type="http://uri.etsi.org/01903/v1.3.2#SignedProperties" URI="#_a4646550-596c-4174-a2c0-2a0118fa1b0e-signedprops">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>eI+YLruTZe3qcPs8blatyKvJxZc=</ds:DigestValue>
</ds:Reference>
<ds:Reference> // -----> without URI
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>k/bzxTU4+icrc+nSaR3WJi6VNEI=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
............
</ds:SignatureValue>
<ds:KeyInfo Id="_d36d665d-470b-429b-921c-f9381d2fc5f9">
........
</ds:KeyInfo>
<ds:Object>
.........
</ds:Object>
</ds:Signature>
</Sgntr>
这是我的验证Java代码
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(new FileInputStream("signedxmlJavaDoc.xml")); // Signed xml with xades
XPath xpath = XPathFactory.newInstance().newXPath();
String xpathExpression = "//*[local-name()='Signature']";
NodeList nodes = (NodeList) xpath.evaluate(xpathExpression, doc.getDocumentElement(), XPathConstants.NODESET);
if (nodes == null || nodes.getLength() == 0) {
throw new Exception("Signature is missing in the document");
}
Node nodeSignature = nodes.item(0);
CertificateDetails certDetails = CertificateUtil.getCertificateDetails("keystore.jks", "pass"); // signed jks also for verification
final KeySelector mockKeySelector = new KeySelector() {
@Override
public KeySelectorResult select(KeyInfo keyInfo, Purpose purpose, AlgorithmMethod method, XMLCryptoContext context) throws KeySelectorException {
return new KeySelectorResult() {
@Override
public Key getKey() {
return certDetails.getX509Certificate().getPublicKey();
}
};
}
};
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
DOMValidateContext valContext = new DOMValidateContext(mockKeySelector, nodeSignature);
final NodeList docNodes = doc.getElementsByTagName("Document:Document");
final Node docNode = docNodes.item(0);
ByteArrayOutputStream refOutputStream = new ByteArrayOutputStream();
Transformer xform = TransformerFactory.newInstance().newTransformer();
xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
xform.transform(new DOMSource(docNode), new StreamResult(refOutputStream));
InputStream refInputStream = new ByteArrayInputStream(refOutputStream.toByteArray());
DOMSignContext dsc = new DOMSignContext(certDetails.getX509Certificate().getPublicKey(), doc.getDocumentElement()); //added ----------
dsc.putNamespacePrefix(XMLSignature.XMLNS, "ds"); // ---------added
dsc.setURIDereferencer(new NoUriDereferencer(refInputStream));
NodeList nl = doc.getElementsByTagNameNS("http://uri.etsi.org/01903/v1.3.2#", "SignedProperties");
if (nl.getLength() == 0) {
throw new Exception("Signature is missing in signature");
}
Element elemSignedProps = (Element) nl.item(0);
valContext.setIdAttributeNS(elemSignedProps, null, "Id");
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
boolean coreValidity = signature.validate(valContext);
if (coreValidity) {
// signature verified
System.out.println("signature verified");
} else {
// signature verification failed
System.out.println("Signature failed core validation");
boolean sv = signature.getSignatureValue().validate(valContext);
System.out.println("signature validation status: " + sv);
// check the validation status of each Reference
Iterator i = signature.getSignedInfo().getReferences().iterator();
for (int j = 0; i.hasNext(); j++) {
final Reference ref = (Reference) i.next();
final String refURI = ref.getURI();
boolean refValid = ref.validate(valContext);
System.out.println("ref[" + j + "] validity status: " + refValid + ", ref URI: [" + refURI + "]");
}
}
}