SSL client certificate is failing with "ValidatorException: Certificate chaining error"

Solution Unverified - Updated -

Environment

  • Any SSL-secured listener with client certificate authentication using Oracle Java Secure Socket Extensions (JSSE)
    • Red Hat JBoss Fuse
    • Red Hat JBoss Enterprise Application Platform

Issue

  • Client certificate validation is failing although the intermediate certificate is in the truststore
  • Getting certificate_unknown or other SSL alert with:
Caused by: sun.security.validator.ValidatorException: Certificate chaining error
    at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:207)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1596)

Resolution

Verify the client or server is sending a valid certificate chain with the certificates in the correct order.

Also, check if you are using SunX509 TrustManagerFactory instead of the preferred PKIX TrustManagerFactory. PKIX TrustManagerFactory handles incorrect server certificate order while SunX509 does not.

There are several ways to have this occur, but one example is code like the following:

        String alg = KeyManagerFactory.getDefaultAlgorithm();  // returns "SunX509"
        TrustManagerFactory fac = TrustManagerFactory.getInstance(alg);

This is getting the wrong algorithm, and the first line should have called TrustManagerFactory.getDefaultAlgorithm.

Root Cause

The client certificate chain provided by the client must be unbroken. For example, if you have three certificates forming a chain:
* CN=Client Certificate (which is signed by CN=Intermediate CA Certificate)
* CN=Intermediate CA Certificate (which is signed by CN=Root CA Certificate)
* CN=Root CA Certificate (which is self signed)

The client can send either just the client certificate (CN=Client Certificate), the client certificate and the intermediate certificate (CN=Client Certificate and CN=Intermediate CA Certificate), or all three certificates. It can not send just the Root and Client certificate (CN=Client Certificate and CN=Root CA Certificate) because it forms a broken chain.

Further, the order must be correct. The certificate should be sent in the above order. The client certificate must be first and then each subsequent certificate must be the signing certificate for the previous certificate.

The above is the same when discussing the server's certificate sent in the ServerHello.

It should also be noted that this error only comes from the SunX509 TrustManagerFactory, but by default Java will use the PKIX TrustManagerFactory which doesn't have this error. To cause this error, the SunX509 factory must be configured either programmatically or overriding ssl.TrustManagerFactory.algorithm in java.security. Usage of SunX509 TrustManagerFactory is not recommended since SunX509 is considered obsolete and isn't updated since PKIX TrustManagerFactory was introduced.

Diagnostic Steps

You can view the certificates the client is sending by enabling SSL debugging by setting the system property, javax.net.debug, to "ssl,handshake" as described in How can I enable SSL debugging in JBoss?

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.