1 min read

Why Nginx needs the SSL certificate with chain, not just the bare certificate

Last year I ran into problems using a certificate-only PEM file with Nginx and had to use the whole-chain PEM. I'm attempting to understand why.

The reason as I understand it is that the website certificate you're issued isn't signed directly by a root certificate (which web browsers have), and there's no other place to get the intermediate certificates.

Between the final SSL certificate \(C\) and a root authority certificate \(R\), there may be intermediate signing certificates \(X_1, \dots, X_N\). Say \(R\) signs \(X_1\), \(X_i\) signs \(X_{i+1}\) for \(i\) between 1 and \(N - 1\), and \(X_N\) signs \(C\).

The browser has \(R\) and if you send it it has \(C\), but it can't use \(R\) to verify \(C\) because a signature from \(R\) is not the same as a signature from \(X_N\) and we can't obtain \(X_1, \dots, X_N\) from \(R\) and \(C\).

So, to verify \(C\) the browser needs to obtain \(X_1\) through \(X_N\) somehow. Since there is no outside certificate server to ask for \(X_1, \dots, X_N\), we have to get it from the web server. (X.500 was a proposal, I think, for global certificate servers, but it sounds like they never materialized.) That's why Nginx needs \(X_1, \dots, X_N\): So it can send them.

The obvious question: Why complicate things? Why not just have \(R\) sign \(C\)? Why make up these intermediates \(X_1, \dots, X_N\)?

We have the intermediate certificates (as I understand it) because they make it possible to revoke keys without needing to revoke and reissue a root certificate. Clients need to store a list of trusted root certificates, which means the operating system or the browser need to provide them. I expect verifying root certificates is expensive, and that it has to be done every time a root certificate is issued. Intermediary certificates should be less expensive to work with, because revoking them doesn't revoke everything using that root certificate—only the specific intermediate.