我有一个Android应用程序,通过SSL调用Web服务。 在生产中,我们将有一个由可信CA签名的正常的SSL证书 然而,我们需要能够支持自签名证书(由我们自己的CA签名)。
我已经成功地实现接受自签名证书的建议的解决方案,但是这并不会因人在中间攻击的危险工作。 然后,我创建了一个验证证书链实际上是由我们的CA签名的的TrustManager
问题是我必须绕过正常的SSL验证 - 应用程序将现在只能在已安装我们的自签名证书的一个服务器的说话。
我有点失落,我已经广泛地用Google搜索,但无法找到任何东西。 我希望能找到的编程方式将我们的CA的信任存储设备上,因为这将是处理这一问题的侵入性最小的方式方法。
我想达到什么:正常的SSL证书1.完全标准的支持。 2.由我们自己的CA签名的自签名证书的额外支持
有什么建议?
您还没有发布任何代码,所以我不能确定你真正做到了。 不过,我会假设你正在设置SSLContext
只用你的自定义X509TrustManager
子类。 这很好,但你可以做的是有你的自定义信任管理器实现也链条内置的信任管理器。 为此,您可以设置您的信任管理器; 这样的事情应该工作:
private List<X509TrustManager> trustManagers = new ArrayList<X509TrustManager>();
public MyCustomTrustManager() {
TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmFactory.init((KeyStore)null);
for (TrustManager tm : tmFactory.getTrustManagers()) {
if (tm instanceof X509TrustManager)
trustManagers.add((X509TrustManager)tm);
}
}
所以,现在您的自定义信任管理器拥有所有内置的信任管理器的列表。 在您的覆盖checkServerTrusted()
你要通过内置的信任管理循环,并通过调用检查每一个checkServerTrusted()
上的每一个设置。 如果没有他们的信任证书,您可以使用自己的证书检查。 如果通过,就可以正常返回。 如果没有,只是抛出一个CertificateException
作为否则你做的。
编辑:添加低于约做这样的事情主机名验证。
您也可以验证证书中的主机名匹配你希望它是什么。 您将要在有效的主机名通过在构造函数为您定制信任管理器和类藏匿它。 你checkServerTrusted()
方法会传递数组X509Certificate
。 许多“链”将包含只是一个单一的证书,但其他人将有好几个,这取决于CA如何签署的证书。 无论哪种方式,阵列中的第一个证书应该是要比较对“你”的证书。
当您使用的信任管理器检查基本证书的有效性,你会再想要做这样的事情:
Principal subjectDN = chain[0].getSubjectDN();
String subjectCN = parseDN(subjectDN.getName(), "CN");
if (this.allowedCN.equals(subjectCN)) {
// certificate is good
}
实施parseDN()
留给了你。 subjectDN.getName()
将返回一个逗号分隔的键值对列表(分立=
),像C=US,ST=California,L=Mountain View,O=Google Inc,CN=www.google.com
。 你想要CN(“通用名称”)为您的主机名比较值。 需要注意的是,如果你有一个通配符证书,它会被列为像*.example.com
,所以你需要做更多的不是简单的在这种情况下等于匹配。
文章来源: Android - validating self-signed certificates in addition to normal SSL certificates