FIDO is based on Public Key Cryptography. However, it does not use a Public Key Infrastructure (PKI), (except when using Device Attestation). Instead, FIDO uses raw keys, much like SSH does.
However, it can make sense to embed public keys from FIDO credentials in traditional X.509 certificates, for instance when verifiers are offline and there are many verifiers leading to a key distribution issue.
With a PKI, verifiers can be offline: they do not need to synchronize individual public keys. Instead, a Certification Authority (CA) certifies public keys and a verifier only needs a CA public key to validate a prover's certificate carying a public key.
This directory contains a small Proof-of-Concept where a certificate is issued carying a FIDO credential's public key. The certificate is stored as a largeBlob on a FIDO security key.
Hardware:
- a FIDO security key with largeBlob support. Any YubiKey with firmware version 5.5 and newer will work.
Software:
- OpenSSL
- Python
- libfido2 tools
Note that the PoC code is only tested on macOS.
This demo uses python to read the largeBlob from the security key, using the python-fido2 library. That library can be installed using a python VirtualEnv:
python3 -m venv venv
. venv/bin/activate
pip install fido2
We use a very simple CA, consisting of a CA key and CA Root certificate. To generate:
openssl genpkey -algorithm EC -out cakey.pem -pkeyopt ec_paramgen_curve:P-384 -pkeyopt ec_param_enc:named_curve
openssl x509 -new -key cakey.pem -subj '/CN=Example CA' -extfile /path/to/openssl.cnf -extensions v3_ca -out cacert.pem
The openssl.cnf
file that comes with your distribution can be found in the OPENSSLDIR
directory.
To locate that directory, use:
openssl version -a
A simple script is used to generate both the FIDO credential and the X.509 certificate issued by our CA:
./issue.sh
The script will ask for the PIN twice: first to create a FIDO credential and then to store the X.509 certificate as a largeBlob on a security key.
A simple script is used to retrieve the X.509 certificate from the FIDO security key, to generate an assertion, and to validate that assertion using the certificate:
./assert.sh
The scripts store a credential and a certificate on a security key. To clean up:
Delete the FIDO credential:
fido2-token -D -b -n localhost ${HID}
Delete the largeBlob associated with your FIDO credential:
fido2-token -D -i $(fido2-token -Lk localhost ${HID} | cut -d' ' -f2) ${HID}
Note that the environment variable HID
stands for the device ID of your security key.
To define HID
for the first security key found:
HID="$(fido2-token -L | tail -1 | cut -d: -f1-2)"
Below are some hints for troubleshooting.
Make sure you are using a FIDO security key with largeBlob support.
To check for largeBlob support:
fido2-token -I "${HID}" | egrep -o largeBlobs
You may need to disable alwaysUV
if creating assertions fail:
fido2-token -D -u $HID
To check the status of your key's alwaysUV setting:
fido2-token -I "${HID}" | egrep -o -e largeBlobs -e '(no)?alwaysUv'
X.509 certificates can contain extension attributes. These attributes can cary arbitrary information, typically metadata about the subject or the public key embedded in the certificate.
One example would be a Physical Access Control (PAC) system where a card ID is stored, similar to a Mifare Chip Serial Number (CSN)
This PoC simply issues a certificate from a script. As FIDO is designed for the web, the credential can be generated using the WebAuthn API from a web page. Modern browsers like Chrome and Edge also support the WebAuthn largeBlob extension, meaning that the certificate can be issued from a web page. This is typically not possible with traditional smart cards without installing additional middleware!
The benefit of having a PKI is to be able to validate assertions without a network connection. The downside is that revocation is a problem. Revocation is not part of FIDO, but it is part of a PKI using OCSP transponders or Certificate Revocation Lists (CRLs).
Without a network, OCSP is not possible. CRLs however can be used if network connectivity is available at certain intervals, when CRLs can be synchronized.