为什么我得到“找不到名称匹配”CertificateException?

时间:2014-11-07 01:59:35

标签: java apache tomcat https solaris

据我所知,在大多数情况下,此异常表明证书所有者CN(公用名)与URL中的主机名不匹配。但是在我的情况下,他们匹配,但例外仍然提出..

远程服务器证书层次结构是:

  1. 使用CN=sms.main.ru
  2. 的自签名证书
  3. 使用第一个和CN=client.sms.main.ru
  4. 签署的证书

    我的java客户端是在apache-tomcat 6下启动的,并尝试连接到https://client.sms.main.ru/并抛出以下异常:

    No name matching client.sms.main.ru found
    

    这两个证书都通过$JAVA_HOME/jre/lib/security/cacerts添加到$JAVA_HOME/bin/keytool,如{+ 3}}所示,在unixtippse的回答中。

    Java代码非常简单:

    URL url = new URL(strurl);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setRequestMethod("GET");
    con.setRequestProperty("Connection", "close");
    con.setDoOutput(true);
    con.connect();
    

    我错过了什么?


    有趣的是,当我尝试使用Windows PC上的浏览器访问此URL时,它表示该证书不受信任,我将其添加到浏览器例外列表中并且工作正常。所以看起来我错误地将这些证书添加到cacerts,因此java无法使用它们。但我可以通过别名或CN轻松找到它们:

    $JAVA_HOME/bin/keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts | less
    

3 个答案:

答案 0 :(得分:3)

最后,我所要做的就是:

  1. 禁用主机名验证:

    // Create all-trusting host name verifier
    HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };
    // Install the all-trusting host verifier
    HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    
  2. 确保使用默认的cacerts文件,因为在研究时我试图禁用ssl证书验证并使用可在SO上的大量线程中找到的代码(实现自己的{{ 1}}),即Java: Overriding function to disable SSL certificate check。此代码替换了我需要的默认X509TrustManager。所以我不得不删除所有这些内容并使用代码来禁用主机名验证。

  3. 我离开了SSLSocketFactory。无需将其替换为HttpURLConnection

    如果我设法避免禁用主机名验证,那肯定会好得多,但我不能。证书可能有问题..

答案 1 :(得分:1)

以前这是我在tomcat上信任自签名证书的方式

static private SSLSocketFactory newSslSocketFactory(String jksFile, char[] password) {

    try {
        KeyStore trusted = KeyStore.getInstance("JKS");
        InputStream in = StaticHttpsClient.class.getClassLoader().getResourceAsStream(jksFile);
        try {
            trusted.load(in, password);
        } finally {
            in.close();
        }

        SSLSocketFactory socketFactory = new SSLSocketFactory(trusted);
        HostnameVerifier hostnameVerifier =    org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
        socketFactory .setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
        return socketFactory;
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

static protected ClientConnectionManager createClientConnectionManager(String jksFile, char[] password) {
    SchemeRegistry registry = new SchemeRegistry();

    registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
    registry.register(new Scheme("https", 443, newSslSocketFactory(jksFile, password)));
    return new SingleClientConnManager(registry);

}   

答案 2 :(得分:-4)

使用HttpsURLConnectionSSLSocketFactory执行SSL握手。