使用HTTP客户端 - 如何让Java自动下载中间SSL证书

3
我正在建立与一台我无法控制的远程服务器的HTTPS连接。该服务器具有由受信任的CA生成的SSL证书,但在其SSL握手中未包含中间证书。
例如。 受信任的CA证书-> 中间证书(未提供)->服务器证书(已提供)
通常,服务器会提供服务器证书和中间证书。如果没有中间证书,则我的HTTP客户端无法识别SSL证书,从而导致SSL连接失败。
我正在尝试使用Apache HTTP客户端4.5进行连接。
  val httpClientBuilder = HttpClientBuilder.create()
    .useSystemProperties()

如果我下载证书并将其设置在密钥库中再将其附加到连接上,那么我就可以让事情正常运行:

  Security.addProvider(new BouncyCastleProvider())
  val certPem = new PEMParser(new PemReader(new FileReader("trust-chain.crt")))
  val certHolder = certPem.readObject().asInstanceOf[X509CertificateHolder]
  val cert = new JcaX509CertificateConverter()
    .setProvider("BC")
    .getCertificate(certHolder)
  val keyStore = KeyStore.getInstance(KeyStore.getDefaultType)
  keyStore.load(null)
  keyStore.setCertificateEntry("cert-alias", cert)

  val sslContextBuilder = SSLContextBuilder.create()
    .loadKeyMaterial(keyStore, "changeit".toCharArray)
    .loadTrustMaterial(keyStore, null)

  val httpClientBuilder = HttpClientBuilder.create()
    .useSystemProperties()
    .setSSLContext(sslContextBuilder.build())

但是这个方法在证书过期后就会失效。我也可以启用信任自签名证书,但这会带来相当大的安全隐患,我不想走这条路:

  val sslContextBuilder = SSLContextBuilder.create()
    .loadKeyMaterial(keyStore, "changeit".toCharArray)
    .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy)

有没有办法设置 Apache HTTP Client (或另一个JVM HTTPS / SSL库),使其在服务器未提供中间证书的情况下自动下载这些证书(类似于大多数 Web 浏览器)?


从哪里下载它们? - President James K. Polk
@JamesKPolk 这是一个好问题 - 我不完全确定,可能是受信任的CA - 我知道ssllabs ssltest(https://www.ssllabs.com/ssltest/index.html)能够从某个地方获取它们并指出“此服务器的证书链不完整。等级限制为B。”我还能够通过另一个站点下载它们,该站点将整个证书链提取到-----BEGIN CERTIFICATE----- .... -----END CERTIFICATE-----格式中,因此我认为这是一个可解决的问题。 - Allan5
一些CA在其网站的某个位置提供它们的一些中间根证书。这并不是获取中间证书的可靠或标准方式。你不需要下载中间证书就可以知道它们是否丢失。我怀疑SSLabs有没有下载它们。 - President James K. Polk
@JamesKPolk 我猜(希望)一定有某种标准方法,因为我能够使用我的网络浏览器访问同一台服务器,并且网络浏览器能够下载中间证书并验证该站点,我只是希望在JVM中有一种自动化的方式来完成相同的操作。 - Allan5
顺便提一下,在这里没有必要使用BouncyCastle;标准的CertificateFactory可以读取PEM或DER证书(从文件或流中),只需要两行甚至一行代码,自Java开始就可以了。 - dave_thompson_085
1个回答

4
我找到了一个答案
使用Oracle JRE,您可以通过Java系统属性-Dcom.sun.security.enableAIAcaIssuers=true启用中间证书的自动下载。
为使此功能正常工作,服务器证书必须提供指向中间证书(即证书的颁发者)的URI。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接