Java 存在根 CA 证书 - 出现 SSL 握手异常
Java Root CA Certificate present - getting SSL Handshake Exception
我编写了一个 java JAX-WS 网络服务客户端。当我尝试使用 public CA 签名证书访问服务器时,出现 SSL 握手异常:
com.sun.xml.internal.ws.client.ClientTransportException: HTTP transport error: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
我进一步调查并打开了 JVM 的网络跟踪,发现服务器 public CA 签名证书的颁发者是:
Issuer: CN=Symantec Class 3 Secure Server SHA256 SSL CA, OU=Symantec Trust Network, O=Symantec Corporation, C=US
我已验证此颁发者的根 CA 证书是:
CN=VeriSign Universal Root Certification Authority, OU="(c) 2008 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
而且我还通过日志跟踪验证了该证书确实已加载。
这是 SSL 日志跟踪的一部分:
keyStore is :
keyStore type is : jks
keyStore provider is :
init keystore
init keymanager of type SunX509
trustStore is: C:\Program Files\Java\jdk1.7.0_79\jre\lib\security\cacerts
trustStore type is : jks
trustStore provider is :
init truststore
[ omitted]
adding as trusted cert:
Subject: CN=VeriSign Universal Root Certification Authority, OU="(c) 2008 VeriSign
, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
Issuer: CN=VeriSign Universal Root Certification Authority, OU="(c) 2008 VeriSign
, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
Algorithm: RSA; Serial number: 0x401ac46421b31321030ebbe4121ac51d
Valid from Tue Apr 01 17:00:00 PDT 2008 until Tue Dec 01 15:59:59 PST 2037
[ omitted]
trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
main, setSoTimeout(0) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie: GMT: 1468680588 bytes =
Session ID: {}
Cipher Suites: [ ... ]
Compression Methods: { 0 }
Extension elliptic_curves, curve names:
Extension ec_point_formats, formats: [uncompressed]
Extension server_name, server_name: [host_name: redacted]
***
[write] MD5 and SHA1 hashes: len = 181
[omitted]
*** ServerHello, TLSv1
RandomCookie: GMT: 1524806833
Session ID:
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
Extension server_name, server_name:
***
%% Initialized: [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
** TLS_DHE_RSA_WITH_AES_128_CBC_SHA
[read] MD5 and SHA1 hashes: len = 85
[omitted]
*** Certificate chain
chain [0] = [
[
Version: V3
Subject: CN=redacted, OU=redacted, O=redacted, L=redacted, ST=redacted, C=US
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 2048 bits
modulus:
public exponent: 65537
Validity: [From: Sun Oct 16 17:00:00 PDT 2016,
To: Thu Nov 02 16:59:59 PDT 2017]
Issuer: CN=Symantec Class 3 Secure Server SHA256 SSL CA,
OU=Symantec Trust Network, O=Symantec Corporation, C=US
SerialNumber: [ ... ]
Certificate Extensions: 9
[1]: ObjectId: 1.3.6.1.4.1.11129.2.4.2 Criticality=false
Extension unknown: DER encoded OCTET string =
[omitted]
***
%% Invalidated: [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
main, SEND TLSv1 ALERT: fatal, description = certificate_unknown
main, WRITE: TLSv1 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 01 00 02 02 2E .......
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException:
有人对可能导致此问题的原因有任何建议吗?
信任树看起来像
root-> VeriSign Universal Root Certification Authority
chain-> Symantec Class 3 Secure Server SHA256 SSL CA
leaf-> somewebsite
您可以有多个链,也可以没有链。
浏览器倾向于在其信任库中包含根证书和流行的链证书。
但看起来 java 信任库缺少那个特定的链证书。
因此,当您尝试连接到它时,java 无法知道根证书最终是否信任叶证书,因为它找不到路径。
有两种处理方法,理想情况下,服务器操作员会将其服务器配置为呈现证书链,如果不可能,您可以手动将链证书导入 java 的信任库。
keytool -import -file Example.cer -keystore examplekeystore
unable to find valid certification path to requested target
表示由于
客户端不信任服务器证书
- 从叶证书到根证书的链不完整或
- 信任库中不存在根证书
我检查过 Symantec Class 3 Secure Server SHA256 SSL CA
是由 VeriSign Universal Root Certification Authority
发布的(参见 Symantec page)
而 Verisign root 有效地包含在 jdk1.7 中。0_79,所以我放弃了 2)。因此,我的猜测是服务器端的链条不完整。
操作
检查 https://www.ssllabs.com 中的服务器寻找 'incomplete chain errors'。
验证中间CA确实是Symantec Class 3 Secure Server SHA256 SSL CA
,序列号69 87 94 19 d9 e3 62 70 74 9d bb e5 9d c6 68 5e
如果第 1 步出现错误,请下载 Symantec 证书(从上面 link)并导入到您的信任库
如果中间证书不是来自 Symantec 的预期证书,则获取根 CA 并将其导入到您的 trustore
已编辑 SSL 信任验证
证书是按层次结构颁发的。每个证书都由上层的颁发者签署,从根 CA 到叶证书。数字签名允许检查认证链。
SSL服务器必须提供证书和链(不包括根)。信任管理器检查从叶到根的认证链。如果在信任库中找到任何证书,则证书为 "trusted"(即使它已过期...)
您应该在信任库中包含根 CA,而不是叶
我编写了一个 java JAX-WS 网络服务客户端。当我尝试使用 public CA 签名证书访问服务器时,出现 SSL 握手异常:
com.sun.xml.internal.ws.client.ClientTransportException: HTTP transport error: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
我进一步调查并打开了 JVM 的网络跟踪,发现服务器 public CA 签名证书的颁发者是:
Issuer: CN=Symantec Class 3 Secure Server SHA256 SSL CA, OU=Symantec Trust Network, O=Symantec Corporation, C=US
我已验证此颁发者的根 CA 证书是:
CN=VeriSign Universal Root Certification Authority, OU="(c) 2008 VeriSign, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
而且我还通过日志跟踪验证了该证书确实已加载。
这是 SSL 日志跟踪的一部分:
keyStore is :
keyStore type is : jks
keyStore provider is :
init keystore
init keymanager of type SunX509
trustStore is: C:\Program Files\Java\jdk1.7.0_79\jre\lib\security\cacerts
trustStore type is : jks
trustStore provider is :
init truststore
[ omitted]
adding as trusted cert:
Subject: CN=VeriSign Universal Root Certification Authority, OU="(c) 2008 VeriSign
, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
Issuer: CN=VeriSign Universal Root Certification Authority, OU="(c) 2008 VeriSign
, Inc. - For authorized use only", OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
Algorithm: RSA; Serial number: 0x401ac46421b31321030ebbe4121ac51d
Valid from Tue Apr 01 17:00:00 PDT 2008 until Tue Dec 01 15:59:59 PST 2037
[ omitted]
trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
main, setSoTimeout(0) called
%% No cached client session
*** ClientHello, TLSv1
RandomCookie: GMT: 1468680588 bytes =
Session ID: {}
Cipher Suites: [ ... ]
Compression Methods: { 0 }
Extension elliptic_curves, curve names:
Extension ec_point_formats, formats: [uncompressed]
Extension server_name, server_name: [host_name: redacted]
***
[write] MD5 and SHA1 hashes: len = 181
[omitted]
*** ServerHello, TLSv1
RandomCookie: GMT: 1524806833
Session ID:
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
Extension server_name, server_name:
***
%% Initialized: [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
** TLS_DHE_RSA_WITH_AES_128_CBC_SHA
[read] MD5 and SHA1 hashes: len = 85
[omitted]
*** Certificate chain
chain [0] = [
[
Version: V3
Subject: CN=redacted, OU=redacted, O=redacted, L=redacted, ST=redacted, C=US
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 2048 bits
modulus:
public exponent: 65537
Validity: [From: Sun Oct 16 17:00:00 PDT 2016,
To: Thu Nov 02 16:59:59 PDT 2017]
Issuer: CN=Symantec Class 3 Secure Server SHA256 SSL CA,
OU=Symantec Trust Network, O=Symantec Corporation, C=US
SerialNumber: [ ... ]
Certificate Extensions: 9
[1]: ObjectId: 1.3.6.1.4.1.11129.2.4.2 Criticality=false
Extension unknown: DER encoded OCTET string =
[omitted]
***
%% Invalidated: [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
main, SEND TLSv1 ALERT: fatal, description = certificate_unknown
main, WRITE: TLSv1 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 01 00 02 02 2E .......
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException:
有人对可能导致此问题的原因有任何建议吗?
信任树看起来像
root-> VeriSign Universal Root Certification Authority
chain-> Symantec Class 3 Secure Server SHA256 SSL CA
leaf-> somewebsite
您可以有多个链,也可以没有链。 浏览器倾向于在其信任库中包含根证书和流行的链证书。
但看起来 java 信任库缺少那个特定的链证书。
因此,当您尝试连接到它时,java 无法知道根证书最终是否信任叶证书,因为它找不到路径。
有两种处理方法,理想情况下,服务器操作员会将其服务器配置为呈现证书链,如果不可能,您可以手动将链证书导入 java 的信任库。
keytool -import -file Example.cer -keystore examplekeystore
unable to find valid certification path to requested target
表示由于
- 从叶证书到根证书的链不完整或
- 信任库中不存在根证书
我检查过 Symantec Class 3 Secure Server SHA256 SSL CA
是由 VeriSign Universal Root Certification Authority
发布的(参见 Symantec page)
而 Verisign root 有效地包含在 jdk1.7 中。0_79,所以我放弃了 2)。因此,我的猜测是服务器端的链条不完整。
操作
检查 https://www.ssllabs.com 中的服务器寻找 'incomplete chain errors'。
验证中间CA确实是
Symantec Class 3 Secure Server SHA256 SSL CA
,序列号69 87 94 19 d9 e3 62 70 74 9d bb e5 9d c6 68 5e
如果第 1 步出现错误,请下载 Symantec 证书(从上面 link)并导入到您的信任库
如果中间证书不是来自 Symantec 的预期证书,则获取根 CA 并将其导入到您的 trustore
已编辑 SSL 信任验证
证书是按层次结构颁发的。每个证书都由上层的颁发者签署,从根 CA 到叶证书。数字签名允许检查认证链。
SSL服务器必须提供证书和链(不包括根)。信任管理器检查从叶到根的认证链。如果在信任库中找到任何证书,则证书为 "trusted"(即使它已过期...)
您应该在信任库中包含根 CA,而不是叶