SSL client certificate authentication returns "21:unable to verify the first certificate"
I'm in the process of transferring some of my old-and-busted apache2 web servers to newer and more resilient nginx containers.
On my old web server, I have an apache2 server that hosts secretbackdoor.example.com
, which authenticates "users" (only me) using a signed certificate. The CA is setup in the following way:
> ROOT CA (self-signed, obviously)
|--> Intermediate CA (Signed by ROOT CA)
|--> Client Certificate (Signed by Intermediate CA)
This stack overflow question showed that I can't do direct intermediate CA verification. Aside: I agree technically that nginx is right but practically, it's useful to have certificates scoped to a specific Intermediate CA....I digress.
That being said, I've followed the instructions on the question but have hit a wall. I've set ssl_client_certificate
to be the CA certificate. When I try to connect with my browser that has a client certificate, I get the following error in my error.log
file:
client SSL certificate verify error: (21:unable to verify the first certificate) while reading client request headers, client: 1.1.1.1, server: secretbackdoor.example.com, request: "GET / HTTP/2.0", host: "secretbackdoor.example.com"
I've tried using the intermediary CA in addition to setting ssl_client_certificate
to the chained certificates to no avail.
I'm running nginx using docker with letsencrypt certificates securing the traffic. I'm not sure if that's what's causing the issues, but thought it shouldn't be a problem since client certificates can and often are signed by different CA authorities.
Here is my site setup:
server {
listen 443;
server_name secretbackdoor.example.com;
ssl_certificate /etc/letsencrypt/live/secretbackdoor.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/secretbackdoor.example.com/privkey.pem;
ssl_client_certificate /etc/nginx/conf.d/certs/root_ca.pem;
ssl_verify_client on;
ssl_verify_depth 2;
# https://github.com/certbot/certbot/blob/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
include /etc/letsencrypt/options-ssl-nginx.conf;
# https://github.com/certbot/certbot/blob/master/certbot/certbot/ssl-dhparams.pem
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Any assistance would be greatly appreciated!
TLDR; include the entire certificate chain in the ssl_client_certificate
file.
I'm not sure if this will help you now, but I am able to verify client certificates issued by a tertiary CA. Here is how it is laid out:
> Root CA (self-signed, obviously)
|--> Intermediate CA (Signed by Root CA)
|--> Department CA (Signed by Intermediate CA)
|--> Client Certificate (Signed by Department CA)
The file that I use for ssl_client_certificate
has all 3 CA certs in it. I also have ssl_verify_depth
set to 3
. The other important step I took was to ensure that error_log
was set to info
and was isolated to the specific server
section I was testing. This is the error message nginx was producing when I only had part of the certificate chain in the configuration:
[info] 20996#20996: *1 client SSL certificate verify error: (21:unable to verify the first certificate) while reading client request headers, client: 10.0.1.33, server: , request: "GET / HTTP/1.1", host: "dept-connector"