信任库中的根证书是否足以建立连接?

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 信任库连接到 google,那么它工作正常。有人可以帮我吗? 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                                        ....
        ]
        ]
      }
    ]}
)

所以回到你的问题,可能你的密钥库没有加载。您可以验证您的密钥库文件是否不为空吗?

这里有一个关于它如何工作的更详细的答案:

在TLS握手过程中,服务器发送一个形成链的证书列表。在TLS 1.2 RFC 5246中解释为:

This is a sequence (chain) of certificates. The sender's certificate MUST come first in the list. Each following certificate MUST directly certify the one preceding it. Because certificate validation requires that root keys be distributed independently, the self-signed certificate that specifies the root certificate authority MAY be omitted from the chain, under the assumption that the remote end must already possess it in order to validate it in any case.

证书的根始终是自签名的,对于全球接受的根 CA(证书颁发机构),证书存储在客户端平台(即 Mozilla、MacOS、Java、Android、Windows 等)。因此服务器不需要发送此证书。

同样的RFC也提到:

Implementations are responsible for verifying the integrity of certificates and should generally support certificate revocation messages. Certificates should always be verified to ensure proper signing by a trusted Certificate Authority (CA). The selection and addition of trusted CAs should be done very carefully. Users should be able to view information about the certificate and root CA.

换句话说,平台实现将遍历证书链并继续验证证书,直到它找到信任库中的证书。信任库中存在的任何证书都不会被验证,并将被假定为受信任的证书。

这在 TLS 1.3 RFC 8446 中提到为:

Implementations are responsible for verifying the integrity of certificates and should generally support certificate revocation messages. Absent a specific indication from an application profile, certificates should always be verified to ensure proper signing by a trusted certificate authority (CA). The selection and addition of trust anchors should be done very carefully. Users should be able to view information about the certificate and trust anchor.

它进一步说:

The signatures on certificates that are self-signed or certificates that are trust anchors are not validated, since they begin a certification path

现在,在 Google 的情况下,如果我们在 https://www.ssllabs.com/ 中测试服务器,我们可以看到证书 www.google.comGTS CA 101 是由服务器发送的,而 GlobalSign 证书存在于平台的信任库中。

希望这能澄清我之前的评论。

抱歉 Saptarshi Basu 的回答。在我的外行术语中

  • 如果您信任商店只有根证书,服务器必须发送链
  • 如果您的信任存储有链(因此包括中间证书),则服务器可以 只发送它颁发的证书

疑难解答 https://gist.github.com/4ndrej/4547029#file-sslpoke-javaopenssl(它使用 OS 证书存储)

openssl version -d
openssl s_client -connect google.com:443 -showcerts