javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

前端 未结 11 706
清酒与你
清酒与你 2020-11-27 15:59

I am using Retrofit to access my REST API. However, when I put my API behind ssl and access it by http://myhost/myapi then I get this error:

Do I need t

相关标签:
11条回答
  • 2020-11-27 16:45

    The reason this occur is the JVM/Dalvik haven't not confidence in the CA certificates in the system or in the user certificate stores.

    To fix this with Retrofit, If you are used okhttp, with another client it's very similar.
    You've to do:

    A). Create a cert store contain public Key of CA. To do this you need to launch next script for *nix. You need openssl install in your machine, and download from https://www.bouncycastle.org/ the jar bcprov-jdk16-1.46.jar. Download this version not other, the version 1.5x is not compatible with android 4.0.4.

    #!/bin/bash
    
    if [ -z $1 ]; then
      echo "Usage: cert2Android<CA cert PEM file>"
      exit 1
    fi
    
    CACERT=$1
    BCJAR=bcprov-jdk16-1.46.jar
    
    TRUSTSTORE=mytruststore.bks
    ALIAS=`openssl x509 -inform PEM -subject_hash -noout -in $CACERT`
    
    if [ -f $TRUSTSTORE ]; then
        rm $TRUSTSTORE || exit 1
    fi
    
    echo "Adding certificate to $TRUSTSTORE..."
    keytool -import -v -trustcacerts -alias $ALIAS \
          -file $CACERT \
          -keystore $TRUSTSTORE -storetype BKS \
          -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
          -providerpath $BCJAR \
          -storepass secret
    
    echo "" 
    echo "Added '$CACERT' with alias '$ALIAS' to $TRUSTSTORE..."
    

    B). Copy the file truststore mytruststore.bks in res/raw of your project truststore location

    C). Setting SSLContext of the connection:

    .............
    okHttpClient = new OkHttpClient();
    try {
        KeyStore ksTrust = KeyStore.getInstance("BKS");
        InputStream instream = context.getResources().openRawResource(R.raw.mytruststore);
        ksTrust.load(instream, "secret".toCharArray());
    
        // TrustManager decides which certificate authorities to use.
        TrustManagerFactory tmf = TrustManagerFactory
            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ksTrust);
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);
    
        okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
    } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) {
        e.printStackTrace();
    }
    .................
    
    0 讨论(0)
  • 2020-11-27 16:46

    After a some research i found the way to bypass ssl error Trust anchor for certification path not found. This might be not a good way to do but you can use it for a testing purpose.

     private HttpsURLConnection httpsUrlConnection( URL urlDownload) throws Exception {
      HttpsURLConnection connection=null;
            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
    
                @SuppressLint("TrustAllX509TrustManager")
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }
    
                @SuppressLint("TrustAllX509TrustManager")
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }
            };
            SSLContext sc = SSLContext.getInstance("SSL"); // Add in try catch block if you get error.
            sc.init(null, trustAllCerts, new java.security.SecureRandom()); // Add in try catch block if you get error.
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    
            HostnameVerifier usnoHostnameVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
    
            SSLSocketFactory sslSocketFactory = sc.getSocketFactory();
    
            connection = (HttpsURLConnection) urlDownload.openConnection();
            connection.setHostnameVerifier(usnoHostnameVerifier);
            connection.setSSLSocketFactory(sslSocketFactory);
    
            return connection;
        }
    
    0 讨论(0)
  • 2020-11-27 16:48

    Fix for Android N & above: I had similar issue and mange to solve it by following steps described in https://developer.android.com/training/articles/security-config

    But the config changes, without any complicated code logic, would only work on Android version 24 & above.

    Fix for all version, including version < N: So for android lower then N (version 24) the solution is to via code changes as mentioned above. If you are using OkHttp, then follow the customTrust: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java

    0 讨论(0)
  • 2020-11-27 16:54

    Hi same problem i have solved you can try this

    java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.NETWORK

     // SET SSL
    public static OkClient setSSLFactoryForClient(OkHttpClient client) {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }
    
                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }
    
                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }
                    }
            };
    
            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    
    
            client.setSslSocketFactory(sslSocketFactory);
            client.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
    
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return new OkClient(client);
    }
    
    0 讨论(0)
  • 2020-11-27 16:54

    My answer might not be solution to your question but it will surely help others looking for similar issue like this one: javax.net.ssl.SSLHandshakeException: Chain validation failed

    You just need to check your Android Device's Date and Time, it should be fix the issue. This resoled my problem.

    0 讨论(0)
提交回复
热议问题