I hit a problem in Android, trying to talk HTTPS with an Apache web-server that has an SSL certificate purchased from Dynadot/AlphaSSL:

javax.net.ssl.SSLHandshakeException: 
  java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.

The code to talk to the server looks something like this:

...
HttpsURLConnection _conn = null;
try {
    _conn = (HttpsURLConnection) 
        new URL(aUrl).openConnection();
    if ((_conn.getResponseCode() >= 200) && 
        (_conn.getResponseCode() < 300)) {
        return handleSuccessResponse(_conn);
    } else if (...) {
        ...
    } else {
        return handleErrorResponse(_conn);
    }
finally {
    _conn.disconnect();
}
...

I googled the message "Trust anchor for certification path not found". Unsurprisingly, StackOverflow shows up several times in the results, but several of the top hits I got suggest reaching immediately for a custom trust manager as the preferred solution.

This set off alarm bells for me, ranging from "that sounds like a lot of effort" through "so, why does connecting to another https site (e.g. my bank) work?".

You do need a custom trust manager if you signed your own certificate.

I haven't thought about it much, but the extra effort actually seems to outweigh the cost of buying a certificate.

You do not need a custom trust manager if you bought your certificate!

If you bought a certificate, building a custom trust manager is a complicated, slow, high-effort workaround for your actual problem, and - worse - you'd have to repeat the workaround on each client (imagine you are building apps for Android, iOS and Windows Mobile).

Certificates are signed in a "chain", where the chain eventually leads back to a set of root authority certificates that are known and trusted by Android. The point is to be able to trace a certificate back to a trusted signing authority without having to have any advance knowledge of the certificate.

So why is my certificate not trusted?

It turns out the server I was connecting to was misconfigured. It was returning its own certificate, but it was not returning the intermediate certificate, so there was no chain, and Android was unable to verify its authenticity, hence "trust anchor not found". Happily I was able to get access to the server to fix up the configuration.

One way to investigate your certificate chain is with openssl client:

openssl s_client -debug -connect www.thedomaintocheck.com:443

This lists some useful information about your cert, including the chain. If you are experiencing a trust anchor not found, your chain will probably only contain one element, like this:

Certificate chain
  0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
    i:/O=AlphaSSL/CN=AlphaSSL CA - G2

.. and openssl will finish its output with something like

Verify return code: 21 (unable to verify the first certificate)

A server configured correctly with intermediate certificates will return a complete chain, like this:

Certificate chain
  0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
    i:/O=AlphaSSL/CN=AlphaSSL CA - G2
  1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
    i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
  2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
    i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

.. and Android's HttpsURLConnection will happily accept the certificate - no custom trust manager keystore nonsense here, thank you.

blog comments powered by Disqus