I'm a big fan of throw-away certificates, i.e., self-signed certificates you may dispose of any time. It seems, the generation of proper certificates is still a mystery to some, so let me briefly include a recipe how to create them:
Create a cert-client.conf of the following form: ---------------------snip-----snip------------------------ # Client certificate request [ req ] default_bits = 4096 # RSA key size encrypt_key = yes # Protect private key default_md = sha256 # MD to use utf8 = yes # Input is UTF-8 string_mask = utf8only # Emit UTF-8 strings prompt = no # Prompt for DN distinguished_name = email_dn # DN template req_extensions = email_reqext # Desired extensions [ email_dn ] 0.domainComponent = "com" 1.domainComponent = "example" 2.domainComponent = "project" organizationName = "{{ORG}}" organizationalUnitName = "{{CUSTOMER}}" commonName = "{{NAME}}" emailAddress = "{{EMAIL}}" [ email_reqext ] keyUsage = critical,digitalSignature,keyEncipherment extendedKeyUsage = emailProtection,clientAuth subjectKeyIdentifier = hash subjectAltName = email:{{EMAIL}} ---------------------snip-----snip------------------------ Replace project.example.com and the stuff in {{...}} accordingly. I keep the domain components usually fixed for a project, while the rest is dynamically replaced with sed. Assume, you have an instance of cert-client.conf replaced properly, and it's in wherever the value of $conf points to. Assume $name is the name you want to give to this certificate. Then you create it with ---------------------snip-----snip------------------------ openssl req -new -newkey rsa:4096 -x509 -days 365 -nodes -config $conf -sha256 \ -passout "pass:" -out "$name.pem" \ -keyout "$name.key" openssl pkcs12 -export \ -inkey "$name.key" -in "$name.pem" \ -passin "pass:" \ -out "$name.pkcs12" \ -passout "pass:" \ -name "$name" openssl x509 -text -noout -in "$name.pem" \ -passin "pass:" > "$name.info" ---------------------snip-----snip------------------------ This creates a PEM file (public key), key file (private key), and pkcs12 file (certificate). For Chrome and Firefox, use the respective configuration tool of the browser to introduce this as a new personal certificate. For IE, it is sufficient to import the certificate into the Windows certificate store. For the server side of TLS, I usually use something of this sort: ---------------------snip-----snip------------------------ # SAN certificates are defined once on the http context level # ssl_certificate /etc/nginx/certs/fullchain.pem; ssl_certificate_key /etc/nginx/certs/private.pem; ssl_protocols TLSv1.2 TLSv1.3; # TLSv1.3 requires openssl 1.1.1 or later. This tries to enable 0-RTT. #ssl_early_data on; # Prefer the faster Diffie Hellman Parameters over slower RSA algorithms # ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; ssl_prefer_server_ciphers on; ssl_ecdh_curve secp384r1; # openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096 ssl_dhparam /etc/nginx/certs/dhparam.pem; # SSL session parameters # ssl_session_cache shared:SSL:36m; ssl_session_timeout 3m; ssl_session_tickets on; ssl_session_ticket_key /etc/nginx/certs/ticket.key; ssl_session_ticket_key /etc/nginx/certs/ticket.key.old; ---------------------snip-----snip------------------------ with fullchain.pem being the public keys of the certificate chain, starting with the most specific, i.e., the server's SAN certificate. I use a little awk script to re-arrange public keys in the proper order - from the output of a "openssl pkcs7 -print_certs ..." and with dhparam.pem generated by openssl dhparam -out /etc/nginx/certs/dhparam.pem 4096 and ticket.key generated by openssl rand 80 > /etc/nginx/ticket.key Next thing is that TLS can only be switched on per server, not per location. I generally don't like SNI, so I prefer to have SAN certificates for servers. ---------------------snip-----snip------------------------ server { listen 443 ssl; server_name ...{all the names you need}...; ssl_trusted_certificate /etc/nginx/certs/clients.pem; ssl_verify_client optional_no_ca; ssl_verify_depth 1; ... } ---------------------snip-----snip------------------------ will do the trick, if clients.pem is simply a concatenation of all .pem files you have produced earlier (the public keys of clients who are supposed to have access). Note that I use the directive "ssl_trusted_certificate", so the list of permitted CAs is not communicated, but rather the client has to present a certificate. There is no requirement to use any specific CA. As each certificate is self-signed, the "CA" (issuer) of each certificate is the certificate itself. You may now check in the nginx.conf or in a Javascript handler what the client status is: $ssl_client_verify will be NONE if no certificate was presented, SUCCESS if the client specified one of the permitted certificates, and FAILED... if there was some failure. Once this is done, you can check $ssl_client_s_dn to find out who was authenticated. You may use a map directive to map this variable to the e-mail address from the certificate's DN, or look at any one of the other attributes. What you can query you'll find here: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#variables This should be a complete recipe on how to set up working self-signed client certificates. If this works, you may play with other options :-) Cheers, --j. Posted at Nginx Forum: https://forum.nginx.org/read.php?2,285456,285481#msg-285481 _______________________________________________ nginx mailing list nginx@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx