这些问题可能用分开的方式更加清晰,但它们都涉及同一个问题。
SSL证书服务器名称是如何解析的?
为什么浏览器似乎使用证书的CN字段,而Java的机制似乎只查看“主题备用名称”?
是否可以使用keytool添加SSL证书的替代名称?如果不行,使用openSSL是否是一个好的选择?
背景:我需要让一个主服务器使用HTTPS与多个服务器通信。很明显,我们不想为每台服务器(可能有很多)购买SSL证书,所以我想使用自签名证书(我一直在使用keytool生成它们)。在将证书添加到操作系统中作为受信任的证书之后,浏览器(IE和Chrome)高兴地接受连接并将其视为可信。然而,即使在将证书添加到Java的cacerts之后,Java仍然不会接受连接并抛出以下异常:
Caused by: java.security.cert.CertificateException: No subject alternative names present at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:142) at sun.security.util.HostnameChecker.match(HostnameChecker.java:75) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(X509T rustManagerImpl.java:264) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted( X509TrustManagerImpl.java:250) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien tHandshaker.java:1185) ... 14 more
我发现,使用自己实现的HostNameVerifier可以让Java信任证书,我从这里复制了HostNameVerifier:com.sun.jbi.internal.security.https.DefaultHostnameVerifier 只是为了测试(顺便说一句,传递给HostNameVerifier的主机名是正确的,所以我认为它应该被接受)。
我一直将证书字段CN用作主机名(通常是IP地址)。
请问我是否做错了什么,并指出正确的方向?