我一直在尝试使用apache HttpClient库注册我的自定义TrustManger。以下链接包含有关如何执行此操作的说明:Https Connection Android
不幸的是,我想使用的构造函数(公共SSLSocketFactory(SSLContext sslContext))在Android版本的HttpClient中不可用。我会使用sslContext来初始化我的自定义TrustManager。似乎Android已经用'KeyStore'取代了它。
我的问题是:如何在Android中使用DefaultHttpClient注册自定义TrustManger? KeyStore类中是否有替代方法?
最终我想忽略证书检查... 请仅考虑HttpClient库,因为我的整个应用都基于它。
答案 0 :(得分: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并将其https架构替换为使用您的SocketFactory的架构。
/**
* 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,它将验证证书到&#34; System KeyStore&#34;以及你拥有的私人钥匙商店&#34; (两个关键商店)。然后,您不需要尝试将证书添加到System KeyStore。您可以在getFilesDir()文件夹中创建自己的KeyStore。
我仍然没有完成从HttpResult = HttpClient.execute(HttpPost)中捕获证书的逻辑;方法,但我现在正在积极地写这个。如果您需要帮助,我现在可以和您一起工作。
如果有人知道如何在HttpRequestBase对象中捕获/获取SSLSocekt的证书,请告诉我。我试图追捕它。
答案 1 :(得分: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));