Java can load certificates from different types of key store files. Apart from standard JKS format, the well known PKCS #12 format can be used as well. Files of this format usually have .pfx or .p12 extension.
Goal of this exercise is to download certificate chain from a server, extract a certificate of a certificate authority and create a PKCS #12 file / key store, which can be loaded into a KeyStore implementation.
-
Print the server certificates to a terminal window.
openssl s_client -showcerts -connect google.com:443 < /dev/null- The
-showcertsargument ensures that all certificates are printed out, not just a certificate of a server itself. /dev/nullinput is sent to a server, so the connection is closed.
- The
-
Copy the PEM data of the certificate into
cacert.pemfile.PEM data are located between "begin" and "end certificate" separators, included. E.g.:
-----BEGIN CERTIFICATE----- MIIOoDCCDYigAwIBAgIQCVam9E4NfB8SeRzeQq7StjANBgkqhkiG9w0BAQsFADBG ... 8vhozb/K3UBYPwfJ8yzidLMs2BuOAf3TuJne60x1K0l17BY3dgm3Sr0y1IDP0j+E Yosc8w== -----END CERTIFICATE----- -
Create a key store file, using
keytool.Use an alias (
ASN.1 OID 1.2.840.113549.1.9.20 = friendlyName), so refer to the certificate via theKeyStoreAPI. Without the argument, thekeytoolwill generate random alias.keytool -import -alias cacert -file cacert.pem -keystore keystore.p12 -storetype PKCS12Note: The PKCS #12 files can be created with the
opsenssl pkcs12command as well. But, OpenSSL does not inject all necessary "Bag Attributes" (including alias) into the file. These attributes are required by Java. If you try to use such file, you may encounter thethe trustAnchors parameter must be non-emptyerror.Actually, you can debug a key store in the
TrustManagerFactoryImplon a line with theTrustStoreUtil.getTrustedCerts(ks)method call. This call returns all certificates recognised by the key store. If no certificates are returned, the key store file is broken. -
Verify the key store file.
openssl pkcs12 -info -in keystore.p12
Load key store into Java
The generated key store file can then be loaded into Java and subsequently used.
For this, you can use standard Java key store implementation, without specifying a provider in the KeyStore.getInstance() method. E.g.:
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(location.getInputStream(), password.toCharArray());
Or, you can link Bouncy Castle library, and use its more benevolent implementation in terms of loading PKCS #12 files (it can use ASN.1 OID 1.2.840.113549.1.9.21 = localKeyId to identify entry, not just friendlyName like the Java implementation). E.g.:
Security.addProvider(new BouncyCastleProvider());
KeyStore keyStore = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
keyStore.load(location.getInputStream(), password.toCharArray());
On the surface, there is no difference. Both implementations are "hidden" behind the java.security.KeyStore API.