简体   繁体   中英

Is root certificate in the trust store enough to establish a connection?

Is having the root certificate in truststore enough for establishing the connection with a website? If so, just to test, I've imported the root certificate of google to new trust store which I have created and pointed to that trust store. Even then I am getting the following exception. 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

But if I try to connect to google using default java trust store then it's working fine. Can someone please help me with this? TIA.

I just tried out to build a https get request for google.com. Loaded GlobalSign certificate. Google's certificate is signed by this CA, so the ssl handshake should pass. Below is the code what I used and it works.

    @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);
    }

See here the specific certificate in the keystore file: 谷歌的根 ca

I couldn't upload the keystore file here, but this is the pem file I used for importing the certificate to a new keystore:

-----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-----

During the handshake process I am getting the following information:

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                                        ....
        ]
        ]
      }
    ]}
)

So back to your issue, probably your keystore is not loaded. Could you validate if your keystore file is not null?

sorry bit TLDR for Saptarshi Basu answer. here in my laymen terms

  • if you trust store only has the root cert the server must send the chain
  • if your trust store has the chain (so including the intermediate cert) the server can only send it's issued cert

Troubleshoot with https://gist.github.com/4ndrej/4547029#file-sslpoke-java and openssl (it uses the OS cert store)

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

Here is a more detailed answer on how it works:

During the TLS handshake process, the server sends a certificate list forming a chain. In TLS 1.2 RFC 5246 , it is explained as:

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.

The root of the certificate is always self-signed and for a globally accepted root CA (Certificate Authority), the certificate is stored in the client platform (viz. Mozilla, MacOS, Java, Android, Windows etc.). Therefore the server need not send this certificate.

The same RFC also mentions:

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.

In other words, the platform implementation will traverse down certificate chain and keep verifying the certificates until it hits a certificate that is in the trust store. Any certificate that is present in the trust store will not be verified and will be assumed as a trusted certificate.

This is mentioned in TLS 1.3 RFC 8446 as:

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.

It further says:

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

Now, in case of Google, if we test the server in https://www.ssllabs.com/ , we can see that the certificates www.google.com and GTS CA 101 are sent by the server, whereas GlobalSign certificate is present in the trust store of the platform.

Hope this clarifies my earlier comments.

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM