EMO has the ability to use passwordless login capabilities via certificate authentication using SSL. As many people will bemoan, however, setting up the Public Key Infrastructure (PKI) to provide this capability is actually fairly difficult.
This guide will walk you through the steps of setting up your own PKI as well as how to set up Tomcat to handle Certificate-based authentication.
The basic steps for handling the creation of the PKI are:
While other SSL-management systems are available, because OpenSSL is cross platform and free, we will be documenting OpenSSL for the handling of our PKI. However, if you wish to use other PKI-enabling programs, the basic steps outlined in this document will still generally apply.
Most linux distributions these days provide OpenSSL as part of their distribution. If you are a windows user you may obtain a precompiled binary installation package from the OpenSSL web site.
NOTE: Please watch for new releases to the OpenSSL packages. Every few months a new version of OpenSSL is released and most releases contain security-related bugfixes.
Once you have OpenSSL properly set up and the OpenSSL binary in your path, execute the following commands (unix OS assumed):
cd .../emo # your directory where emo is hosted, or wherever you would like keystore info to reside mkdir keys cd keys # we will generate various files into this directory # the following will prompt for a few values to put into the certificate request openssl req -new -newkey rsa:1024 -nodes -out ca.csr -keyout ca.key -dname "cn=$DOMAINNAME" openssl x509 -trustout -signkey ca.key -days 1825 -req -in ca.csr -out ca.pem
OpenSSL has several 'subparts' in its command. The portion of the command line that follows the openssl binary is the portion to use. For example, the first part:
openssl req ...
deals with X.509 Certificate Signing Request (CSR) Management., whereas
openssl x509 ...
deals with X.509 certificate data management. So the first command created a Certificate request as well as a new private key for the certificate authority, and the second command created a new Certificate Authority Certificate with a 5 year duration.
At this point in time, you have two main artifacts that need to be protected: ca.key, the private key for the certificate authority, and ca.pem the public certificate of the certificate authority. The private key of the certificate authority must be the most guarded portion of your security! Typically, this is given restricted privileges. If someone manages to steal the Certificate Authority private key, they may issue client certificates in your name.
Each certificate that is signed by the certificate authority will have a serial number assigned to the signed certificate. It helps when tracing when and where certificates were signed. To create the certificate serial number file in shell environments you can issue the command:
echo "02" > ca.srl
In a Windows environment, you may simply create a new file called ca.srl, open it with NotePad or equivilant text editor, and give the file the contents 02 and save it.
Each SSL handshake that is mutually authenticated requires two certificates: One for the server, and one for the client. Java also requires a keystore in which to store the certificate that is used by the Tomcat server.
Generate the keystore with the following command:
EMO_DIR=`pwd` PASS=mypassword DOMAINNAME=codeguild.net keytool -genkey -dname "cn=$DOMAINNAME" -alias emo -keyalg RSA -keystore $EMO_DIR/emokeystore -keypass $PASS -storepass $PASS
The important items in the command line are:
Next we import the certificate created in OpenSSL:
keytool -import -keystore $EMO_DIR/emokeystore -file ca.pem -alias selfca
The items in the command line are:
At this point, the keystore should be ready to go for tomcat.
Open Tomcat's server.xml in the TOMCAT_HOME/conf directory.
Locate the lines:
<Connector port="8443" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="conf/tomcatcerts" keystorePass="changeit" keyAlias="tomcat" />
By default, these lines are commented-out, so you probably need to uncomment them.
Set the attributes for keystore file (for us, same as truststore file), etc., to the values you created, such as:
<Connector port="8443" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="$EMO_DIR/emokeystore" truststoreFile="$EMO_DIR/emokeystore" keystorePass="$PASS" truststorePass="$PASS" keyAlias="emo" />
NOTE: replace $EMO_DIR with absolute path
NOTE: replace $PASS with the password
Leave "clientAuth=false" for now.
Fire up tomcat, and using your browser, attempt to connect to https://localhost:8443/. REMEMBER to use https, not http! If you have properly installed the certificate, your browser should prompt you whether you should really connect to this host because the Certificate Authority is not recognized. If you view the certificate you should see all the information you have input when creating the certificate request (CSR) your own certificate authority (CA).
Open the TOMCAT_HOME/conf/server.xml file and scroll down to where you enabled the SSL protocol. Change the client authentication attribute to true (clientAuthentication="true"). (Re)start Tomcat. Now if you attempt to connect to the SSL port (8443 by default). You will get an error message. That's good!
The procedure for the browser setup is nearly the same as for the server: first generate a CSR, then have the CA create a certificate.
openssl req -new -newkey rsa:1024 -nodes -out client1.req -keyout client1.key -subj '/C=US/ST=California/CN=emoclient/EMAILADDRESSfirstname.lastname@example.org'
The biggest difference here is that the email address on the certificate should be the email address on file (in Emo) of the login that should be used.
Note:For the email address (EMAILADDRESS), use the email address registered in Emo for the desired login.
This generates two artifacts: client1.req, and client1.key.
Now use the CA keys to sign the client:
openssl x509 -CA ca.pem -CAkey ca.key -CAserial ca.srl -req -in client1.req -out client1.pem
Now client1.pem will be a PEM encoded public key.
Now for the tricky part. Browsers like PKCS#12 certificates WITH a private key included, we have a PEM encoded public key only. So we use OpenSSL along with the client's private key to generate a PKCS#12 encoded certificate that the browser can use:
openssl pkcs12 -export -in client1.pem -inkey client1.key -out client1.p12 -name "Sample Client Cert"
The components of this command is:
Now copy this file client1.p12 and import it into your browser:
mkdir clientkey cd clientkey scp myuser@myserver:/path/to/emo/openkey/client1.p12 .
If you are using the Firefox browser, you can reach this via Tools -> Options. Click on the Advanced tab, and click on the "View Certificates" button. The screen displayed will have the option to import a new certificate.
Once you have imported the certificate into your browser, attempt to connect to the SSL port with Tomcat running. If you have more than one client certificate installed in the browser, the browser will ask you which certificate to present. Otherwise, it will attempt to send the only certificate you have available. If things have proceeded correctly, you should now see the Tomcat start page in SSL!
The basic concept is the same as browser-based passwordless logins. But the browser has its own 'truststore' of certificate authorities, and a Java application will default to the one embedded in its VM code. But the default truststore in the client will not know about the self-signed certificate on the server (assuming they are different computers). The browser, when presented with a server self-signed certificate, puts up a dialog asking whether the user wants to trust the server certificate. But a Java application offers no such luxury, and fails immediately. Further, instead of importing the PKCS#12 certificate into the browser, the application USES IT as a keystore.
You can list the contents of your PKCS#12 certificate in the following way:
keytool -v -list -keystore client.p12 -storetype pkcs12
That command line argument has the following components:
See the Sun JSSE Guide for more information.
The client certificate is only the first part of the chain. You also need a truststore that validates the client certificate. We take a shortcut here and copy the truststore from the server:
# assume we are in the clientkey directory scp myuser@myserver:/path/to/emo/openkey/emokeystore ./clientkeystore
Put these values (change as necessary, and omit the "-D" prefix) into a file named 'ant.properties' in order to use the ssl-test target in ant. Or make sure they are in the startup script for any Java application you write.
-Djavax.net.ssl.keyStoreType=pkcs12 -Djavax.net.ssl.trustStoreType=jks # assume directory 'clientkey' is in the emo directory, adjacent to build.xml -Djavax.net.ssl.keyStore=clientkey/clientcert.p12 -Djavax.net.ssl.trustStore=clientkey/clientkeystore -Djavax.net.debug=ssl -Djavax.net.ssl.keyStorePassword=$PASS -Djavax.net.ssl.trustStorePassword=$PASS
When creating your SSL client in Java, it is always best to use debug output until you have a successful connection. This can be turned on with the command line argument:
Setting up a PKI (public key infrastructure) is no easy task, but hopefully this document will point you down the right path. If you need assistance setting up your own PKI, CodeGuild can provide consulting to get you going.
The Tomcat docs have some good information on getting SSL set up: http://tomcat.apache.org/tomcat-5.5-doc/ssl-howto.html
There is a sample security chapter in Tomcat: The Definitive Guide available online at http://www.oreilly.com/catalog/tomcat/ Click on "sample chapter" to view the PDF formatted section of the book.