javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found
我正在使用Retrofit访问我的REST API。 但是,当我将我的API放在ssl后面并通过
我的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中
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及更高版本。
修复了所有版本,包括版本
发生这种情况可能有多种原因,其中包括:
请查看此链接以获取解决方案:https://developer.android.com/training/articles/security-ssl.html#CommonProblems
嗨,我解决了同样的问题,您可以尝试一下
java.security.cert.CertPathValidatorException:找不到证书路径的信任锚
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
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错误通常意味着找不到信任库。检查您的配置,并确保您实际上指向的是信任存储,并且该存储已安装到位。
确保设置了
您还可以通过设置此系统属性
这是服务器端问题。
服务器端有用于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,
这些步骤是:
公共类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; } } |