【问题标题】:Subject Alternative Name must have scheme to be working in java?主题备用名称必须有方案才能在 java 中工作?
【发布时间】:2019-05-31 19:34:56
【问题描述】:

我有一个带有 SAN 扩展的 SSL 证书,其域如下:

  • foo.com
  • bar.foo.com
  • something.foo.com

我已将此证书添加到 cacerts 并尝试使用 apache http 客户端连接到 bar.foo.com。 没想到我得到了异常:

Unparseable SubjectAlternativeName extension due to java.io.IOException: URI name must include scheme: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记录:

人们声称这确实是一个错误,但这些记录已有 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

【问题讨论】:

    标签: java ssl ssl-certificate x509certificate x509


    【解决方案1】:

    有几种类型的 SAN 名称。在 TLS 中,仅使用 dnsName 名称类型(ipAddress 很少使用)。 dnsName 名称类型仅包含没有任何 URI 方案的域部分。

    您引用的链接 (URIName.java) 正在谈论另一种 SAN 名称类型,称为 uriName,它确实必须包含协议方案。此名称类型通常用于表示证书和 CRL 中 CRT/CRL/OCSP 资源的 URL。并且uriName 不用于身份验证。所以你真的需要这个名字类型:DNSName.java

    【讨论】:

    • 我认为不是这样。我已经编辑了我的问题并添加了 keytool 也失败的信息
    • 好的,你能提供一个 SAN 扩展的转储吗?我根据您在最初问题中提供的内容发布了我的答案。我可以假设您的 SAN 格式不正确。 SAN 扩展的文本转储会很有帮助。
    • 我不得不更改一些字母,但基本上是这样的 0P..q-fth-sct.xqlav-fth.com..sct.xqlav.com..q-fth-sct.xqlav-fth.com..sct.xqlav.com 和我使用 apache http 调用的域是 sct.xqlav.com 并且它失败了,除了我提到的例外 - 与 keytool 相同抛出
    • 根据我的 ISP 的 DNS 和 Google (8.8.8.8) Cloudfront (1.1.1.1) Level3 (4.2.2.1),sct.xqlav.com 不存在(nxdomain)。如果您拥有(或获得)OpenSSL,openssl s_client -connect host:443 -servername host 将显示您的 PEM 格式证书(破折号-BEGIN 行、几行 base64 行、破折号-END 行);将其添加到您的 Q 和/或执行 openssl x509 -noout -text <certPEMfile
    • @dave_thompson_085 是的,此域不公开。这只是一个例子
    【解决方案2】:

    我知道这是一个旧的,但也许它会对某人有所帮助。

    @bodziec - 我不知道您是如何生成证书的,但以下内容对我有用:

    1. 这将生成一个证书并将其存储在 mykeystore.p12 中:

      keytool -keystore mykeystore.p12 -storepass changeit -storetype PKCS12 -alias certAlias -validity 1234 -genkey -keyalg RSA -ext SAN=DNS:foo.com,DNS:bar.foo.com,DNS:something.foo。 com

    2. 验证证书是使用您的 SAN 信息创建的 希望你能跑:

      keytool -list -keystore mykeystore.p12 -storepass changeit

      寻找

    SubjectAlternativeName [
      DNSName: foo.com
      DNSName: bar.foo.com
      DNSName: something.foo.com
    ]
    
    1. 要签署证书,您需要创建一个证书签名 请求:

      keytool -alias certAlias -certreq -keystore client.keystore.jks -file my_cert_sign_req.csr -storepass changeit

    2. 使用您的 CA 签署证书。这将需要为 openssl 创建扩展配置文件的额外步骤:

    • 创建一个新文件:ext.conf 粘贴以下内容并更改 req_distinguished_name 和 keyUsage。
    [ req ]
    default_bits       = 4096
    distinguished_name = req_distinguished_name
    x509_extensions    = req_ext
    
    [ req_distinguished_name ]
    countryName                 = Country Name (2 letter code)
    countryName_default         = XX
    stateOrProvinceName         = State or Province Name (full name)
    stateOrProvinceName_default = default_great_place
    localityName                = Locality Name (eg, city)
    localityName_default        = default_somecity
    organizationName            = Organization Name (eg, company)
    organizationName_default    = your_org
    commonName                  = Common Name (e.g. server FQDN or YOUR name)
    commonName_max              = 64
    commonName_default          = default_common-name
    
    [req_ext]
    keyUsage = digitalSignature, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign
    extendedKeyUsage = serverAuth,clientAuth, timeStamping
    subjectAltName = @alt_names
    
    [alt_names]
    DNS.1   = foo.com
    DNS.2   = bar.foo.com
    DNS.3   = something.foo.com
    
    • 确保您拥有 CA 证书和密钥,然后运行:

    openssl x509 -req -CA cacert.pem -CAkey cakey.pem -in my_cert_sign_req.csr -out my_cert_sign_req.signed -days 1234 -CAcreateserial -extfile ../ext.conf -extensions 'req_ext'

    1. 将 cacert 和签名证书导入您的密钥库(确保将签名证书的别名设置为与在步骤 1 中创建证书时使用的原始别名相同)

    keytool -import -keystore server.keystore.jks -storepass k1test1 -alias caroot -file cacert.pem

    keytool -import -keystore server.keystore.jks -storepass k1test1 -alias certAlias -file my_cert_sign_req.signed

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-21
      • 2017-12-08
      • 2020-06-23
      • 1970-01-01
      • 2021-02-24
      • 2021-09-08
      • 2023-03-31
      相关资源
      最近更新 更多