SSL Fun with Tomcat and Android

I pieced together lots of things from Google results.

Creating a CA

This was mostly kind of easy. I put all my CA stuff in my own stash. First was to make all the directories and files needed in openssl.cnf.

mkdir -p ~/.local/etc/ssl/omgren.com_CA/{certs,crl,newcerts,private}
cp /etc/ssl/openssl.cnf ~/.local/etc/ssl/

Edit the openssl.cnf file so that the default CA section has

-dir    = /etc/ssl    # Where everything is kept
+dir    = /home/ren/.local/etc/ssl/omgren.com_CA    # Where everything is kept

Make a couple required files that don’t make themselves:

touch index.txt
echo 1000 | tee serial | tee crlnumber

Then create the CA cert:

openssl req -new -x509 -days 3650 -extensions v3_ca \
  -keyout private/cakey.pem -out cacert.pem \
  -config ../openssl.cnf

Generating CRL

openssl ca -config ../openssl.cnf -gencrl -out crl.pem

Adding CA to /etc/certs

cp cacert.pem /usr/local/share/ca-certificates/omgren.com/omgren.com_SSLCA.crt
update-ca-certificates -v -f

I saw Adding debian:omgren.com_SSLCA.pem so I was happy. Then I had to add the CA cert to Chrome and my phone.

Adding CA to Chrome

This was really easy, just download the CA cert, then go into Settings > Advanced Settings > HTTPS/SSL > Manage Certificates > Authorities > Import.

Adding CA to Android

This was easy on Android 4.0 (and not possible on 2.3). Just download the CA cert and it’s put into the system keystore!

It turns out you have to use BouncyCastle to create a truststore on android phones. I downloaded the Bouncy Castle Provider and then did the following command on my CA certificate:

keytool -importcert -v -trustcacerts -file ~/ssl/omgren.com_CA/cacert.pem \
  -alias ca -keystore trust.bks \
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath bcprov-jdk16-145.jar -storetype BKS

This then was put inside res/raw/ in my Android project directory.

Creating Tomcat SSL Keys

I just followed the Apache How-To for “Installing a Certificate from a Certificate Authority”.

keytool -genkey -alias tomcat -keyalg RSA -keystore awesome.jks

Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  awesome.omgren.com
What is the name of your organizational unit?
  [Unknown]:  awesome.omgren.com
What is the name of your organization?
  [Unknown]:  omgren.com
What is the name of your City or Locality?
  [Unknown]:  Los Angeles
What is the name of your State or Province?
  [Unknown]:  California
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=awesome.omgren.com, OU=awesome.omgren.com, O=omgren.com, L=Los Angeles, ST=California, C=US correct?
  [no]:  yes

Enter key password for <tomcat>
  (RETURN if same as keystore password):  

keytool -certreq -keyalg RSA -alias tomcat -file certreq.csr -keystore awesome.jks

Now copy the certreq.csr to the CA and sign it.

cp certreq.csr ~ren/ssl/omgren.com_CA/certs/awesome.omgren.com_req.pem

cd certs
openssl ca -config ../../openssl.cnf -in awesome.omgren.com_req.pem -out awesome.omgren.com_cert.pem

Now copy it and the CA cert back to Tomcat

cp ~ren/ssl/omgren.com_CA/cacert.pem ~ren/ssl/omgren.com_CA/certs/awesome.omgren.com_cert.pem /etc/tomcat7/ssl

keytool -import -alias root -keystore awesome.jks -trustcacerts -file cacert.pem
keytool -import -alias tomcat -keystore awesome.jks -file awesome.omgren.com_cert.pem

I had to remove everything except the certificate at the end fo awesome.omgren.com_cert.pem for it to work.

The next important thing to do is to create the truststoreFile in tomcat. this was pretty easy, too.

keytool -genkey -alias dummy -keyalg RSA -keystore truststore.jks
keytool -delete -alias dummy -keystore truststore.jks
keytool -import -v -trustcacerts -alias my_ca -file cacert.pem -keystore truststore.jks

Then to make Tomcat use it, just enable it in the server.xml. Uncomment this connector block:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="150" scheme="https" secure="true"
           keystoreFile="conf/ssl/awesome.jks" keystorePass="changeit"
           truststoreFile="conf/ssl/truststore.jks" truststorePass="changeit"
           clientAuth="true" sslProtocol="TLS" />

New problem is I can’t get android to use client certificates to connect to the page. So for the time being, I have to leave clientAuth="false".

Creating Client SSL certificates

cd certs
openssl req -config ../../openssl.cnf -new -nodes -out user_req.pem -keyout ../private/users/user_key.pem
openssl ca -config ../../openssl.cnf -out user_cert.pem -infiles user_req.pem
cd ../private/users
openssl pkcs12 -export -out user.p12 -inkey user_key.pem -in ../../certs/user_cert.pem

Then just download or otherwise send user.p12 to the user to install into their browser. This worked on Chrome, this did not work on Android.

Playing nicely with Android

For now, because I can’t install client certificates, I’m just trying to get plain SSL to work (clientAuth="false"). My first try was to just do a normal HttpURLConnection, but I get this error:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

This was fixed! I had to add my user.p12 key and the trust.bks I made, into res/raw/. Then I could do the ManagerFactories with them.