Do you understand how HTTPS works? Most Java developers will answer, “yes” to this question without much hesitation. In general they’re correct. Public-key cryptography is such a ubiquitous Internet technology that comprehending the theory behind digital certificates and key exchanges is commonplace.
Configuring Resin for HTTP with either OpenSSL or JSSE isn’t terribly complicated either, and the Resin documentation provides a decent reference when you need it. But what most people don’t understand is what all those different key-pair and certificate file formats are, which ones OpenSSL uses compared to JSSE, and how to convert from one format to the other.
The objective of this discussion really isn’t to show you how to create certificates and configure Resin for HTTPS, although that’s included. What I really want to do is review the file formats and encodings used to store keys and certificates, compare and contrast OpenSSL with JSSE, and discuss how to convert from OpenSSL to JSSE and back.
File Formats and Naming Conventions
PEM and DER
In OpenSSL, key-pairs and certificates are almost always encoded in either DER or PEM format. DER is a binary encoding of a key-pair following notation described in the ASN.1 standard. PEM format is simply the Base64 encoded DER with headers and footers. OpenSSL expects PEM format by default. Nearly all OpenSSL commands can be modified to use DER on input or output by adding -inform DER or -outform DER respectively.
The JSSE keytool accepts both PEM and DER encoded files without complaint. When exporting with keytool, the default format is DER. However adding the -rfc parameter will produce PEM encoding.
There is no standard file naming extension to distinguish between DER and PEM encoded files, but the following rules usually apply:
|.der||A DER encoded key-pair|
|.cer||A DER encoded certificate|
|.pem||A PEM encoded key-pair|
|.key||A PEM encoded key-pair|
|.crt||A PEM encoded certificate|
|.csr||A PEM encoded certificate signing request|
If you’re not sure if the file is PEM or DER encoded, simply open it in a text editor; PEM encoded files are human readable ASCII.
JKS keystore and PKCS #12
JSSE’s JKS keystore is a proprietary file format capable of storing multiple key-pairs, certificates, and symmetric encryption keys. All entries are indexed using an alias.
PKCS #12 is a standard published by RSA Laboratories that defines a file format for storing multiple key-pairs and certificates. All entries are indexed using a name.
JKS and PKCS #12 are similar enough that JSSE’s keytool can read either. This is fortunate because it allows us to convert between OpenSSL and JSSE, as described below.
Like DER and PEM, there is no standard naming convention, but there are a few common extensions:
|.jks||A JKS keystore|
|.keystore||A JKS keystore|
|.p12||A PKCS #12 file|
|.pfs||A PKCS #12 file|
Key-pair and certificate generation
OpenSSL Key-Pair Generation
openssl genrsa -aes256 -out private.key 2048
Generates a new 2048 bit RSA key-pair encrypted with AES 256 bit symmetric key encrption and stored on disk to the file private.key.
JSSE Key-Pair Generation
JSSE does not support simple key-pair generation like OpenSSL. JSSE always wraps the key-pair in a self-signed certificate, so this step does not directly apply to JSSE. See JSSE Self-Signed Certificate Generation below.
OpenSSL Self-Signed Certificate Generation
openssl req -new -x509 -key private.key -out demo.crt -days 365
Generates a self-signed X.509 format certificate valid for 365 days based on the PEM encoded key file private.key and stored in the PEM encoded file demo.crt. You will be prompted to enter certificate-identifying information.
JSSE Self-Signed Certificate Generation
keytool -genkeypair -alias demo -keystore keystore.jks -keyalg RSA -keysize 2048
Generates a new 2048 bit RSA key-pair stored in the JKS format file keystore.jks under the alias demo and associates it with a generated self-signed X.509 certificate. You will be prompted to enter certificate-identifying information.
OpenSSL Certificate Signing Request Generation
openssl req -new -key private.key -out demo.csr
Generates a certificate-signing request based on the PEM encoded key-pair file private.key and stored in the PEM encoded file demo.csr.
JSSE Certificate Signing Request Generation
keytool -certreq -alias demo -keystore keystore.jks -file demo.csr
Generate a certificate-signing request based on the key-pair stored in the JKS keystore file keystore.jks under the alias demo and stored in the PEM encoded file demo.csr.
OpenSSL Signing a CSR
openssl x509 -req -days 365 -in demo.csr -signkey private.key -out demo.crt
Uses the key-pair in the PEM encoded file private.key to generate a signed X.509 certificate from the PEM encoded CSR file demo.crt, valid for 365 days, stored in the PEM encoded file demo.crt.
JSSE Signing a CSR
JSSE certificates are automatically self-signed. keytool does not support CSR signing.
At this point we’ve generated key-pairs and self-signed certificates in both OpenSSL and JSSE. The following examples simply demonstrate how to configure Resin for HTTPS.
OpenSSL HTTPS in resin.xml
<http address="*" port="443"> <openssl> <certificate-file>keys/demo.crt</certificate-file> <certificate-key-file>keys/private.key</certificate-key-file> <password>password</password> </openssl> </http>
JSSE HTTPS in resin.xml
<http address="*" port="443"> <jsse-ssl> <key-store-type>jks</key-store-type> <key-store-file>keys/keystore.jks</key-store-file> <alias>demo</alias> <password>password</password> </jsse-ssl> </http>
Converting between OpenSSL and JSSE
Up to this point most of the commands have been straight forward and should not come as much of a surprise to anyone who has setup HTTPS before. However moving between OpenSSL and JSSE is not as simple, because keytool does not support direct importing or exporting of private keys! Remember from above, all key-pairs in a JKS keystore are attached to a certificate, even if it’s only a self-signed certificate.
JSSE’s keytool however does support PKCS #12 format, as mentioned in the introduction. We can take advantage of this to allow conversion between OpenSSL and JSSE.
OpenSSL to JSSE
Create a PKCS #12 file
openssl pkcs12 -export -out demo.p12 -inkey private.key -in demo.crt -name demo -descert
Instructs OpenSSL to create a PKCS #12 format file named demo.p12, using private.key as the key-pair, demo.crt as the signed certificate, stored in the PKCS #12 file with the alias demo, and encrypting the private key in the PKCS #12 file using 3DES encryption. (This command does not seem to support AES 256.) This complex command merges our key-pair and signed certificate into one entry with an alias, just the way JSSE expects it.
Convert the PKCS #12 file to JSSE JKS
keytool -importkeystore -srckeystore demo.p12 -srcstoretype PKCS12 -destkeystore keystore.jks
Converts the PKCS #12 format file named demo.p12 to a JKS keystore file named keystore.jks. You do not specify an alias for the imported key-pair/certificate because the keystore will automatically use the name we specified while creating the PKCS #12 file above. keystore.jks will be created automatically.
Note, this step is not entirely necessary. JSSE in Resin can be configured to use the PKCS #12 file directly by setting <keys-store-type>PKCS12<keys-store-type>
You now have a loaded JKS keystore that can be configured in resin.xml’s
JSSE to OpenSSL
Convert the JSSE JKS file to PKCS #12
keytool -importkeystore -srckeystore keystore.jks -destkeystore demo.p12 -deststoretype PKCS12
Converts the JKS keystore file named keystore.jks to a PKCS #12 format file named demo.p12. The certificate and key-pair name will match the JKS keystore alias.
Extract the key-pair
openssl pkcs12 -in demo.p12 -nocerts -aes256 -out private.key
Extracts the key-pair from the PKCS #12 format file named demo.p12 to a PEM format file named private.key encrypted with AES 256 bit symmetric key encryption.
Extract the certificate
openssl pkcs12 -in demo.p12 -nokeys -out demo.crt
Extracts the certificate from the PKCS #12 format file named demo.p12 to a PEM format file named demo.crt.
You now have a key-pair file and a signed certificate file that can be configured in resin.xml’s