如何解决SSL证书服务器名称/我可以使用keytool添加替代名称?
为了清楚起见,这些表述可能是单独的问题,但它们都涉及同一个问题。
如何解决SSL证书服务器名称?
为什么浏览器似乎使用证书的CN域,但是Java的机制似乎只能看“主体替代名”?
是否有可能使用keytool向SSL证书添加替代名称? 如果没有,是使用openSSL而不是一个好的select?
只是一点点的背景:我需要一个主服务器使用HTTPS与几台服务器进行通信。 显然,我们不想为每个服务器购买SSL证书(可能有很多),所以我想使用自签名证书(我一直在使用keytool来生成它们)。 在操作系统中添加可信的证书之后,浏览器(IE和Chrome)高兴地将连接接受为可信。 但是,即使在将证书添加到Java的cacerts之后,Java仍然不会将该连接接受为可信,并引发以下exception:
导致:java.security.cert.CertificateException:在sun.security.util.HostnameChecker.match(HostnameChecker.java:75)处的sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:142)在com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:250)com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(X509T rustManagerImpl.java:264)。 sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien tHandshaker.java:1185)… 14更多
我发现我可以让Java信任实施我自己的HostNameVerifier的证书,我从这里复制了这个证书: com.sun.jbi.internal.security.https.DefaultHostnameVerifier只是为了testing(顺便说一句,作为parameter passing给主机名HostnameVerifier是正确的,所以我认为它应该被接受)。
我一直使用证书字段CN作为主机名(通常是IP地址)。
任何人都可以告诉我,如果我做错了什么,并指出我在正确的方向吗?
在RFC 6125中定义了如何进行主机名validation,这是相当新近的,并且将所有协议的实践推广到一般,并取代了特定于HTTPS的RFC 2818 。 (我什至不知道Java 7使用RFC 6125,这可能是太近了。)
RFC 2818(第3.1节) :
如果存在dNSNametypes的subjectAltName扩展名,则必须将其用作标识。 否则,必须使用证书的主题字段中的(最具体的)通用名称字段。 虽然通用名称的使用是现有的惯例,但已被弃用,并鼓励证书颁发机构使用dNSName。
[…]
在某些情况下,URI被指定为IP地址而不是主机名。 在这种情况下,iPAddress subjectAltName必须存在于证书中,并且必须与URI中的IP完全匹配。
从本质上讲,您所遇到的具体问题来自于您在CN中使用IP地址,而不是主机名。 一些浏览器可能会工作,因为并不是所有的工具都严格遵循这个规范,特别是因为RFC 2818中的“最具体”没有明确定义(参见RFC 6215中的讨论)。
如果您使用的是keytool
, keytool
Java 7开始, keytool
可以包含一个Subject Alternative Name(请参阅文档中的表格):您可以使用-ext san=dns:www.example.com
或-ext san=ip:10.0.0.1
。
编辑:
您可以通过更改openssl.cnf
来请求OpenSSL中的SAN(如果您不想编辑全局configuration,它将在当前目录中select副本),或者您可以使用OPENSSL_CONF
select明确的位置环境variables)。
设置以下选项(首先在括号内find适当的部分):
[req] req_extensions = v3_req [ v3_req ] subjectAltName=IP:10.0.0.1 # or subjectAltName=DNS:www.example.com
在这里使用一个环境variables(而不是修复它在configuration文件中)也是一个很好的技巧: http : //www.crsr.net/Notes/SSL.html