clevis-encrypt-fido2 - Encrypts using a FIDO2 token by using the hmac-secret extension for generating a symmetric key.
The clevis encrypt fido2 command encrypts using a FIDO2 token. Its only argument is the JSON configuration object.
FIDO2 is a standard for web authentication using secure tokens, such as a security key. For symmetrically encrypting data using a FIDO2 token, the token must support the hmac-secret extension. The encryption then works by generating a random 32 byte public hmac-salt that is sent to the token/authenticator, where an hmac over the salt is created using a key only known to the authenticator. This secret value is then used to as a "keyWrap" JWK.
Clevis provides support for encrypting data using such symmetric keys derived from a FIDO2 hardware token. The following shows a basic example, using the default configuration options:
$ clevis encrypt fido2 '{}' < PT > JWE
Enter PIN for /dev/hidraw0:
By default, a new (non-discoverable) credential will be generated and its credential id, as well as the randomly generated hmac-salt, is stored as metadata along with the ciphertext. Creating the credential might require entering the device PIN (as shown above) and verifying user presence by touching the token. If the "pin" option is set to true, the PIN must be entered again and at every decryption. For example:
$ clevis encrypt fido2 '{"pin": true}' < PT > JWE
Enter PIN for /dev/hidraw0:
Enter PIN for /dev/hidraw0:
The options "up" and "uv" can be used to set the desired behaviour for user presence and user verification when decrypting the ciphertext (see below). In a "headless" setup, e.g., when encrypting a LUKS partition, those could be set to "false" in order to automatically decrypt without any user actions. Note that there are currently no prompts when you need to tap on the device, but the token might signal that by blinking.
This command uses the following configuration properties:
-
type (string) : The type of the credential, as supported by libfido2, i.e., "es256", "rs256" or "eddsa". Default: "es256".
-
cred_id (string) : A base64-encoded credential ID generated with the specific token. If not specified, a new (non-discoverable) will be generated using the fido2-cred command, requiring additional verification of user presence (tapping on the token). Please note that the credential must support the "hmac-secret" extension.
-
rp_id (string) : The reyling party id of the credential (that will be created or is provided via the "cred_id" field). Default: fido2.clevis.
-
up (boolean) : Whether or not to ask the authenticator to require user presence. Default: true.
-
uv (boolean) : Whether or not to ask the authenticator to require user verification. Default: false.
-
pin (boolean) : Whether or not to ask the authenticator to require the PIN and user verification. Default: false.
-
device (string) : The device path to use (e.g., "/dev/input/by-id/my-yubikey") for encryption and for every future decryption. The device path MUST NOT start with "/dev/hid" (e.g., "/dev/hidraw5") since such paths are known to be ephemeral and not suitable to identify a specific token long term. Use the environment variable FIDO2_TOKEN instead to set the device path once without storing it as metadata (works for both encryption and decryption).
If you set both the "device" option and the env variable, then FIDO2_TOKEN will be used for encryption, but the path of "device" will be stored in the metadata.
If neither the "device" option nor the FIDO2_TOKEN env variable is specified, the first device from the list of connected tokens will be picked by default.
This option is likely needed if you want to use the "sss" pin with multiple fido2 pins.
PLEASE NOTE: Unlinkability of the ciphertext is lost if the "device" option contains an unique identifier (such as a serial number). As a user, you are responsible to make the token available under the specified path before or during the script is executed.
Default: ""
-
timeout (string) : The number of seconds to wait for a device to become available for encryption AND every future decryption. To override the timeout temporarily use the TIMEOUT env variable. Default: 50.
The following shows how you can assign your Yubikey a fixed name using its serial number in order to specify it in the "device" option (does not work with fido2-only Yubikeys).
First, create the following script at /lib/udev/yubikey-name (don’t forget to make it executable):
#!/bin/bash
# This script tries to create a deterministic name for a Yubikey. The name is "yubikey_${last two digits of serial}".
# The serial is not fully included on purpose to improve privacy. There's a non-zero chance you could have two keys
# with the same name.
#
# WARNING: This script DOES NOT work with fido2-only Yubikeys since they don't have a serial number!
YUBIKEY_NAME=""
if [[ -n "$(command -v ykman)" ]]; then
# if ykman is already running, chances are that the below "ykman --diagnose" will not yield the desired serial number (required channel might be busy)
# (this usually works if you wait five seconds between inserting two Yubikey devices, but might become a problem at boot time if they're already inserted)
OUTPUT="$(ykman --diagnose)"
SERIAL="$(echo "${OUTPUT}" | grep -B1 -A20 "${DEVNAME}" | tr '\n' ' ' | grep "HID FIDO" | sed -e 's/.*serial://' -e 's/version:.*//' -e 's/ //g')"
[[ "${SERIAL,,}" == "none" ]] && SERIAL=""
[[ -n "${SERIAL}" ]] && YUBIKEY_NAME="yubikey_${SERIAL: -2}"
fi
printf "%s" "${YUBIKEY_NAME:-unknown}"
Then, create a new udev rule (/etc/udev/rules.d/99-yubikey.rules)
ACTION=="add|change", KERNEL=="hidraw[0-9]*", ENV{ID_FIDO_TOKEN}=="1", PROGRAM="/lib/udev/yubikey-name", SYMLINK+="input/by-id/$result"
Your Yubikey should automatically be linked under a fixed path, e.g. "/dev/input/by-id/yubikey_12". This can be used as a "device" option. For example:
echo "secret message" | clevis-encrypt-fido2 {"device": "/dev/input/by-id/yubikey_12"}