Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JCE:验证X509自签名证书时发生异常_Java_Ssl_X509certificate_Jce - Fatal编程技术网

Java JCE:验证X509自签名证书时发生异常

Java JCE:验证X509自签名证书时发生异常,java,ssl,x509certificate,jce,Java,Ssl,X509certificate,Jce,我们为SSL/TLS开发了一个定制的JCE安全提供者 我们的一个用户在客户端遇到服务器证书验证失败。这是常见的“找不到请求目标的有效认证路径”错误。(是的,证书在信任库中。) 注意:尽管我们正在实现一个自定义提供程序,但我们依赖于信任管理器的标准JCE提供程序,在TLS握手期间使用javax.net.ssl.X509TrustManager.checkServerTrusted(X509Certificate[]chain,String) sun.security.validator.Valid

我们为SSL/TLS开发了一个定制的JCE安全提供者

我们的一个用户在客户端遇到服务器证书验证失败。这是常见的“找不到请求目标的有效认证路径”错误。(是的,证书在信任库中。)

注意:尽管我们正在实现一个自定义提供程序,但我们依赖于信任管理器的标准JCE提供程序,在TLS握手期间使用javax.net.ssl.X509TrustManager.checkServerTrusted(X509Certificate[]chain,String)

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
        at sun.security.validator.Validator.validate(Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:105)
        [snip]
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:146)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
        ...
与我们的所有用户一样,他们安装了无限制的安全策略jar

服务器证书是自签名的(不是CA)。它们使用127.0.0.1作为主机名,因为它们只是连接到后端进程

JRE/JDK的默认安装可以正常工作(使用Sun/Oracle安全提供程序)。使用javax.net.debug输出,我已经确认这些成功的连接使用相同的自签名证书

然而,当我将一些代码拼凑在一起以简单地建立连接时,它在同一台机器上使用相同的信任库、密钥库、证书和JDK时不会出现问题。这使用相同的验证函数,该函数使用相同的证书和相同的authType字符串对X509TrustManager.checkServerTrusted()进行相同的调用。我无法解释为什么checkServerTrusted()在这种情况下验证证书,但在用户的情况下失败

是否有可能通过某种方式调整JCE,使X509TrustManager无法验证此证书?可能是因为它是自签名的,或者因为公共名称是服务的名称而不是域名?我在他们的JVM参数或安全属性中看不到任何东西表明这一点。但也许他们在打JCE电话,我不知道是什么改变了X509TrustManager的行为?

下面是证书的javax.net.debug输出。通用名称只是我们采用者服务的名称。我觉得这有点可疑。但是,它与默认的安全提供程序一起工作

***
Found trusted certificate:
[
[
  Version: V3
  Subject: CN=[snip], OU=[snip], O=[snip], L=Bangalore, ST=[snip], C=IN
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 2048 bits
  modulus: [snip]
  public exponent: 65537
  Validity: [From: Wed Feb 17 14:45:40 IST 2016,
               To: Thu Nov 20 14:45:40 IST 2070]
  Issuer: CN=[snip], OU=[snip], O=[snip], L=Bangalore, ST=[snip], C=IN
  SerialNumber: [    5cf68160]

Certificate Extensions: 1
[1]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
[snip]
]
]

]
  Algorithm: [SHA256withRSA]
  Signature:
[snip]

]
添加一些额外的日志后,很明显,无论出于何种原因,接受的发行人的填充方式都不同。在失败的情况下,从[trust manager]返回过多的已接受发行人;它们不包括有问题的证书。在通过的情况下,只有有问题的证书包括在接受的发行人中

[编辑1]已更正证书

[编辑2]更正了粗体问题中的常用名称


[编辑3]添加了接受的发行人段落

事实证明,这是缓存信任管理器的问题

使用默认提供程序或我们的自定义提供程序,信任管理器最初使用cacerts信任库进行实例化

使用默认提供程序,新的信任管理器稍后将使用javax.net.ssl.trustStore指定的信任库进行实例化。我们的自定义提供程序只是重新使用以前实例化的cacerts信任管理器


解决方案:实例化一个新的信任管理器,它将尊重javax.net.ssl.trustStore。

事实证明,这是缓存信任管理器的问题

使用默认提供程序或我们的自定义提供程序,信任管理器最初使用cacerts信任库进行实例化

使用默认提供程序,新的信任管理器稍后将使用javax.net.ssl.trustStore指定的信任库进行实例化。我们的自定义提供程序只是重新使用以前实例化的cacerts信任管理器


解决方案:实例化一个新的信任管理器,它将尊重javax.net.ssl.trustStore。

此问题不是名称检查,因为只有在路径验证成功后才会发生,并且仅适用于某些应用程序,例如HTTPS。但是,如果/当它完成时,您的文本显示“他们”(用户?)使用127.0.0.1,但您的跟踪显示证书具有CN=localhost;这些名称不相同,在尝试时将不匹配,即使通常都是同一主机和伪接口的名称。至于您的实际问题,我可以确认自签名证书和hostname=localhost工作正常,您显然也这样做了。。。。。。除了(secprop)jdk.certpath.disabledAlgorithms之外,我想不出任何JVM设置,它对于给定JRE中的所有应用都应该是相同的,并且无论如何都不会影响这种情况。我能建议的最好方法是尝试使用sysprop java.security.debug=certpath运行,看看它所说的是否有帮助?我意识到127.0.0.1和localhost是不同的。然而,在我的测试代码中,无论我使用127.0.0.1还是localhost(有或没有提供程序),都可以使用该证书成功地建立连接。而且,我设法把错误的证书放在了帖子里。这是来自以前的连接,我们在其中充当服务器(没有问题)。我会试试certpath,看看它给了我什么。谢谢,这里有点奇怪。java.security.debug=certpath在使用默认提供程序或使用我的测试代码时(即所有不显示异常的场景)似乎不会产生任何输出。但是对于失败的案例,我得到了大量的输出(使用采用者的应用程序和我们的安全提供商)。调试功能直接打印在
系统上。err
,所以我看不出它失败的任何原因,除非你做一些奇怪的事情,比如
2>/dev/null
。但是
tm.getAcceptedissuers()
是信任库内容,因此如果该内容不包含所需的证书,则您的前提“证书在信任库中”是错误的。您确定正在使用的信任库是如何创建的吗?相关代码是否创建明确的SSLContext,如果是,如何创建,或者使用默认值,如果是,请检查sysprops
javax.net.ssl.trustStore*
此问题不是名称检查,因为只有在路径验证成功后才会发生,并且仅适用于某些应用程序,例如HTTPS。但是,如果/当它完成时,您的文本会显示