Nginx – SSL client certification

certificatenginxsslverification

OS: CentOS 7

SW: NginX

Existing stuff

  • dhparam.pem
  • mydomain.com.crt
  • mydomain.com.csr
  • mydomain.com.key

Issue:

I'm trying to create a client verification by creating client certificates and then authenticate one servers requests with NginX to my destination server. However I constantly get the 400 Bad Request - No required SSL certificate was sent error message. What am I doing wrong? Here is what I did:

  • openssl genrsa -out client.key 4096

  • openssl req -new -key client.key -out client.csr

  • openssl x509 -req -days 365 -sha256 -in client.csr -CA mydomain.com.crt -CAkey client.key -set_serial 2 -out client.crt

Every command runs successfully, however, the error stays. Also in my NginX, on the destination server, I have:

ssl_certificate         /etc/nginx/ssl/mydomain.com.crt;
ssl_certificate_key     /etc/nginx/ssl/mydomain.com.key;
ssl_client_certificate  /etc/nginx/ssl/mydomain.com.crt;

NGINX Configuration:

server {
    listen 80;
    listen 443 ssl;

    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";

    ssl_certificate         /etc/nginx/ssl/mydomain.com.crt;
    ssl_certificate_key     /etc/nginx/ssl/mydomain.com.key;
    ssl_client_certificate  /etc/nginx/ssl/client.crt;

    ssl_verify_client optional;

    server_name uploads.mydomain.com;
    root /var/www/html/com.mydomain.uploads/public;

    error_log /var/log/nginx/mydomain.com/error.log;
    access_log /var/log/nginx/mydomain.com/access.log main;

    index index.php;

    rewrite ^/index\.php?(.*)$ /$1 permanent;

    location / {
        try_files $uri @rewrite;
    }

    location @rewrite {
        rewrite ^(.*)$ /index.php/$1 last;
    }

    location ~ ^/index.php(/|$) {
        fastcgi_pass unix:/var/run/php-fpm/uploads.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param SSL_CLIENT_VERIFY    $ssl_client_verify;
        fastcgi_param SSL_CLIENT_S_DN       $ssl_client_s_dn;
    }
}

Best Answer

It was a very stupid mistake and now I'm ashamed of myself.

I though that the website certificates are the same as the CA ones. So now I've created new ca.key and ca.crt files and signed the clients certificate with them and voila. :(

ssl_certificate /etc/nginx/ssl/mydomain.com.crt; ssl_certificate_key /etc/nginx/ssl/mydomain.com.key; ssl_client_certificate /etc/nginx/ssl/ca.crt;

So all the commands in order:

Create CA key and cert:

  • openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout nginx-selfsigned.key -out nginx-selfsigned.crt

Create client key and CSR

  • openssl genrsa -out client.key 2048
  • openssl req -new -key client.key -out client.csr

Sign client CSR with CA files

  • openssl x509 -req -days 3652 -sha256 -in client.csr -CA nginx-selfsigned.crt -CAkey nginx-selfsigned.key -set_serial 2 -out client.crt

OPTIONAL: Convert client.crt to a base64 encoded pem including the private key

  • openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
  • openssl pkcs12 -in client.p12 -out client.pem -nodes

HUGE NOTE! The Organization name of the CA files and Client files CANNOT BE EQUAL! Otherwise it will break and fail to authenticate.

I hope I've helped others who also as dumb as I was.