cURL Authentication using certificates from smartcard.

Dmitrii Pushkarev
4 min readJan 30, 2024

--

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!

Other stories about Yubikey.

--

--