在android app端訪問(wèn)https服務(wù)時(shí),搜到的資料大都是自簽名證書(shū)認(rèn)證的邏輯。想辦法扒到了Google官方的資料看了一下,豁然開(kāi)朗。
基礎(chǔ)概念就不解釋了,只說(shuō)使用方法。
使用CA簽署的證書(shū)
如果服務(wù)端使用的是知名CA機(jī)構(gòu)簽名的證書(shū),android連接https的代碼非常簡(jiǎn)單:
URL url = new URL("https://wikipedia.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);
常見(jiàn)問(wèn)題
如果在鏈接https時(shí)遇到錯(cuò)誤:
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:374)
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.getInputStream(HttpURLConnectionImpl.java:177)
at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
可能有以下幾個(gè)原因:
1.簽名證書(shū)的CA機(jī)構(gòu)不知名
2.使用了自簽名的證書(shū)
3.服務(wù)端配置問(wèn)題
解決方案
1.導(dǎo)致SSLHandshakeException是由于簽署證書(shū)的CA不被系統(tǒng)所信任。一種原因是CA機(jī)構(gòu)比較新,還沒(méi)被android系統(tǒng)證書(shū)庫(kù)內(nèi)置?;蛘吣愕腶ndroid版本比較舊,證書(shū)庫(kù)不全。
這種情況的解決方案和使用了自簽名證書(shū)的方案是一樣的,重寫(xiě)Google默認(rèn)的證書(shū)校驗(yàn)邏輯。
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAsString keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContextURL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);
2.服務(wù)器配置問(wèn)題
修改服務(wù)器配置或者使用上面的解決方案,直接信任該證書(shū)