2011-03-02 64 views
3

我一直在試圖註冊我的自定義TrustManger與Apache HttpClient庫。以下鏈接包含有關如何執行此操作的說明:Https Connection AndroidHttpClient和自定義TrustManager上android

不幸的是,我想使用(public SSLSocketFactory(SSLContext sslContext))的構造函數在Android版本的HttpClient中不可用。我會使用一個sslContext來初始化我的自定義TrustManager。看來Android已經取代了這個'KeyStore'。

我的問題是:(如何)我可以在Android中使用DefaultHttpClient註冊一個自定義的TrustManger? KeyStore類中是否有其他替代方法?

最終我想忽略證書檢查現在... 請考慮HttpClient庫,因爲我的整個應用程序是基於它。

+1

安裝自定義TrustManager的全部原因是爲了避免證書檢查。在看了博客,java代碼和android資源一週後,結果發現問題實際上是我連接的網站上的SSL證書的順序。因此,如果遇到證書驗證問題,請始終仔細檢查證書是否以正確的順序呈現給您,並且根證書是否存在於Android設備上! – Ivo 2011-03-04 10:34:12

+0

我仍然對這個問題的答案感興趣,我自己... – Cephron 2011-03-21 15:22:34

+0

@ivo我認爲我也有一個無序的證書問題!你做了什麼來解決這個問題?你做一些排序? – 2011-10-21 10:07:19

回答

3

解決方案是創建自己的套接字工廠。

public class NetworkSSLSocketFactory implements LayeredSocketFactory { 

    private SSLContext sslContext; 
    private SSLSocketFactory socketFactory; 
    private X509HostnameVerifier hostnameVerifier; 

    /** 
    * Creates a socket factory that will use the {@link SSLContext} and 
    * {@link X509HostnameVerifier} specified. The SSLContext provided should 
    * have the {@link NetworkTrustManager} associated with it. 
    * 
    * @param sslContext 
    * @param hostnameVerifier 
    */ 
    public NetworkSSLSocketFactory(SSLContext sslContext, 
      X509HostnameVerifier hostnameVerifier) { 
     this.sslContext = sslContext; 
     this.socketFactory = sslContext.getSocketFactory(); 
     this.hostnameVerifier = hostnameVerifier; 
    } 
} 

然後創建一個使用TrustManager的SSLContext中,然後創建一個AndroidHttpClient,並使用您的SocketFactory一個替換其HTTPS模式。

/** 
    * Return the SSLContext for use with our HttpClient or create a new Context 
    * if needed. 
    * <p> 
    * This context uses our {@link NetworkTrustManager} 
    * 
    * @return an {@link SSLContext} 
    */ 
    public SSLContext getSSLContext() { 

     if (mSSLContextInstance != null) 
      return mSSLContextInstance; 

     try { 
      mSSLContextInstance = SSLContext.getInstance("TLS"); 
      TrustManager trustManager = new NetworkTrustManager(getKeyStore()); 
      TrustManager[] tms = new TrustManager[] { trustManager }; 
      mSSLContextInstance.init(null, tms, new SecureRandom()); 
     } catch (NoSuchAlgorithmException e) { 
      Log.e(TAG, e.getMessage()); 
     } catch (KeyManagementException e) { 
      Log.e(TAG, e.getMessage()); 
     } 

     return mSSLContextInstance; 
    } 

現在客戶

/** 
* Return an HttpClient using our {@link NetworkTrustManager} and 
* {@link NetworkHostnameVerifier} 
* 
* @return an {@link HttpClient} 
*/ 
public HttpClient getHttpClient() { 

    if (mHttpClientInstance != null) 
     return mHttpClientInstance; 

    SSLContext sslContext = getSSLContext(); 

    // Now create our socket factory using our context. 
    X509HostnameVerifier hostnameVerifier = new NetworkHostnameVerifier(); 
    NetworkSSLSocketFactory sslSocketFactory = new NetworkSSLSocketFactory(
      sslContext, hostnameVerifier); 

    // Some services (like the KSOAP client) use the HttpsURLConnection 
    // class 
    // to establish SSL connections. 
    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); 
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext 
      .getSocketFactory()); 

    // Generate the Client for the Server 
    mHttpClientInstance = AndroidHttpClient.newInstance(getAgent(), 
      mContext); 

    // Get the registry from the AndroidHttpClient and change the 
    // HTTPS scheme to use our socket factory. This way we can 
    // control the certificate authority and trust system. 
    SchemeRegistry schemeRegistry = mHttpClientInstance 
      .getConnectionManager().getSchemeRegistry(); 

    schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); 

    return mHttpClientInstance; 
} 

如果你不知道如何創建一個新的密鑰庫,在這裏你去:

/** 
    * Get the current KeyStore or if not yet created, create a new one. This 
    * will <b>NOT</b> load the KeyStore file identified by 
    * {@link #KEYSTORE_NAME}. To load the KeyStore file, use the function 
    * {@link #loadKeyStore()} which will automatically call this function (so 
    * you don't need to). 
    * <p> 
    * 
    * @return a {@link KeyStore} 
    */ 
    public KeyStore getKeyStore() { 

     if (mKeyStore != null) 
      return mKeyStore; 

     try { 
      String defaultType = KeyStore.getDefaultType(); 
      mKeyStore = KeyStore.getInstance(defaultType); 
      mKeyStore.load(null, null); 
     } catch (Exception e) { 
      Log.w(TAG, e.getMessage()); 
     } 

     return mKeyStore; 
    } 

上述解決方案是一個解決方案的開始它允許您創建一個TrustManager,它將驗證「System KeyStore」以及您擁有的「Private KeyStore」(兩個密鑰庫)的證書。然後,您不需要嘗試將證書添加到System KeyStore。您可以在getFilesDir()文件夾中創建自己的KeyStore。

我仍然沒有完成從HttpResult = HttpClient.execute(HttpPost)陷阱證書的邏輯;方法,但我現在正在積極撰寫此文。如果你需要幫助,我現在可以和你一起工作。

如果有人知道如何從HttpRequestBase對象中的SSLSocekt陷阱/獲取證書,請告訴我。我試圖追捕這件事。

+0

從SSLSocket獲取認證方面取得任何成功? – Nativ 2014-06-26 08:46:45

0

實際上,該方法存在但隱藏。它由getHttpSocketFactory()在內部使用。我通過簡單地使用反射來實現它。不是安全的,但可以用於開發目的。

Class<org.apache.http.conn.ssl.SSLSocketFactory> c = org.apache.http.conn.ssl.SSLSocketFactory.class; 
Constructor<org.apache.http.conn.ssl.SSLSocketFactory> ctor = c.getConstructor(javax.net.ssl.SSLSocketFactory.class); 
SSLSocketFactory ssf = ctor.newInstance(SSLCertificateSocketFactory.getInsecure(getSSLHandshakeTimeout(), null));