I encountered issues while working with CXF WS-Security and Signature verification. I use WSS4JInInterceptor
on server side in order to verify signature over Body
element.
- When I usee BinarySecurityToken
(DirectReference
) as a key identifier type everything works fine;
- When I use X509IssuerSerial
(IssuerSerial
) as a key identifier type signature verfication on Server side fails.
This is configuration on server side:
<bean id="wss4jIn" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="Signature" />
<entry key="signaturePropFile" value="config/security/truststore.properties" />
<entry key="signatureAlgorithm" value="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<entry key="signatureKeyIdentifier" value="X509IssuerSerial"/>
<entry key="signatureParts"
value="{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body" />
</map>
</constructor-arg>
</bean>
If I send (from client side) SOAPEnvelope with this SOAPHeader:
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" SOAP-ENV:mustUnderstand="1">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-69c28b5e-3566-4fab-b26f-bd28e97c21e9">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="SOAP-ENV enc xsd xsi"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_e078e477-59bc-401d-83f5-a11925947d19">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="enc xsd xsi"/>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>MMQ1CZWFv5ZK3KMzEpWyBVpFas73hXiedDeKyKjRUQ4=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>Amn7favWhD9RA6SHrJ6RYf6BIhdRH2N2r3WXh2+auBi3MlPstcBFA1oqBrVt3PPvTs/LZrrt6AfZWspp0YpjPEdTuDuEd1x8HrSKBgxBt+QUqfiio4WGhUJ4k/5b/loNd9D1a48ic0PloM3FsNHf+kQJeb5rPeW5f8aeRtFBUCg=</ds:SignatureValue>
<ds:KeyInfo Id="KI-b49617ba-b2d8-4bad-9c46-d772389537df">
<wsse:SecurityTokenReference wsu:Id="STR-4e662377-c736-48c5-a0c1-11a1473769ee">
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>1.2.840.113549.1.9.1=#xxx,CN=xxx,OU=xxx,O=xxx,L=xxx,ST=xx,C=xx</ds:X509IssuerName>
<ds:X509SerialNumber>xxx</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
</SOAP-ENV:Header>
I will get SOAPFault:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode xmlns:ns1="http://ws.apache.org/wss4j">ns1:SecurityError</faultcode>
<faultstring>A security error was encountered when verifying the message</faultstring>
</soap:Fault>
</soap:Body>
With debug log output I didn't get much information. But while debugging, I discovered that org.apache.wss4j.dom.processor.SignatureProcessor
fails at this point:
if ((certs == null || certs.length == 0 || certs[0] == null)
&& secretKey == null
&& publicKey == null) {
throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK);
}
It is line 197 that throws exception in wss4j-ws-security-dom-2.1.0. This means that certificate and publicKey are null. This drives me to a conclusion that I didn't think enough from beginning - I didn't realize that there is no Certificate that Signature can be validated against. Also, my conclusion is that in case of X509IssuerSerial, you can verify signature only in case you have Certificate on receiving (in this case Server) side.
Does anyone have better explanation?