SunCertPathBuilderException: unable to find valid certification path to requested target in CN1 app
Asked Answered
R

2

5

Please can you help. I have a Codenameone app that issues a GET request to a cloud Tomcat 8 server, and expects back some response JSON. Importantly this is a HTTPS call.

When i run the request in Postman it works fine:

https://www.mydomain.co.uk:8443/MyProject/v1/generate_token

The same URL through my browser works and shows as 'Secure' and i can see my certificate details. I have bought a certificate for my SSL/TLS configuration, and seems to function fine in the logs on startup.

In the simulator i get back the following error at the point of reading the response back from the URL call - which i guess must be encrypted:

Exception: 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
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
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1959)
    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:1514)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
    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:1564)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:347)
    at com.codename1.impl.javase.JavaSEPort.getResponseCode(JavaSEPort.java:7591)
    at com.codename1.io.ConnectionRequest.performOperation(ConnectionRequest.java:702)
    at com.codename1.io.NetworkManager$NetworkThread.run(NetworkManager.java:282)
    at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)

Why should the app be any different to Postman making the call (the Network Monitor window confirms the same URL call) ?

None of the logs are being updated after my call, so nothing to check there. I haven't made any changes to my app (which was working) since moving from http to https.

Here is the CN1 code making the call:

public String fetchTokenIntoStorage(String userName, String password) {
        ConnectionRequest r = new ConnectionRequest();
        r.setUrl(Constants.URL_HOST_PORT + "/MyProject" + Constants.LIVE_OR_TEST
                + "/v1/generate_token");
        r.addRequestHeader("Content-Type", "application/json");
        r.addRequestHeader("userName", userName);
        r.addRequestHeader("password", password);
        r.setHttpMethod("GET");
        r.setFailSilently(false);
        r.setPost(false);
        // show spinning dialog while connecting
        InfiniteProgress prog = new InfiniteProgress();
        Dialog dlg = prog.showInifiniteBlocking();
        r.setDisposeOnCompletion(dlg);
        NetworkManager.getInstance().setTimeout(10000);
        // NetworkManager.getInstance().addErrorListener(new ActionListener() {
        //
        // @Override
        // public void actionPerformed(ActionEvent evt) {
        // MessageBox.showDialogMessage("Unable to connect to server. Please
        // retry later.");
        // }
        // });
        // NetworkManager.getInstance().updateThreadCount(2);
        NetworkManager.getInstance().addToQueueAndWait(r);

        if (r.getResponseData() != null) {
            JSONParser parser = new JSONParser();
            Map<String, Object> json = null;
            try {
                json = parser.parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData())));
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (json.get("error") != null) {
                return String.valueOf(json.get("error"));
            }
            JwtRecord record = new JwtRecord();
            record.userId = Integer.parseInt(String.valueOf(json.get("userId")));
            record.jsonWebToken = (String) json.get("jwt");
            record.theme = "LIGHT";
            Storage.getInstance().writeObject("MyToken", record);
            return "";
        }
        if (!r.getResponseErrorMessage().equalsIgnoreCase("")) {
            return r.getResponseErrorMessage();
        } else {
            return "Unable to connect to server. Please check connection.";
        }
    }

Stepping through the code it seems to error just after

NetworkManager.getInstance().addToQueueAndWait(r);

The r.getResponseData() and r.getResponseErrorMessage() are null.

Many thanks

Redcoat answered 23/5, 2018 at 23:7 Comment(1)
You seem to have fixed the issue by importing the certificate. I had a similar issue and fixed it by upgrading the version of Java 8 from 1.8.0_25-b17 to 1.8.0_241-b07. Do you happen to know what version you were running ?Ellsworth
R
3

It is now working.

  1. (On cloud tomcat) I made sure the root certificate and the intermediary certificate were in my keystore (as per the links i previously included). I included my .ca-bundle in the keystore for good measure.

  2. (On cloud tomcat) And i noticed i was using an older version of the Apache configuration (lesson learned about relying on older forum posts). Needed to have SSLCACertificateFile pointing to my .ca-bundle file, rather than using SSCertificateChainFile, in my apache .conf file.

  3. It still error on my simulator but works on my iphone, which points (as Shai says) to differing JDK's i expect, so upgraded my laptop to the higher JDK 1.8.171. This didn't in itself make a difference but probably required.

  4. Through digging around i realised that simulators on my laptop needed the above also. So i ended up running the statements below, in command prompt as Administrator, and now my simulator is working.

    cd %java_home%\jre\lib\security

    path=%java_home\bin

    keytool -import -alias comodo -keystore cacerts -file C:\path\ComodoRoot.cer

    keytool -import -alias comodo_intermediate -keystore cacerts -file C:\path\ComodoInter.cer

    keytool -import -alias purchased_cert -keystore cacerts -file C:\path\my_purchased_cert.crt

Redcoat answered 25/5, 2018 at 8:30 Comment(0)
F
5

This happens if the signing authority isn't recognized by the underlying JDK. Assuming you purchased your certificate from a valid source it's possible that it uses a relatively new root which means you need to use the latest version of JDK 8.

E.g. letsencrypt was only added in JDK 8 update 101.

Fraser answered 24/5, 2018 at 3:54 Comment(8)
Just checked Tomcat and its running JDK 1.8 update 171, which seems high enough.Redcoat
Confirmed that my cacerts did contain my root CA, so it's not that. Used magicmonster.com/kb/prg/java/ssl/pkix_path_building_failed.htmlRedcoat
Further reading shows that it could well the the intermediate certificate that shows in my certificates hierarchy. I will adding that to the keystore later. Incidentally my keystore doesn't contain my child certificate (the one i bought) so don't know if thats a problem? Good info here: #6909448Redcoat
Unfortunately i still have the same problem. Can anyone help. I have added the root certificate, the intermediary and my own to the keystore successfully. I can see them in there. Bounced everything and when i run the simulator it error still. I've read a lot of forums and drawn a blank. Is there an area i need to check for? ThanksRedcoat
Is that same JDK used for the client side JVM in the simulator? Could that be picking up an older JDK install?Fraser
This made me check the app on my iphone and it worked. Simulator\Eclipse is running java 8 but a lower point release, so will update the client to the higher version and see if that makes a difference, which it should. ThanksRedcoat
I have a Server with SSL from GlobalSign and works perfectly in chrome, but java client is giving the above exception, I upgraded Java to 11Kentigera
Try creating a simple hello world in plain Java unrelated to Codename One to see that this issue is a problem between the JVM/certificate. Then narrow that down with the signing authorities support staffFraser
R
3

It is now working.

  1. (On cloud tomcat) I made sure the root certificate and the intermediary certificate were in my keystore (as per the links i previously included). I included my .ca-bundle in the keystore for good measure.

  2. (On cloud tomcat) And i noticed i was using an older version of the Apache configuration (lesson learned about relying on older forum posts). Needed to have SSLCACertificateFile pointing to my .ca-bundle file, rather than using SSCertificateChainFile, in my apache .conf file.

  3. It still error on my simulator but works on my iphone, which points (as Shai says) to differing JDK's i expect, so upgraded my laptop to the higher JDK 1.8.171. This didn't in itself make a difference but probably required.

  4. Through digging around i realised that simulators on my laptop needed the above also. So i ended up running the statements below, in command prompt as Administrator, and now my simulator is working.

    cd %java_home%\jre\lib\security

    path=%java_home\bin

    keytool -import -alias comodo -keystore cacerts -file C:\path\ComodoRoot.cer

    keytool -import -alias comodo_intermediate -keystore cacerts -file C:\path\ComodoInter.cer

    keytool -import -alias purchased_cert -keystore cacerts -file C:\path\my_purchased_cert.crt

Redcoat answered 25/5, 2018 at 8:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.