如何解析SSL证书服务器名称/我可以使用keytool添加替代名称吗?



为了清楚起见,这些问题可能被表述为单独的问题,但它们都与同一个问题有关。

如何解析SSL证书服务器名称?

为什么浏览器似乎使用证书的CN字段,但Java的机制似乎只看"主题替代名称"?

是否可以使用keytool为SSL证书添加替代名称?如果不是,使用openSSL是一个好的选择吗??

只是一点背景:我需要得到一个主服务器使用HTTPS与几个服务器通信。显然,我们不想为每台服务器购买SSL证书(可能有很多),所以我想使用自签名证书(我一直使用keytool来生成它们)。当我在操作系统中添加了受信任的证书后,浏览器(IE和Chrome)很高兴地接受了受信任的连接。但是,即使将证书添加到Java的cacerts中,Java仍然不会将连接作为受信任的连接接受,并抛出以下异常:

由:java.security.cert.CertificateException: No subject alternative names引起现在sun.security.util.HostnameChecker.matchIP (HostnameChecker.java: 142)sun.security.util.HostnameChecker.match (HostnameChecker.java: 75)com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity (X509TrustManagerImpl.java: 264)com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted (X509TrustManagerImpl.java: 250)com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate (ClientHandshaker.java: 1185)…14个

我发现我可以使Java信任实现我自己的HostNameVerifier的证书,我从这里复制:com.sun.jbi.internal.security.https.DefaultHostnameVerifier只是为了测试(顺便说一下,作为参数传递给HostNameVerifier的主机名是正确的,所以我认为它应该被接受)。

我一直使用证书字段CN作为主机名(通常是IP地址)。

谁能告诉我,如果我做错了什么,并指出我在正确的方向?

主机名验证应该如何完成在RFC 6125中定义,它是相当新的,并将实践推广到所有协议,并取代了RFC 2818,这是特定于HTTPS的。(我甚至不确定Java 7是否使用RFC 6125,这可能太新了。)

来自RFC 2818 (Section 3.1):

如果存在dNSName类型的subjectAltName扩展,则必须被用作标识。否则,使用(最具体的)Common Name必须使用证书的Subject字段中的字段。虽然通用名称的使用是现有的做法,它是不赞成和建议证书颁发机构使用dNSName。

[…]

在某些情况下,URI被指定为IP地址而不是主机名。在这种情况下,iPAddress subjectAltName必须存在

本质上,您遇到的具体问题来自于您使用的是CN中的IP地址,而不是主机名。某些浏览器可能会正常工作,因为并非所有工具都严格遵循此规范,特别是因为"最规范"。在RFC 2818中没有明确定义(参见RFC 6215中的讨论)。

如果您使用的是keytool,从Java 7开始,keytool有一个包含主题替代名称的选项(参见-ext文档中的表):您可以使用-ext san=dns:www.example.com-ext san=ip:10.0.0.1

编辑:

您可以通过更改openssl.cnf在OpenSSL中请求SAN(如果您不想编辑全局配置,它将选择当前目录中的副本,据我所知,或者您可以使用OPENSSL_CONF环境变量选择显式位置)。

设置以下选项(先在括号内找到相应的部分):

[req]
req_extensions = v3_req
[ v3_req ]
subjectAltName=IP:10.0.0.1
# or subjectAltName=DNS:www.example.com

还有一个很好的技巧可以使用环境变量(而不是在配置文件中修复它):http://www.crsr.net/Notes/SSL.html

最新更新