据我所知,在大多数情况下,此异常表明证书所有者CN(公用名)与URL中的主机名不匹配。但是在我的情况下,他们匹配,但例外仍然提出..
远程服务器证书层次结构是:
CN=sms.main.ru
CN=client.sms.main.ru
我的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
答案 0 :(得分:3)
最后,我所要做的就是:
禁用主机名验证:
// 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);
确保使用默认的cacerts
文件,因为在研究时我试图禁用ssl证书验证并使用可在SO上的大量线程中找到的代码(实现自己的{{ 1}}),即Java: Overriding function to disable SSL certificate check。此代码替换了我需要的默认X509TrustManager
。所以我不得不删除所有这些内容并使用代码来禁用主机名验证。
我离开了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)
使用HttpsURLConnection
和SSLSocketFactory
执行SSL握手。