tl;dr - get KeyStore Explorer (http://keystore-explorer.org/) and save yourself a world of trouble.
p.s. - the keystore alias setting is extremely significant to certain java applications (for example: iDempiere in its Jetty provider ssl configuration (. . ./jettyhome/etc/jetty-ssl-context.xml). In these cases one must ensure that the alias of the certificate java is looking for matches the alias it is actually using to find it.
O.P.
I have a need to use a private CA and its certificates in a java application. I am unable to discover how a private CA root certificate and its intermediates are added to the java trusted certificates. I have found and read multiple articles on how this is supposed to be done but my efforts are not able to accomplish what I need.
I am using OpenJDK11. The java cacerts fie is located in /usr/local/openjdk11/lib/security/cacerts
. This, I believe contains the trusted certificate list used by Java.
I have manually added the private CA root and intermediate certificates to this store:
cp -p /usr/local/openjdk11/lib/security/cacerts /usr/local/openjdk11/lib/security/cacerts.cln
cp -p /usr/local/openjdk11/lib/security/cacerts /root/hll_jdk11_cacerts
JAVA_VERSION="11" keytool -import \
-trustcacerts \
-file /usr/local/etc/pki/tls/certs/CA_HLL_ROOT_2016.crt \
-alias 'hartelyneroot2016 [hll]' \
-keystore /root/hll_jdk11_cacerts
JAVA_VERSION="11" keytool -import \
-trustcacerts \
-file /usr/local/etc/pki/tls/certs/CA_HLL_ISSUER_2016.crt \
-alias 'hartelyneissuer2016 [hll]' \
-keystore /root/hll_jdk11_cacerts
JAVA_VERSION="11" keytool -list -rfc -keystore /root/hll_jdk11_cacerts | grep hll
Enter keystore password: changeit
Alias name: hartelyneissuer2016 [hll]
Alias name: hartelyneroot2016 [hll]
cp -p /root/hll_jdk11_cacerts /usr/local/openjdk11/lib/security/cacerts
As far as I can determine, certificates issued by CA_HLL_ISSUER_2016 and CA_HLL_ROOT_2016 should now be recognized as trusted by java on this host. But, they are not. I need to discover why.
JAVA_VERSION="11" java SSLPoke google.ca 443
Successfully connected
JAVA_VERSION="11" java SSLPoke webmail.harte-lyne.ca 443
sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchor
But I have no trouble with openssl s_client
:
openssl s_client -connect webmail.harte-lyne.ca:443
CONNECTED(00000003)
depth=2 CN = CA_HLL_ROOT_2016, ST = Ontario, O = Harte & Lyne Limited, OU = Networked Data Services, C = CA, DC = harte-lyne, DC = ca, L = Hamilton
verify return:1
depth=1 CN = CA_HLL_ISSUER_2016, OU = Networked Data Services, O = Harte & Lyne Limited, L = Hamilton, ST = Ontario, C = CA, DC = harte-lyne, DC = ca
verify return:1
depth=0 CN = webmail.hamilton.harte-lyne.ca, OU = Networked Data Services, O = Harte & Lyne Limited, L = Hamilton, ST = Ontario, C = CA, DC = hamilton, DC = harte-lyne, DC = ca
verify return:1
---
Certificate chain
0 s:CN = webmail.hamilton.harte-lyne.ca, OU = Networked Data Services, O = Harte & Lyne Limited, L = Hamilton, ST = Ontario, C = CA, DC = hamilton, DC = harte-lyne, DC = ca
i:CN = CA_HLL_ISSUER_2016, OU = Networked Data Services, O = Harte & Lyne Limited, L = Hamilton, ST = Ontario, C = CA, DC = harte-lyne, DC = ca
1 s:CN = CA_HLL_ISSUER_2016, OU = Networked Data Services, O = Harte & Lyne Limited, L = Hamilton, ST = Ontario, C = CA, DC = harte-lyne, DC = ca
i:CN = CA_HLL_ROOT_2016, ST = Ontario, O = Harte & Lyne Limited, OU = Networked Data Services, C = CA, DC = harte-lyne, DC = ca, L = Hamilton
2 s:CN = CA_HLL_ROOT_2016, ST = Ontario, O = Harte & Lyne Limited, OU = Networked Data Services, C = CA, DC = harte-lyne, DC = ca, L = Hamilton
i:CN = CA_HLL_ROOT_2016, ST = Ontario, O = Harte & Lyne Limited, OU = Networked Data Services, C = CA, DC = harte-lyne, DC = ca, L = Hamilton
---
Server certificate
-----BEGIN CERTIFICATE-----
. . .
---
Acceptable client certificate CA names
. . .
CN = CA_HLL_ROOT_2016, ST = Ontario, O = Harte & Lyne Limited, OU = Networked Data Services, C = CA, DC = harte-lyne, DC = ca, L = Hamilton
. . .
CN = CA_HLL_ISSUER_2016, OU = Networked Data Services, O = Harte & Lyne Limited, L = Hamilton, ST = Ontario, C = CA, DC = harte-lyne, DC = ca
. . .
What am I missing here? How does one add private CAs to the Java truststore?
Following the suggestion given in the answer I did exactly this in the order given:
openssl s_client -connect webmail.harte-lyne.ca:443 -showcerts > harte.crt
JAVA_VERSION="11" keytool -import -alias harte -file harte.crt -keystore cacerts -storepass changeit
. . .
Trust this certificate? [no]: yes
Certificate was added to keystore
JAVA_VERSION="11" java SSLPoke webmail.harte-lyne.ca 443
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
I am encountering a bug in OpenJDK?
I understand that you want to perform client certificate authentication on some HTTPS call. Trusting the certificate is not enough. You need to use keypair that has been signed with this CA for the HTTPS handshake to succeed.
Try something like this