我正在尝试覆盖Android中的信任管理器。我希望让底层的信任管理器检查证书,但我需要确定证书是否过期。如果证书已过期,则我需要忽略它并接受该证书。某些移动设备在电池被拆卸后会重置日期,导致证书看起来已过期。即使发生这种情况,我的应用程序也必须继续运行。
我遇到的问题是,这行代码会抛出NullPointerException:
根据文档,checkServerTrusted不应该抛出NullPointerExeption。certs中有两个项。authType设置为"RSA"。如果我不实现自定义Trust Manager,将会抛出一个明确表明证书已过期的异常,因此我知道基础Trust Manager正在发挥作用。即使我将设备的日期和时间设置为证书的有效时间内,上面的checkServerTrusted行仍会生成一个异常。为什么?显然我做错了什么。这是我的自定义Trust Manager的代码以及我如何访问Url:
我遇到的问题是,这行代码会抛出NullPointerException:
origTrustmanager.checkServerTrusted(certs, authType);
根据文档,checkServerTrusted不应该抛出NullPointerExeption。certs中有两个项。authType设置为"RSA"。如果我不实现自定义Trust Manager,将会抛出一个明确表明证书已过期的异常,因此我知道基础Trust Manager正在发挥作用。即使我将设备的日期和时间设置为证书的有效时间内,上面的checkServerTrusted行仍会生成一个异常。为什么?显然我做错了什么。这是我的自定义Trust Manager的代码以及我如何访问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());
tmf.init((KeyStore) null);
会导致TMF
返回默认的系统TrustManager
。这一点在 API 文档中没有记录。我之前错误地使用了tmf.init(KeyStore.getDefaultKeyStore())
。 - DoriSSLContext.getInstance()
时,请确保使用TLSv1.2
或类似的协议。 - Alex W