使用HttpUrlConnection在没有中间证书的情况下建立SSL连接

Joe*_*lla 5 java ssl ssl-certificate

是否可以使用SSL连接到站点,其中客户端只有根证书,但服务器同时具有根证书和中间证书?

我试图使用HttpUrlConnection与包含我的根的TrustManager连接,我得到通常的握手错误:

javax.net.ssl.SSLHandshakeException:
  sun.security.validator.ValidatorException:
  Certificate chaining error
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379)
Run Code Online (Sandbox Code Playgroud)

我知道一般的解决方案是安装中间证书,但我想避免不断获得供应商X的新中间证书.

我熟悉使用接受所有内容的TrustManager,但这不是一个选项.

sle*_*ske 13

是否可以使用SSL连接到站点,其中客户端只有根证书,但服务器同时具有根证书和中间证书?

这不仅是可能的,而且实际上是TLS工作的常用方式:

  1. TLS客户端仅具有根证书.Java - 至少是Oracle JVM - 从lib/security/cacertsJRE安装目录中读取它们.浏览器要么拥有自己的内部列表,要么使用操作系统提供的列表.
  2. 当客户端启动TLS连接时,服务器应该发送回自己的证书以及任何中间证书(如果它使用任何证书) - 此列表称为证书链.对于当前版本1.2.TLS的这一点在RFC 5246的7.4.2节中规定(参见下面的报价).
  3. 客户端接收这些证书,并验证签名,从服务器证书到其知道的根证书之一.这称为证书路径构建,并在RFC 4158中进行了描述.
  4. 如果客户端可以构建有效的证书路径,则继续进行连接设置.否则,它会中止错误消息 - 类似于可怕的"此连接不受信任"错误.

我知道一般的解决方案是安装中间证书

不,实际上不是,如上所述,服务器自动发送所有中间证书.

然而:

服务器上一个相当常见的配置错误是不在服务器上安装所有中间证书.在这种情况下,服务器将在连接设置期间发送不完整的证书链.然后客户端将无法构建有效的证书路径,并将中止连接.

一些并发症可能使这个问题难以诊断:

  • 某些客户端(特别是浏览器)仍可以成功连接,因为它们具有缺少的中间证书的缓存副本.
  • 大多数客户端没有或无法区分缺少的中间证书(在服务器发送的链中),缺少的根证书(在他们自己的列表中)和自签名证书,所以你必须弄清楚自己是什么问题实际上是.

诊断这些问题的有用工具:

  • OpenSSL的命令行客户端可以显示服务器发送的证书链: openssl s_client -showcerts -connect google.com:443
  • Qualys的SSL服务器测试将列出证书链以及任何验证错误

RFC 5246第7.4.2节中的相关引用:

7.4.2.服务器证书

当此消息将被发送时:

只要商定的密钥交换方法使用证书进行身份验证,服务器必须发送证书消息(这包括本文档中定义的除DH_anon之外的所有密钥交换方法).此消息将始终紧跟在ServerHello消息之后.

这条消息的含义:

此消息将服务器的证书链传送给客户端.

[...]

此消息的结构:

[...]

certificate_list

这是证书的序列(链).发件人的证书必须在列表中排在第一位.以下每个证书必须直接证明其前面的证书.由于证书验证要求根密钥独立分发,因此可以在链中省略指定根证书颁发机构的自签名证书,前提是远程端必须已经拥有它以便在任何情况下验证它.

  • 是的。这个。对。这里。 (2认同)

use*_*421 6

服务器应在消息中发送整个证书链,包括中间证书Certificate.客户端将检查整个链并找到它信任的根证书.所以你所描述的应该是有效的.

当然,有可能(错误)配置服务器不发送整个链 - 在这种情况下,客户端的检查可能会失败.

  • 我同意,逻辑上它应该有用.整个链都可以由客户端验证,它只需要检查受信任的Root是否签署了收到链中的最后一个人.如果我们在这里遗漏了什么,我想了解一下.唯一的办法是确保将服务器配置为发送完整链而不仅仅是自己的证书.不同意接受的答案. (2认同)

Cra*_*lus -2

当服务器具有由子CA 签名且由根CA(例如Verisign)签名的证书时,服务器将发送所有证书作为服务器问候的一部分,以便可以验证服务器的证书。

在您的情况下,您的信任库中只有根 CA。

因此,由于您缺少子 ca 证书,因此无法建立信任验证链。
这样做不仅不可能,而且是错误的/不安全的。所以你所做的事情已经偏离了正确的道路。

所以你只有2个选择。
服务器的实际证书放入信任库中作为可信。
整个链放入信任库中,即中间 CA 证书和根证书。

您有什么顾虑?中级证书过期?

  • 我不明白这个答案。服务器将发送所有证书,包括中间证书和根证书。客户端有根。因此,客户端可以验证整个链,并找到可信的锚点。所以OP所描述的应该有效。 (5认同)