javax.net.ssl.SSLHandshakeException:java.security.cert.CertPathValidatorException:未找到证书路径的信任锚

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21047414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 06:10:31  来源:igfitidea点击:

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

javaandroidsslretrofit

提问by birdy

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

我正在使用 Retrofit 访问我的 REST API。但是,当我将 API 放在 ssl 之后并访问它时,http://myhost/myapi我收到此错误:

Do I need to do something extra now that my API is behind SSL?

现在我的 API 位于 SSL 之后,我是否需要做一些额外的事情?

Here is how I connect:

这是我的连接方式:

private final String API = "https://myhost/myapi";

private final RestAdapter REST_ADAPTER = new RestAdapter.Builder()
        .setServer(API)
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .build();

01-10 09:49:55.621    2076-2100/com.myapp.mobile D/Retrofit﹕ javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:401)
            at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
            at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
            at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
            at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
            at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:90)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:48)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:287)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:222)
            at $Proxy12.signin(Native Method)
            at com.myapp.loginactivity.doInBackground(LoginActivity.java:143)
            at com.myapp.loginactivity.doInBackground(LoginActivity.java:136)
            at android.os.AsyncTask.call(AsyncTask.java:287)
            at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at java.lang.Thread.run(Thread.java:841)
     Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
            at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:282)
            at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:202)
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:595)
            at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:398)
????????????at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
????????????at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
????????????at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
????????????at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
????????????at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
????????????at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
????????????at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
????????????at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
????????????at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:90)
????????????at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:48)
????????????at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:287)
????????????at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:222)
????????????at $Proxy12.signin(Native Method)
????????????at com.myapp.LoginActivity.doInBackground(LoginActivity.java:143)
????????????at com.myapp.LoginActivity.doInBackground(LoginActivity.java:136)
????????????at android.os.AsyncTask.call(AsyncTask.java:287)
????????????at java.util.concurrent.FutureTask.run(FutureTask.java:234)
????????????at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:230)
????????????at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
????????????at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
????????????at java.lang.Thread.run(Thread.java:841)

回答by Kevin Bowersox

The SSL is not properly configured. Those trustAnchor errors usually mean that the trust store cannot be found. Check your configuration and make sure you are actually pointing to the trust store and that it is in place.

SSL 未正确配置。那些 trustAnchor 错误通常意味着无法找到信任存储。检查您的配置并确保您确实指向信任存储并且它就位。

Make sure you have a -Djavax.net.ssl.trustStoresystem property set and then check that the path actually leads to the trust store.

确保您设置了-Djavax.net.ssl.trustStore系统属性,然后检查该路径是否实际通向信任存储。

You can also enable SSL debugging by setting this system property -Djavax.net.debug=all. Within the debug output you will notice it states that it cannot find the trust store.

您还可以通过设置此系统属性来启用 SSL 调试-Djavax.net.debug=all。在调试输出中,您会注意到它指出它找不到信任存储。

回答by kupsef

There are 4 ways that I know of:

我知道有4种方法:

  • import the certificate to your app and use it for the connection
  • disable certificate checking
  • add your certificate to the trusted system certificates in Android
  • buy a verified certificate that is accepted by Android
  • 将证书导入您的应用程序并将其用于连接
  • 禁用证书检查
  • 将您的证书添加到 Android 中受信任的系统证书
  • 购买 Android 接受的经过验证的证书

I assume you don't want to pay for this, so I think the most elegant solution is the first one, what can be accomplished this way:

我假设您不想为此付费,所以我认为最优雅的解决方案是第一个,可以通过这种方式完成:

http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

回答by Defuera

This can happen for several reasons, including:

这可能有多种原因,包括:

  1. The CA that issued the server certificate was unknown
  2. The server certificate wasn't signed by a CA, but was self signed
  3. The server configuration is missing an intermediate CA
  1. 颁发服务器证书的 CA 未知
  2. 服务器证书不是由 CA 签署的,而是自签名的
  3. 服务器配置缺少中间 CA

please check out this link for solution: https://developer.android.com/training/articles/security-ssl.html#CommonProblems

请查看此链接以获取解决方案:https: //developer.android.com/training/articles/security-ssl.html#CommonProblems

回答by Fernando.

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.

发生这种情况的原因是 JVM/Dalvik 不信任系统或用户证书存储中的 CA 证书。

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

要使用 Retrofit 解决此问题,如果您使用 okhttp,则与另一个客户端非常相似。
你必须做:

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.

一种)。创建一个包含 CA 公钥的证书存储。为此,您需要为 *nix 启动下一个脚本。您需要在您的机器上安装 openssl,并从https://www.bouncycastle.org/下载jar bcprov-jdk16-1.46.jar。下载这个版本不是其他的,1.5x版本不兼容android 4.0.4。

#!/bin/bash

if [ -z  ]; then
  echo "Usage: cert2Android<CA cert PEM file>"
  exit 1
fi

CACERT=
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

B)。将文件 truststore mytruststore.bks 复制到项目的 res/raw 中 信任库位置

C). Setting SSLContext of the connection:

C)。设置连接的 SSLContext:

.............
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();
}
.................

回答by sushant gosavi

Hi same problem i have solved you can try this

你好,我已经解决了同样的问题,你可以试试这个

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

java.security.cert.CertPathValidatorException:未找到证书路径的信任锚。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);
}

回答by Ali Bagheri

I use this class and have no problem.

我使用这个类并且没有问题。

public class WCFs
{
    // https://192.168.30.8/myservice.svc?wsdl
    private static final String NAMESPACE = "http://tempuri.org/";
    private static final String URL = "192.168.30.8";
    private static final String SERVICE = "/myservice.svc?wsdl";
    private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/";


    public static Thread myMethod(Runnable rp)
    {
        String METHOD_NAME = "myMethod";

        SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

        request.addProperty("Message", "Https WCF Running...");
        return _call(rp,METHOD_NAME, request);
    }

    protected static HandlerThread _call(final RunProcess rp,final String METHOD_NAME, SoapObject soapReq)
    {
        final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        int TimeOut = 5*1000;

        envelope.dotNet = true;
        envelope.bodyOut = soapReq;
        envelope.setOutputSoapObject(soapReq);

        final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut);

        try
        {
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake
            {
                @Override
                public boolean verify(String hostname, SSLSession session)
                {
                    return true;
                }
            });

            KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password");
            ((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL"));


        }
        catch(Exception e){}

        HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber())
        {
            @Override
            public void run()
            {
                Handler h = new Handler(Looper.getMainLooper());
                Object response = null;

                for(int i=0; i<4; i++)
                {
                    response = send(envelope, httpTransport_net , METHOD_NAME, null);

                    try
                    {if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){}

                    if(response != null)
                        break;

                    ThreadHelper.threadSleep(250);
                }

                if(response != null)
                {
                    if(rp != null)
                    {
                        rp.setArguments(response.toString());
                        h.post(rp);
                    }
                }
                else
                {
                    if(Thread.currentThread().isInterrupted())
                        return;

                    if(rp != null)
                    {
                        rp.setExceptionState(true);
                        h.post(rp);
                    }
                }

                ThreadHelper.stopThread(this);
            }
        };

        thread.start();

        return thread;
    }


    private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List<HeaderProperty> headerList)
    {
        try
        {
            if(headerList != null)
                androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList);
            else
                androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope);

            Object res = envelope.getResponse();

            if(res instanceof SoapPrimitive)
                return (SoapPrimitive) envelope.getResponse();
            else if(res instanceof SoapObject)
                return ((SoapObject) envelope.getResponse());
        }
        catch(Exception e)
        {}

        return null;
    }

    public static KeyStore getFromRaw(@RawRes int id, String algorithm, String filePassword)
    {
        try
        {
            InputStream inputStream = ResourceMaster.openRaw(id);
            KeyStore keystore = KeyStore.getInstance(algorithm);
            keystore.load(inputStream, filePassword.toCharArray());
            inputStream.close();

            return keystore;
        }
        catch(Exception e)
        {}

        return null;
    }

    public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String SSLAlgorithm)
    {
        try
        {
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustKey);

            SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS"
            context.init(null, tmf.getTrustManagers(), null);

            return context.getSocketFactory();
        }
        catch(Exception e){}

        return null;
    }
}

回答by Kishan Solanki

OK, So I faced the same issue for my android app which have secured domain i.e. HTTPS,

好的,所以我的 android 应用程序遇到了同样的问题,它有安全的域,即 HTTPS,

These are the steps:

这些是步骤:

  1. You need SSL certificate file i.e. ".pem"file for your domain.
  2. put that file into the assets folder
  3. Just copy and paste this class in your project
  1. 您的域需要 SSL 证书文件,即“.pem”文件。
  2. 将该文件放入资产文件夹
  3. 只需将此类复制并粘贴到您的项目中

public class SSlUtilsw {

公共类 SSLUtilsw {

public static SSLContext getSslContextForCertificateFile(Context context, String fileName){

    try {
        KeyStore keyStore = SSlUtilsw.getKeyStore(context, fileName);
        SSLContext sslContext = SSLContext.getInstance("SSL");
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        sslContext.init(null,trustManagerFactory.getTrustManagers(),new SecureRandom());
        return sslContext;

    }catch (Exception e){
        String msg = "Error during creating SslContext for certificate from assets";
        e.printStackTrace();
        throw new RuntimeException(msg);
    }
}

public static KeyStore getKeyStore(Context context,String fileName){
    KeyStore keyStore = null;
    try {
        AssetManager assetManager=context.getAssets();
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream caInput=assetManager.open(fileName);
        Certificate ca;
        try {
            ca=cf.generateCertificate(caInput);

        }finally {
            caInput.close();
        }
        String keyStoreType=KeyStore.getDefaultType();
        keyStore=KeyStore.getInstance(keyStoreType);
        keyStore.load(null,null);
        keyStore.setCertificateEntry("ca",ca);
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return keyStore;
}}
  1. In your http client class of retrofit, add this

        val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
    trustManagerFactory.init(null as KeyStore?)
    val trustManagers: Array<TrustManager> = trustManagerFactory.trustManagers
    if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
        throw IllegalStateException("Unexpected default trust managers:" + trustManagers.contentToString())
    }
    val trustManager = trustManagers[0] as X509TrustManager
    
    httpClient.sslSocketFactory(SSlUtils.getSslContextForCertificateFile(
            applicationContextHere, "yourcertificate.pem").socketFactory, trustManager)
    
  1. 在你的 http 客户端改造类中,添加这个

        val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
    trustManagerFactory.init(null as KeyStore?)
    val trustManagers: Array<TrustManager> = trustManagerFactory.trustManagers
    if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
        throw IllegalStateException("Unexpected default trust managers:" + trustManagers.contentToString())
    }
    val trustManager = trustManagers[0] as X509TrustManager
    
    httpClient.sslSocketFactory(SSlUtils.getSslContextForCertificateFile(
            applicationContextHere, "yourcertificate.pem").socketFactory, trustManager)
    

And that's it.

就是这样。

回答by Muhammed Irfan

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

我的回答可能不是您问题的解决方案,但它肯定会帮助其他人寻找类似的问题: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.

您只需要检查您的 Android 设备的日期和时间,就可以解决问题。这解决了我的问题。

回答by vijay

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

修复 Android N 及更高版本:我遇到了类似的问题,并按照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.

但是配置更改,没有任何复杂的代码逻辑,仅适用于 Android 24 及更高版本。

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

修复所有版本,包括版本 < N:因此,对于低于 N(版本 24)的 android,解决方案是通过如上所述的代码更改。如果您使用的是 OkHttp,请遵循 customTrust:https: //github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java