cURL Authentication using certificates from smartcard.
Hi. In this story I will explain how to make HTTP requests in CURL using smart card certificates, in my case yubikey.
Let’s prepare certificates
I will use certificates from Let’s Encrypt for web server and self-signed CA and client certificates for authentication. Server OS — Debian GNU/Linux 12 (bookworm).
# install certbot
apt-get install certbot
# get certificate
certbot certonly --standalone -d test.qwerty1q2w.com
# Generate a private key for the CA:
openssl genrsa -out ca.key 2048
# Create the CA certificate using the private key:
openssl req -x509 -new -nodes -key ca.key -sha256 -days 20000 -out ca.crt
# Generate a private key for the client certificate:
openssl genrsa -out client.key 2048
# Create a CSR for the client certificate:
openssl req -new -key client.key -out client.csr
Create a Config File for Client Certificate Extensions. name client_cert.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
email = client@example.com # Change to the client's email or other identifiers
Sign the Client CSR with the CA.
# Use the CA to sign the client's CSR and create the client certificate:
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 1024 -sha256 -extfile client_cert.ext
# Convert the client certificate and key into a PKCS#12 file (.p12 or .pfx), which is easier to import into many clients
openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -certfile ca.crt
# Now we have the following files
client.p12
ca.crt
client.crt
client.key
Import client certificate and key to smartcard.
# sudo apt-get install yubico-piv-tool
yubico-piv-tool -a import-key -a import-certificate -s 9a -k -i client.p12 --pin-policy=once --touch-policy=cached -K PKCS12
# input p12 file password
# input mgt key
# check
yubico-piv-tool -a status
We can generate or import certificate in YubiKey Manager as well.
Certificates have been prepared.
Let’s configure a test Nginx.
Nginx configuration file. Default Nginx page
server {
listen 80;
server_name test.qwerty1q2w.com;
return 301 https://$server_name$request_uri; # Redirect HTTP to HTTPS
}
server {
# SSL configuration
listen 443 ssl;
server_name test.qwerty1q2w.com;
ssl_certificate /etc/letsencrypt/live/test.qwerty1q2w.com/fullchain.pem; # Your certificate
ssl_certificate_key /etc/letsencrypt/live/test.qwerty1q2w.com/privkey.pem; # Your private key
# Client Certificate Authentication
ssl_client_certificate /etc/ssl/ca.crt; # our self-signed CA cert
ssl_verify_client on;
root /var/www/html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
}
### It's not a production example. CRL also can be configured
Now nginx requires client certificates.
We can verify that everything works, but without a smart card for now.
curl --cert client.crt --key client.key --cacert ca.crt https://test.qwerty1q2w.com
### output
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Perform authentication with smart card
I use Ubuntu 22.04 Desktop for example.
Install packages
sudo apt-get install opensc libengine-pkcs11-openssl gnutls-bin
Get a list of tokens.
p11tool --list-tokens
# copy the url and run curl
curl -E 'pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=3169531ea57ce62f;token=test' https://test.qwerty1q2w.com
# Then the OS will request a pin code and the token will start blinking. Touch it
# you will see the http response. Hooray.
# You can also specify the pin code in the command parameters
curl -v -E 'pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=3169531ea57ce62f;token=test;pin-value=90123330' https://test.qwerty1q2w.com
Then the token will request a pin code and will start blinking. Touch it. You can disable touch request when you import or generate key on yubikey.
Hooray!
💲 💸 🪙 Got a coin for a pint? Cheers, mate!
Other stories about Yubikey.