A Utility for Viewing Java Keystore Contents

I end up dealing with a lot of certificates and private keys, and since I still work primarily in Java, I necessarily end up dealing with quite a few Java Key Store files. You need them to get Tomcat up and running, you need them to do mutual SSL authentication, you need them to sign jar files... yet I always find the keytool that comes standard with Java a bit lacking.

In particular, I usually want to know who the subject, the issuer and the end date of each certificate are. keytool, unfortunately, doesn't seem to offer any easy way to output just that data. Of course, I can always do something like this:

$ keytool -list -keystore /Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/jre/lib/security/cacerts
Enter keystore password:  

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 87 entries

digicertassuredidrootca, Apr 16, 2008, trustedCertEntry, 
Certificate fingerprint (SHA1): 05:63:B8:63:0D:62:D7:5A:BB:C8:AB:1E:4B:DF:B5:A8:99:B2:4D:43
...
$ keytool -export -alias digicertassuredidrootca -keystore /Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/jre/lib/security/cacerts \
	| openssl x509 -inform der -noout -enddate
Enter keystore password:  
notAfter=Nov 10 00:00:00 2031 GMT
... But that's sort of a hassle. For one thing, I have to list the contents to find out what the aliases are, and for another, I can only see one at a time.

The keytool -list command includes a "verbose" -v option, but that's a little bit too verbose for my tastes:

$ keytool -list -v -keystore /Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/jre/lib/security/cacerts
Enter keystore password:
...
*******************************************

Alias name: affirmtrustpremiumca
Creation date: Apr 14, 2014
Entry type: trustedCertEntry

Owner: CN=AffirmTrust Premium, O=AffirmTrust, C=US
Issuer: CN=AffirmTrust Premium, O=AffirmTrust, C=US
Serial number: 6d8c1446b1a60aee
Valid from: Fri Jan 29 08:10:36 CST 2010 until: Mon Dec 31 08:10:36 CST 2040
Certificate fingerprints:
	 MD5:  C4:5D:0E:48:B6:AC:28:30:4E:0A:BC:F9:38:16:87:57
	 SHA1: D8:A6:33:2C:E0:03:6F:B1:85:F6:63:4F:7D:6A:06:65:26:32:28:27
	SHA256: 70:A7:3F:7F:37:6B:60:07:42:48:90:45:34:B1:14:82:D5:BF:0E:69:8E:CC:49:8D:F5:25:77:EB:F2:E9:3B:9A
	Signature algorithm name: SHA384withRSA
	Version: 3

	Extensions: 

#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
	  PathLen:2147483647
	]

#2: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  Key_CertSign
	Crl_Sign
]

#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 9D C0 67 A6 0C 22 D9 26   F5 45 AB A6 65 52 11 27  ..g..".&.E..eR.'
0010: D8 45 AC 63                                        .E.c
]
]

*******************************************
...
Here, I really just wanted the subject and the end date in a consolidated form.

You can output the keystore contents with the "-rfc" option:

$ keytool -export -alias mykey -rfc -keystore testkeystore.jks
But this isn't much better:
-----BEGIN CERTIFICATE-----
MIID5TCCAs2gAwIBAgIJAJAJCpRdEBfSMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzEO
MAwGA1UECAwFVGV4YXMxEzARBgNVBAoMCk5hbnRoZWFsdGgxFTATBgNVBAsMDEFyY2hpdGVjdHVy
ZTEWMBQGA1UEAwwNSm9zaHVhIERhdmllczElMCMGCSqGSIb3DQEJARYWamRhdmllc0BuYW50aGVh
...

$ keytool -list -rfc -keystore keystore.jks | openssl x509 -noout -subject seems promising, but it only outputs one certificate, and also doesn't echo the keystore alias.

I finally got tired of repeating myself and broke down and wrote a utility to output exactly what I wanted, shown in Listing 1. Since Java exposes the KeyStore directly, it wasn't difficult; I wish I could have extended keytool directly, but I was able to mimic most of the behavior of the tool without much effort.

import java.io.FileInputStream;
import java.io.IOException;
import java.io.Console;
import java.util.Enumeration;
import java.security.KeyStore;
import java.security.PublicKey;
import java.security.GeneralSecurityException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

public class KeyStoreShow	{
	public static void main(String[] args) throws IOException, 
			GeneralSecurityException {
		String keyStoreFile = System.getProperty("user.home") + 
			System.getProperty("file.separator") + ".keystore";
		String storeType = KeyStore.getDefaultType();	// JKS
		char[] storePassword = null;
		boolean showSubject = false;
		boolean showIssuer = false;
		boolean showStartDate = false;
		boolean showEndDate = false;
		boolean showPubKey = false;

		for (int i = 0; i < args.length; i++)	{
			if (args[i].equals("-keystore"))	{
				keyStoreFile = args[++i];
			} else if (args[i].equals("-storetype"))	{
				storeType = args[++i];
			} else if (args[i].equals("-storepass"))	{
				storePassword = args[++i].toCharArray();
			} else if (args[i].equals("-subject")) {
				showSubject = true;
			} else if (args[i].equals("-issuer")) {
				showIssuer = true;
			} else if (args[i].equals("-startdate")) {
				showStartDate = true;
			} else if (args[i].equals("-enddate")) {
				showEndDate = true;
			} else if (args[i].equals("-pubKey")) {
				showPubKey = true;
			} else	{
				System.out.println("Illegal option " + args[i]);
				System.out.println("-keystore <keystore>\tkeystore name");
				System.out.println("-storetype <storetype>\tkeystore type");
				System.out.println("-storepass <arg>\tkeystore password");
				System.out.println("-subject\tprint subject DN");
				System.out.println("-issuer\tprint issuer DN");
				System.out.println("-startdate\tnotBefore field");
				System.out.println("-enddate\tnotAfter field");
				System.out.println("-pubkey\toutput the public key");
				System.exit(0);
			}
		}

		if (!showSubject &&
				!showIssuer &&
				!showStartDate &&
				!showEndDate &&
				!showPubKey )	{
			showSubject = true;	// make sure something shows up; default is subject
		}

		if (storePassword == null)	{
			System.out.print("Password: ");
			storePassword = System.console().readPassword();
		}

		KeyStore ks = KeyStore.getInstance(storeType);

		FileInputStream in = new FileInputStream(keyStoreFile);
		try	{
			ks.load(in, storePassword);
		} finally	{
			in.close();
		}

		Enumeration<String> aliases = ks.aliases(); // [1]
		while (aliases.hasMoreElements())	{
			String alias = aliases.nextElement();
			System.out.print(alias + ": ");
			if (ks.isCertificateEntry(alias))	{
				System.out.println("Certificate Entry");
			} else	{
				System.out.println("Private Key Entry");
			}
			Certificate cert = ks.getCertificate(alias);
			if (cert != null)	{
				if ("X.509".equals(cert.getType()))	{
					X509Certificate x509 = (X509Certificate) cert;
					if (showSubject)	{
						System.out.println("Subject: " + x509.getSubjectX500Principal().toString());
					}
					if (showIssuer)	{
						System.out.println("Issuer: " + x509.getIssuerX500Principal().toString());
					}
					if (showStartDate)	{
						System.out.println("Start Date: " + x509.getNotBefore().toString());
					}
					if (showEndDate)	{
						System.out.println("End Date: " + x509.getNotAfter().toString());
					}
					if (showPubKey)	{
						PublicKey key = x509.getPublicKey();
						System.out.println(key.toString());
					}
				} else	{
					System.out.println("Unrecognized certificate type '" + cert.getType() + "'");
				}
			}
		}
	}
}

Listing 1: KeyStoreShow utility

Yes, Java's official Keystore implementation still uses the Enumeration class!

Here I merged the syntax of java's keytool with OpenSSL's x509 utility; if you want to see, for example, the expiration date of each of the certificates in the trusted roots file, you would do this:

$ java -classpath . KeyStoreShow -keystore \
	/Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/jre/lib/security/cacerts -enddate
Password: 
digicertassuredidrootca: Certificate Entry
End Date: Sun Nov 09 18:00:00 CST 2031
trustcenterclass2caii: Certificate Entry
End Date: Wed Dec 31 16:59:59 CST 2025
...

Add a comment:

Completely off-topic or spam comments will be removed at the discretion of the moderator.

You may preserve formatting (e.g. a code sample) by indenting with four spaces preceding the formatted line(s)

Name: Name is required
Email (will not be displayed publicly):
Comment:
Comment is required
My Book

I'm the author of the book "Implementing SSL/TLS Using Cryptography and PKI". Like the title says, this is a from-the-ground-up examination of the SSL protocol that provides security, integrity and privacy to most application-level internet protocols, most notably HTTP. I include the source code to a complete working SSL implementation, including the most popular cryptographic algorithms (DES, 3DES, RC4, AES, RSA, DSA, Diffie-Hellman, HMAC, MD5, SHA-1, SHA-256, and ECC), and show how they all fit together to provide transport-layer security.

My Picture

Joshua Davies

Past Posts