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

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

我正在使用Retrofit访问我的REST API。 但是,当我将我的API放在ssl后面并通过http://myhost/myapi访问它时,出现此错误:

我的API位于SSL之后,我还需要做些额外的事情吗?

这是我的连接方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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$3.doInBackground(LoginActivity.java:143)
            at com.myapp.loginactivity$3.doInBackground(LoginActivity.java:136)
            at android.os.AsyncTask$2.call(AsyncTask.java:287)
            at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            at android.os.AsyncTask$SerialExecutor$1.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$3.doInBackground(LoginActivity.java:143)
at com.myapp.LoginActivity$3.doInBackground(LoginActivity.java:136)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at android.os.AsyncTask$SerialExecutor$1.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)


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

要使用Retrofit修复此问题,如果您将okhttp与其他客户端一起使用,则非常相似。
您必须:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/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)。将文件truststore mytruststore.bks复制到项目的res / raw中
truststore location

C)。设置连接的SSLContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.............
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();
}
.................


修复Android N及以上版本:
我有类似的问题并希望通过执行以下步骤来解决此问题:https://developer.android.com/training/articles/security-config

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

修复了所有版本,包括版本


发生这种情况可能有多种原因,其中包括:

  • 颁发服务器证书的CA未知
  • 服务器证书不是由CA签名的,而是自签名的
  • 服务器配置缺少中间CA
  • 请查看此链接以获取解决方案:https://developer.android.com/training/articles/security-ssl.html#CommonProblems


    嗨,我解决了同样的问题,您可以尝试一下

    java.security.cert.CertPathValidatorException:找不到证书路径的信任锚

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     // 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);
    }


    我知道4种方法:

    • 将证书导入到您的应用程序并将其用于连接
    • 禁用证书检查
    • 将您的证书添加到Android中的受信任系统证书
    • 购买Android接受的经过验证的证书

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

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


    未正确配置SSL。这些trustAnchor错误通常意味着找不到信任库。检查您的配置,并确保您实际上指向的是信任存储,并且该存储已安装到位。

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

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


    这是服务器端问题。

    服务器端有用于HTTPS的.crt文件,在这里我们必须结合

    1
    cat your_domain.**crt** your_domain.**ca-bundle** >> ssl_your_domain_.crt

    然后重新启动。

    1
    sudo service nginx restart

    对我来说工作很好。


    我的答案可能无法解决您的问题,但肯定会帮助其他人寻找类似的问题:
    javax.net.ssl.SSLHandshakeException:链验证失败

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


    好的,所以我的Android应用程序也遇到了同样的问题,该应用程序具有安全域,即HTTPS,

    这些步骤是:

  • 您需要域的SSL证书文件,即" .pem"文件。
  • 将该文件放入资产文件夹
  • 只需将此类复制并粘贴到您的项目中
  • 公共类SSlUtilsw {

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    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;
    }}
  • 在您的HTTP客户改造类中,添加此代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    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;
        }
    }