SSL Certificates Troubleshooting

Article ID:115002505772
3 minute readKnowledge base

Symptoms

  • I have added a certificate to a truststore but I am still getting sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException

Diagnostic/Treatment

Check Jenkins JVM can reach out to a Server via SSL

From the Script Console ($JENKINS_URL/script):

def url = "$serverUrl" def connection = new URL(url).openConnection() as HttpURLConnection connection.with { println "ResponseCode: ${responseCode}" println "Body: ${inputStream.text}" }

A more extended script is here: checkSSLConnection.

Validate the truststore outside of the product

When using Java 17 or Java 11

The jshell command can be used to validate the truststore outside of the product, this command is part of the JDK (Java Development Kit), not the JRE (Java Runtime Environment). It was introduced in JDK 9 as a tool for running snippets of Java code interactively.

The steps to test a truststore at the path ./cacerts as as follows, modify the path to ./cacerts if required, as well as PASSWORD in the following command:

jshell -R-Djavax.net.ssl.trustStore=./cacerts -R-Djavax.net.ssl.trustStorePassword=PASSWORD

You should now be at the jshell prompt line jshell>. If you instead see command not found: jshell, ensure you have a JDK, as this command is not included with the JRE. Then paste in the following code replacing URL on the first line with the URL of the service you want to ensure the truststore validates the TLS certificate:

String url = "URL"; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder().uri(new URI(url)).build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode());

When you’re done, you can exit jshell with /exit.

Here’s an example running this with https://www.cloudbees.com, and seeing the expected successful response code response =⇒ (GET https://www.cloudbees.com) 200:

jshell -R-Djavax.net.ssl.trustStore=./cacerts -R-Djavax.net.ssl.trustStorePassword=PASSWORD | Welcome to JShell -- Version 17.0.8 | For an introduction type: /help intro jshell> String url = "https://www.cloudbees.com"; ...> import java.net.http.HttpClient; ...> import java.net.http.HttpRequest; ...> import java.net.http.HttpResponse; ...> import java.net.URI; ...> ...> HttpClient client = HttpClient.newHttpClient(); ...> HttpRequest request = HttpRequest.newBuilder().uri(new URI(url)).build(); ...> HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); ...> System.out.println(response.statusCode()); url ==> "https://www.cloudbees.com" client ==> jdk.internal.net.http.HttpClientImpl@a67c67e(1) request ==> https://www.cloudbees.com GET response ==> (GET https://www.cloudbees.com) 200 200 jshell> /exit | Goodbye

If you see a PKIX path building failed exception, it means the truststore is not correctly configured, and you can correct this by following the steps from PKIX path building failed error message:

request ==> URL GET | Exception javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

If you see a Caused by: java.security.KeyManagementException: problem accessing trust store exception, then a common reason is that the provided truststore password is incorrect.

When using Java 11 or Java 8

To test the connection using jrunscript, modify the path to ./cacerts if required, as well as PASSWORD and URL in the below command:

jrunscript -Djavax.net.ssl.trustStore=./cacerts \ -Djavax.net.ssl.trustStorePassword=PASSWORD \ -e "println(new java.net.URL(\"URL\").openConnection().getResponseCode())"

Note:

  1. Do not forget to include all quotes (").

  2. If the TLS certificate is trusted, the expected response is 200

In case you get a different result that expect response (200).

A - Firstly, verify your certificate is included in the <JENKINS_TRUSTSTORE_FILE> by:

keytool -list -v -keystore cacerts -alias <YOUR_ALIAS_HERE>

B -In case the javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching <SERVER_HOSTNAME> found. Check that the "CN" (Common Name) attribute of the "Owner" entry matches with the <SERVER_HOSTNAME> used by CJE or CJOC (also check the "SubjectAlternativeName" section for Multi hostname certificates)

keytool -printcert -file path/to/<YOUR_CA_FILE>.pem

Example:

> jrunscript -Djavax.net.ssl.trustStore=./cacerts-with-jenkins.example.com.jks -Djavax.net.ssl.trustStorePassword=changeit -e "println(new java.net.URL(\"https://jenkins.example.com\").openConnection().getResponseCode())" java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching "https://jenkins.example.com found at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:397) at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:446) at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:403) at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:399) at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155) at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264) at com.sun.tools.script.shell.Main.evaluateString(Main.java:298) at com.sun.tools.script.shell.Main.evaluateString(Main.java:319) at com.sun.tools.script.shell.Main.access$300(Main.java:37) at com.sun.tools.script.shell.Main$3.run(Main.java:217) at com.sun.tools.script.shell.Main.main(Main.java:48) Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching jenkins.example.com found at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979) at sun.security.ssl.Handshaker.process_record(Handshaker.java:914) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1546) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474) at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338) at jdk.nashorn.internal.scripts.Script$1$\^string\_.:program(<string>:1) at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637) at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494) at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393) ... 10 more Caused by: java.security.cert.CertificateException: No name matching jenkins.example.com found at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:221) at sun.security.util.HostnameChecker.match(HostnameChecker.java:95) at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455) at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:200) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491) ... 27 more

Then checking the hostname, we realized that differs from example.com, it is CN=*.notExample.com

> keytool -printcert -file /path/mycerts/example.ca.pem Owner: CN=*.notExample.com, O="Not Example Technologies, Inc", L=San Francisco, ST=California, C=US Issuer: CN=GeoTrust SSL CA - G3, O=GeoTrust Inc., C=US Serial number: 27ce5d06960d3796b9e8f6bb000d2de9 Valid from: Mon Jan 26 01:00:00 CET 2015 until: Sun Feb 19 00:59:59 CET 2017 Certificate fingerprints: MD5: CB:15:CD:A9:49:2C:D3:D1:AC:21:57:D9:12:F2:08:6D SHA1: AB:F0:5B:A9:1A:E0:AE:5F:CE:32:2E:7C:66:67:49:EC:DD:6D:6A:38 SHA256: 31:33:B1:2F:37:92:4B:67:FC:CF:14:42:58:FC:BC:7D:E2:89:27:E8:7C:25:EC:67:47:EC:4D:95:29:15:7A:8D Signature algorithm name: SHA256withRSA Version: 3 Extensions: ...

If you see the correct CN, but it’s still failing, you can correct this by following the steps from PKIX path building failed error message.