By Jim Connors-Oracle on Nov 16, 2015
As software environments continue to ratchet up security measures, the odds of having to deal with digital certificates in more than a superficial manner only increases over time. Furthermore, platforms are not only mandating the use of certificates, they are to a greater extent shunning the self-signed variety and instead insisting upon certs that originate from a trusted authority. When managing certificates in the Java world, the utility you're most likely to encounter is keytool, an integral part of the Java Development Kit. Although keytool can be effectively used to generate self-signed private/public key pairs, it's a little lacking when it comes to incorporating in certs generated by trusted authorities. [Based upon feedback and recommendations received after the original posting of this article, a Postscript section has been appended which discusses alternative solutions to the original discussed below]
In particular, we'll focus on overcoming the following two shortcomings:
- An existing private key and certificate generated by a trusted Certificate Authority (CA) cannot be imported by keytool, at least not in the format traditionally provided by CAs.
- Not only must the unique private key be imported into the keystore, in some instances the root CA certificate and any intermediate certificates (referred to as a certificate chain) must be included, and more importantly in the correct order. The keytool utility doesn't help much in the way of ensuring a valid order.
The following example uses a real SSL certificate chain from a real certificate authority and was done in the context of the Java Advanced Management Console 2.1 application. Java AMC is a Java EE application and requires Oracle's WebLogic application server to function. In this instance we'll be updating a keystore associated with WebLogic, but in reality this Java keystore should be no different from any other Java keystore, so these steps should apply elsewhere just fine.
We'll leave the minutiae of applying for a trusted certificate as an exercise for the reader; one of the first steps towards getting a certificate involves creating and submitting a CSR (Certificate Signing Request) to a Certificate Authority. A byproduct of this process is that a private key file is generated based on the information in the CSR. This file, when opened, looks something like this:
-----BEGIN PRIVATE KEY-----
encryptedgobbledygook line 1
encryptedgobbledygook line n
-----END PRIVATE KEY-----
This private key file is in PEM (Privacy Enhanced Mail) format, and will take a .pem suffix. For our example, the file is stored as:
For this article, we used Comodo (one of many alternatives) as our Certificate Authority. When the entire process with Comodo was complete, the following documents were ultimately received from them:
- amc-server_jtconnors_com.crt - This is the Comodo-generated host-specific SSL certificate for a machine with a Fully Qualified Domain Name (FQDN) of amc-server.jtconnors.com
- AddTrustExternalCARoot.crt - Comodo Root Certificate
- COMODORSAAddTrustCA.crt - Comodo Intermediate Certificate 1
- COMODORSADomainValidationSecureServerCA.crt - Comodo Intermediate Certificate 2
With these files in place we can now begin the importing process. We will take advantage of enhancements added to keytool with the Java 6 release: namely that keytool can merge and import keystores that are in PKCS12 format.
With this new information what remains is to figure out how to convert our private key and certificate chain into a PKCS12 file. For this functionality we resort to the capabilities found in the ubiquitous OpenSSL toolkit, available on virtually all popular compute platforms. In the example that follows, we'll be running on a Windows system and will utilize the Cygwin environment to run the required OpenSSL commands.
Step 1. (From Cygwin) Concatenate the certificates comprising the CA-supplied root certificate chain to one file. Include only the root certificate and intermediate certificate(s) and exclude the host-specific SSL certificate.
$ cat AddTrustExternalCARoot.crt COMODORSAAddTrustCA.crt COMODORSADomainValidationSecureServerCA.crt > BUNDLE.crt
Step 2. (From Cygwin) Create a PKCS12 keystore. This command incorporates both the certificate chain along with the SSL private key and certificates. Your passwords may vary.
$ openssl pkcs12 -export -chain -in amc-server_jtconnors_com.crt -inkey private-key.pem -out keystore.p12 -name amc-server -CAfile BUNDLE.crt
Enter Export Password: changeit
Verifying - Enter Export Password: changeit
Step 3. (From Windows CMD) Using keytool, import the PKCS12 keystore into the resulting JKS keystore called keystore.jks. Again, you may select different passwords.
> "c:\Program Files\Java\jdk1.8.0_66\bin\keytool.exe" -importkeystore -destkeystore keystore.jks -srckeystore keystore.p12 -alias amc-server
Enter destination keystore password: changeit
Re-enter new password: changeit
Enter source keystore password: changeit
Step 4. With the keystore successfully created we can now take the optional step of further verifying it. Certain Java-based application frameworks, like Oracle's WebLogic for example, can be finicky about the completeness and order of the certificate chain. To help validate the keystore, we can use the ValidateCertChain program which comes bundled with WebLogic 12c and can be found in the distribution's weblogic.jar file. Here's a sample invocation of the program on our recently created keystore.jks file:
> java -cp %MW_HOME%\wlserver\server\lib\weblogic.jar utils.ValidateCertChain -jks amc-server keystore.jks
Cert: CN=amc-server.jtconnors.com,OU=PositiveSSL,OU=Domain Control Validated
Cert: CN=COMODO RSA Domain Validation Secure Server CA,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
Cert: CN=COMODO RSA Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB
Cert: CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
Certificate chain appears valid
Here's hoping these examples save you some time, and more importantly, a little grief.
After having received recommendations from the engineers far better versed in AMC and WebLogic, the following section was added to briefly discuss alternatives to the above mentioned OpenSSL solution.
Alternative A: For people that have complete control of the certificate generating process, they can, as previously hinted, use keytool exclusively for this process. For the first phase of the process they can use keytool in the following general manner (arguments to keytool will vary) to generate a keypair and certificate request:
keytool -keystore keystore.jks -genkeypair -keyalg rsa
keytool -keystore keystore.jks -certreq
In this scenario, OpenSSL would not be required since the keypair is already stored in the keystore. From here you can import the certificates following a form similar to this:
keytool -import -keystore keystore.jks -alias root -file AddTrustExternalCARoot.crt
keytool -import -keystore keystore.jks -alias intermediate1 -file COMODORSAAddTrustCA.crt
keytool -import -keystore keystore.jks -alias intermediate2 -file COMODORSADomainValidationSecureServerCA.crt
keytool -import -keystore keystore.jks -alias mykey -file amc-server_jtconnors_com.crt
In the last command, "-alias mykey" is essential and must match the key pair in the keystone. As a shortcut, you could also concatenate all PEM-encoded certificates into a big file and then call:
keytool -import -keystore keystore.jks -alias mykey -file thebigfile
Alternative B: Along with the ValidateChain program WebLogic 12c's weblogic.jar file also includes a utility called ImportPrivateKey which can also used to import a certificate chain into a Java keystore. This utility command is described in Creating a Keystore Using ImportPrivateKey subsection of WebLogic documention on Configuring Keystores. The command follows a form like this:
java -cp %WL_HOME%\server\lib\weblogic.jar utils.ImportPrivateKey -keystore newkeystore -storepass **keystorepassword** -alias amctrust -certfile certificate.pem -keyfile privatekey.pem [-keyfilepass **privatekeypassword**]
For further edification please consult the WebLogic docs.