Hot To Use Java Keystore with Custom SSL Certificates
Certificates play a critical role in establishing trust between clients and servers. Managing these certificates typically involves generating them, signing them, and storing them in a keystore. This article provides a comprehensive guide to generating custom SSL certificates and integrating them into a Java Keystore
Introduction to Java Keytool and Keystore
Java Keytool is a command-line utility provided with Java Development Kit (JDK) (I used JDK 17 for this post) that allows users to create and manage their own keystores (collections of security certificates either in public-key pairs or trusted certificates/certificate chains). A keystore is a binary file used by Java applications for encryption, authentication, and verifiable transmission of data.
Java Keytool and keystores support various keystore types including JKS (Java KeyStore), PKCS12, and others. By managing these certs and keystores, applications can ensure secure communications and operations. Lets follow the example on how we can use a keystore for storing our custom certificates.
Generating Custom Certificates and Configurations
Below are the series of commands used to generate custom certificates, and we will describe each command and the outputs they produce:
Generate CA Certificate and Key
The first step in our journey is creating our own Root Certificate Authority (CA). This self-signed certificate will act as the trusted anchor for all subsequent certificates we generate.
openssl req -new -nodes -x509 -days 3650 -newkey rsa:2048 -keyout certs/ca.key -out certs/ca.crt -config ./cnf/ca.cnf
- openssl req: Initiates a certificate request.
- -new: Creates a new certificate request.
- -nodes: Prevents passphrase encryption of the private key (for demonstration purposes; use with caution in production).
- -x509: Outputs a self-signed certificate instead of a certificate request.
- -days 3650: Sets the certificate's validity period to 10 years (365 days/year * 10 years).
- -newkey rsa:2048: Generates a new RSA key of 2048 bits.
- -keyout certs/ca.key: The private key file output.
- -out certs/ca.crt: The certificate output file.
- -config ./cnf/ca.cnf: References a configuration file (ca.cnf) that typically contains subject information for the certificate (e.g., organization name, country code).
Output files:
certs/ca.key
: This file contains the Root CA's private key in PEM (Privacy-Enhanced Mail) format. It is critical to keep this file secure and never share it.certs/ca.crt
: This file holds the self-signed Root CA certificate, also in PEM format. It represents the public part of your CA and will be used to sign other certificates.
For more content like this, subscribe to the blog
Combine CA Certificate and Key
cat certs/ca.crt certs/ca.key > certs/ca.pem
This command combines the CA certificate and key into a single ca.pem file for convenience in later steps.
Generate Server Certificate Signing Request (CSR) and Private Key
Next, we'll generate a server certificate that will be signed by our Root CA, establishing a chain of trust.
openssl req -new -newkey rsa:2048 -keyout certs/server.key -out certs/server.csr -config ./cnf/server.cnf -nodes
- -new: Creates a new certificate request.
- -newkey rsa:2048: Generates a new 2048-bit RSA key.
- -nodes: No encryption of the private key.
- -keyout certs/server.key: Private key for the server certificate.
- -out certs/server.csr: Server certificate signing request.
- -config ./cnf/server.cnf: A configuration file (server.cnf) is used, which includes details specific to the server, such as the common name (domain name).
Output files:
certs/server.key
: Private key for the server.certs/server.csr
: Certificate Signing Request for server.
Generate Server Certificate
openssl x509 -req -days 3650 -in certs/server.csr -CA certs/ca.crt -CAkey certs/ca.key -CAcreateserial -out certs/server.crt -extfile ./cnf/server.cnf -extensions v3_req
- x509: Generates an X.509 certificate.
- -req: Indicates it's a certificate request.
- -days 3650: Certificate validity period.
- -in certs/server.csr: Input CSR file.
- -CA certs/ca.crt: CA certificate for signing.
- -CAkey certs/ca.key: CA private key.
- -CAcreateserial: Creates a serial number file for the CA (if it doesn't exist) and increments it for each certificate signed.
- -out certs/server.crt: Output server certificate.
- -extfile ./cnf/server.cnf: Configuration file with extensions.
- -extensions v3_req: Section in the configuration file for extensions.
Output files:
certs/server.crt
: Server certificate signed with CA certificate.
Create PKCS#12 Archive
To facilitate convenient importing into the Java Keystore, we'll package the server certificate and its private key into a PKCS#12 file.
openssl pkcs12 -legacy -export -in certs/server.crt -inkey certs/server.key -chain -CAfile certs/ca.pem -name your-domain.com -out certs/server.p12 -password pass:test1234
- pkcs12: Utility to manage PKCS#12 files.
- -legacy: Compatible with older policies.
- -export: Export objects into PKCS#12 file.
- -in certs/server.crt: Server certificate.
- -inkey certs/server.key: Server private key.
- -chain: Include entire certificate chain.
- -CAfile certs/ca.pem: Includes the entire certificate chain (server certificate and Root CA certificate) in the PKCS#12 file to establish trust.
- -name your-domain.com: Alias for the entry.
- -out certs/server.p12: Output PKCS#12 file.
- -password pass:test1234: Password to protect the PKCS#12 file.
Output file:
certs/server.p12
: PKCS#12 archive containing the server certificate, private key, and CA certificates.
Import PKCS#12 into Java KeyStore
Finally, we'll import the contents of the PKCS#12 file into a Java Keystore.
keytool -importkeystore -deststorepass test1234 -destkeystore certs/server.keystore.jks \
-srckeystore certs/server.p12 \
-deststoretype PKCS12 \
-srcstoretype PKCS12 \
-noprompt \
-srcstorepass test1234 \
-deststoretype JKS
- keytool: Java Keytool utility.
- -importkeystore: Imports one keystore into another.
- -deststorepass test1234: Password for the destination keystore.
- -destkeystore certs/server.keystore.jks: Destination keystore file in JKS format.
- -srckeystore certs/server.p12: The source Keystore (our PKCS#12 file).
- -deststoretype PKCS12: Destination keystore type is PKCS#12.
- -srcstoretype PKCS12: Source keystore type is PKCS#12.
- -noprompt: Disables any prompts (useful for scripting).
- -srcstorepass test1234: Password for source keystore.
Output files:
certs/server.keystore.jks
: The Java Keystore file containing your server's certificate and private key, ready to be deployed with your Java application.
Import CA Certificate into Truststore
To ensure that your Java application trusts certificates signed by your Root CA, you must add the Root CA certificate to a truststore.
keytool -keystore certs/truststore.jks -alias CARoot -import -file certs/ca.crt -storepass test1234 -trustcacerts -noprompt -storetype PKCS12
- keytool: Java Keytool utility.
- -keystore certs/truststore.jks: Destination truststore file.
- -alias CARoot: Alias for the CA certificate entry.
- -import: Import command.
- -file certs/ca.crt: CA certificate file to import.
- -storepass test1234: Password for the truststore.
- -trustcacerts: Trust the certificate as a CA (Certificate Authority).
- -noprompt: No interactive prompts.
- -storetype PKCS12: Ensure the truststore is in PKCS#12 format.
Output files:
certs/truststore.jks
: The Java truststore containing your Root CA's certificate. This file can be used by your Java applications to verify the trust chain of certificates signed by your CA.
Useful Keytool Commands
Keytool List Certs
The keytool -list
command is used to display the contents of a keystore.
keytool -list -keystore PATH_TO_KEYSTORE
-keystore PATH_TO_KEYSTORE
: Specifies the path to the keystore file.- Optional Parameters:
-storepass PASSWORD
: Password for the keystore.-v
: Provides a verbose listing of the keystore entries.
This command enables you to see all the entries in the specified keystore, including aliases and certificate types.
Keytool Delete Alias
The keytool -delete
command allows you to delete an entry identified by its alias from the keystore.
keytool -delete -alias ALIAS -keystore PATH_TO_KEYSTORE
-alias ALIAS
: Specifies the alias of the entry you wish to delete.-keystore PATH_TO_KEYSTORE
: Path to the keystore file.- Optional Parameters:
-storepass PASSWORD
: Password for the keystore.-storetype TYPE
: Type of the keystore, e.g., JKS, PKCS12.
This command is useful for removing outdated or compromised certificates from the keystore.
Keytool List Cacerts
To view the default Java truststore, use the following command targeting cacerts
:
keytool -list -keystore ${JAVA_HOME}/lib/security/cacerts
${JAVA_HOME}
: Environment variable pointing to the Java installation directory.-storepass changeit
: Default password for thecacerts
truststore.
The cacerts
file contains trusted CA certificates. It's crucial for verifying SSL/TLS connections in Java applications.
Keytool Change Alias
If you need to rename an alias in the keystore, the keytool -changealias
command is what you need:
keytool -changealias -alias OLD_ALIAS -destalias NEW_ALIAS -keystore PATH_TO_KEYSTORE
-alias OLD_ALIAS
: Current alias that you want to change.-destalias NEW_ALIAS
: New alias name.-keystore PATH_TO_KEYSTORE
: Path to the keystore file.- Optional Parameters:
-storepass PASSWORD
: Password for the keystore.
This command is particularly useful when you need to update the naming conventions of your keystore entries.
Default Java Keystore Password
The default password for Java's default keystore is often changeit
. This is applicable mostly for the cacerts
file found under ${JAVA_HOME}/lib/security/cacerts
. Changing this default password is a good security practice.
keytool -storepasswd -new NEW_PASSWORD -keystore ${JAVA_HOME}/lib/security/cacerts
-storepasswd
: Subcommand to change the keystore password.-new NEW_PASSWORD
: New password for the keystore.
Keytool Export Private Key
Exporting a private key from a Java keystore requires a bit of workaround since keytool
does not directly support this. Here's an approach using openssl
to accomplish this task.
First, export the certificate and private key into a PKCS#12 file:
keytool -importkeystore -srckeystore PATH_TO_KEYSTORE -destkeystore OUTPUT.p12 -srcalias ALIAS -deststoretype PKCS12
Then, use openssl
to extract the private key:
openssl pkcs12 -in OUTPUT.p12 -nocerts -out private_key.pem -nodes
-nocerts
: Excludes certificates from the output.-nodes
: Leaves the private key unencrypted.
This multi-step process allows you to export a private key if absolutely necessary, although it's generally advised to protect private keys carefully within the keystore.
Conclusion
You've successfully created a Java Keystore containing your custom SSL certificates! By following the steps outlined in this article, you've gained a deeper understanding of the certificate generation process, the importance of keystores, and how to seamlessly integrate these elements into your Java projects for enhanced security. Remember to replace placeholder values with your specific information and keep your private keys secure.