【问题标题】:How are SSL certificate server names resolved/Can I add alternative names using keytool?SSL 证书服务器名称如何解析/我可以使用 keytool 添加替代名称吗?
【发布时间】:2012-01-16 14:28:41
【问题描述】:

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

如何解析 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) 在 sun.security.util.HostnameChecker.match(HostnameChecker.java:75) 在 com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(X509T rustManagerImpl.java:264) 在 com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted( X509TrustManagerImpl.java:250) 在 com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(客户端 tHandshaker.java:1185) ... 14 更多

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

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

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

【问题讨论】:

标签: java security ssl


【解决方案1】:

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

来自RFC 2818 (Section 3.1)

如果存在 dNSName 类型的 subjectAltName 扩展,则必须 用作身份。否则,(最具体的)通用名称 必须使用证书的主题字段中的字段。虽然 通用名称的使用是现有的做法,它已被弃用并且 鼓励证书颁发机构改用 dNSName。

[...]

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

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

如果您使用 keytoolas of 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

【讨论】:

  • 这正是我需要知道的......但是,Java 6 似乎没有这个 -ext 选项。我将尝试将我的 VM 更改为 Java 7 并进行测试。
  • 请注意,您可以在不同的机器上使用 Java 7 中的 keytool 并在以后复制密钥库(您不必运行 Java 7)。或者,我已经编辑了使用 OpenSSL 执行此操作的答案。话虽如此,从长远来看,您可能会发现使用主机名而不是 IP 地址更灵活(无论如何,使用 SAN 是个好主意)。
  • -ext 选项在 Java6 中不起作用!我将切换到 Java 7,看看我是否可以仅使用 keytool 来做到这一点...非常感谢您的回答..(PS。一旦我测试过,我会接受答案)
  • 在这种情况下,您在证书中使用 IP 地址这一事实将成为更大的问题。可能会更改 IP 地址是 DNS 的用途。通过使用动态 DNS 服务并使用具有该名称(或任何可以解析为该动态名称的 CNAME)的证书,您更有可能解决您的问题。
  • 只是为了增加一些混乱,许多浏览器会接受像 DNS:10.0.0.1 这样的 SAN,但不接受 IP:10.0.0.1,但好消息是你可以同时拥有两者
猜你喜欢
  • 2017-05-14
  • 2012-02-03
  • 2013-10-09
  • 1970-01-01
  • 2019-04-04
  • 2017-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多