Android平臺實現https信任所有證書的方法

l_serein發表於2012-06-09

Android平臺上經常有使用https的需求,對於https伺服器使用的根證照是受信任的證照的話,實現https是非常簡單的,直接用httpclient庫就行了,與使用http幾乎沒有區別。但是在大多數情況下,伺服器所使用的根證照是自簽名的,或者簽名機構不在裝置的信任證照列表中,這樣使用httpclient進行https連線就會失敗。解決這個問題的辦法有兩種,一是在發起https連線之前將伺服器證照加到httpclient的信任證照列表中,這個相對來說比較複雜一些,很容易出錯;另一種辦法是讓httpclient信任所有的伺服器證照,這種辦法相對來說簡單很多,但安全性則差一些,但在某些場合下有一定的應用場景。這裡要舉例說明的就是後一種方法:例項化HttpClinet物件時要進行一些處理主要是繫結https連線所使用的埠號,這裡繫結了443和8443:

[java] view plaincopy
  1. SchemeRegistry schemeRegistry = new SchemeRegistry();  
  2. schemeRegistry.register(new Scheme("https",  
  3.                     new EasySSLSocketFactory(), 443));  
  4. schemeRegistry.register(new Scheme("https",  
  5.                     new EasySSLSocketFactory(), 8443));  
  6. ClientConnectionManager connManager = new ThreadSafeClientConnManager(params, schemeRegistry);  
  7. HttpClient httpClient = new DefaultHttpClient(connManager, params);  


上面的EasySSLSocketFactory類是我們自定義的,主要目的就是讓httpclient接受所有的伺服器證照,能夠正常的進行https資料讀取。相關程式碼如下:

[java] view plaincopy
  1. public class EasySSLSocketFactory implements SocketFactory,  
  2.         LayeredSocketFactory {  
  3.   
  4.     private SSLContext sslcontext = null;  
  5.   
  6.     private static SSLContext createEasySSLContext() throws IOException {  
  7.         try {  
  8.             SSLContext context = SSLContext.getInstance("TLS");  
  9.             context.init(nullnew TrustManager[] { new EasyX509TrustManager(  
  10.                     null) }, null);  
  11.             return context;  
  12.         } catch (Exception e) {  
  13.             throw new IOException(e.getMessage());  
  14.         }  
  15.     }  
  16.   
  17.     private SSLContext getSSLContext() throws IOException {  
  18.         if (this.sslcontext == null) {  
  19.             this.sslcontext = createEasySSLContext();  
  20.         }  
  21.         return this.sslcontext;  
  22.     }  
  23.   
  24.      
  25.     public Socket connectSocket(Socket sock, String host, int port,  
  26.             InetAddress localAddress, int localPort, HttpParams params)  
  27.             throws IOException, UnknownHostException, ConnectTimeoutException {  
  28.         int connTimeout = HttpConnectionParams.getConnectionTimeout(params);  
  29.         int soTimeout = HttpConnectionParams.getSoTimeout(params);  
  30.   
  31.         InetSocketAddress remoteAddress = new InetSocketAddress(host, port);  
  32.         SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());  
  33.   
  34.         if ((localAddress != null) || (localPort > 0)) {  
  35.             // we need to bind explicitly  
  36.             if (localPort < 0) {  
  37.                 localPort = 0// indicates "any"  
  38.             }  
  39.             InetSocketAddress isa = new InetSocketAddress(localAddress,  
  40.                     localPort);  
  41.             sslsock.bind(isa);  
  42.         }  
  43.   
  44.         sslsock.connect(remoteAddress, connTimeout);  
  45.         sslsock.setSoTimeout(soTimeout);  
  46.         return sslsock;  
  47.   
  48.     }  
  49.   
  50.      
  51.     public Socket createSocket() throws IOException {  
  52.         return getSSLContext().getSocketFactory().createSocket();  
  53.     }  
  54.   
  55.      
  56.     public boolean isSecure(Socket socket) throws IllegalArgumentException {  
  57.         return true;  
  58.     }  
  59.   
  60.      
  61.     public Socket createSocket(Socket socket, String host, int port,  
  62.             boolean autoClose) throws IOException, UnknownHostException {  
  63.         return getSSLContext().getSocketFactory().createSocket(socket, host,  
  64.                 port, autoClose);  
  65.     }  
  66.   
  67.     // -------------------------------------------------------------------  
  68.     // javadoc in org.apache.http.conn.scheme.SocketFactory says :  
  69.     // Both Object.equals() and Object.hashCode() must be overridden  
  70.     // for the correct operation of some connection managers  
  71.     // -------------------------------------------------------------------  
  72.   
  73.     public boolean equals(Object obj) {  
  74.         return ((obj != null) && obj.getClass().equals(  
  75.                 EasySSLSocketFactory.class));  
  76.     }  
  77.   
  78.     public int hashCode() {  
  79.         return EasySSLSocketFactory.class.hashCode();  
  80.     }  
  81. }  
  82.   
  83. public class EasyX509TrustManager implements X509TrustManager {  
  84.   
  85.     private X509TrustManager standardTrustManager = null;  
  86.   
  87.      
  88.     public EasyX509TrustManager(KeyStore keystore)  
  89.             throws NoSuchAlgorithmException, KeyStoreException {  
  90.         super();  
  91.         TrustManagerFactory factory = TrustManagerFactory  
  92.                .getInstance(TrustManagerFactory.getDefaultAlgorithm());  
  93.         factory.init(keystore);  
  94.         TrustManager[] trustmanagers = factory.getTrustManagers();  
  95.         if (trustmanagers.length == 0) {  
  96.             throw new NoSuchAlgorithmException("no trust manager found");  
  97.         }  
  98.         this.standardTrustManager = (X509TrustManager) trustmanagers[0];  
  99.     }  
  100.   
  101.      
  102.     public void checkClientTrusted(X509Certificate[] certificates,  
  103.             String authType) throws CertificateException {  
  104.         standardTrustManager.checkClientTrusted(certificates, authType);  
  105.     }  
  106.   
  107.      
  108.     public void checkServerTrusted(X509Certificate[] certificates,  
  109.             String authType) throws CertificateException {  
  110.         if ((certificates != null) && (certificates.length == 1)) {  
  111.             certificates[0].checkValidity();  
  112.         } else {  
  113.             standardTrustManager.checkServerTrusted(certificates, authType);  
  114.         }  
  115.     }  
  116.   
  117.      
  118.     public X509Certificate[] getAcceptedIssuers() {  
  119.         return this.standardTrustManager.getAcceptedIssuers();  
  120.     }  
  121. }  

相關文章