我有一个带有 SAN 扩展的 SSL 证书,其域名如下:
- foo.com
- bar.foo.com
- something.foo.com
我已将此证书添加到 cacerts 并尝试使用 apache http 客户端连接到 bar.foo.com
。
没想到我得到了异常:
由于 java.io.IOException 导致无法解析 SubjectAlternativeName 扩展:URI 名称必须包含方案:foo.com
将我带到 sun.security.x509.URIName
类第 112 行:
https://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/security/x509/URIName.java#l112
if (uri.getScheme() == null) {
throw new IOException("URI name must include scheme:" + name);
}
对我来说,这意味着 SAN 域必须在实际域之前有方案才能有效。看起来应该是:
事实上,当我在调试代码时替换域时,一切正常!
所以也许我得到的证书不正确?我查看了 Stackoverflow 证书,我看到了什么? SAN 域也没有方案,所以我猜这些是正确的。
当我随后使用 cURL 时,它也可以正常工作,因此证书是正确的。
我发现了以下java bug记录:
- > https://bugs.openjdk.java.net/browse/JDK-4834694
- > https://bugs.openjdk.java.net/browse/JDK-4917253
- > https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4834694
人们声称这确实是一个错误,但这些记录已有 15 年历史 - 它们来自 2003/2004。
很明显我做错了什么,因为 java 不可能有这个错误这么久
编辑: 看到我用keytool查看证书的时候出现了类似的bug:
keytool -list -keystore truststore.jks -v
(...)
#10: ObjectId: 2.5.29.17 Criticality=false
Unparseable SubjectAlternativeName extension due to
java.io.IOException: URI name must include scheme:foo.com
最佳答案
SAN 名称有多种类型。在 TLS 中,仅使用 dnsName
名称类型(ipAddress
很少使用)。 dnsName
名称类型仅包含没有任何 URI 方案的域部分。
您引用的链接 ( URIName.java ) 正在谈论另一种 SAN 名称类型,称为 uriName
,它确实必须包含协议(protocol)方案。此名称类型通常用于表示证书和 CRL 中 CRT/CRL/OCSP 资源的 URL。并且 uriName
不用于身份验证。所以你真的需要这个名字类型:DNSName.java
关于java - 主题备用名称必须具有在 java 中工作的方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54052331/