如何在使用SSLEngine进行x509 SSL / TLS握手后验证服务器(对等方)名称?

时间:2012-07-13 10:29:48

标签: java jsse sslengine

我正在使用SSLEngineNIO进行非阻止TLS通信。

引擎运行正常,可以验证CA信任,即服务器证书的有效期。

但我缺少的是验证证书主题名称与我正在连接的服务器名称相匹配。

考虑所有SSL扩展程序(如subject alternative names等),实施它的最佳方法是什么?

我只是尝试检查主题名称,但即使使用google.nl它也不起作用,证书中的主题为google.com,而google.nl只能在{{1}}中找到替代名称扩展。

1 个答案:

答案 0 :(得分:0)

再次回答我自己的问题......

到目前为止,我能够接受这个。它仅限于Sun JSSE实现。不确定这是否是一个完整的解决方案。

void checkServerName(String serverName, SSLSession session) throws IOException {
    String name;
    boolean matches = false;
    X509CertImpl cert = (X509CertImpl)session.getPeerCertificates()[0];
    SubjectAlternativeNameExtension altNames = cert.getSubjectAlternativeNameExtension();
    if (altNames != null) {
        GeneralNames names = (GeneralNames) altNames.get(SubjectAlternativeNameExtension.SUBJECT_NAME);
        for (GeneralName genName : names.names()) {
            switch (genName.getType()) {
                case GeneralNameInterface.NAME_DNS:
                    name = ((DNSName)genName.getName()).getName();
                    break;
                case GeneralNameInterface.NAME_IP:
                    name = ((IPAddressName)genName.getName()).getName();
                    break;
                case GeneralNameInterface.NAME_RFC822:
                    name = ((RFC822Name)genName.getName()).getName();
                    break;
                case GeneralNameInterface.NAME_ANY:
                    DerValue derValue = new DerValue(((OtherName)genName.getName()).getNameValue()); 
                    name = derValue.getData().getUTF8String();
                    break;
                default:
                    continue;
            }
            if (name.startsWith("*"))
                matches |= serverName.endsWith(name.substring(1).toLowerCase());
            else
                matches |= serverName.equals(name.toLowerCase());
            if (matches)
                break;
        }
    }
    name = ((X500Name)cert.getSubjectDN()).getCommonName();
    if (!matches)
        matches = serverName.equals(name.toLowerCase());
    if (!matches)
        throw new SSLPeerUnverifiedException("server name mismatch, certificate issued to: " + name);
}