It's my first question over the web. Hope it will make sense.
I have seen several blogs related to this issue over the Web, and I have tried few of the ideas presented in them with no success. Here's my situation:
I have a web App calling a WCF web service which then call a Java web service. They are all on different servers. The call between the WCF web service to the java web service is not over https as the certificate will be enough to identify the caller (Message security therefore).
- Java web service (black box)
The Java web service requires to received a signed message and works as per below:
Before each request is processed a handler intercepts all incoming messages and performs the following validation rules:
1. Does the message contain a security header
2. Does the message contain the correct security header ID
3. Is the message been signed correctly
4. Does the message contain a KeyInfo x.509 certificate
5. Is the certificate issued from a trusted CA – configuration based
6. Is the certificate valid (not expired, revoked)
7. Does the certificate contain the correct policy OID
Once all of these steps have been confirmed then the message can be processed, if any step fails then a soap message exception will be returned.
The SOAP security header should validate against xxx…w3.org/TR/SOAP-dsig/ digital signature specification.
The most complete description can be found here xxx…ibm.com/developerworks/webservices/library/ws-security.html this IBM article lists the details of each WS-Security header, additionally a sample signed SOAP message has been provided.
When signing the SOAP message you must also add they x.509 certificate into the message KeyInfo this is required for the certificate validation.
SOAP Request should like this:
<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<ds:Signature xmlns:ds="xxx...w3.org/2000/09/xmldsig#" Id="Signature001">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="xxx...w3.org/TR/2001/REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="xxx...w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="xxx...w3.org/2000/09/xmldsig#enveloped-signature"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="xxx...w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>soe1PnaGXVGrsauC61JSHD+uqGw=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#KeyInfo001">
<ds:DigestMethod Algorithm="xxx...w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>Y9SRPQ9TcDu+GazO3LFwodEdhaA=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>jBX/8XkY2aCte7qgXEp1sbNWmQcK/90iVL58sAvwYAEcBABGzOk2agxR0HvWrNa6ixkocAQ205lggwOxnxZJvoVozVYAAjcLtayPBOUYrnSEBFrwKWP/vxgvUDRIdXeIuw5GLY87NrTQMm1Ehf/HvMX9hTBJn4Nm8RdDiUmPcIo=</ds:SignatureValue>
<ds:KeyInfo Id="KeyInfo001">
<ds:X509Data>
<ds:X509Certificate>MIIEbZCCA1WgAwIBAgIES1XpMjANBgkqhkiG9w0BAQUFADBYMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdlbnRydXN0MRIwEAYDVQQDEwllbnRydXN0U00xEjAQBgNVBAMTCWVudHJ1c3RDQTAeFw0xMDA0MjIxMDQ4MDBaFw0xMzA0MjIxMTE4MDBaMGoxFTATBgoJkiaJk/IsZAEZFgVsb2NhbDEXMBUGCgmSJomT8ixkARkWB2VudHJ1c3QxEjAQBgNVBAMTCWVudHJ1c3RTTTESMBAGA1UEAxMJZW50cnVzdENBMRAwDgYDVQQDEwdSYnMgUmJzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMf88L2JjLPG1hNmTA/KBiC53WVwS2WU9Jh3lC1Rob6RMzOojomZ/dNrvSRB6nzWeXJpZXwik4XFrsAq24By2SZpLTO4p8Vcq71mTAfDu33cnO49Au2pwNvcMn5qIKBk1Xx+oVb4fzK9ncTRu7bW46HsIYth+qkGhbI2JEHwr/zwIDAQABo4IBrzCCAaswCwYDVR0PBAQDAgeAMCsGA1UdEAQkMCKADzIwMTAwNDIyMTA0ODAwWoEPMjAxMjA1MjgxNTE4MDBaMCMGA1UdIAQcMBowCwYJYIZIAYb6awoEMAsGCSqGSIb2fQdLAzAbBgNVHQkEFDASMBAGCSqGSIb2fQdEHTEDAgEBMIHGBgNVHR8Egb4wgbswb6BtoGukaTBnMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFzAVBgoJkiaJk/IsZAEZFgdlbnRydXN0MRIwEAYDVQQDEwllbnRydXN0U00xEjAQBgNVBAMTCWVudHJ1c3RDQTENMAsGA1UEAxMEQ1JMMTBIoEagRIZCZmlsZTovLy8vTVNJREhVLTQ0NUE0RkVFL0NSTC9lbnRydXN0Y2FfZW50cnVzdHNtX2xvY2FsX2NybGZpbGUuY3JsMB8GA1UdIwQYMBaAFBvSL6cPz8L5shubV58yf0pczKzuMB0GA1UdDgQWBBT1/j6OSS8FTjwqluvew16sv7h+VzAJBgNVHRMEAjAAMBkGCSqGSIb2fQdBAAQMMAobBFY4LjADAgSwMA0GCSqGSIb3DQEBBQUAA4IBAQBXxRIA4HUvGSw4L+4uaR51pY4ISjUQWo2Fh7FYBMt29NsKCTdur1OWVVdndt1yjXP4yWXxoAhHtvZL+XNALUFlR2HAWiXuL1nRcxHkB98N5gPqQzW/lJk9cLtL4hVp28EiEpgmKT3I3NP2Pdb2G5MMOdvQ/GFb2y6OwblR8ViPQ8B2aHWzXMrH+0qadPAuBhXyAohwb+mMuYT/ms6xpGi1NMYuYMf6XONz9GkZgnGnMwa+9CCQws1HNz8WYHtmFIxLsVuEWc/0a1vg4IYX1Ds/ttyhJGTVXOSJSkBz8kRyj1pNBDdc1KeG8M++O8m8VgRTJvYaPc7NMiclISukGpea</ds:X509Certificate> </ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</S:Header>
<S:Body Id="ABC">
<ns2:createUser xmlns:ns2="http://webservice.rbs.emea.ps.entrust.com/" xmlns:ns3="http://webservice.rbs.emea.ps.entrust.com/types/CertificateException" xmlns:ns4="http://webservice.rbs.emea.ps.entrust.com/types/UserException">
<userID>0061020051</userID>
</ns2:createUser>
</S:Body>
</S:Envelope>
- WCF web service
I have one server certificate (p7b format from a trusted CA) that I installed where my WCF web service workstation (dev) is by using the mmc Certificate Snap-in (at the moment cert is in the Trusted Publishers). I don't think I need another cert on the Java server as the response should be in clear (neither signed or encrypted). I am still a bit confused on this certificate -and certificates in general- as it seems to hold only a public key.
Here is the app.config of my test project:
<client>
<endpoint address="http://entrust-user-certification-uat.fm.rbsgrp.net/rbs/WebAS"
behaviorConfiguration="endpointCredentialsBehavior" binding="wsHttpBinding"
bindingConfiguration="WebAsServicePortTypeBinding" contract="IWebAsServicePortType"
name="WebAsServicePortType">
<!--<identity>
<dns value="entrust-user-certification-uat.fm.rbsgrp.net" />
</identity>-->
</endpoint>
</client>
<bindings>
<wsHttpBinding>
<binding name="WebAsServicePortTypeBinding" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Message">
<message clientCredentialType="Certificate" negotiateServiceCredential="false"
establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="endpointCredentialsBehavior">
<clientCredentials>
<clientCertificate findValue="entrust-user-certification-uat.fm.rbsgrp.net"
storeLocation="LocalMachine" storeName="TrustedPublisher"
x509FindType="FindBySubjectName"></clientCertificate>
<serviceCertificate>
<!--
Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate
is in the user's Trusted People store, then it will be trusted without performing a
validation of the certificate's issuer chain. This setting is used here for convenience so that the
sample can be run without having to have certificates issued by a certificate authority (CA).
This setting is less secure than the default, ChainTrust. The security implications of this
setting should be carefully considered before using PeerOrChainTrust in production code.
-->
<authentication certificateValidationMode="None" revocationMode="NoCheck" trustedStoreLocation="LocalMachine"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
When I ran a simple test:
WebAS entrustService = new WebAS();
ActivationCodes certCodes = entrustService.createUser("testNomad");
I've got the error:
failed: System.Web.Services.Protocols.SoapException:
javax.xml.soap.SOAPException: No Signature element found in soap message
How could I force the signing process for each message? I was thinking I could do it through WCF configuration quite easily. Any help would be greatly appreciated !
Best Answer
OK. After few tries and errors here is the solution using SignedXml and IClientMessageInspector/BeforeSendRequest pattern. Thanks a lot to Yaron Naveh for his relevant suggestions.
and the CustomSignedXml class: