
[英]java raises an SSLHandshakeException even if the root certificate in the trust store
[英]Is root certificate in the trust store enough to establish a connection?
在信任库中拥有根证书是否足以与网站建立连接? 如果是这样,只是为了测试,我已将 google 的根证书导入到我创建的新信任库中并指向该信任库。 即便如此,我还是收到以下异常。 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
但是,如果我尝试使用默认的 java 信任库连接到谷歌,那么它工作正常。 有人可以帮我吗? TIA。
我只是尝试为 google.com 构建一个 https get 请求。 已加载 GlobalSign 证书。 Google 的证书是由这个 CA 签署的,所以 ssl 握手应该会通过。 下面是我使用的代码,它可以工作。
@Test
public void callGoogleWithRootCA() throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException, KeyManagementException {
String trustStorePath = "keystores-for-unit-tests/truststore.jks";
String trustStorePassword = "secret";
KeyStore trustStore;
try(InputStream keystoreInputStream = this.getClass().getClassLoader().getResourceAsStream(trustStorePath)) {
if (isNull(keystoreInputStream)) {
throw new RuntimeException(String.format("Could not find the keystore file with the given location %s", trustStorePath));
}
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(keystoreInputStream, trustStorePassword.toCharArray());
trustStore = keystore;
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
HttpsURLConnection connection = (HttpsURLConnection) new URL("https://www.google.com").openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
connection.setRequestMethod("GET");
String responseBody = IOUtils.toString(connection.getInputStream(), StandardCharsets.UTF_8);
int responseCode = connection.getResponseCode();
assertThat(responseCode).isEqualTo(200);
}
我无法在此处上传密钥库文件,但这是我用于将证书导入新密钥库的 pem 文件:
-----BEGIN CERTIFICATE-----
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
-----END CERTIFICATE-----
在握手过程中,我得到以下信息:
javax.net.ssl|DEBUG|01|main|2019-12-02 01:29:04.529 CET|CertificateMessage.java:358|Consuming server Certificate handshake message (
"Certificates": [
"certificate" : {
"version" : "v3",
"serial number" : "75 20 46 4B 8D AC DC 10 08 00 00 00 00 1D 8A 52",
"signature algorithm": "SHA256withRSA",
"issuer" : "CN=GTS CA 1O1, O=Google Trust Services, C=US",
"not before" : "2019-11-05 08:46:45.000 CET",
"not after" : "2020-01-28 08:46:45.000 CET",
"subject" : "CN=www.google.com, O=Google LLC, L=Mountain View, ST=California, C=US",
"subject public key" : "EC",
"extensions" : [
{
ObjectId: 1.3.6.1.4.1.11129.2.4.2 Criticality=false
},
{
ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[
accessMethod: ocsp
accessLocation: URIName: http://ocsp.pki.goog/gts1o1
,
accessMethod: caIssuers
accessLocation: URIName: http://pki.goog/gsr2/GTS1O1.crt
]
]
},
{
ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 98 D1 F8 6E 10 EB CF 9B EC 60 9F 18 90 1B A0 EB ...n.....`......
0010: 7D 09 FD 2B ...+
]
]
},
{
ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]
},
{
ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.pki.goog/GTS1O1.crl]
]]
},
{
ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
[CertificatePolicyId: [2.23.140.1.2.2]
[] ]
[CertificatePolicyId: [1.3.6.1.4.1.11129.2.5.3]
[] ]
]
},
{
ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
serverAuth
]
},
{
ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
]
},
{
ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: www.google.com
]
},
{
ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 63 55 73 A0 9D C3 D5 FA 3C 1A 17 EA 0B 72 AB EF cUs.....<....r..
0010: D3 15 15 BB ....
]
]
}
]},
"certificate" : {
"version" : "v3",
"serial number" : "01 E3 B4 9A A1 8D 8A A9 81 25 69 50 B8",
"signature algorithm": "SHA256withRSA",
"issuer" : "CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R2",
"not before" : "2017-06-15 02:00:42.000 CEST",
"not after" : "2021-12-15 01:00:42.000 CET",
"subject" : "CN=GTS CA 1O1, O=Google Trust Services, C=US",
"subject public key" : "RSA",
"extensions" : [
{
ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[
accessMethod: ocsp
accessLocation: URIName: http://ocsp.pki.goog/gsr2
]
]
},
{
ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 9B E2 07 57 67 1C 1E C0 6A 06 DE 59 B4 9A 2D DF ...Wg...j..Y..-.
0010: DC 19 86 2E ....
]
]
},
{
ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:0
]
},
{
ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.pki.goog/gsr2/gsr2.crl]
]]
},
{
ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
[CertificatePolicyId: [2.23.140.1.2.2]
[PolicyQualifierInfo: [
qualifierID: 1.3.6.1.5.5.7.2.1
qualifier: 0000: 16 1C 68 74 74 70 73 3A 2F 2F 70 6B 69 2E 67 6F ..https://pki.go
0010: 6F 67 2F 72 65 70 6F 73 69 74 6F 72 79 2F og/repository/
]] ]
]
},
{
ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
serverAuth
clientAuth
]
},
{
ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
Key_CertSign
Crl_Sign
]
},
{
ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 98 D1 F8 6E 10 EB CF 9B EC 60 9F 18 90 1B A0 EB ...n.....`......
0010: 7D 09 FD 2B ...+
]
]
}
]}
]
)
javax.net.ssl|DEBUG|01|main|2019-12-02 01:29:04.566 CET|X509TrustManagerImpl.java:242|Found trusted certificate (
"certificate" : {
"version" : "v3",
"serial number" : "04 00 00 00 00 01 0F 86 26 E6 0D",
"signature algorithm": "SHA1withRSA",
"issuer" : "CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R2",
"not before" : "2006-12-15 09:00:00.000 CET",
"not after" : "2021-12-15 09:00:00.000 CET",
"subject" : "CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R2",
"subject public key" : "RSA",
"extensions" : [
{
ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 9B E2 07 57 67 1C 1E C0 6A 06 DE 59 B4 9A 2D DF ...Wg...j..Y..-.
0010: DC 19 86 2E ....
]
]
},
{
ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
},
{
ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.globalsign.net/root-r2.crl]
]]
},
{
ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
Key_CertSign
Crl_Sign
]
},
{
ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 9B E2 07 57 67 1C 1E C0 6A 06 DE 59 B4 9A 2D DF ...Wg...j..Y..-.
0010: DC 19 86 2E ....
]
]
}
]}
)
所以回到你的问题,可能你的密钥库没有加载。 你能验证你的密钥库文件是否不为空吗?
抱歉 Saptarshi Basu 的回答有点 TLDR。 在我的外行术语中
使用https://gist.github.com/4ndrej/4547029#file-sslpoke-java和openssl进行故障排除(它使用操作系统证书存储)
openssl version -d
openssl s_client -connect google.com:443 -showcerts
这是有关其工作原理的更详细的答案:
在 TLS 握手过程中,服务器发送形成链的证书列表。 在 TLS 1.2 RFC 5246 中,它被解释为:
这是证书序列(链)。 发件人的证书必须排在列表的首位。 后面的每个证书必须直接证明它前面的证书。 因为证书验证需要独立分发根密钥,指定根证书颁发机构的自签名证书可以从链中省略,假设远程端必须已经拥有它以便在任何情况下验证它。
证书的根始终是自签名的,对于全球接受的根 CA(证书颁发机构),证书存储在客户端平台(即 Mozilla、MacOS、Java、Android、Windows 等)中。 因此服务器不需要发送这个证书。
相同的 RFC 还提到:
实现负责验证证书的完整性,并且通常应该支持证书撤销消息。 应始终验证证书以确保受信任的证书颁发机构 (CA) 正确签名。 应非常谨慎地选择和添加受信任的 CA。 用户应该能够查看有关证书和根 CA 的信息。
换句话说,平台实现将向下遍历证书链并不断验证证书,直到遇到信任存储中的证书。 信任存储中存在的任何证书都不会被验证,并将被假定为受信任的证书。
这在 TLS 1.3 RFC 8446 中提到:
实现负责验证证书的完整性,并且通常应该支持证书撤销消息。 如果应用程序配置文件中没有特定指示,则应始终验证证书以确保受信任的证书颁发机构 (CA) 的正确签名。 信任锚的选择和添加应该非常小心。 用户应该能够查看有关证书和信任锚的信息。
它还说:
自签名证书或作为信任锚的证书上的签名未经过验证,因为它们开始了认证路径
现在,对于谷歌,如果我们在https://www.ssllabs.com/ 中测试服务器,我们可以看到证书www.google.com
和GTS CA 101
是由服务器发送的,而GlobalSign
证书是存在的在平台的信任存储中。
希望这能澄清我之前的评论。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.