是否可以为HttpClient 4.4的现有SSL证书添加其他子域?

时间:2015-03-26 11:10:20

标签: java ssl apache-httpclient-4.x keytool apache-httpcomponents

我们正在使用HttpClient 4.4与一些外部服务器(server1.company.com,server2.company.com,server3.company.com)进行通信。他们最近添加了一个额外的环境(server4.company.com),该环境使用与另一个相同的证书3.有问题的证书将前3个服务器列为“证书主题备用名称”,但未提及server4。

我可以告诉keytool证书对其他SAN有效吗?或者有没有其他方法告诉HttpClient“信任”这个额外域名的证书?还有其他选择,还是我必须回到company.com并要求他们获得新证书?

2 个答案:

答案 0 :(得分:1)

证书验证有两个方面(一般而言):

  1. 验证证书是否为真品并由您信任的人签发(即PKI方面)。
  2. 验证它是否属于您要连接的主机名(这是主机名验证)。
  3. (如果您需要类比,可能会感兴趣this question, about libcurl。)

    根据您的说法,该特定证书对其他主机名称是可信且有效的。因此,它将通过PKI验证(TrustStrategy实现的内容)。

    您需要的是为主机名验证方面构建一个特殊情况,仅针对该特定证书。

    我不记得如何在Apache HTTP Client 4.4中使用它,但您应该使用自己的验证程序而不是DefaultHostnameVerifier

    要实施的方法是verify(String hostYouAreAfter, SSLSession sessionYouActuallyGet)verify(String hostYouAreAfter, X509Certificate certYouActuallyGet)

    您可以按照这些方式提供自己的实现:

    public verify(String hostYouAreAfter, X509Certificate certYouActuallyGet) {
        if (certYouActuallyGet.equals(referenceCertificate)) {
             if ("server4.company.com".equalsIgnoreCase(hostYouAreAfter)) {
                 // All good, don't fail and throw an exception.
             } else {
                 super.verify(hostYouAreAfter, certYouActuallyGet);
             }
        } else {
             super.verify(hostYouAreAfter, certYouActuallyGet);
        }
    }
    

    您可以对verify(String,SSLSession)执行相同的操作,并从X509Certificate的对等链(位置0)获取SSLSession。逻辑是一样的,但你需要返回true / false而不是抛出异常。

    在这里,我假设您已从具有该特定证书的引用位置加载referenceCertificate。例如,您可以从已知密钥库加载它,或者从应用程序中配置的参考PEM文件加载CertificateFactory


    TrustStrategyisTrusted(final X509Certificate[] chain, final String authType)实施return "nice guy".equalsIgnoreCase(issuerDN.getName());有两个主要区别:

    • 您实际上只针对该证书提出此例外情况,而不是任何其他可能与您所使用的名称相关的证书。
    • 它仅影响您希望连接到该特定主机(而不是其他主机)的连接。您确实可以访问String的第一个HostnameVerifier.verify(...)参数,该参数是您打算连接的主机名。至少你可以将它用于与你获得的证书进行比较,这是TrustStrategy无法获得的。

答案 1 :(得分:0)

可以使用自定义TrustStrategy

来信任某些选定证书
SSLContext sslcontext = SSLContexts.custom()
  .loadTrustMaterial(new TrustStrategy() {
    @Override
    public boolean isTrusted(final X509Certificate[] chain, final String authType) 
        throws CertificateException {
      X509Certificate x509Certificate = chain[0];
      Principal issuerDN = x509Certificate.getIssuerDN();
      return "nice guy".equalsIgnoreCase(issuerDN.getName());
    }
  }).build();
CloseableHttpClient client = HttpClients.custom()
  .setSslcontext(sslcontext)
  .build();