And not because the theory is over my head, or because I couldn't find information on the subject - but because I was asked to simulate an existing production environment in development. A Two-Way SSL (or Mutual Authentication) setup, to be specific. A configuration that takes SSL setup to the limit!
If you need a primer on this subject, the theory and an example using Weblogic's demo setup is laid out clearly in this excellent article:
Usually in development environments you can cut corners - but not with security. In fact I discovered it is more of a challenge for a couple of reasons:
1) Just about everyone who writes about it assumes you're setting it up for real and skips over the details if you don't want to get involved with a signing authority like Verisign - or, like the article above, you're using a test CA that has already been set up.
2) You have to simulate all the parts - including the bits the Verisigns and Thawtes usually take care of.
So to try to do the noble thing and save one or two of you that may be tortured with the same task, I am going to reveal the secrets of setting up Two-Way SSL using Java and Weblogic Tools using a Self-Signed CA certificate for development environments.
The tools we need for the job are:
- Java keytool
- BEA's modifed keytool: ImportPrivateKey
- BEA's CertGen - Certificate Generator
All these tools do similar things and it's the subtle differences that'll kill ya. Be warned - you may be safer playing with a chainsaw! ;)
(I have a hunch there may be a way you can do this with just Java keytool, but I'll try to crack that one later on. If I do I'll post the solution here.)
I'm assuming, of course, that you've got Weblogic installed. For the record I'm using 9.2 and you should be somewhere in that vicinity too.
Note: Before you start, run setDomainEnv in the bin directory of your server domain.
e.g. on Windows:
- Use CertGen to Generate Server Private Key and Certificate
What we need at the outset is for everyone to trust us. We're all going to trust each other here because I say so. That's what the selfsigned switch is all about. In the real world, we trust each other because we mutually trust a Certificate Authority (CA) like Verisign. Here we're saying "I am the CA".
java utils.CertGen -selfsigned -certfile MyOwnSelfCA.cer -keyfile MyOwnSelfKey.key -keyfilepass mykeypass -cn "My Own Self CA"
You should see this response in the command window:
Generating a self signed certificate with common name My Own Self CA and key strength 1024
- Create the Identity Keystore
CertGen created a unique and secret Private Key for the server we're using and the Self-signed Root Certificate for us. But Java wants them packaged up neatly into a keystore.
The one thing Java keytool doesn't do is import a ready-made private key...
Fortunately BEA are a smart bunch and created a utility to help.
And just to make sure there was no confusion about what it does, they called it ImportPrivateKey.
Told you they were smart, didn't I?
Now run this:
java utils.ImportPrivateKey -keystore MyOwnIdentityStore.jks -storepass identitypass -keypass keypassword -alias trustself -certfile MyOwnSelfCA.cer.pem -keyfile MyOwnSelfKey.key.pem -keyfilepass mykeypass
Imported private key MyOwnSelfKey.key.pem and certificate MyOwnSelfCA.cer.pem
into a new keystore MyOwnIdentityStore.jks of type jks under alias trustself
- Import the Certificate into a new Trust keystore
If you read the Monduke article from above, you'll know the name of the game is trust.
When the client asks the server for a connection, the server will only allow access if it trusts the signer of the client's certificate. This is going to be the "My Own Self CA" and to make it happen we need our trusty MyOwnSelf certificate packed up into a separate keystore called the Trust Keystore. When the client presents it's certificate, this is where the server will look to see if it trusts the signature of the CA.
keytool -import -trustcacerts -alias trustself -keystore TrustMyOwnSelf.jks -file MyOwnSelfCA.cer.der -keyalg RSA
(Replace with equivilent ImportPrivateKey command?)
Here's the tool's response:
Enter keystore password: trustpass
Owner: CN=My Own Self CA, OU=FOR TESTING ONLY, O=MyOrganization, L=MyTown, ST=My
Issuer: CN=My Own Self CA, OU=FOR TESTING ONLY, O=MyOrganization, L=MyTown, ST=M
Serial number: ...
Trust this certificate? [no]: yes
Certificate was added to keystore
- Configure WLS with Identity and Trust stores
Now we have an Identity Keystore for Server to Client communication (to supply certificates to the client) and a Trust Keystore for Client to Server communication (to accept certificates supplied by the client). We now need to tell Weblogic to use them.
In the Weblogic Admin Console jump to the Keystores page and choose "Custom Identity and Custom Trust"
Enter the locations of your Identity and Trust keystores, the passphrases identitypass and trustpass respectively, along with the alias in the SSL tab (I used 'trustself' above). The Private Key password in this example is 'keypassword'.
When you've saved and activated your changes in the admin console, check the Weblogic command output window to verify that your Identity and Trust keystores were loaded with no problems.
- Test One Way SSL
Under the SSL tab, make sure Two Way Client Cert Behavior is set to "Client Certificates Not Requested".
This is important - make sure you have these entries in your config.xml file in the config directory of your domain:
If any are different, edit and save the config.xml to match, and then restart the Weblogic server.
Now browse to https://localhost:7002/console
All being well, the server should present the client with a certificate.
However, the client has no reason to trust our Self-Signed Certificate yet, so it will throw up a dialog. (Also the name doesn't match that of the server. This isn't too important in a development environment - but something you'd definitely fix for production.)
- Install the Server Certificate on the Client
To have the client trust the server permanently, we need to Install the certificate. Hit install and follow the instructions. When you next go into the Certificate Management screen you will see the "My Own Self CA" listed under "Trusted Root Certification Authorities"
- Test Two Way SSL without Client Certs required
- Create a client certificate using the Self-certified CA certificate
Now we basically need to set up the opposite situation on the client that we did on the server. But, of course, there are some crucial differences. Wouldn't be any fun otherwise...
It's time to generate the certificate for the client. This time we want the Certificate to identify the client machine (usually the user of the machine - you can set up one client certificate per user and have more than one on a machine if you need to), AND we want to ensure that the Client is linked to the Trusted CA Root Certificate we fabricated earlier. (This is why the ou (operating unit) of the client certificate must match the identity of the Trusted CA Certificate - in this case "My Own Self CA".)
java utils.CertGen -certfile MyClientCert.cer -keyfile MyClientKey.key -keyfilepass clientkeypass -cacert MyOwnSelfCA.cer.der -cakey MyOwnSelfKey.key.der -cakeypass mykeypass -cn "My Client" -e "firstname.lastname@example.org" -ou "My Own Self CA"
Generating a certificate with common name Client User and key strength 1024 issued by CA with certificate from MyOwnSelfCA.cer.der file and key from MyOwnSelfKey.key.der file
- Bundle up the Certificate and Key into a Format the Browser will like (it's PKCS12 if you have to know)
Having the client certificate in bits won't be much appreciated by the browser, so we need to package it up - like a identity keystore, but in a different format that browsers like.
java utils.ImportPrivateKey -keystore MyClientCert.p12 -storepass clientpass -storetype pkcs12 -keypass clientkeypass -alias clientcert -certfile MyClientCert.cer.pem -keyfile MyClientKey.key.pem -keyfilepass clientkeypass
- Import Trusted CA Certificate and Client Certificate into Browser There are essentially two pieces to the pie. First you need to import the Root CA Certificate so the browser trusts certificates sent from the server.Locate the MyOwnSelfCA.cer.der file that was made in the very first step, and import it into your browser as a Trusted Root Certification Authority (Tools > Options > Content > Certificates in IE)If using IE doesn't make you go weak at the knees, the easiest thing to do now is double-click the certificate file you just made. (MyClientCert.p12) IE will launch it's import certificate wizard and you'll be ready to roll.
- Test Two-Way SSL
The moment of truth:
Browse to https://localhost:7002/console
This is what should happen:
- Client request to server
- Server response - sends certificate signed by "My Own Self CA" and requests a certificate from the client
- Client examines certificate - decides to Trust it since it has the CA certificate for "My Own Self CA"
- Client sends its certificate to the server, again signed by "My Own Self CA"
- Server finds up "My Own Self CA" in its Trust store and decides to trust the client
- Server sends requested resource back to the client in encrypted form
- Client deciphers the encryption and displays the result - in this case the Weblogic Admin Console login page.
Now go into the WLS Admin Console and switch the
Take a look at the WebLogic server console output:
The only way we got to the page was because we set Weblogic to ignore the fact that there was no client certificate. For truly secure Two-Way SSL where only authorized clients can talk to our server, we need to put a certificate on the client to send and require that the server check it.
If you want to make life hard for yourself, then I'll assume you know how to import client certificates in your favourite browser and move on...