Validity and name are two checks out of three. The third is who signed the certificate.
A certificate is signed by a certificate authority, a CA, with its key — the CA's name is in issuer. The client trusts the signature if the CA's certificate is in its trust store. On Ubuntu the store is the file /etc/ssl/certs/ca-certificates.crt, holding the root certificates of public CAs. Your own CA is added with a file in /usr/local/share/ca-certificates and the update-ca-certificates command — that is how the training Lab Root CA was added on this machine.
openssl verify checks a certificate file the way curl does: the issuer against the store, and the validity.
A CA's root certificate is signed by itself: its subject and issuer are the same. Such a certificate is called self-signed. The root is trusted because it sits in the store, while a self-signed site certificate is trusted only where someone added it to the store by hand. curl --cacert ca.crt checks the issuer against that one file instead of the store.
curl -k skips all three checks and will get the page from any server. It tells you whether nginx answers at all, but it does not fix the site: browsers never turn the checks off.
For a test, a colleague issued a test.lab.test certificate to itself — its subject and issuer are the same, CN = test.lab.test. Validity and name are fine. What will curl https://test.lab.test/ print?
-
Validity is fine by the setup. The error will be about the issuer: test.lab.test is not in the trust store.
-
The third check fails: the issuer test.lab.test is not in the trust store.
openssl verifyon such a file saysself-signed certificate. -
The name is fine by the setup. curl trips over the signature: the issuer is not in the trust store.
A certificate signed by itself passes the issuer check only if it sits in the trust store itself. That is how root CA certificates work, while a site's certificate would have to be added to the store explicitly on every client.
Key points
- The client checks three things: the issuer is in the trust store, the name from the address is in the SAN, and now is between notBefore and notAfter.
- If any of them fails, curl exits with code 60 and names the reason in the error text.
-
Your own CA goes into the store as a file in
/usr/local/share/ca-certificatesplusupdate-ca-certificates.