Client Side Certificate Authentication in Nginx with Elliptic Curve Cryptography

We will setup a client side certificate authentication in Nginx with Elliptic curve cryptography using ECDSA (curve secp384r1) for certificates and a self signed Certificate Authority (CA).

Create Server Key and Certificate Signing Request (CSR) in PEM format:

1
2
$ openssl ecparam -out server_ecdsa.pem.key -name secp384r1 -genkey
$ openssl req -new -key server_ecdsa.pem.key -out server_ecdsa.pem.csr

Create CA Key and Certificate (CRT) in PEM format:

1
2
$ openssl ecparam -out ca_ecdsa.pem.key -name secp384r1 -genkey
$ openssl req -new -x509 -days 3652 -sha512 -key ca_ecdsa.pem.key -out ca_ecdsa.pem.crt

Sign server certificate with our own Certificate Authority (CA):

1
$ openssl x509 -req -days 365 -sha512 -in server_ecdsa.pem.csr -CA ca_ecdsa.pem.crt -CAkey ca_ecdsa.pem.key -set_serial 01 -out server_ecdsa.pem.crt

Create client Key and Certificate Signing Request (CSR):

1
2
$ openssl ecparam -out client_ecdsa.pem.key -name secp384r1 -genkey
$ openssl req -new -key client_ecdsa.pem.key -out client_ecdsa.pem.csr

Sign client certificate with our own Certificate Authority (CA):

1
$ openssl x509 -req -days 365 -sha512 -in client_ecdsa.pem.csr -CA ca_ecdsa.pem.crt -CAkey ca_ecdsa.pem.key -set_serial 01 -out client_ecdsa.pem.crt

Convert client Key and Certificate to PKCS:

1
$ openssl pkcs12 -export -clcerts -in client_ecdsa.pem.crt -inkey client_ecdsa.pem.key -out client_ecdsa.p12

Of course clients can generate their own key, send the CSR to the CA, the CA signs it end send certificates to clients. Then the client can generate the PKCS himself for his browser.

An example of Nginx config is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server {
listen 443 ssl http2;
server_name example.org;
root /usr/share/nginx/html/example;
index index.php index.html index.htm;
##
# SSL
##
# Certificate
ssl_certificate /etc/nginx/ssl/server_ecdsa.pem.crt;
ssl_certificate_key /etc/nginx/ssl/server_ecdsa.pem.key;
ssl_client_certificate /etc/nginx/ssl/ca_ecdsa.pem.crt;
ssl_verify_client on;
# ECC
ssl_ecdh_curve secp384r1;
# Strong cryptography
ssl_protocols TLSv1.2;
ssl_ciphers EECDH+CHACHA20:EECDH+AESGCM:EECDH+AES;
ssl_prefer_server_ciphers on;
# ssl optimizations
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:20m;
ssl_session_tickets on;
}

We can now import the client PKCS certificate (.p12) into a browser and try to reach our website or try it with openssl or curl:

1
2
3
$ openssl s_client -connect example.org:443 -key client_ecdsa.pem.key -cert client_ecdsa.pem.crt
$ curl -k --key client_ecdsa.pem.key --cert client_ecdsa.pem.crt https://example.org
Share