Validating a Signature of a SOAP Message
The solution is:
private boolean validateSignature(Node signatureNode, Node bodyTag, PublicKey publicKey) {
boolean signatureIsValid = false;
try {
// Create a DOM XMLSignatureFactory that will be used to unmarshal the
// document containing the XMLSignature
String providerName = System.getProperty
("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",
(Provider) Class.forName(providerName).newInstance());
// Create a DOMValidateContext and specify a KeyValue KeySelector
// and document context
DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(publicKey), signatureNode);
valContext.setIdAttributeNS((Element) bodyTag, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id");
// Unmarshal the XMLSignature.
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
// Validate the XMLSignature.
signatureIsValid = signature.validate(valContext);
} catch (Exception ex) {
logger.error("An Error Raised while Signature Validation");
logger.error("Cause: " + ex.getCause());
logger.error("Message: " + ex.getMessage());
}
return signatureIsValid;
}
where
public class X509KeySelector extends KeySelector {
PublicKey key;
/**
* Constructor.
*
* @param key a public key of a certificate which need to be validated.
*/
public X509KeySelector(PublicKey key) {
this.key = key;
}
/**
* @return a KeySelectorResult with a predefined key.
*/
public KeySelectorResult select(KeyInfo keyInfo,
KeySelector.Purpose purpose,
AlgorithmMethod method,
XMLCryptoContext context) throws KeySelectorException {
return new KeySelectorResult() {
@Override
public Key getKey() {
return key;
}
};
}
}
and give to the X509KeySelector a public key you need to validate the signature.
Well, I've managed to validate the reference digest: canonicalize -> sha1 -> base64. The problem is I can't validate the signature itself. I've tried:
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(signedInfoTag);
trans.transform(source, result);
String xmlString = sw.toString();
Signature sig = Signature.getInstance("SHA1withRSA", "BC");
sig.initVerify(cert.getPublicKey());
sig.update(xmlString.getBytes());
byte[] signatureValueDecoded = Translator.base64StringToByteArray(signatureValue);
sig.verify (signatureValueDecoded);
where xmlString is a < SignedInfo > tag. I've read this. Still I don't know, how to format the xml in such a way. Actually it has to be done in-memory somehow