如何解析 SSL 证书服务器名称/是否可以使用 keytool 添加备用名称?

2022-08-31 12:32:45

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

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

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

是否可以使用 keytool 向 SSL 证书添加备用名称?如果没有,使用openSSL是一个不错的选择吗?

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

由以下原因引起: java.security.cert.CertificateException: 在 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) atcom.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien tHandshaker.java:1185) ...另外 14

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

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

任何人都可以告诉我,如果我做错了什么,并指出我正确的方向?


答案 1

如何进行主机名验证是在RFC 6125中定义的,RFC 6125是最近才开始的,它将这种做法推广到所有协议,并取代了特定于HTTPS的RFC 2818。(我甚至不确定Java 7是否使用RFC 6125,这可能太新了。

来自 RFC 2818(第 3.1 节):

如果存在 dNSName 类型的主题AltName扩展,则必须将其用作标识。否则,必须使用证书的“使用者”字段中的(最具体的)公用名字段。尽管使用公用名是现有做法,但它已弃用,并鼓励证书颁发机构改用 dNSName。

[...]

在某些情况下,URI 被指定为 IP 地址而不是主机名。在这种情况下,iPAddress 使用者别名必须存在于证书中,并且必须与 URI 中的 IP 完全匹配。

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

如果您使用的是 Java 7,则 keytool 可以选择包含主题备用名称(请参阅文档中的表:您可以使用 或 。keytool-ext-ext san=dns:www.example.com-ext san=ip:10.0.0.1

编辑:

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


答案 2