【问题标题】:Why am I getting "No issuer certificate for certificate in certification path found" error for a known and trusted certificate?为什么我收到已知且受信任的证书的“在证书路径中找不到证书的颁发者证书”错误?
【发布时间】:2017-03-02 22:19:18
【问题描述】:

我正在尝试使用 Java Http 客户端连接到服务器以进行 Web 服务调用。如果我用下面的代码打开网络调试..

System.setProperty("javax.net.debug", "all");

我看到来自 Entrust 的证书似乎被添加为受信任的证书。其中添加了以下...

 adding as trusted cert:
 Subject: CN=Entrust.net Certification Authority (2048), OU=(c)    1999   Entrust.net Limited, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), O=Entrust.net
 Issuer:  CN=Entrust.net Certification Authority (2048), OU=(c) 1999 Entrust.net Limited, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), O=Entrust.net
 Algorithm: RSA; Serial number: 0x3863def8
 Valid from Fri Dec 24 12:50:51 EST 1999 until Tue Jul 24 10:15:12 EDT 2029

似乎服务器正在使用来自 Entrust 的证书,因为我也在调试中看到...

main, READ: TLSv1 Handshake, length = 2649
*** Certificate chain
chain [0] =   [0]         Version: 3
     SerialNumber: 1356119177
       IssuerDN: C=US,O=Entrust\, Inc.,OU=See www.entrust.net/legal-terms,OU=(c) 2012 Entrust\, Inc. - for authorized use only,CN=Entrust Certification Authority - L1K
       Start Date: Wed Jul 15 11:50:20 EDT 2015
       Final Date: Sun Jul 15 18:27:04 EDT 2018

然而在握手过程中我得到了以下异常......

***
Caught: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
PKIX path building failed: java.security.cert.CertPathBuilderException: 
No issuer certificate for certificate in certification path found.
main, SEND TLSv1 ALERT:  fatal, description = certificate_unknown

【问题讨论】:

  • IssuerDN 与您显示的受信任证书不同,因此它可能是中间证书,而您的信任存储中没有中间证书。一个好的服务器应该包含中间证书,所以如果你可以控制服务器,请修复它。否则,找到中间证书并将其添加到您的信任库中。
  • 据此,如果我的信任库中有根证书而无需添加中间证书security.stackexchange.com/questions/83874/… 就足够了
  • 您是否阅读了该链接中的second answer?让我为你重新解释一遍,重复我已经说过的话:服务器应该在它们的握手中包含中间证书,在这种情况下,只有根证书需要在你的信任存储中。 Bad 服务器不会,因此您的信任库也需要拥有这些中间证书才能正常工作。如果您对服务器有任何发言权,请将其设为良好、表现良好的服务器。否则,将中间证书添加到您的信任库中,以便您可以与行为不端的服务器进行交互。
  • 所以您是说服务器可能不包含中间证书,所以在这种情况下,我需要请求拥有该服务器的人向我发送中间证书以添加到我的信任库中?我想我不清楚服务器端还是我端(客户端的信任库)缺少证书?
  • 为了验证实际的服务器证书,整个证书必须可用,并且必须信任根证书。如果缺少中间证书,则无法验证服务器证书。正如我所说,good 服务器将在 SSL 握手中包含中间证书。配置不当的服务器不会,但您可以通过在自己的信任库中安装中间证书来解决该问题。这是配置错误的服务器的解决方法,因此最好正确配置服务器,但是解决方法有效,因此如果无法修复服务器,请使用它。

标签: java ssl https


【解决方案1】:

我可以通过将服务器证书添加到我的 java 客户端(jre 的 cacerts 和 jssecacerts)来解决此问题。

如果我们以这种方式向 java 客户端添加证书,我们要求 jre 信任该服务器的证书。

echo | openssl s_client -showcerts -connect www.xyz.com:443 2>&1 |
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /tmp/cert.pem

#cacerts
keytool -import -alias certname -file /tmp/cert.pem -keystore
/usr/java/jdk1.8.0_45/jre/lib/security/cacerts -storepass changeit

#jssecacerts(Normally we remove this file)
keytool -import -alias certname -file /tmp/cert.pem -keystore
/usr/java/jdk1.8.0_45/jre/lib/security/jssecacerts -storepass changeit

如果这段客户端代码是通过应用服务器执行的,请重启你的应用服务器

确保您在环境变量中有 openssl、keytool 并更改您各自的 JAVA_HOME 位置。

【讨论】:

    【解决方案2】:

    我通过创建一个接受服务器证书并指示我的 Apache HttpClient 使用该信任管理器的信任管理器解决了这个问题...

     private class TrustAll implements X509TrustManager
    {
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
    {
    }
    
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
    {
    }
    
    public X509Certificate[] getAcceptedIssuers()
    {
        return new X509Certificate[0];
    }
    

    }

    TrustManager[] trustArray = [new TrustAll()] as TrustManager[]
    SSLContext ctx = SSLContext.getInstance("TLSv1");
    ctx.init(null, trustArray, null);
    
    // create an http client builder
    HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
     httpClientBuilder.setSslcontext(ctx)
    
     httpclient = httpClientBuilder.build();
    

    【讨论】:

    • 该信任管理器接受任何证书。这是根本不安全的。不要使用。
    猜你喜欢
    • 1970-01-01
    • 2017-04-19
    • 2020-04-25
    • 1970-01-01
    • 2015-11-29
    • 2021-04-13
    • 2013-09-28
    • 2015-01-17
    • 1970-01-01
    相关资源
    最近更新 更多