TLS seems very complex to a newb. It can - and probably will - send you to dark places before you eventually find the working solution.
- It’s all about the certificates, stupid
- Generate a certificate
- Protect them certs!
- Teach java to trust you
- Arguments with Java
Today I can diagnose most TLS issues, but know that several cute, innocent kittens had to be sacrificed to get to this point. Hopefully many more cute kittens can be spared now that you’re reading this guide.
There are three main types of certificate: root, server and client. Root certificates belog to a Certificate Authority. Server and Client certificates are signed by a root certificate, and differ in some keywords used to identify itself to the other side of the connection.
For example, it is possible to refuse server - server connections, and allow only client - server connections.
All three types of certificate consist of a public certificate and a private key.
openssl req -x509 \ -newkey rsa:4096 \ -keyout key.pem -nodes \ -out crt.pem \ -days 36500 \ -subj '/CN=Local Host' \ -addext "subjectAltName = DNS:localhost"
In the past it was typical to put the DNS address in the subject field, but now this is more often used as a descriptive subject, with DNS in the subjectAltName field.
Certificates and keys generated by OpenSSL are in plain text unless stored in a key store.
Depending on the application, you may need to protect the certificates. A key store is encrypted and protected by a password. OpenSSL keys can be exported to a PKCS12 key store, which is the industry standard format:
openssl pkcs12 -export \ -in crt.pem \ -inkey key.pem \ -out keystore.p12 \ -password pass:stellirin \ -name APP
A lot of software is written in Java. For a long time Java has had its own key store format that is not compatible with PKCS12 key stores.
Oracle finally transitioned to the PKCS12 format from Java 9. However many applications still require the Java key store format. We can import keys from a PKCS12 key store into a Java key store.
keytool -importkeystore \ -srckeystore keystore.p12 \ -srcstoretype PKCS12 \ -srcstorepass 'stellirin' \ -destkeystore keystore.jks \ -deststoretype JKS \ -deststorepass 'stellirin' \ -alias APP
Key stores are password protected, and the keys inside them are may also be password protected. These passwords may differ. Many Java applications cannot easily read a key that has a different password to the key store password.
When you import a key from a PKCS12 Keystore to a Java Keystore, the key will be password protected with the PKCS12 key store password. Therefore you should use the same PKCS12 key store password for your Java key store password.
If your key password differs from your Java key store password, you can change the key password:
keytool -list \ -keystore keystore.jks \ -keypasswd \ -alias APP
Generating these key stores is not useful if nobody will trust them. Java uses a trust store to store trusted certificates.
By default Java includes a trust store with certificates from most popular Certificate Authorities. however if you need to use a self generated certificate then you have two options:
- add the certificate to the default trust store
- create a new trust store and use only that
Actually a trust store is simply a key store with only public certificates:
keytool -import \ -file crt.pem \ -keystore truststore.jks \ -storepass 'stellirin' \ -alias APP
The default trust store has the default password
changeit. This is a potential weak point as an attacker could add their own certificate to the default trust store and it will be accepted by Java without error.
Java arguments can be used to set the key store and trust store:
-Djavax.net.ssl.keyStore=/path/to/keystore.jks -Djavax.net.ssl.keyStorePassword=stellirin -Djavax.net.ssl.trustStore=/path/to/truststore.jks -Djavax.net.ssl.trustStorePassword=stellirin