Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts
cacerts_updates=yes
/etc/default/cacerts
sudo mkdir /usr/share/ca-certificates/test/  # don't mess with other certs
sudo cp ~/tmp/test.loc.crt /usr/share/ca-certificates/test/
sudo dpkg-reconfigure --force ca-certificates  # check your cert in curses GUI!
sudo update-ca-certificates --fresh --verbose
sudo rm /usr/share/ca-certificates/test/test.loc.crt
sudo rm /etc/ssl/certs/java/cacerts
sudo update-ca-certificates --fresh --verbose
Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class Test
{
    private static final DynamicIntProperty MAX_TOTAL_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty ROUTE_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty CONNECT_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connect.timeout", 60000);
    private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.socket.timeout", -1);
    private static final DynamicIntProperty CONNECTION_REQUEST_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connectionrequest.timeout", 60000);
    private static final DynamicBooleanProperty STALE_CONNECTION_CHECK = DynamicPropertyFactory.getInstance().getBooleanProperty("X.checkconnection", true);

    public static void main(String[] args) throws Exception
    {

        SSLContext sslcontext = SSLContexts.custom()
                .useTLS()
                .loadTrustMaterial(null, new TrustStrategy()
                {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
                    {
                        return true;
                    }
                })
                .build();
        SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(sslcontext, new AllowAll());

        Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
                .register("http", NoopIOSessionStrategy.INSTANCE)
                .register("https", sslSessionStrategy)
                .build();

        DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT);
        PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor, sessionStrategyRegistry);
        connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS.get());
        connectionManager.setDefaultMaxPerRoute(ROUTE_CONNECTIONS.get());

        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT.get())
                .setConnectTimeout(CONNECT_TIMEOUT.get())
                .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT.get())
                .setStaleConnectionCheckEnabled(STALE_CONNECTION_CHECK.get())
                .build();

        CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
                .setSSLStrategy(sslSessionStrategy)
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();

        httpClient.start();

        // use httpClient...
    }

    private static class AllowAll implements X509HostnameVerifier
    {
        @Override
        public void verify(String s, SSLSocket sslSocket) throws IOException
        {}

        @Override
        public void verify(String s, X509Certificate x509Certificate) throws SSLException {}

        @Override
        public void verify(String s, String[] strings, String[] strings2) throws SSLException
        {}

        @Override
        public boolean verify(String s, SSLSession sslSession)
        {
            return true;
        }
    }
}

I needed something similar, @JonasBergstrm, your solution with SSLContext help a lot.

I was able to get it working with code only, i.e. no need to use keytool:

Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt
sudo keytool -importcert -file ~/example.crt -alias example -keystore $(/usr/libexec/java_home)/jre/lib/security/cacerts -storepass changeit

.crt and .pem are commonly used file extensions for the same file format. If you already have the file, just run the second command and pass it into the -file argument.

Here's what reliably works for me on macOS. Make sure to replace example.com and 443 with the actual hostname and port you're trying to connect to, and give a custom alias. The first command downloads the provided certificate from the remote server and saves it locally in x509 format. The second command loads the saved certificate into Java's SSL trust store.

This doesn't work with SNI endpoint. For that case you need to add: -servername example.com when fetching the cert

Works for me why? You need to provide an explanation.

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt - what is example.crt in the command i have a .pem certificate i need to give that here ??

Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt
sudo keytool -importcert -file ~/example.crt -alias example -keystore $(/usr/libexec/java_home)/jre/lib/security/cacerts -storepass changeit

.crt and .pem are commonly used file extensions for the same file format. If you already have the file, just run the second command and pass it into the -file argument.

Here's what reliably works for me on macOS. Make sure to replace example.com and 443 with the actual hostname and port you're trying to connect to, and give a custom alias. The first command downloads the provided certificate from the remote server and saves it locally in x509 format. The second command loads the saved certificate into Java's SSL trust store.

This doesn't work with SNI endpoint. For that case you need to add: -servername example.com when fetching the cert

Works for me why? You need to provide an explanation.

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt - what is example.crt in the command i have a .pem certificate i need to give that here ??

Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


java.security.cert.CertificateException: No name matching localhost found

In this article author describes how to fetch the certificate from your browser and add it to cacerts file of your JVM. You can either edit JAVA_HOME/jre/lib/security/cacerts file or run you application with -Djavax.net.ssl.trustStore parameter. Verify which JDK/JRE you are using too as this is often a source of confusion.

The problem also appears with a certificate signed by someone else that isn't trusted.

The problem appears when your server has self signed certificate. To workaround it you can add this certificate to the list of trusted certificates of your JVM.

this hasn't worked for me. I have the root and the chain cert installed, but Tomcat-7 still reports validatorException caused by "unable to find valid certification path to requested target" any way to debug this?

Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


@AgilePro SSL gives you four assurances: authentication, privacy, integrity, and the possibilty of authorization. It does not give you any assurance that you are talking to a server known to the NSA. Caring only about privacy without authentication is a contradiction in terms.

@EJP Agree that if you use a client certificate you can get authentication and I suppose the possibility of authorization ... but most uses are not with a client certificate. What would you call the difference between a "self-signed" certificate, and a certificate from a signing authority? Does signing authority give "integrity". My Joke about NSA is that all signing authorities can not positively guarantee independence from everything. Not that paranoid really, but the point is your certificate is ONLY as secret as the signing authority can make it. Self-signed can be more secret.

Basically, you want to add the server's certificate to the KeyStore with your trusted certificates

Certificate validation is a very important part of SSL security, but I am not writing this entry to explain the details. If you are interested, you can start by reading the Wikipedia blurb. I am writing this entry to show a simple way to talk to that host with the test certificate, if you really want to.

The part about "Certificate validation is a very important part of SSL security" is not necessarily true. SSL gives you two assurances: (1) that your communication is private, and (2) that you are talking to a server which is known to the NSA.(:-) Sometimes you only care about privacy of the conversation, and then a self-signed certification is fine. See social-biz.org/2011/10/16/the-anti-ssl-conspiracy

Try the code provided there. It might help.

when trying to open an SSL connection to a host using JSSE. What this usually means is that the server is using a test certificate (possibly generated using keytool) rather than a certificate from a well known commercial Certification Authority such as Verisign or GoDaddy. Web browsers display warning dialogs in this case, but since JSSE cannot assume an interactive user is present it just throws an exception by default.

Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


@AgilePro SSL gives you four assurances: authentication, privacy, integrity, and the possibilty of authorization. It does not give you any assurance that you are talking to a server known to the NSA. Caring only about privacy without authentication is a contradiction in terms.

@EJP Agree that if you use a client certificate you can get authentication and I suppose the possibility of authorization ... but most uses are not with a client certificate. What would you call the difference between a "self-signed" certificate, and a certificate from a signing authority? Does signing authority give "integrity". My Joke about NSA is that all signing authorities can not positively guarantee independence from everything. Not that paranoid really, but the point is your certificate is ONLY as secret as the signing authority can make it. Self-signed can be more secret.

Basically, you want to add the server's certificate to the KeyStore with your trusted certificates

Certificate validation is a very important part of SSL security, but I am not writing this entry to explain the details. If you are interested, you can start by reading the Wikipedia blurb. I am writing this entry to show a simple way to talk to that host with the test certificate, if you really want to.

The part about "Certificate validation is a very important part of SSL security" is not necessarily true. SSL gives you two assurances: (1) that your communication is private, and (2) that you are talking to a server which is known to the NSA.(:-) Sometimes you only care about privacy of the conversation, and then a self-signed certification is fine. See social-biz.org/2011/10/16/the-anti-ssl-conspiracy

Try the code provided there. It might help.

when trying to open an SSL connection to a host using JSSE. What this usually means is that the server is using a test certificate (possibly generated using keytool) rather than a certificate from a well known commercial Certification Authority such as Verisign or GoDaddy. Web browsers display warning dialogs in this case, but since JSSE cannot assume an interactive user is present it just throws an exception by default.

Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


java.security.cert.CertificateException: No name matching localhost found

In this article author describes how to fetch the certificate from your browser and add it to cacerts file of your JVM. You can either edit JAVA_HOME/jre/lib/security/cacerts file or run you application with -Djavax.net.ssl.trustStore parameter. Verify which JDK/JRE you are using too as this is often a source of confusion.

The problem also appears with a certificate signed by someone else that isn't trusted.

The problem appears when your server has self signed certificate. To workaround it you can add this certificate to the list of trusted certificates of your JVM.

this hasn't worked for me. I have the root and the chain cert installed, but Tomcat-7 still reports validatorException caused by "unable to find valid certification path to requested target" any way to debug this?

Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 22 more

In this case, the "unable to find valid certification path to requested target" message is being produced due to the missing intermediate certificate. You can check which certificate is missing using SSL Labs test against the server. Once you find the appropriate certificate, download it and (if the server is under your control) add it to the certificate bundle. Alternatively, you can import the missing certificate locally. Accommodating this issue on the server is a more general solution to the problem.

The source of this error on my Apache 2.4 instance (using a Comodo wildcard certificate) was an incomplete path to the SHA-1 signed root certificate. There were multiple chains in the issued certificate, and the chain leading to a SHA-1 root certificate was missing an intermediate certificate. Modern browsers know how to handle this, but Java 7 doesn't handle it by default (although there are some convoluted ways to accomplish this in code). The result is error messages that look identical to the case of self-signed certificates:

ssllabs.com/ssltest is a savior, just have to compare it with a working cert validation.

Note
Rectangle 27 0

ssl Java: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target?


Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 22 more

In this case, the "unable to find valid certification path to requested target" message is being produced due to the missing intermediate certificate. You can check which certificate is missing using SSL Labs test against the server. Once you find the appropriate certificate, download it and (if the server is under your control) add it to the certificate bundle. Alternatively, you can import the missing certificate locally. Accommodating this issue on the server is a more general solution to the problem.

The source of this error on my Apache 2.4 instance (using a Comodo wildcard certificate) was an incomplete path to the SHA-1 signed root certificate. There were multiple chains in the issued certificate, and the chain leading to a SHA-1 root certificate was missing an intermediate certificate. Modern browsers know how to handle this, but Java 7 doesn't handle it by default (although there are some convoluted ways to accomplish this in code). The result is error messages that look identical to the case of self-signed certificates:

ssllabs.com/ssltest is a savior, just have to compare it with a working cert validation.

Note