So far, our WebService is readily configured for only accepting signed messages, forcing clients to include their Certificate for decrypting the digital Signature again on server side (verifying that the message is originally send from an authorized client). In addition to that, the client’s Certificate has to be signed (issued) itself by a Certificate Authority (CA) which is accepted by the WebService (in that the CAs Certificate is contained within the WebServices Truststore)
In this entry, we will set up the clients security infrastructure in that we create a Key-Pair and let the related Certificate be signed by the WebServices trusted CA. In the next episode, we’re going to build an accordant WebService-Client using Spring-WS’ WebServiceTemplate which will be configured to sign its outgoing messages by using the generated clients’ private Key and the associated signed Certificate.
First of all, we’ll create a new Keystore along with the client’s private Key (needed for encrypting the messages digital Signature) and the related Certificate (holding the public Key, needed to decrypt the encrypted digital Signature again). Again we’ll use Javas’ Keytool for that purpose, creating the Keystore on an arbitrary location on the clients file system, answering the upcoming questions accordingly.
keytool -genkey -alias wsClient -keyalg RSA -keystore Keystore.jks
Note, that we chose ‘wsClient‘ as the alias name for refering to that Key-Pair any time further.
If you remember the second part of this tutorial, we did some authorization based on the Common Name of the client Certificate. So if you rely on that kind of pattern, be sure to choose an appropriate Common Name when asked about it while generating the Clients’ Key-Pair.
Signing the Clients’ Certificate
The Certificate we’ve created is initially self signed. It needs to be signed by the WebServices’ trusted CA in order to be recognized as an accredited client Certificate. Hence we have to initiate a Certificate Signing Request and ‘send’ it to the CA in question:
keytool -certreq -keystore Keystore.jks -alias wsClient -file wsClient.cert.req
We’ve created a new Certificate Signing Request based on the Certificate which belongs to our newly generated Key-Pair (pointing to it by refering to the associated alias name). You’ll find a new file ‘wsClient.cert.req‘ which represents that Sigining Request which you now have to ‘send’ to the CA for signing.
Switching back to the server side, we now have to sign the ‘incoming’ Certificate Signing Request (after we made sure that the client behind that request is a trustworthy one). Following up the last episode, we’ll extend the folder structure within our ‘Certificate Factory‘ by creating a folder [CERTFACTORY_HOME]\signing in order to hold
Certificate Signing Requests and the resulting signed client Certificates. After putting the incoming Signing Request into that folder, we can start to sign the embedded client Certificate, again using OpenSSL (being on the command line at [CERTFACTORY_HOME]):
openssl ca -config openssl.cfg -out signing\signedWsClient.pem -infiles signing\wsClient.cert.req
Again, we have to convert the signed Certificate from PEM to DER format in order to be compatible with a Java Keystore:
openssl x509 -outform DER -in signing\signedWsClient.pem -out sigining\signedWsClient.cert
After that, we’ll send the signed client Certificate signedWsClient.cert (along with the CAs Certificate which you’ll still find under [CERTFACTORY_HOME]\ca\cacert.cert back to the Client. Note, that we also need to send the CAs Certificate because a Java Keystore need to establish a valid Certificate Chain when importing (signed) Certificates into a Keystore (and that’s exactly what we’re now going to to).
Importing the signed Client Certificate
Back on the client side, we now have to import the signed Certificate (which we’ve received from the CA) into the Keystore, since there’s still the original self signed one inside. First we have to import the CAs Certificate, statisfying the mentioned need for exhibiting a valid Certificate Chain when importing the signed client Certificate afterwards:
keytool -import -file cacert.cert -alias wsCA -keystore keystore.jks
Now we’re able to import the signed client certificate, which will automatically substitute the original self signed Certificate:
keytool -import -file signedWsClient.cert -alias wsClient -keystore keystore.jks
Note, that it’s essential to import the signed Certificate under the alias name under we’ve generated the clients Key-Pair originally.
We’ve created a clients’ Keystore which contains a private Key and a related signed Certificate. The Certificate has to be signed by the CA which our WebService trusts in. Having a client Certificate inside a request message which may be signed by another CA would result in the Rejection of that request, since that CAs Certificate don’t reside in the WebServices Truststore (of course you could also import more than one CA Certificate into your Truststore, so that the WebService would accept request messages with embedded Certificates which in turn are signed by different CAs).
For receiving a signed Certificate, we first have to generate and ‘send’ a Certificate Signing Request to the CA in question, which in turn have to sign the client’s Certificate and return it along with the CAs Certificate back to the client. The client will then import the CAs Certificate (as the root of the Certificate Chain for the signed client Certificate) and afterwards substitute the original self signed client Certificate with the new signed Certificate.
With that infrastruture at hand, we’re now prepared to implement a WebService-Client which will use the contained private Key in order to encrypt the digital Signature for arbitrary request messages (since your WebService asks for ‘Message Signing‘ according to its configured security policies from episode one) which automatically results in the embedding of the clients (now signed) Certificate within the request messages’ security header (which will be used by the WebService to decrypt the encrypted digital Signature along with some of our desired ‘side effects’ of being able to access to the Certificates’ attributes for authorization purposes or restricting access to our WebService to only a group of accredited Clients).
So in the next episode, we’re going to implement that Web-Service Client, also using Spring-WS (namely WebServiceTemplate and WebServiceGatewaySupport), which will sign all outgoing request messages accordingly (configuring the clients’ application context using Message Signing, leveraging the Keystore we’ve build within this episode).