Wiki

Clone wiki

BibSonomy / development / SSL-Certificates

Introduction

For a SSL-secured connection to a (remote) MySQL database you have to hold the corresponding certificates for Java.

Links:

Java Security documentation

JSSE reference guide

keytool man-page

MySQL ConnectorJ and SSL

Definitions

There exists a truststore and a keystore which are described in the section Terms and Definitions:

Keystores and Truststores

A keystore is a database of key material. Key material is used for a variety of purposes, including authentication and data integrity. There are various types of keystores available, including "PKCS12" and Oracle's "JKS."

Generally speaking, keystore information can be grouped into two different categories: key entries and trusted certificate entries. A key entry consists of an entity's identity and its private key, and can be used for a variety of cryptographic purposes. In contrast, a trusted certificate entry only contains a public key in addition to the entity's identity. Thus, a trusted certificate entry can not be used where a private key is required, such as in a javax.net.ssl.KeyManager. In the JDK implementation of "JKS", a keystore may contain both key entries and trusted certificate entries.

A truststore is a keystore which is used when making decisions about what to trust. If you receive some data from an entity that you already trust, and if you can verify that the entity is the one it claims to be, then you can assume that the data really came from that entity.

An entry should only be added to a truststore if the user makes a decision to trust that entity. By either generating a keypair or by importing a certificate, the user has given trust to that entry, and thus any entry in the keystore is considered a trusted entry.

It may be useful to have two different keystore files: one containing just your key entries, and the other containing your trusted certificate entries, including Certification Authority (CA) certificates. The former contains private information, while the latter does not. Using two different files instead of a single keystore file provides for a cleaner separation of the logical distinction between your own certificates (and corresponding private keys) and others' certificates. You could provide more protection for your private keys if you store them in a keystore with restricted access, while providing the trusted certificates in a more publicly accessible keystore if needed.

=== Defaults ===

See CustomizingStores:

  • The default keystore is empty

  • The default truststore is stored in <java-home>/lib/security/

Both can be changed with the following system properties

-Djavax.net.ssl.keyStore=path_to_keystore_file
-Djavax.net.ssl.keyStorePassword=password
-Djavax.net.ssl.trustStore=path_to_truststore_file
-Djavax.net.ssl.trustStorePassword=password 

However, standard CA certificates from <java-home>/lib/security/cacerts will not be available and therefore https-connections to other servers will not be possible anymore without further ado. Therefore this is no good solution.

It is better to add new certificates to the existing truststore or to copy the truststore, add the certificates and communicate that to the JVM via the system properties.

Adding SSL-certificates to the truststore

Importing a truststore

In the directory <java-home>/lib/security/ (in ubuntu use a symlink to /etc/java-7-sun/security) add the keys from /home/bibsonomy/tomcat/conf/truststore via

sudo keytool -importkeystore -srckeystore /home/bibsonomy/tomcat/conf/truststore -destkeystore cacerts

to the default truststore. The default password for the file cacerts is "changeit" and can be found in the manual for keytool.

Note: The keystore has to be configured via the above mentioned system properties anyway because otherwise it is empty!

Adding a certificate to cacerts

sudo keytool -importcert -alias StartCom -file /home/bibsonomy/StartComCertificationAuthority -keystore cacerts

Apache rewrite rules for BibSonomy with SSL

Rules

  • HTTP basic auth should only be possible via SSL, apart from access to the path /api/*
 RewriteCond %{HTTPS} !=on
 RewriteCond %{HTTP:AUTHORIZATION} ^Basic
 RewriteCond %{REQUEST_URI} !^/api/
 RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R=403,L]
  • Via SSL only HTTP basic auth should be possible, apart from access to the path /api/*
 RewriteCond %{HTTPS} on
 RewriteCond %{HTTP:AUTHORIZATION} !^Basic
 RewriteCond %{REQUEST_URI} !^/api/
 RewriteRule ^/(.*) http://%{SERVER_NAME}/$1 [R=401,L]

Setup SSL for REST-API synchronisation

Note: database synchronisation via SSL is described here.

Client

In this case the client is PUMA. There the client certificates have to be created

# prepare directory
mkdir -p /etc/ssl/ca/private
chown -R root:root /etc/ssl/ca
chmod 700 /etc/ssl/ca/private

# generate a private key and a certificate request, and then self-sign the certificate.
openssl genrsa -out ca.key 1024
openssl req -new -key ca.key -out ca.csr
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt

# generate a private key and certificate request:
openssl genrsa -out client.key 1024
openssl req -new -key client.key -out client.csr -config openssl.cnf

# sign the client request with the CA's private key
openssl x509 -req -days 365 -CA ca.crt -CAkey ca.key -CAcreateserial -in client.csr -out client.crt

(see also http://www.impetus.us/~rjmooney/projects/misc/clientcertauth.html)

... and installed

# keystore:
cat client.crt client.key > client.pem
openssl pkcs12 -export -in client.pem -out client.p12
keytool -importkeystore -srckeystore client.p12 -srcstoretype PKCS12 -destkeystore client.keystore

(see also http://quakology.blogspot.com/2009/06/how-to-use-ssl-with-client-certificate.html)

Warning: the password for the keystore belonging to the private key should be the same as for the private key itself. We do not know at the moment how the configuration could work otherwise. Maybe you could state several passwords in the Java properties?

BibSonomy owns a certificate signed by an authorized CA, so therefore this certificate doesn't have to be added. This does not apply to the test server so we need to add its key to the truststore on PUMA. To avoid loosing the default CA-key we copy the file cacerts from the directory <java-home>/lib/security/ (symlink to /etc/java-7-sun/security in Ubuntu) and add the server certificate:

cd $TOMCAT/conf
cp /etc/java-6-sun/security/cacerts .
keytool -importcert -keystore cacerts -file server.crt 
keytool -importcert -alias cacert -keystore cacerts -file /etc/ssl/ca.crt     
# add ca.crt to the keystore as well - I'm not sure if this is absolutely necessary

(As above: the default password for the file cacerts is "changeit".)

The Tomcat then as to be started with the following parameters

-Djavax.net.ssl.trustStore=/pfad/zu/tomcat/conf/cacerts
-Djavax.net.ssl.trustStorePassword=password
-Djavax.net.ssl.keyStore=/pfad/zu/client.keystore
-Djavax.net.ssl.keyStorePassword=password

It is best to add them to $TOMCAT/conf/wrapper.conf:

# Java Additional Parameters
wrapper.java.additional.1=-Xmx3000m
wrapper.java.additional.2=-XX:MaxPermSize=512m
wrapper.java.additional.3=-Djava.endorsed.dirs=../common/endorsed
wrapper.java.additional.4=-Dcatalina.base=..
wrapper.java.additional.5=-Dcatalina.home=..
wrapper.java.additional.6=-Djava.io.tmpdir=../temp
wrapper.java.additional.7=-Djava.awt.headless=true
wrapper.java.additional.8=-Djavax.net.ssl.trustStore=/pfad/zu/tomcat/conf/cacerts
wrapper.java.additional.9=-Djavax.net.ssl.trustStorePassword=password
wrapper.java.additional.10=-Djavax.net.ssl.keyStore=/pfad/zu/client.keystore
wrapper.java.additional.11=-Djavax.net.ssl.keyStorePassword=password

or $TOMCAT/bin/startup.sh:

export $JAVA_OPTS="$JAVA_OPTS " \
-Djavax.net.ssl.trustStore=/pfad/zu/tomcat/conf/cacerts \
-Djavax.net.ssl.trustStorePassword=password \
-Djavax.net.ssl.keyStore=/pfad/zu/client.keystore \
-Djavax.net.ssl.keyStorePassword=password 

Server

Create the certificate directory and CA just like above:

# Directory
mkdir -p /etc/ssl/ca/private
chown -R root:wheel /etc/ssl/ca
chmod 700 /etc/ssl/ca/private
# CA
openssl genrsa -out ca.key 1024
openssl req -new -key ca.key -out ca.csr
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
# Certificate
openssl genrsa -out server.key 1024
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Additionally we need the file ca.crt of the CA with which the client certificate was created (see above).

The following rules have to be added to the SSL configuration of the Apache:

Lists 443
NameVirtualHost *:443
<VirtualHost *:443>
   RewriteEngine On
   ServerName localhost
   AllowEncodedSlashes On

   ErrorLog /var/log/httpd/443.error.log
   CustomLog /var/log/httpd/443.access.log combined

   #RewriteRule ^/api/sync/(http://.+?/)/(.*)$ http://localhost:8080/bibsonomy-webapp/api/sync/$1/$2 [P,B]
   RewriteRule ^/api/sync/(http://.+?/)/(.*)$ http://localhost:8080/api/sync/$1/$2 [P,B,NE]
   RewriteRule ^/(.*)$ http://localhost:8080/bibsonomy-webapp/$1 [P]

   # activate HTTPS on the reverse proxy
   SSLEngine On
   SSLCertificateFile    /pfad/zu/server.crt
   SSLCertificateKeyFile    /pfad/zu/server.key

   # activate the client certificate authentication
   SSLCACertificateFile /pfad/zu/client/ca.crt
   SSLVerifyClient require
   SSLVerifyDepth 1

   <Proxy *>
     AddDefaultCharset Off
     Order deny,allow
     Allow from all
   </Proxy>

   # initialize the special headers to a blank value to avoid http header forgeries
   RequestHeader set SSL_CLIENT_S_DN    ""
   RequestHeader set SSL_CLIENT_I_DN    ""
   RequestHeader set SSL_SERVER_S_DN_OU ""
   RequestHeader set SSL_CLIENT_VERIFY  ""

   <Location />
     SSLVerifyClient require
     # add all the SSL_* you need in the internal web application
     RequestHeader set SSL_CLIENT_S_DN "%{SSL_CLIENT_S_DN}s"
     RequestHeader set SSL_CLIENT_I_DN "%{SSL_CLIENT_I_DN}s"
     RequestHeader set SSL_SERVER_S_DN_OU "%{SSL_SERVER_S_DN_OU}s"
     RequestHeader set SSL_CLIENT_VERIFY "%{SSL_CLIENT_VERIFY}s"
     #ProxyPass          http://localhost:8080/bibsonomy-webapp/

   </Location>
   ProxyPassReverse  / http://localhost:8080/bibsonomy-webapp/

</VirtualHost>

Tips & tricks

Print information about a certificate:

openssl x509 -in puma_ca.crt -noout -text

Updated