Core Java

How to Check JVM Keystore Locations

In Java applications, understanding which keystore the JVM is using is crucial for troubleshooting SSL/TLS issues, debugging certificate problems, or ensuring our applications use the correct keys and certificates. The JVM typically relies on a keystore to manage cryptographic keys and certificates, but depending on configuration, it might not always be obvious which keystore is being used. This article examines multiple approaches to determine the keystore our JVM is utilising.

1. Checking Default Keystore Locations

When no specific keystore is set via system properties, the JVM automatically falls back to its default locations. By default, the truststore is located at $JAVA_HOME/lib/security/cacerts.

We can manually verify this path by examining our Java installation directory, which allows us to confirm the presence of the cacerts file and ensure the JVM will use it for SSL/TLS certificate validation.

echo $JAVA_HOME
ls $JAVA_HOME/lib/security/

This lists security-related files and keystores in the JVM’s directory. The typical output may vary depending on the JDK distribution and version, but generally, we can expect to see files such as cacerts, and other security-related files within the $JAVA_HOME/lib/security/ directory.

blocked.certs		default.policy
cacerts			public_suffix_list.dat

2. Inspecting the Keystore Programmatically

One way to determine which keystore the JVM is using is by checking system properties. The JVM exposes properties, such as javax.net.ssl.trustStore, which indicates the path to the truststore used for validating certificates. By reading these properties at runtime, we can programmatically identify the default keystore, any custom truststore, and the user-specific keystore location.

public class KeystoreLocator {

    private static final Logger logger = Logger.getLogger(KeystoreLocator.class.getName());

    public static void main(String[] args) {
        // Java installation directory
        String javaHomeDir = System.getProperty("java.home");
        String fileSeparator = System.getProperty("file.separator");

        if (javaHomeDir == null) {
            logger.severe("Java home directory is not defined!");
            return;
        }

        // Default JVM truststore path
        String defaultTruststorePath = javaHomeDir + fileSeparator + "lib" + fileSeparator
                + "security" + fileSeparator + "cacerts";
        logger.log(Level.INFO, "Java Home Directory: {0}", javaHomeDir);
        logger.log(Level.INFO, "Default JVM truststore expected at: {0}", defaultTruststorePath);

        File defaultTruststoreFile = new File(defaultTruststorePath);
        if (defaultTruststoreFile.exists()) {
            logger.info("Default JVM truststore found.");
            logger.log(Level.INFO, "Absolute path: {0}", defaultTruststoreFile.getAbsolutePath());
        } else {
            logger.warning("Default JVM truststore not found at the expected location.");
        }

        // Check for a custom truststore specified via system property
        String truststoreProperty = System.getProperty("javax.net.ssl.trustStore");
        String trustStorePath;
        if (truststoreProperty != null) {
            logger.log(Level.INFO, "Custom truststore detected at: {0}", truststoreProperty);
            trustStorePath = truststoreProperty;
        } else {
            logger.info("No custom truststore specified; JVM will use the default.");
            trustStorePath = defaultTruststorePath;
        }

        // User-specific keystore
        String userHomeDir = System.getProperty("user.home");
        if (userHomeDir == null) {
            logger.severe("User home directory is not defined!");
            return;
        }

        String userKeystorePath = userHomeDir + fileSeparator + ".keystore";
        logger.log(Level.INFO, "User keystore path: {0}", userKeystorePath);

        File userKeystoreFile = new File(userKeystorePath);
        if (userKeystoreFile.exists()) {
            logger.info("User keystore detected.");
            logger.log(Level.INFO, "Absolute path: {0}", userKeystoreFile.getAbsolutePath());
        } else {
            logger.log(Level.INFO, "No user keystore found at the default location.");
        }

        // Inspecting the keystore programmatically
        try {
            // Default algorithm for key managers 
            String keystoreAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
            logger.log(Level.INFO, "Keystore algorithm: {0}", keystoreAlgorithm);

            // Load the keystore
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            try (FileInputStream fis = new FileInputStream(trustStorePath)) {
                // Default password for cacerts is "changeit" unless modified
                ks.load(fis, "changeit".toCharArray());
            }

            logger.log(Level.INFO, "Keystore type: {0}", ks.getType());
            logger.log(Level.INFO, "Keystore entry count: {0}", ks.size());

        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error loading keystore: {0}", e.getMessage());
            e.printStackTrace();
        }
    }
}

This program examines the JVM system properties and common keystore locations, including the default JVM truststore (cacerts in $JAVA_HOME/lib/security), any custom truststore specified via javax.net.ssl.trustStore, and the user-specific keystore ($HOME/.keystore). By running it, we can quickly identify which keystores are present and determine which one the JVM will use for certificate validation.

3. Using JVM Arguments

We can explicitly instruct the JVM to use a specific keystore using these arguments.

-Djavax.net.ssl.trustStore=/path/to/truststore -Djavax.net.ssl.trustStorePassword=yourpassword

Adding these arguments at JVM startup ensures the application uses the intended keystore.

4. Conclusion

In this article, we discussed how to determine which keystore the Java JVM is using, covering the default truststore, any custom truststores, and user-specific keystores. We also demonstrated how to verify these keystore locations both manually and programmatically, providing a clear approach to managing and inspecting the JVM’s certificate stores.

This article walks through how to identify the keystore currently in use by the Java JVM.

Omozegie Aziegbe

Omos Aziegbe is a technical writer and web/application developer with a BSc in Computer Science and Software Engineering from the University of Bedfordshire. Specializing in Java enterprise applications with the Jakarta EE framework, Omos also works with HTML5, CSS, and JavaScript for web development. As a freelance web developer, Omos combines technical expertise with research and writing on topics such as software engineering, programming, web application development, computer science, and technology.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button