The Story so far
In the first episodes, we configured Spring-WS for rejecting incoming Messages which were sent from ‘unauthorized’ Clients, including the demand for Clients to be trusted by our WebService Endpoint: We only trust in a Client, if its Certificate is in turn issued by a Signer we trust. In our case, the Clients Certificate have to be issued by a Certificate Authority (CA) we trust. We inform Spring-WS about that trusted CA by importing the CAs Certificate into our Truststore (a common Java Keystore), which is declared as the Truststore to check against within Spring-WS’ application context.
In other words, we trust all Client Certificates which are directly issued by the CA which itself is trusted by
the Service Endpoint (by providing its Certificate in the WebServices Truststore). This ‘Chain of Trust’ is going to be validated for every Client’s Certificate (by trying to build a so called Certificate Chain) whenever a Client is transmitting an appropriate Request Message to our WebService.
Certificate Authority … again
As we’ve already mentioned, the Certificate Authority is an ‘entity’, which issues Certificates for use by other parties. Within this role, it kind of acts like an autonomous, accepted party which all participants rely on. Although there are some commercial CAs (like VeriSign or Thawte Digital Certificates) we are free to come up with an own CA.
Let’s say, we want to create a custom CA, ‘representing’ the Host of our WebService, e.g. a CA which is commonly used by the Company which provides the WebService (so to say a Companies own CA). All potential Clients of that WebService have to ask to be signed by that Companies CA (we’ll get back to that task called ‘Certificate Signing Request’ in a further episode, when switching to the client side) in order to be recognized as an accredited Client who is allowed to access the Companies WebService.
The following sections will give some step by step instructions on how to build your own CA using OpenSSL and importing the CAs Certificate into Spring-WS’ Truststore afterwards. In this regard, this episode is not too strongly related to Spring-WS but rather serve as a general approach on setting up a CA Key-Pair as a vital part of a custom Security infrastructure (sometimes called PKI – Public Key Infrastructure).
Before we start to create the CAs Key-Pair, we have to install OpenSSL (i will show how to do so for Windows, but the
steps are very similar on a unix based operating system). If not done yet, you first have to download and install OpenSSL (you might get a download of a precompiled win version via this site – you may also have to download the ‘Visual C++ 2008 Redistributables’ fom the same site should you detect and need to fix some problems under Windows …)
Next, we’ll build an appropriate folder structure where we’ll initially create and store our CAs private Key and the related Certificate (holding the associated public Key). We’ll extend that structure in some following sessions in order to store some more data like Certificate Signing Requests and the like.
I’ll use [CERTFACTORY_HOME] for an arbitrary folder of your choice as the root folder for our structure to build:
Next, we have to place some files, which are needed by OpenSSL for properly creating a new CA:
- Create a new (empty) Textfile named index.txt under [CERTFACTORY_HOME]\ca
- Copy file serial from [OpenSSL_HOME]\bin\PEM\demoCA to [CERTFACTORY_HOME]\ca
- Copy OpenSSLs Master-Configuration-File openssl.cfg from [OPENSSL_HOME]\bin directly to [CERTFACTORY_HOME]
The file openssl.cfg serves as OpenSSLs Master-Configuration. Here we have to configure OpenSSL in order to create a CA according to our whiches. For this purpose we’ll append a new configuration section that should be used whenever
we want to create a new CA, defining some defaults on where OpenSSL should place the generated Keys, which input data to use and some settings used for building the CAs certificate:
[ WEBSERVICE_CA ] dir = ./ca certs = $dir/certs crl_dir = $dir/crl database = $dir/index.txt new_certs_dir = $dir/newcerts certificate = $dir/cacert.pem serial = $dir/serial crlnumber = $dir/crlnumber crl = $dir/crl.pem private_key = $dir/private/cakey.pem RANDFILE = $dir/private/.rand x509_extensions = usr_cert default_days = 365 default_crl_days = 30 default_md = sha1 preserve = no policy = policy_anything [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional
Note, that we named our new section WEBSERVICE_CA (of course you are free to come up with a name of your own).
The only thing left is to link to our customized configuration section as the configuration to use whenever a new CA should be created via this configuration file. This is done some lines above within section [ ca ], where we now will link to our section as the default configuration:
[ ca ] default_ca = WEBSERVICE_CA
Look … it’s a … new CA
We’re now ready to create our custom CA. Make sure that [OpenSSL_HOME]\bin is on your path, so that you’re able to
invoke OpenSSL from everywhere from the command line. Now, switch to [CERTFACTORY_HOME]> (where we’ve placed our adapted configuration file) and start to build your own CA by typing the following command:
openssl req -x509 -newkey rsa:1024 -keyout ca\private\cakey.pem -out ca\cacert.pem -config openssl.cfg
You will be asked to give some relevant information related to the new CA (like some organisational data and a pass phrase for restricting access to the CAs Key-Pair – you’re asked for it again, at least when signing some Client Certificates with the CAs private Key at later time). After you’ve answered the questions appropriately, you’ll find the new CAs public Key (embedded within an accordant Certificate) under [CERTFACTORY_HOME]\ca\cacert.pem and the related private Key under [CERTFACTORY_HOME]\ca\private\cakey.pem.
Note, that the created Certificate is supplied in so called PEM-Format – in order to import it into a Java-Keystore, we have to convert it accordingly:
openssl x509 -outform DER -in ca\cacert.pem -out ca\cacert.cert
Now if you take a look at [CERTFACTORY_HOME]\ca, you’ll find the converted Certificate with the specified name cacert.cert.
Now let’s come up with a new Java-Keystore which will serve as the before mentioned Truststore for Spring-WS (used by our Security Interceptor, or better by the injected KeyStoreHandler). We’ll use Java’s keytool for that purpose, so be sure to have [JAVA_HOME]\bin on your path.
Unfortunately, if using keytool you can’t create a new Keystore without also creating a new Key-Pair initially, which is automatically embedded within the new Keystore. As we don’t need this Key-Pair within our Truststore (we only need the CAs Certificate within), we’ll provide a Dummy which we’ll delete afterwards. It’s a good idea to initially place that Java-Keystore within our folder structure, so we might create another separate folder for storing our Truststore, like [CERTFACTORY_HOME]\truststore. After switching to that new folder, we’re ready to go:
keytool -genkey -alias dummy -keyalg RSA -keystore truststore.jks
Again you have to answer some questions, related to the new Keystore (like the password to securely refer to the Keystores content or getting permission to import some other Certificates), again some organisational data belonging to the initial Key-Pair and an associated individual passwort.
As you may have seen, the initial created Key-Pair is ‘labeled’ by an alias Name (the name to uniquely refer to that Key-Pair within the Keystore) called dummy, which we’ll use immediately to delete the dummy Key-Pair:
keytool -delete -alias dummy -keystore truststore.jks
Now we’re ready to import the (already converted) Certificate of our trusted CA:
keytool -import -file ..\ca\cacert.cert -alias trustedCA -keystore truststore.jks
Know the Score
We’re ready to go with our newly created Trustore (containing the Certificate of our also newly created custom CA) now. The only thing left is to place the Keystore accordingly, so that Spring-WS is able to refer to it at runtime within your deployed environment. If you remember the first episode, we already configured Spring-WS for that purpose:
<bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean"> <property name="location" value="/WEB-INF/MyTruststore.jks"/> <property name="password" value="MyJavaKeyStorePassword"/> </bean>
As you see, we have to make sure that our Keystore will be deployed under /WEB-INF using the Name MyTruststore.jks (Spring-WS needs to run within a Web-Container, as it’s front controller / message dispatcher is a Servlet). Of course you also have to keep the property password in sync with the password you’ve assigned to the Keystore (while we created it).
OpenSSL allows for the creation of new Certificate Authorities. We created a custom CA which will serve as the WebServices entity to trust. Now, all Client Certificates, which will arrive within incoming request messages have to be signed by that new CA. We said so by importing the CAs Certificate into a newly created Java-Keystore, which have to be provided as the Truststore, which is refered by Spring-WS’ Security Interceptor (more precisely, the KeyStoreHandler, which gets called by the Security Interceptor).
In the next episode, we’ll switch to the client side and see how to come up with a Client’s private Key and a related Certificate which gets signed by our CA. We’ll then implement a WebService-Client that will sign its request messages
in accordance to our claimed security policies (also using Spring-WS) and call our secured WebService.