Nginx – SSL Client Certificates and NginX

curlnginxopenssl

I followed the instructions in this blog post, but when I test it with curl, nginx's $ssl_client_verify variable is always NONE. In fact, curl doesn't even give different output when I don't specify the --cert and --key options at all. It's as if it's ignoring my certs. How can I debug this?

I even tried making it so all of these places have the same value:

  • The Common Name on the CA and Server certs
  • The Server's hostname
  • NginX's virtual host name
  • The server's reverse DNS name

Best Answer

If by "Common Name" in CA and Server certs you mean the entire Subject name, which can contain other items besides Common Name although most people doing ad-hoc SSL certs like this don't bother with them, is the same -- don't do that. OpenSSL, which both nginx and curl use, cannot chain a child cert to a parent that has the same name; this is not a normal case in X.509 and may not be handled at least in general in other software either.

  • The CA cert should have as Subject (which automatically is also Issuer, since this is a root, see below) a name which is a name for the CA -- this doesn't need to be a domain name, but can be if you like.
  • The (SSL) server req and cert should have as Subject.CommonName the domain name of the server, which can be a wildcard if the server has multiple but closely related domain names, or the IP address if all clients will access by address (which in practice works only if the clients are all your very close coworkers or friends). The Issuer name in the server cert is automatically set to the CA name.
  • Similarly the/each client req and cert should have a Subject name different from the CA name, and Issuer becomes the CA name. If you want the client certs to securely identify the clients, which is presumably the purpose of this exercize, each client cert should have a name different from every other client cert, and preferably different from the server cert to avoid confusion.

With that I believe it should work. A more basic and probably better test tool is openssl commandline:

openssl s_client -connect $addr:$port -cert $clicert -key $clikey -CAfile $cacert 

which will output detailed information about the (attempted) SSL/TLS connection. If fairly near the end it says Acceptable client certificate CA names followed by the correct name of your CA, the server is setup correctly for client auth (as well as basic SSL). If it has some other name, or says No client certificate CA names sent, something is wrong. When s_client waits for input just enter EOF (Unix usually ^D, Windows ^Z).

Aside: the website is wrong to say signing the server request with your self-created ad-hoc CA key&cert is "self signing". Self-signing is specifically signing a cert with the same keypair whose public half is in that cert; in practice this is used only of a toplevel CA, called a "root". You are signing your server cert with your own CA, but you are not self-signing. Signing your server cert with your own CA is bad if you want to handle connections from strangers because it doesn't provide them any evidence to trust your server the way a "commercial" server cert from a well-known CA like Verisign or GoDaddy does. That is commonly the case for production as opposed to test, since test is often used only by developers and/or few beta testers, but some production systems can also be limited to few closely-related clients.

EDIT: getting ad-hoc CA (for client certs) signed by well-known CA: this would be difficult and expensive and is not necessary.

If a well-known CA gives you a "sub-CA" or "intermediate CA" cert allowing you to issue certs, they are betting the future of their business on your security -- so either you must provide security at the same level they do (custom hardware, specialized buildings, armed guards around the clock, multiple specially trained and certified personnel, regular external audits -- all expensive) or you have to buy out their business (so they are no longer at risk). In addition to your https://security.stackexchange.com/questions/25551/help-understanding-client-certificate-verification see:

But the only systems that need to trust the certs you issue your clients are your own servers; as long as you control your own servers you just configure them to trust your own CA cert.