覆盖Android中的SSL信任管理器



我正在尝试覆盖Android中的信任管理器。我想让基础信任管理器检查证书,但我需要确定证书是否过期。如果证书过期,我需要忽略它并接受证书。如果卸下电池,某些移动设备会将日期重置为旧日期,从而使证书看起来像过期了一样。即使发生这种情况,我的应用程序也必须继续运行。

我遇到的问题是,这行代码抛出一个NullPointerException:

origTrustmanager.checkServerTrusted(certs, authType);

根据文档,checkServerTrusted永远不应该抛出NullPointerExeption。certs中有两项。authType设置为"RSA"。如果我不实现自定义的信任管理器,则会抛出一个异常,该异常清楚地表明证书已过期,因此我知道底层的信任管理程序正在完成它的工作。即使我将设备上的日期和时间设置为在证书的有效时间内,上面的checkServerTrusted行也会生成异常。为什么?很明显我做错了什么。这是我的自定义信任管理器的代码,以及我如何访问Url:

class SSLTrustManager
{
private X509TrustManager origTrustmanager;
public SSLTrustManager()
{
try
{
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
TrustManager[] trustManagers = tmf.getTrustManagers();
this.origTrustmanager = (X509TrustManager) trustManagers[0];
}
catch (Exception ex)
{
}
}
public javax.net.ssl.SSLSocketFactory GetSocketFactory()
{
try
{
TrustManager[] wrappedTrustManagers = new TrustManager[] {
new X509TrustManager()
{
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return origTrustmanager.getAcceptedIssuers();
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
{
try
{
origTrustmanager.checkClientTrusted(certs, authType);
}
catch (CertificateException e)
{
}
}
public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException
{
try
{
origTrustmanager.checkServerTrusted(certs, authType);
}
catch(Exception ex)
{
}
}
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, wrappedTrustManagers, new java.security.SecureRandom());
javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
return sslSocketFactory;
}
catch (Exception ex)
{
return null;
}
}
}    

访问url的代码:

SSLTrustManager sslTrustManager = new SSLTrustManager();
HttpsURLConnection.setDefaultSSLSocketFactory(sslTrustManager.GetSocketFactory());
URL siteUrl = new URL(url);
HttpsURLConnection conn = (HttpsURLConnection) siteUrl.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());

如果您从未初始化origTrustmanager实例变量,它将具有默认值null,这确实会在您尝试使用它时导致NPE。

我刚刚编辑了我之前对此的回答,以显示TrustManager初始化的示例。(我还没有在Android上尝试过,但它在纯Java中运行良好。)

小心别抓得太多。在这里,您将在您的信任管理器中捕获CertificateExceptionException:这就像什么都没有一样好,因为这些方法旨在抛出这些异常。如果要忽略过期日期,请确保只捕获CertificateExpiredException

请注意,这只是一个技巧,它依赖于这样一个事实,即在实践中,证书验证是在常规信任验证(至少在OpenJDK实现中)之后完成的。据我所知,规范中没有任何规定在之后验证证书过期。它是在对信任元素进行其他验证之前完成的,如果您忽略了该异常,您可以让更多的证书通过。

使用此代码这对我有效

TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
}
};
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { tm }, null);
} catch (Exception e1) {
e1.printStackTrace();
return;
}
AsyncSSLSocketMiddleware sslMiddleWare = Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware();
sslMiddleWare.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
sslMiddleWare.setSSLContext(sslContext);
Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware().setTrustManagers(trustAllCerts);
Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware().setSSLContext(sslContext);
Ion.with(context).load("POST", serverUrl)
.setHeader("Content-Type", "application/json")
.setHeader("Accept", "application/json")
.setLogging("ION_LOGGING", Log.VERBOSE).setJsonObjectBody(json)

相关内容

最新更新