For excessively paranoid client authentication.
Updated Apr 5 2019:
because this is a gist from 2011 that people stumble into and maybe you should AES instead of 3DES in the year of our lord 2019.
some other notes:
I've noticed that across platforms, some browsers/devices like like PFX bundles, others like PEMs, some things will import ECC certs just fine but fail to list them in the "select certificate" menu when the server wants it. Server-side stuff seems good, with most things supporting ECC, but clients are a crapshoot. I'd say unless you've got some time to experiment, you may want to stick to RSA.
(In my own dev servers i just ended up configuring both an RSA CA and an ECC CA and using them both on the server, and provisioning one of each type for each client and trying them both. if, like nginx, your server only lets you use one CA cert root, you can concatenate multiple CA PEMs together and then use that combined file.)
This'll represent you / your org / your server -- basically the thing that vouches for the validity of a key.
# Make an elliptic curve-based key.
# support for ECC varies widely, and support for the predefined curves also varies.
# it's "secp256r1" in this case, which is as well-supported as it gets but if you want to
# avoid NIST-provided things, or if you want to go with bigger/newer keys, you can
# swap that out:
#
# * check your openssl supported curves: `openssl ecparam -list_curves`
# * check client support for whatever browser/language/system/device you want to use:
# https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations#Supported_elliptic_curves
openssl ecparam -genkey -name secp256r1 | openssl ec -out ca.key
# now generate the CA root cert
# when prompted, use whatever you'd like, but i'd recommend some human-readable Organization
# and Common Name.
openssl req -new -x509 -days 3650 -key ca.key -out ca.pem
# client_id is *only* for the output filenames
# incrementing the serial number is important
CLIENT_ID="01-alice"
CLIENT_SERIAL=01
# ec
openssl ecparam -genkey -name secp256r1 | openssl ec -out ${CLIENT_ID}.key
# whichever you picked, you should now have a `client.key` file.
# generate the CSR
# i think the Common Name is the only important thing here. think of it like
# a display name or login.
openssl req -new -key ${CLIENT_ID}.key -out ${CLIENT_ID}.csr
# issue this certificate, signed by the CA root we made in the previous section
openssl x509 -req -days 3650 -in ${CLIENT_ID}.csr -CA ca.pem -CAkey ca.key -set_serial ${CLIENT_SERIAL} -out ${CLIENT_ID}.pem
basically https://www.digicert.com/ssl-support/pem-ssl-creation.htm , with the entire trust chain
cat ${CLIENT_ID}.key ${CLIENT_ID}.pem ca.pem > ${CLIENT_ID}.full.pem
Most browsers will happily use this if they don't like the raw ascii PEM file. You'll possibly need to set a password here, which you'll need on the browser/client end when you import the key+cert PFX bundle.
openssl pkcs12 -export -out ${CLIENT_ID}.full.pfx -inkey ${CLIENT_ID}.key -in ${CLIENT_ID}.pem -certfile ca.pem
Use client.full.pfx
(most commonly accepted in GUI apps) and/or client.full.pem
. Actual instructions vary.
So that the Web server knows to ask for (and validate) a user's Client Key against the internal CA certificate.
ssl_client_certificate /path/to/ca.pem;
ssl_verify_client optional; # or `on` if you require client key
Configure nginx to pass the authentication data to the backend application:
- Client Side Certificate Auth in Nginx, section “Passing to PHP.”
- SSL module documentation
See also:
- my other gist, on doing the key / CSR dance for your HTTPS server: https://gist.github.com/mtigas/6177424
- mozilla's SSL configuration generator: https://mozilla.github.io/server-side-tls/ssl-config-generator/
(removed)