0
votes

I have a web site being served over SSL from node.js. When I visit the site with a web browser (both on the Desktop, and Android). everything is fine - the lock appears indicating that the site is secure, when I inspect the certificates is valid and everything looks ok. That should mean the server is set up correctly, right?

However, when I try to use an Android WebView for the exact same site, the page fails to load - I don't even see a request for the web page in my logs. Andr, after relaxing the filter on logcat, I noticed this message:

I/X509Util: Failed to validate the certificate chain, error: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

In researching this a bit, one suggestion was that this is a configuration error on the server - that some part of the certificate isn't installed correctly. I tested the site with an SSL analysis tool and discovered this:

TLS Certificate is not trusted

The certificate is not signed by a trusted authority (checking against Mozilla's root store). If you bought the certificate from a trusted authority, you probably just need to install one or more Intermediate certificates.

The certificate is from LetsEncrypt which by default puts four files in the directory for the site: privkey.pem, cert.pem, chain.pem, and fullchain.pem. I am using the following code in node.js to load everything:

tls.createSecureContext({
        key: fs.readFileSync(dir+"/privkey.pem", "utf8"),
        cert: fs.readFileSync(dir+"/cert.pem", "utf8")//,
        ca: fs.readFileSync(dir+"/chain.pem","utf8")
    })

From reading the documentation on the createSecureContext function, I think the corresponding PEM files generated by LetsEncrypt are correct. Specifically, it is my understanding that the ca parmameter pointing to the chain.pem file is what allows the intermediate CAs to be presented, which Android requires. However, just for good measure I also tried omitting the ca option (this should cause it to default the Mozilla's default chain), and changing ca to point to "fullchain.pem", neither of which made a difference.

What am I doing wrong here?

1

1 Answers

2
votes

After experimenting with a few other things, I discovered that this works:

tls.createSecureContext({
    key: fs.readFileSync(dir+"/privkey.pem", "utf8"),
    cert: fs.readFileSync(dir+"/fullchain.pem", "utf8")
})

I got the idea from this answer although it is not referring to the naming convention used by LetsEncrypt so I had to adapt it a bit.