Android的 - 除了正常的SSL证书验证自签名证书 [英] Android - validating self-signed certificates in addition to normal SSL certificates

查看:243
本文介绍了Android的 - 除了正常的SSL证书验证自签名证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Android应用程序,通过SSL调用Web服务。在生产中,我们将有一个由可信CA签名的正常SSL证书但是,我们需要能够支持自签名的证书(由我们自己的CA签名)。

I have an Android application that calls web services over SSL. In production we will have normal SSL certificates that are signed by a trusted CA. However, we need to be able to support self-signed certificates (signed by our own CA).

我已经成功地实施了接受自签名证书的建议的解决方案,但是这并不会因人在中间攻击的危险工作。然后,我创建了一个用于验证证书链实际上是由我们的CA签署的的TrustManager。

I have successfully implemented the suggested solution of accepting self-signed certificates but this will not work due to the risk of man in the middle attacks. I then created a trustmanager that validates that the certificate chain was in fact signed by our CA.

问题是我必须绕过正常的SSL验证 - 应用程序将现在只能在已安装我们的自签名证书的一个服务器的说话

The problem is I have to bypass the normal SSL validation - the application will now only speak to a server that has one of our self-signed certificates installed.

我有点失落,我已经广泛用Google搜索,但无法找到任何东西。我希望能找到的编程方式将我们的CA到设备上的信任存储的方式,这将是处理这个问题的侵入性最小的方式。

I am a bit lost, I've googled extensively but can't find anything. I was hoping to find a way of programmatically adding our CA to the trust store on the device as this would be the least intrusive way of dealing with the issue.

我想达到的目标:
正常的SSL证书1.完全标准的支持。
2.由我们自己的CA签署的自签名证书的额外支持。

What I want to achieve: 1. Full standard support for normal SSL certificates. 2. Additional support for self-signed certificates signed by our own CA.

任何意见?

推荐答案

您还没有发布任何code,所以我不能确定你实际做。不过,我会假设你正在建立一个的SSLContext 只用你自定义的 X509TrustManager 子类。这很好,但你可以做的是有你的自定义信任管理器实现的的链内置的信任管理器。为此,您可以设置您的信任管理器;这样的事情应该工作:

You haven't posted any code, so I can't be sure what you actually did. However, I'll assume that you're setting up a SSLContext using only your custom X509TrustManager subclass. That's fine, but what you can do is have your custom trust manager implementation also chain to the built-in trust managers. You can do this while setting up your trust manager; something like this should work:

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 为你做,否则。

So now your custom trust manager has a list of all the built-in trust managers. In your override of checkServerTrusted(), you'll want to loop through the built-in trust managers and check each one by calling checkServerTrusted() on each one in turn. If none of them trust the certificate, you can apply your own cert checking. If that passes, you can return normally. If not, just throw a CertificateException as you'd otherwise do.

编辑:添加低于约做这样的事情主机名验证

Adding the below about doing things like host name verification.

您还可以验证证书中的主机名匹配你希望它是什么。您将要在有效的主机名通过在构造函数为您定制信任管理器,并在类藏匿它。你的 checkServerTrusted()方法将获得通过 X509证书的数组。许多枷锁将包含只是一个单一的证书,但其他人将有好几种,根据CA签署怎样的证书。无论哪种方式,数组中的第一个证书应该是要比较的您的证书。

You can also verify that the hostname in the certificate matches what you expect it to be. You'll want to pass in the valid hostname in your constructor for your custom trust manager and stash it in the class. Your checkServerTrusted() method will get passed an array of X509Certificate. Many "chains" will consist of just a single cert, but others will have several, depending on how the cA signed your cert. Either way, the first cert in the array should be "your" cert that you want to compare against.

在您使用的信任管理器检查基本证书的有效性,你会再想要做这样的事情:

After you check for basic cert validity using the trust managers, you'll then want to do something like this:

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 =加州,L =山景,O =谷歌公司,CN = www.google.com 。你想要的CN(通用名称),为您的主机比较值。需要注意的是,如果你有一个通配符证书,它会被列为类似 *。example.com ,所以你需要做的不是简单的等于多在比赛这种情况下。

The implementation of parseDN() is left up to you. subjectDN.getName() will return a comma-separated list of key-value pairs (separated by =), something like C=US,ST=California,L=Mountain View,O=Google Inc,CN=www.google.com. You want the CN ("Common Name") value for your hostname comparison. Note that if you have a wildcard cert, it'll be listed as something like *.example.com, so you'll need to do more than a simple equals match in that case.

这篇关于Android的 - 除了正常的SSL证书验证自签名证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆