122

I connected with VPN to setup the inventory API to get product list and it works fine. Once I get the result from the web-service and i bind to UI. And also I integrated PayPal with my application for make Express checkout when I make a call for payment I'm facing this error. I use servlet for back-end process. Can any one say how to fix this issue?

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
javanna
  • 59,145
  • 14
  • 144
  • 125
selladurai
  • 6,491
  • 14
  • 56
  • 88
  • 1
    what I would like to know, which exact target was in thath case... You get an exception, but you get no information about target, which might be different of what you expect.. I have such case, I am sure my link has certificate, and I am still getting this exception – ante.sabo Feb 21 '12 at 12:41

5 Answers5

178

First, you need to obtain the public certificate from the server you're trying to connect to. That can be done in a variety of ways, such as contacting the server admin and asking for it, using OpenSSL to download it, or, since this appears to be an HTTP server, connecting to it with any browser, viewing the page's security info, and saving a copy of the certificate. (Google should be able to tell you exactly what to do for your specific browser.)

Now that you have the certificate saved in a file, you need to add it to your JVM's trust store. At $JAVA_HOME/jre/lib/security/ for JREs or $JAVA_HOME/lib/security for JDKs, there's a file named cacerts, which comes with Java and contains the public certificates of the well-known Certifying Authorities. To import the new cert, run keytool as a user who has permission to write to cacerts:

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

It will most likely ask you for a password. The default password as shipped with Java is changeit. Almost nobody changes it. After you complete these relatively simple steps, you'll be communicating securely and with the assurance that you're talking to the right server and only the right server (as long as they don't lose their private key).

Alireza Noorali
  • 3,129
  • 2
  • 33
  • 80
Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • 12
    I'll need a little more detail than "not working". Try updating your question with what you've tried and some error output. Unfortunately, it's way past my bedtime, so maybe someone else will be able to answer your questions. This also is a very common situation. You can find lots of information on it online, including the [keytool docs](http://download.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html). – Ryan Stewart Jul 19 '11 at 05:22
  • Basically i need to include PayPal cert. I did your steps and cert also added in the appropriate location. then i run the app it say same error? –  Jul 19 '11 at 05:28
  • Actually it works well no problem browser and I connected VPN to get inventory list at that time i make payment with PayPal, it say's SSL error but i use offline data or hot coded data means it works. –  Jul 19 '11 at 05:33
  • 4
    @selladurai: You shouldn't need to import a cert for paypal. Unless your cacerts file has been corrupted or modified, it should contain all the trusted root certificates, and paypal's cert should be able to be traced back to one of those. You might try getting a copy of cacerts that you know is good and trying that one instead. If the problem persists, then you may not actually be connecting to paypal. – Ryan Stewart Jul 19 '11 at 14:28
  • @RyanStewart do I need to import it to glassfish somehow ? Because I did add the .cer file to my cacert in my java home directory but glassfish doesn't seem to use it so I'm still getting the error. – Ced Jul 31 '15 at 20:36
  • How does this work for distributing the application. Wouldn't it be really non-user friendly to have to go through all these steps? Or would you package a jdk with it already all setup? – vedi0boy Jun 08 '16 at 20:06
  • @RyanStewart any idea abt http://stackoverflow.com/questions/38910575/how-to-get-access-token-paypal-in-android – Aditya Vyas-Lakhan Aug 12 '16 at 09:04
  • It works! This is exactly what I need to do in order to enable my Java webservices to call a remote SSL endpoint. I was concentrating on adding the certificate to Tomcat; when in fact, the certificate should be added to JDK/JRE security instead. Now I understand. – hb5fa Apr 11 '17 at 14:37
  • This solution worked to me: https://stackoverflow.com/a/59087392/4507034 – Radu Linu Nov 28 '19 at 11:05
14

Whenever we are trying to connect to URL,

if server at the other site is running on https protocol and is mandating that we should communicate via information provided in certificate then we have following option:

1) ask for the certificate(download the certificate), import this certificate in trustore. Default trustore java uses can be found in \Java\jdk1.6.0_29\jre\lib\security\cacerts, then if we retry to connect to the URL connection would be accepted.

2) In normal business cases, we might be connecting to internal URLS in organizations and we know that they are correct. In such cases, you trust that it is the correct URL, In such cases above, code can be used which will not mandate to store the certificate to connect to particular URL.

for the point no 2 we have to follow below steps :

1) write below method which sets HostnameVerifier for HttpsURLConnection which returns true for all cases meaning we are trusting the trustStore.

  // trusting all certificate 
 public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

2) write below method, which calls doTrustToCertificates before trying to connect to URL

    // connecting to URL
    public void connectToUrl(){
     doTrustToCertificates();//  
     URL url = new URL("https://www.example.com");
     HttpURLConnection conn = (HttpURLConnection)url.openConnection(); 
     System.out.println("ResponseCode ="+conn.getResponseCode());
   }

This call will return response code = 200 means connection is successful.

For more detail and sample example you can refer to URL.

AndreyAkinshin
  • 18,603
  • 29
  • 96
  • 155
Shirishkumar Bari
  • 2,692
  • 1
  • 28
  • 36
0

SSLHandshakeException can be resolved 2 ways.

  1. Incorporating SSL

    • Get the SSL (by asking the source system administrator, can also be downloaded by openssl command, or any browsers downloads the certificates)

    • Add the certificate into truststore (cacerts) located at JRE/lib/security

    • provide the truststore location in vm arguments as "-Djavax.net.ssl.trustStore="

  2. Ignoring SSL

    For this #2, please visit my other answer on another stackoverflow website: How to ingore SSL verification Ignore SSL Certificate Errors with Java

Community
  • 1
  • 1
Amit Kaneria
  • 5,466
  • 2
  • 35
  • 38
0

I believe that you are trying to connect to a something using SSL but that something is providing a certificate which is not verified by root certification authorities such as verisign.. In essence by default secure connections can only be established if the person trying to connect knows the counterparties keys or some other verndor such as verisign can step in and say that the public key being provided is indeed right..

ALL OS's trust a handful of certification authorities and smaller certificate issuers need to be certified by one of the large certifiers making a chain of certifiers if you get what I mean...

Anyways coming back to the point.. I had a similiar problem when programming a java applet and a java server ( Hopefully some day I will write a complete blogpost about how I got all the security to work :) )

In essence what I had to do was to extract the public keys from the server and store it in a keystore inside my applet and when I connected to the server I used this key store to create a trust factory and that trust factory to create the ssl connection. There are alterante procedures as well such as adding the key to the JVM's trusted host and modifying the default trust store on start up..

I did this around two months back and dont have source code on me right now.. use google and you should be able to solve this problem. If you cant message me back and I can provide you the relevent source code for the project .. Dont know if this solves your problem since you havent provided the code which causes these exceptions. Furthermore I was working wiht applets thought I cant see why it wont work on Serverlets...

P.S I cant get source code before the weekend since external SSH is disabled in my office :(

Osama Javed
  • 1,432
  • 1
  • 16
  • 21
  • 1
    P.S I found this java code online to extract and store the public keys of my server so keep googling or wait till sundayish – Osama Javed Jul 14 '11 at 17:54
0

This is what I did to POST a JSON to a URL with insecure/invalid SSL certs using latest JDK 11 HttpClient:

    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                }
                public void checkServerTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                }
            }
    };

    try {

        // Install the all-trusting trust manager
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        // Creat HttpClient with new SSLContext.
        HttpClient httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofMillis(3 * 1000))
                .sslContext(sc) // SSL context 'sc' initialised as earlier
                .build();

        // Create request.
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(<URL>))
                .timeout(Duration.ofMinutes(1))
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(<PAYLOAD JSON STRING>))
                .build();

        //Send Request
        HttpResponse<String> response =
                httpClient.send(request, HttpResponse.BodyHandlers.ofString());

        //Access response JSON
        String responseJson = response.body();

   } catch (Exception e) {
     throw new Exception(e);
   }
Max Barrass
  • 2,776
  • 1
  • 19
  • 10