Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making SSL connections without intermediate certificates using HttpUrlConnection

Is it possible to connect to a site using SSL where the client only has the root certificate, but the server has both the root and the intermediate certificates?

I am trying to connect using HttpUrlConnection with a TrustManager containing my roots, and I get the usual handshake error:

javax.net.ssl.SSLHandshakeException:
  sun.security.validator.ValidatorException:
  Certificate chaining error
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379)

I know that the general solution is to install the intermediate certificates, but I would like to avoid the constant one-offing of getting vendor X's new intermediate certificate.

I am familiar with using a TrustManager that accepts everything, but that is not an option.

like image 460
Joe Devilla Avatar asked Apr 12 '12 18:04

Joe Devilla


1 Answers

Is it possible to connect to a site using SSL where the client only has the root certificate, but the server has both the root and the intermediate certificates?

This is not only possible, but actually the usual way that TLS works:

  1. The TLS client only has the root certificates. Java - at least the Oracle JVM - reads them from lib/security/cacerts in the JRE installation directory. Browsers either have their own, internal list, or use a list provided by the operating system.
  2. When a client initiates a TLS connection, the server is supposed to send back its own certificate, along with any intermediate certificates (if it uses any) - this list is called the certificate chain. For the current version 1.2. of TLS this is specified in section 7.4.2 of RFC 5246 (see below for quote).
  3. The client receives these certificate(s), and verifies the signatures, from the server certificate up to one of the root certificates it knows. This is referred to as Certification Path Building, and is described in RFC 4158.
  4. If the client can build a valid certification path, it continues with connection setup. Otherwise, it aborts with an error message - something like the dreaded "This connection is untrusted" error.

I know that the general solution is to install the intermediate certificates

No, actually not, as explained above the server should automatically send all intermediate certificates.

However:

One fairly common configuration error on servers is to not install all intermediate certificates on the server. In that case the server will send an incomplete certificate chain during connection setup. Then the client will not be able to build a valid certification path, and will abort the connection.

Some complications can make this problem hard to diagnose:

  • Some clients (particularly browsers) may still connect successfully, because they have a cached copy of the missing intermediate certificate.
  • Most clients do not or cannot distinguish between a missing intermediate certificate (in the chain sent by the server), a missing root certificate (in their own list), and a self-signed certificate, so you'll have to figure out yourself what the problem actually is.

Useful tools for diagnosing these problems:

  • OpenSSL's command line client can show you the certificate chain a server sends: openssl s_client -showcerts -connect google.com:443
  • Qualys' SSL Server Test will list the certificate chain, along with any verification errors

Relevant quote from section 7.4.2 of RFC 5246:

7.4.2. Server Certificate

When this message will be sent:

The server MUST send a Certificate message whenever the agreed- upon key exchange method uses certificates for authentication (this includes all key exchange methods defined in this document except DH_anon). This message will always immediately follow the ServerHello message.

Meaning of this message:

This message conveys the server's certificate chain to the client.

[...]

Structure of this message:

[...]

certificate_list

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.

like image 184
sleske Avatar answered Apr 29 '23 13:04

sleske