Skip to content

Instantly share code, notes, and snippets.

@daemonhorn
Last active November 8, 2024 02:40
Show Gist options
  • Save daemonhorn/bdd77a7bc0ff5842e5a31d999b96e1f1 to your computer and use it in GitHub Desktop.
Save daemonhorn/bdd77a7bc0ff5842e5a31d999b96e1f1 to your computer and use it in GitHub Desktop.
Setting up yubikey/solo2 for piv, fido, and gpg on FreeBSD (Firefox, Chromium, PAM, SSH, and GnuPG)

Overview

How to configure FreeBSD and applicable applications to work with Yubikey for authentication. This serves as my work-in-progress documentation of the configuration knobs needed to make this work properly.

  • FreeBSD ssh with piv smartcard slot on Yubikey (pkcs11 via libykcs11.so)
  • FreeBSD ssh with fido support on Yubikey
  • FreeBSD Firefox/Chromium with fido + webauthn support on Yubikey
  • FreeBSD local console and gdm authentication using pam on Yubikey
  • FreeBSD official YubiKey tools

Latest Tested FreeBSD versions

  • FreeBSD 13.2 Testing (Aug 2023)
  • FreeBSD stable/13 Testing (Aug 2023) with OpenSSH_9.3p2
  • FreeBSD stable/14 Testing (Oct 2023) with OpenSSH_9.5p1, OpenSSL 3.0.11, and libfido2 1.13

Yubikey PIV Slot Names and numbers

Slot Number Slot Name Default Touch policy Default PIN Policy Notes
9a PIV Authentication never Cached (once) System login slot
9c Digital Signature never Required (always) Document/object signing
9d Key Management never Cached (once) Encrypting Emails/objects/files
9e Card Authentication never Not Required (never) Physical Access
82-95 Retired Key Management never key/cert slots in Y4/Y5 only, originally designed to backup old 9d encryption keys for archival
f9 Attestation never Not a standard slot, used for Attestation of other keys only. Requires f/w 4.3+
9b Managment never always Not a standard slot, Used for master management key

FreeBSD SSH with piv smartcard slot and pkcs11 on Yubikey

Read the excellent documentation here: https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html.

Initial Yubikey piv key generation (If not already done)

  • If you need to do initial configuration or generate piv keys/certs follow these steps (save your PIV pin and puk somewhere safe). If you have already customized pin/puk, you can skip this step. Example below is the default pin/puk after piv applet reset, do not use the defaults for the new values for obvious reasons. yubico-piv-tool can be used with an alternate syntax for the same functions, but ykman is the more actively supported/recent admin toolchain. Note: yubico-piv-tool is required to install the libykcs11.so module
pkg install -g py3*-yubikey-manager
ykman piv access change-pin --pin 123456
ykman piv access change-puk --puk 12345678
  • If you need to configure management key, and some piv-specific objects for better compatability. Use aes256 instead of default tdes for management (if f/w 5.4.0+), and save the management key on the yubikey protected by pin and touch. If you have f/w < 5.4.0, omit -a aes256, as the only supported management key algorithm was tdes .
ykman piv access change-management-key --generate --protect --touch -a aes256
ykman piv objects generate chuid
ykman piv objects generate ccc
ykman piv info
ykman piv keys generate -a eccp384 --pin-policy once --touch-policy cached 9a 9a_pub.pem
ykman piv certificates generate --valid-days 730 --subject "Y5C_9A" 9a 9a_pub.pem

Setup FreeBSD packages, services, and ssh client configuration

  1. Install the FreeBSD yubikey pkcs11 YKCS11 shared library
  • using pkg utility, install Yubico utilities and shared library /usr/local/lib/libykcs11.so for full functionality (other pkcs11 libs can work as well, but untested for this writeup.)
  • Don't forget the ccid usb driver package, or pcsc-lite and libykcs11.so will not find your USB keys at all
  • Detailed information about YKCS11 here: https://developers.yubico.com/yubico-piv-tool/YKCS11/
  • There are cases where other utilities (like scdaemon from gpg) can lock the USB port, try removing/re-inserting the Yubikey if yubico-piv-tool -a status does not find your device.
pkg install yubico-piv-tool pcsc-lite ccid
  • Setup pcscd to startup on boot (changes /etc/rc.conf for you), and manually start now
service pcscd enable
service pcscd start
  • Insert (or remove, then insert) Yubikey, and test ability to connect to USB device with yubico_piv tool This command should display your Yubikey version, serial number, configured slots, and pin tries left if successful.
yubico-piv-tool -a status
  1. Extract public key (ecc or rsa) and save to id_rsa.pub, and copy to destination user@host authorized_keys file. (change user@host to a real host you have ssh access to). Note: This command will export all piv keys stored on the YubiKey. The slot order should remain the same, thereby facilitating identification of the public key associated with your targeted private key.
umask 077
ssh-keygen -D /usr/local/lib/libykcs11.so > ~/.ssh/id_pkcs11.pub
ssh-copy-id -i ~/.ssh/id_pkcs11.pub user@host
  1. Test out connectivity using ssh (change user@host to a real host you have ssh access to)
ssh -v -I /usr/local/lib/libykcs11.so user@host
  1. Configure ssh for current user to automatically load pkcs11 library without long CLI (can also be global if you want via /etc/ssh/ssh_config)
echo "PKCS11Provider	 /usr/local/lib/libykcs11.so" >>~/.ssh/config
  1. (optional) use with ssh-add and/or ssh-agent (will prompt for pin aka passphrase)
ssh-add -s /usr/local/lib/libykcs11.so
  1. (optional) limit which PKCS11 slot keys are being used (default is all keys until #PKCS11 URI support is added) This requires having a seperate Identity public key file for the specific key you want to allow). This support requires OpenSSH 8.3+ to work properly in all of the cases.
  • Create a ~/.ssh/id_pkcs11_slot9a.pub file with only the Public key for PIV Authentication (Slot 9A) by editing with vi and removing non-desired keys.
cp ~/.ssh/id_pkcs11.pub ~/.ssh/id_pkcs11_slot9a.pub
vi ~/.ssh/id_pkcs11_slot9a.pub
  • Create an ~/.ssh/config file with the IdentitiesOnly yes stanza (customize as desired) See https://man.openbsd.org/ssh_config for more information on syntax and alternate options.
Host *
IdentitiesOnly yes
IdentityFile ~/.ssh/id_pkcs11_slot9a.pub
PKCS11Provider /usr/local/lib/libykcs11.so

You can also customize per-instantiation with the ssh -i <identity> -o IdentitiesOnly=yes <user@host> syntax as desired

 ssh -i ~/.ssh/id_pkcs11_slot9a.pub -o IdentitiesOnly=yes -I /usr/local/lib/libykcs11.so user@host

FreeBSD ssh with FIDO support on Yubikey

Starting with OpenSSH 8.2p1+ release, there is native support for FIDO authenticators (like Yubikey) for authentication using some new key formats. Background information here: https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html and https://www.openssh.com/txt/release-8.2. Resident keys are best supported on the latest OpenSSH. All key types should require a PIN to be configured on the token.

  • New Terms: Resident credentials are called “discoverable credentials” in CTAP 2.1.
  • Yubikey firmware version 5.2.3 or newer is required for ed25519-sk key types (and is supported by both recent BLUE security key variant and recent Yubikey 5 variants)
FIDO Device FIDO Device Version Key Algorithms [Non-]Resident Notes
Yubikey Neo f/w 3.4.9 ecdsa-sk Non-Resident YSA-2018-01 in OATH, does not impact FIDO
Yubikey Neo f/w 3.5.0 ecdsa-sk Non-Resident
Yubikey 5 f/w 5.1.1 ecdsa-sk Non-Resident
Yubikey 5 f/w 5.2.3+ ed25519-sk ecdsa-sk Both
Yubikey 4 f/w 4.3.1 ecdsa-sk Non-Resident CVE-2017-15361 in rsa, but does not impact FIDO
Yubikey 4 f/w 4.3.5 ecdsa-sk Non-Resident
Yubikey FIDO U2F Security Key (BLUE) f/w 3.0.0 ecdsa-sk Non-Resident
Yubikey FIDO2 Security Key NFC (BLUE) f/w 5.4.3 ed25519-sk ecdsa-sk Both
Yubikey FIDO2 Bio f/w 5.5.6 ed25519-sk ecdsa-sk Both Requires enrolling Fingerprints with ykman fido fingerprints add ...
Solo 2 f/w 20220822+ ed25519-sk ecdsa-sk Both Update your firmware from solo
  1. Check your OpenSSH client version and make sure it is new enough (recommend 8.9+) ssh -V (If it is older than 8.9+, consider pkg install openssh and execute ssh-keygen from /usr/local/bin/ssh-keygen)
  2. Install libfido2 shared library, u2f-devd rules, and askpass utility (OpenSSH FIDO runtime dependancies):
 pkg install -g libfido2 OpenSSH-askpass u2f-devd py3*-fido2
  1. If you have not already, configure your user for u2f group privs, and your Yubikey token for a pin.
  • Add local user to new u2f group to allow access to usb device mappings created by u2f-devd package. pw group mod u2f -m user (replace user with your actual username) Failure to add your user to the correct u2f group will result in that user not being able to access the USB device/YubiKey with fido2-token and other fido tools. Reboot or (restart devd and remove/re-insert yubikey and logout/login after permissions change).
service devd restart            #Don't forget to remove and re-insert Yubikey after restart
  • Auto-detect uhid/hidraw device assigned to attached Yubikey: If no results are returned from fido2-token -L, permissions or device mapping devd rules are incorrect. Turn up verbose mode, attempt with root account, etc.
 fido2-token -L                  #Query for uhid/hidraw device.  Requires user to have permissions to /dev/uhidXX or /dev/hidrawYY
  • Add an initial pin to the FIDO app (You can skip this step if FIDO pin already set) on the Yubikey. (replace /dev/uhid2 with actual device returned from fido2-token -L command):
 fido2-token -S /dev/uhid2
  • Display supported protocol versions, extensions, and existing resident keys (replace /dev/uhid2 with actual device returned from fido2-token -L command):
 fido2-token -I /dev/uhid2       #List supported protocols/extensions
 fido2-token -L -r /dev/uhid2    #List existing resident keys
  1. Generate the ed25519-sk OR ecsda-sk key (resident or non-resident) on the Yubikey. Replace FIDO2_Y5C with your own friendly name as desired:
    • Resident ed25519-sk: (This will prompt touch, but not PIN during authentication, PIN only required for generation)
    ssh-keygen -t ed25519-sk -O resident -O application=ssh:FIDO2_Y5C
    
    • Resident ecdsa-sk: (This will prompt for PIN and touch during generation and authentication)
    ssh-keygen -t ecdsa-sk -O resident -O application=ssh:FIDO2_Y5C -O verify-required
    
    • Non-Resident ed25519-sk: (This will generate a non-resident/non-discoverable ed25519 key that can not be extracted onto a new machine with ssh-keygen -K) Note: Even with a non-resident key, only the key-handle is stored in the resultant .ssh/id_ed25519_sk file, and you can not authenticate without the Yubikey/FIDO on-device private key material. Example below also disables the requirement for touch using optional -O no-touch-required parameter. See https://man.openbsd.org/ssh-keygen#FIDO_AUTHENTICATOR and https://man.openbsd.org/sshd.8#no-touch-required. Additional Note: no-touch-required also requires an equivalent change to prefix the string no-touch-required to the ssh server users' authorized_keys entry to disable user-presence validation (uv). This can be done before running ssh-copy-id by modifying the resultant id_ed25519_sk.pub file as shown below with a one-liner sed to prepend no-touch required to the public key file id_ed25519_sk.pub.
    umask 077
    ssh-keygen -t ed25519-sk -O no-touch-required
    sed -i '' s/^sk-/no-touch-required\ sk-/1 ~/.ssh/id_ed25519_sk.pub
    ssh-copy-id -i ~/.ssh/id_ed25519_sk <user@host>
    
    • Non-Resident ecdsa-sk: (This will generate a non-resident/non-discoverable ecdsa key that can not be extracted onto a new machine with ssh-keygen -K)
    umask 077
    ssh-keygen -t ecdsa-sk -O no-touch-required
    sed -i '' s/^sk-/no-touch-required\ sk-/1 ~/.ssh/id_ecdsa_sk.pub
    ssh-copy-id -i ~/.ssh/id_ecdsa_sk <user@host>
    
  • -C "FIDO2_Y5C" (or other string identifier) can be appended to the ssh-keygen cli arguments as desired to add a comment to give context to the owner/key. This will replace the default user@domain syntax in the resultant .pub key files as well. This works with both Resident and Non-Resident key generation since it is just a comment.
  • Note: This will generate the private key with a specific SSH_SK_VERSION_MAJOR embedded, and you may only be able to extract the private key handle on a different host when the version is the same or newer (or when OpenSSH SSH_SK_VERSION_MAJOR is stable) Moving the public key around to different versions should not be an issue. YMMV. Windows ssh-keygen 8.9 and FreeBSD ssh-keygen 9.0 seem to be compatible. The purposeful changes to the middleware interface/version happened at OpenSSH version 8.4 and 8.9. I have not seen any issues since upgrading to OpenSSH 9.0+ with recent releases of FreeBSD.
  1. Copy resultant public key to remote host as desired: (Change user@host to applicable remote host)
ssh-copy-id -i ~/.ssh/id_ed25519_sk user@host
  1. Optional Configuration
  • Extract resident key on a new local box for use with FIDO/SSH:
 cd ~/.ssh/ && ssh-keygen -K

or cd ~/.ssh/ && /usr/local/bin/ssh-keygen -K (if you are using from ports) Note: If you enable the kernel driver for the new hidraw device, ssh-keygen may require an optional flag to manually specify the device entry. ssh-keygen -K -v -O device=/dev/hidraw3 is one example of the required syntax. Using the -v verbose flag will give you a better error message like debug1: ssh-sk-helper: sshsk_load_resident failed: device not found when it can not find the device (or lacks permissions) instead of the default Provider "internal" returned failure -4. Try using root, and manually specifying the device reported by fido2-token -L.

  • Rename your private and public key files (as desired) to match ssh_config of id_ed25519_sk[.pub] or id_ecdsa_sk[.pub] as extracting Resident keys with -K attempts alternate naming by default to avoid collisions.
  • Control touch-required, no-touch-required, verify-required, no-verify-required on a destination host
    • Default is touch-required, no-verify-required unless otherwise configured.
    • Using no-touch-required during ssh-keygen option does not embed this directive in the resultant .pub file Bug ? which will result in an authentication failure if the public key is copied to a destination ssh host without prefixing no-touch-required to the authorized_keys entry for the applicable key. Fix is to just add no-touch-required prefix on the public key file just after generation, but before copying to a destination host. (see above example cat/sed/cp)
    • OpenSSH supports per-key configuration in ~/.ssh/authorized_keys files, and global settings in /etc/ssh/sshd_config
    • See https://man.openbsd.org/sshd.8#AUTHORIZED_KEYS_FILE_FORMAT and https://man.openbsd.org/sshd_config#PubkeyAuthOptions for details.
  • Limit which keys are being used for ssh since there is a (default) maxium of 6 authentication attempts. If you have more than 5 keys on your combined list (Yubikey PIV + Yubikey FIDO + id_* keyfiles), you can auth fail before the latest key/password is attempted. This support requires OpenSSH 8.3+ to work properly in all of the cases. Example below assumes id_ed25519_sk identity file. Create an ~/.ssh/config file with the IdentitiesOnly yes stanza (customize as desired).
  • See https://man.openbsd.org/ssh_config#IdentityFile for more information on syntax and alternate options.
Host *
IdentitiesOnly yes
IdentityFile ~/.ssh/id_ed25519_sk

You can also customize per-instantiation with the ssh -i <identity> -o IdentitiesOnly=yes <user@host> syntax as desired. Don't forget about -v to debug what keys are being offered. Also, reminder that -o (lowercase) is used with ssh, and -O (uppercase) is used for options with ssh-keygen.

 ssh -v -i ~/.ssh/id_ed_25519_sk -o IdentitiesOnly=yes user@host
  • Note: You can install OpenSSH v9.3+ from pkg into the /usr/local/bin path if you are running an older base FreeBSD version and need the updated ssh-keygen to support. The relevant error message when calling ssh-keygen with disparate SSH_SK_VERSION_MAJOR variants is "invalid format" on windows and "unsupported xxxx" on FreeBSD. Note: Reminder to run /usr/local/bin/ssh-keygen if you install from ports/pkg.
  1. (debugging) FIDO2 diagnostics using fido2-token pkg install -g py3*-fido2 (To install package) fido2-token -L (To list out current FIDO2 tokens and associated devicenames eg: /dev/uhid0) fido2-token -I /dev/uhid0 (To show current device configuration and capabilities) fido2-token -L -r /dev/uhid0 (To show currently configured resident credentials for FIDO eg: ssh:FIDO2_Y5C)
  2. Known issues/workarounds.
pcsc-shared
disable-ccid
  • You can debug by running pcscd -f (foreground) and watching for errors.
  • Additional known issues around gpg2/pcsc port contention: drduh/YubiKey-Guide#277

FreeBSD Firefox/Chromium with fido2 + webauthn support on Yubikey

This assumes that the user already has a working Xorg/gnome/gdm/dbus configuraton on FreeBSD. If you need help with this part, start with the FreeBSD handbook here: https://docs.freebsd.org/en/books/handbook/x11/

  1. Install libu2f-host, u2f-devd packages and firefox and/or chromium pkg install libu2f-host u2f-devd firefox chromium
  2. Add local user to new u2f group to allow access to usb device mappings created by u2f-devd package. pw group mod u2f -m user (replace user with your actual username,)
  • Failure to add your user to the correct u2f group will result in that user not being able to access the USB device/YubiKey
  1. (optional) Restart the devd service if you want to test before rebooting service devd restart
  2. Confirm Yubikey is detected and applicable permissions granted:
  • usbconfig show_ifdrv should result in something like this:
ugen3.10: <Yubico YubiKey OTP+FIDO+CCID> at usbus3, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (30mA)
ugen3.10.0: ukbd0: <Yubico YubiKey OTP+FIDO+CCID, class 0/0, rev 2.00/5.27, addr 9>
ugen3.10.1: uhid0: <Yubico YubiKey OTP+FIDO+CCID, class 0/0, rev 2.00/5.27, addr 9>
  • Make sure that pwr=ON is displayed for the master device (ugen3.10in this case.)
  • Make sure that FIDO is displayed for the uhid device (may require reconfiguring your Yubikey with ykman)
  • Make sure that the device name (uhid0 in this case) has the correct group permissions ls -alF /dev/uhid0 should result in something like: crw-rw-r-- 1 root u2f 0xc1 Aug 28 12:34 uhid0
  • If the group u2f is not setup, verify your u2f-devd rules/package configuration
  1. Startup X and launch Firefox or Chromium
  2. Go to a website that has 2FA/Webauthn enabled (like github/gitlab/gmail)
  • Firefox will display a little popup notification telling you that your browser is requesting Webauthn access
  • Touch the Yubikey gold disk button when it starts blinking

FreeBSD local console and gdm authentication using pam_pkcs11 on Yubikey

Overview: PAM (Pluggable Authentication Modules) are supported for various services on FreeBSD and Linux. There is an open source implementation of pam_pkcs11 that provides a glue layer to allow PAM to query a configured pkcs11 library and module to authenticate using a PCS#11 token (like a Yubkikey PIV card slot). I chose a simple demonstration configuration below to allow public keys that are already in place (e.g. openssh ~/.ssh/authorized_keys) to be the authority. This was convienient since I already using PIV keys to authenticate using SSH, now I can use the same public/private keys to control authentication on the local console and Xorg/GDM as well.

  1. Install supporting pam_pkcs11 and libykcs11.so modules from FreeBSD package manager: pkg install yubico-piv-tool pam_pkcs11 ccid pcsc-lite will install the desired packages
  2. Verify normal remote ssh works for a local (non-root) user authenticating using piv public/private SSH keys on your Yubikey. If this does not yet work, please follow the receipe above. Keep an active console (or two!) with root access live during testing so you can adjust/revert things without locking yourself out. You have been warned. Take backups/precautions as necessary.
  3. Configure pam_pkcs11 configuration files.
# Take a look at the example configuration to use different certificate/signature validations
mkdir /usr/local/etc/pam_pkcs11
cp /usr/local/share/doc/pam_pkcs11/pam_pkcs11.conf.example /usr/local/etc/pam_pkcs11/
cd /usr/local/etc/pam_pkcs11/
vi pam_pkcs11.conf
  • Minimal /usr/local/etc/pam_pkcs11/pam_pkcs11.conf using openssh-style authenication (copy/paste contents below should be fine)
pam_pkcs11 {
  use_pkcs11_module = ykcs11;
  debug = false;

  pkcs11_module ykcs11 {
    module = /usr/local/lib/libykcs11.so
    description = "Yubico Yubikey PKCS#11 so module";
    slot_description = "none";
    cert_policy = signature;
    token_type = "Smart card";
  }

  use_mappers = openssh;
  # Search public keys from $HOME/.ssh/authorized_keys to match users
  mapper openssh {
        debug = false;
        module = /usr/local/lib/pam_pkcs11/openssh_mapper.so;
  }
}
  1. Configure /etc/pam.d/system configuration file. Take a backup first cp /etc/pam.d/system /etc/pam.d/system.good Prepend auth sufficient /usr/local/lib/security/pam_pkcs11.so to the top of the configuration file
  2. Test to ensure that you can authenticate any/all user(s) with valid authorized_keys file. If things do not work they way you would like, remove the yubikey, and the fallback authentications (password) in the pam system file should take effect. Note: Different keys slots (9a/9c/9d/9e) have different pin-policy and touch-policy defaults and settings. You can adjust as desired with Yubikey Manager, but only at private key generation time, not after a key has already been generated without deleting then re-creating keys. If you want to use slots other than 9a (slot 0 in pam_pkcs11.so parlance), you will have the most luck using the yubico libykcs11.so library. Using other libraries for pkcs11 can work, but YMMV, and extended features can be limited.
  3. (optional) Force smartcard-only authentication by changing sufficient to required , then comment out the #auth required pam_unix.so no_warn try_first_pass nullok line to force smartcard authentication only. You will be unable to login with any account that lacks an appropriate ~/.ssh/authorized_keys file that maps to your local Yubikey authentication. This includes loss of access to the root account. Also recommend having at least two Yubikeys (one on person, one stored in safe) to prevent a lost/damaged key from preventing access. Please be careful, especially if using encrypted root filesystem!
  4. Test using all normal acccess methods to ensure no unexpected behavior(s). If things go horribly wrong, boot into single-user mode and adjust /etc/pam.d/system back to the original state.
  • Debugging: You can turn on the debug flags debug = true; in /usr/local/etc/pam_pkcs11/pam_pkcs11.conf to see lots more details on what is going on with both pkcs11 libraries, and with the openssh match backend as desired.

SSH with multiple key providers [SK(FIDO2)+PKCS11(PIV)+RSA] Corner Cases / Sharp edges

SSH Provides for a variety of supported scenarios for public/private key utilization, but it can be confusing to debug when you are using multiple.

fido2-token -L -r `fido2-token -L | egrep -o -e '/dev/hidraw[0-9]+' -e '/dev/uhid[0-9]+'`

Troubleshooting error in libcrypto

If you see the error message error in libcrypto next to the Load key line, or if you do not get prompted for a pin...

  1. Disconnect your yubikey from the device (unplug)
  2. Run ssh with verbose flag (e.g. ssh -v user@host)
  3. Check for the "flashing gold disk" on the physical yubikey. The slot may have been configured for presence detection/touch during original key generation.

Debug what keys are being used for an interactive ssh session

ssh -v user@host

This will display verbose output indicating what indentity files(e.g. id_rsa, id_ecdsa, id_ed25519,id_ecdsa_sk, id_ed25519_sk), PKCS11 provider, keys, and key hashes will be used during that session. For OpenSSH sshd, the default MaxAuthTries is 6, so be careful of too many keys.

  • See https://man.openbsd.org/sshd_config#MaxAuthTries for additional information on sshd configuration If you have too many private keys, the number of authentication attempts may exceed the /etc/sshd_config allowed configuration. This can also be impacted by ssh-agent forwarding from another host. If you use ssh-agent for key storage, you can list the current active keys with
ssh-add -L  #List public keys - capital L
ssh-add -l  #List hash of public keys - lowercase l

Use Yubikey with VMWare ESXi/Workstation

When your Yubikey device does not show up properly in a virtualized OS, check: https://support.yubico.com/hc/en-us/articles/360013647640-Troubleshooting-Device-Passthrough-with-VMware-Workstation-and-VMware-Fusion then add to your ESXi VM advanced configuration (VM must be powered down), or .vmx file in Workstation. You can control the USB attach from the console client (recommend stand-alone VMWare Console 12.0+ for ESXi/VCenter). Do NOT use the Shared Smartcard or Shared Yubico options as they are not supported for these use cases.

usb.generic.allowHID = "TRUE"
usb.generic.allowLastHID = "TRUE"

Check Supported key signatures

You can determine what key signature types supported by any version of OpenSSH using:

ssh -Q key-sig
  • Example output from FreeBSD 14 (stable/14) as of OpenSSH_9.3p2. Remember that both sides (client/server) must support a key-sig for it to be utilized. All of the sk-ssh*, and sk-ecdsa*, and webauthn-sk* types are "Security Key" or FIDO.
ssh-ed25519
[email protected]
[email protected]
[email protected]
ecdsa-sha2-nistp256
[email protected]
ecdsa-sha2-nistp384
[email protected]
ecdsa-sha2-nistp521
[email protected]
[email protected]
[email protected]
[email protected]
ssh-dss
[email protected]
ssh-rsa
[email protected]
rsa-sha2-256
[email protected]
rsa-sha2-512
[email protected]

FreeBSD official YubiKey tools

YubiKey Manager (ykman)

  • Python 3.9 version as of Aug 2022, 3.11 for newer variants. pkg install -g py3*-yubikey-manager pcsc-lite ccid
  • Enable and Startup pcsc daemon service pcscd enable && service pcscd start
  • Check status of Yubikey using ykman ykman info should result in something like this:
Device type: YubiKey 5C NFC
Serial number: XXXXX
Firmware version: 5.2.7
Form factor: Keychain (USB-C)
Enabled USB interfaces: OTP, FIDO, CCID
NFC transport is enabled.
Configured capabilities are protected by a lock code.

Applications	USB          	NFC          
FIDO2       	Enabled      	Enabled      	
OTP         	Enabled      	Enabled      	
FIDO U2F    	Enabled      	Enabled      	
OATH        	Enabled      	Enabled      	
YubiHSM Auth	Not available	Not available	
OpenPGP     	Enabled      	Enabled      	
PIV         	Enabled      	Enabled      

Yubico PIV Tool (and bundled libykcs11 library for PKCS#11/PKCS11 support)

  • Requires ccid (bundle files for pcscd) and pcsc-lite packages and pcscd service running
  • no need to edit devd rules
  • Install packages: pkg install yubico-piv-tool ccid service pcscd enable && service pcscd start
  • Use pcscd --foreground --debug to look at internals of pcsc-lite. Additional reading: https://blog.apdu.fr/posts/2011/07/pcscd-debug-output/
  • Check to see if it can find your Yubikey: yubico-piv-tool -a list-readers
  • WIP

Yubikey with hidraw(4) usb driver

Enabling usbhid support via hidraw(4) for FreeBSD 13+ can be done by editing /boot/loader.conf. This provides modern hidraw support and legacy compat mode API support as well. Should avoid some of the USB port/device contention issues.

hidraw_load="YES"
hkbd_load="YES"
hw.usb.usbhid.enable="1"
  • Requires patches to libfido (included in 14.0-RELEASE, and stable after 9/23/23) - libfido2 1.13 for automatic detection within base libfido using things like OpenSSH from base.
  • Manual workaround for older OS code is to pass device entry explicitly ssh-keygen -v -K -O device=/dev/hidraw1
  • This example allows YubiKey Manager to access OTP HID in a non-exclusive way, so that the key will still function as a USB keyboard:
  # cat >>/boot/loader.conf<<EOF
  hidraw_load="YES"
  hkbd_load="YES"
  hw.usb.usbhid.enable="1"
  hw.usb.quirk.0="0x1050 0x0010 0 0xffff UQ_KBD_IGNORE"  # YKS_OTP
  hw.usb.quirk.1="0x1050 0x0110 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP
  hw.usb.quirk.2="0x1050 0x0111 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_CCID
  hw.usb.quirk.3="0x1050 0x0114 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_FIDO
  hw.usb.quirk.4="0x1050 0x0116 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_FIDO_CCID
  hw.usb.quirk.5="0x1050 0x0401 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP
  hw.usb.quirk.6="0x1050 0x0403 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_FIDO
  hw.usb.quirk.7="0x1050 0x0405 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_CCID
  hw.usb.quirk.8="0x1050 0x0407 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_FIDO_CCID
  hw.usb.quirk.9="0x1050 0x0410 0 0xffff UQ_KBD_IGNORE"  # YKP_OTP_FIDO
  EOF
  # reboot

fido2-token, fido2-cred, fido2-assert

 pkg install -g py3*-fido2

OpenSC PKCS11 shared library (PIV)

You can choose to use the OpenSC /usr/local/lib/opensc-pkcs11.so PKCS11 shared library instead of the Yubikey variant /usr/local/lib/libykcs11.so for PIV operations.

  • Install OpenSC package (as root): pkg install opensc
  • Update user SSH config (as user): echo "PKCS11Provider /usr/local/lib/opensc-pkcs11.so" >>~/.ssh/config

Open Bugs/Issues/Features

  1. Extract FIDO SK key using ssh-keygen -K does not retain original no-touch-required flag https://bugzilla.mindrot.org/show_bug.cgi?id=3355
  2. OpenSSH does not suport #PKCS11 URI format for selecting specific keys/search criteria https://bugzilla.mindrot.org/show_bug.cgi?id=2817
  3. OpenSSH does not handle multiple FIDO key matching properly in all cases https://bugzilla.mindrot.org/show_bug.cgi?id=3366
  4. Enable specific biometric FIDO features https://bugzilla.mindrot.org/show_bug.cgi?id=3218

Other future projects/links for FreeBSD and Yubikey

FreeBSD GnuPG with Smartcard/Yubikey

How to configure FreeBSD with a Yubikey OpenPGP applet (or smartcard) for Gnu Privacy Guard (GnuPG or GPG). This guide is only applicable to recent (v.2.3.2+) versions of GnuPG.

  • GnuPG v2.4.3 was used to write this guide on FreeBSD stable/14, but should work on FreeBSD 13.2 or later:
gpg --version

gpg (GnuPG) 2.4.3

References

OS Packages

On a recent FreeBSD, you will need to install some software to enable effective utlization of GPG with your Smartcard/Yubikey in a compatible way so as to not exclusively lock the Yubikey/USB device:

pkg install -g pcsc-lite ccid gnupg u2f-devd py3*-yubikey-manager

OS Configuration

  1. Configure modern hidraw(4) FreeBSD kernel USB driver by adding the following to /boot/loader.conf:
hidraw_load="YES"
hkbd_load="YES"
hw.usb.usbhid.enable="1"
  1. Add applicable users to u2f group to allow permission to device /dev/uhid* or /dev/hidraw* Replace with actual username.
pw group mod u2f -m <user>
  1. Configure GnuPG to use pcscd for access to the smartcard rather than internal gpg drivers to avoid locking device conflicts. This can be done by creating a ~/.gnupg/scdaemon.conf file for each applicable user:
gpgconf --kill all && \
umask 077 && \
mkdir -p ~/.gnupg ; \
cat <<EOF >> ~/.gnupg/scdaemon.conf
pcsc-shared
disable-ccid
EOF
  1. Enable pcscd to automatically start on boot, and start now:
service pcscd enable && service pcscd start
  1. Insert your Yubikey and verify OpenPGP applet support and configuration
ykman info

Should display the following (or similar). Look for OpenPGP line:

Device type: YubiKey 5C NFC
Serial number: XXXXXX
Firmware version: 5.2.7
Form factor: Keychain (USB-C)
Enabled USB interfaces: OTP, FIDO, CCID
NFC transport is enabled.
Configured capabilities are protected by a lock code.

Applications    USB             NFC
OTP             Enabled         Enabled
FIDO U2F        Enabled         Enabled
FIDO2           Enabled         Enabled
OATH            Enabled         Enabled
PIV             Enabled         Enabled
OpenPGP         Enabled         Enabled
YubiHSM Auth    Not available   Not available

The following will display the global OpenPGP applet status for your Yubikey:

ykman openpgp info
  1. Reboot your FreeBSD box to load the new kernel driver, start pcscd before scdaemon, and use the new u2f-devd rules for the usb device attach.
  2. Verify that your Yubikey/Smartcard is detected (after reboot):
gpg --card-status

If this results in an error, see the Troubleshooting section below.

Configure / Reset Yubikey OpenPGP applet

  1. Configure smartcard applet settings:
gpg --card-edit
  • Change default PIN / PUK (Admin PIN), and change key type to something modern (ECC curve 25519) instead of default of rsa. This requires a Yubikey firmware v5.2.3+ / OpenPGP applet v3.4.
  • Factory default PIN is: 123456 and PUK(Admin PIN) is: 12345678 for all OpenPGP compliant smartcards (including Yubikey)
  • At the gpg/card> prompt:
admin
kdf-setup
passwd
key-attr
list
  • admin Enables admin commands in gpg --card-edit
  • passwd Make Certain to update both the PIN and PUK (Admin PIN). Save them somewhere safe.
  • key-attr Repeat entry of PUK for each of the prompted 3 keys (Signature/Encryption/Authentication) during key-attr configuration to ECC Curve 25519.
  • kdf-setup Protects your PIN from snooping by using KDF (Key derivation Function). This is only compatible with modern Yubikey 5 and modern GPG, and MUST be completed prior to generation of key material on the Yubikey.
  • Results from list should be similar to:
Reader ...........: Yubico YubiKey OTP FIDO CCID (XXXYYY) 01 00
Application ID ...: XXXYYY
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: XXXYYY
Name of cardholder: [not set]
Language prefs ...: [not set]
Salutation .......:
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: not forced
Key attributes ...: ed25519 cv25519 ed25519
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 0
KDF setting ......: on
UIF setting ......: Sign=off Decrypt=off Auth=off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
  1. Configure OpenPGP card identity data:
    • At the gpg/card> prompt:
verify
name
lang
salutation
login
list

You will be prompted for Admin PIN or User PIN as required.for each command.

  1. Generate Public and 3 private keys (Signature/Encryption/Authentication) and associate with identity/email.
  • At the gpg/card> prompt:
    generate
    quit
    

You will be prompted for identity information, and your PIN and PUK multiple times. When complete, you should receive the message: gpg: revocation certificate stored as '/home/<user>/.gnupg/openpgp-revocs.d/xxxyyy.rev' public and secret key created and signed. when complete. After typing quit, you should see a listing of your pub, uid, and sub keys.

  1. Export your public key:
gpg --armor --export >public.asc
  • List your exported key data:
gpg --show-keys <public.asc

You can take your GPG public.asc public key and import them to either a keyserver, or to a service that supports (e.g.: github). 5. (Optional) Update your smartcard url for the public key (keyserver or webserver)

gpg --card-edit
  • At the gpg/card> prompt:
 admin
 url
  • When prompted, update to applicable url (e.g. https://github.com/daemonhorn.gpg). You will need to manually publish the public key data from public.asc contents to the github or other url.

Setup GPG with Yubikey on a new machine (Fetch public key from url)

  1. Follow above steps for OS Packages and OS Configuration to ensure you have a good baseline config.
  2. Insert Yubikey
  3. Configure gpg keyring and fetch public key from url embedded
    gpg --card-edit
    
  4. At the gpg/card> prompt
    • Retrieve public keys from keyserver/http(s) url defined on smartcard url configuration
      fetch
      
      This should result in something like:
      gpg: requesting key from 'https://github.com/daemonhorn.gpg'
      gpg: C:\\Users\\dhorn\\AppData\\Roaming\\gnupg\\trustdb.gpg: trustdb created
      gpg: key 831034C20D914B4E: public key "Daemonhorn (Y5C) <[email protected]>" imported
      gpg: key FC8F3B1BB11489E8: public key "Daemon Horn (ZC) <[email protected]>" imported
      gpg: Total number processed: 2
      gpg:               imported: 2
      
    Note: Make note of the key id imported FC8F3B1BB11489E8 that you are interested in trusting for use in signing/encrypting, as you will need it for the next step and edit-key mode.
    • Exit card-edit mode
      quit
      
  5. Update trust level of your keys
    • Use the --edit-key with applicable key id (from above) to change an individiual key trust level.
      gpg --edit-key FC8F3B1BB11489E8
      
      Example output:
      Secret key is available.
      sec  nistp384/FC8F3B1BB11489E8
           created: 2024-09-01  expires: 2029-08-31  usage: SC
           card-no: 0005 00009073
           trust: unknown       validity: unknown
      ssb  nistp384/EAA668D56F42B8C1
           created: 2024-09-01  expires: 2029-08-31  usage: A
           card-no: 0005 00009073
      ssb  nistp384/C2E2B7C9CFD2A515
           created: 2024-09-01  expires: 2029-08-31  usage: E
           card-no: 0005 00009073
      [ unknown] (1). Daemon Horn (ZC) <[email protected]>
      
    • Edit the public key trust level using trust command and ultimate level (since this is our key/Yubikey) Example Output:
      Please decide how far you trust this user to correctly verify other users' keys
      (by looking at passports, checking fingerprints from different sources, etc.)
        1 = I don't know or won't say
        2 = I do NOT trust
        3 = I trust marginally
        4 = I trust fully
        5 = I trust ultimately
        m = back to the main menu
      Your decision? 
      
    • Set trust to ultimate with choice 5 Example output:
      Do you really want to set this key to ultimate trust? (y/N)
      
    • Confirm ultimate trust with y response
    • Exit key-edit mode with quit
    • Validate keys are trusted with --list-keys Look for the Ultimate designation next to the key id.
      gpg --list-keys
      
      Example Output:
      pub   ed25519 2023-10-14 [SC]
            1ECFF5F709D04FAD4FD04F11831034C20D914B4E
      uid           [ unknown] Daemonhorn (Y5C) <[email protected]>
      sub   ed25519 2023-10-14 [A]
      sub   cv25519 2023-10-14 [E]
      
      pub   nistp384 2024-09-01 [SC] [expires: 2029-08-31]
            822272ED18F4524F8CB6F246FC8F3B1BB11489E8
      uid           [ultimate] Daemon Horn (ZC) <[email protected]>
      sub   nistp384 2024-09-01 [A] [expires: 2029-08-31]
      sub   nistp384 2024-09-01 [E] [expires: 2029-08-31]
      
  6. You should now be able to use your Yubikey OpenPGP applet on the new machine with GPG.
    • Double check that your public key is properly signed/validated against the private key as well:
      gpg --check-sign FC8F3B1BB11489E8
      
      This should return 3 good signatures and [ultimate] trust next to the uid line.

Troubleshooting

  1. Enable pcscd debugging messages to /var/log/pcscd.log:
  • Turn on pcscd debug flag -d in /etc/rc.conf using sysrc(8)
    sysrc pcscd_flags="-d"
    
  • Enable logging in /usr/local/etc/syslog.d/pcscd.conf
    umask 077 && \
    mkdir -p /usr/local/etc/syslog.d && \
    touch /var/log/pcscd.log && \
    cat <<EOF > /usr/local/etc/syslog.d/pcscd.conf
    # See syslog.conf(5) for a description of this file's format.
    !pcscd
    *.*                                             /var/log/pcscd.log
    !*
    EOF
  • Restart services to take effect immediately.
    service syslogd restart && service pcscd restart
    
    • Don't forget to remove and re-insert your Yubikey after pcscd restart.
  1. Enable gpg debugging in ~/.gnupg/scdaemon.conf
WIP

OpenPGP applet reset (forgot PIN/PUK or want to start over). This destroys all private key material on the openpgp applet on your yubikey, so only perform if you are certain.

*Reset the card:

gpg --card-edit
  • At the gpg/card> prompt:
    admin
    factory-reset
    

Automate GnuPG pinentry for smartcards

  • Setup $GPG_HOME/gpg-agent.conf
    allow-loopback-pinentry
    
    Don't forget to restart the gpg processes. gpgconf --kill all
  • Pass specific set of gpg command line args for automation of passphrase entry via CLI or from a UTF-8 text file
    CLI example:
    gpg --batch --pinentry-mode loopback --passphrase-fd 0 --encrypt --sign -r <recipient email/keyid> <file>
    
    Text fle example: replace <passphrase_file> with a simple UTF-8 encoded text file with the pin. Ensure you set permissions appropriately to prevent other users from reading. If automating, keep this secret on disk only long enough to utilize, then delete.
    gpg --batch --pinentry-mode loopback --passphrase-file <passphrase_file> --encrypt --sign -r <recipient email/keyid> <file>
    

ref: https://unix.stackexchange.com/questions/330305/encrypt-with-gpg-using-a-key-passed-as-cli-argument

FreeBSD Yubikey 5 NFC Support

How to use the Yubikey with an NFC reader on FreeBSD.

What works

  • GnuPG
    • Need to wait several seconds for the NFC device to beep a second time before scdaemon will be able to interact. Be patient. If you have issues, use normal gpg troubleshooting for scdaemon like: gpgconf --kill all and try again.
    • --card-edit and --card-status both work as normal.
    • --encrypt and --sign both work as normal.
    • No need to specify the specific NFC transport. pcscd should take care of automatically if configured as per FreeBSD GnuPG documentation above.
  • PKCS11 (PIV Support)
    • ssh-keygen -D /usr/local/lib/libykcs11.so will export the public keys from all of your PIV slots.
    • Worked without any specific configuration (very similar to GnuPG) since the reader is supported well enough by pcscd and ccid driver/package. Same limitations on the PKCS11 library as normal USB connectivity:
      • Using the PKCS11 shared library from Yubico provides access to all of the key slots /usr/local/lib/libykcs11.so provided by package: yubico-piv-tool
      • Using the PKCS11 shared library from OpenSC provides access to the primary key slots (9A/9C/9D/9E) /usr/local/lib/opensc-pkcs11.so provided by the package: opensc
  • FIDO2 Authentication (Web Browser): Testing In-Progress
    • Chromium
    • Firefox
  • ykman (Yubikey Manager):
    • YKMan will NOT auto-detect the NFC reader for your device, and requires explicit -r <reader> parameter for NFC support, where <reader> is the text string of the NFC USB device returned by the USB Stack after device probe. Should match strings seen by usbconfig list, but NOT device names (which is a bit odd).
    • For example: On my NFC USB Device, I get the following returned from usbconfig list:
      ugen1.5: <ACS ACR122U PICC Interface> at usbus1, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (200mA)
      
    • You can successfully use the string ACS or ACR or ACR122U to select the device, but NOT ugen1.5.
    • ykman -r ACR122U info works and ykman -r ugen1.5 info does not.
    • ykman does NOT seem to allow piv applet configuration via NFC at this time (bug?). Needs investigation.

Tested Hardware

  • Yubikey Hardware:
    • Yubikey 5 NFC USB-A f/w 5.1.1 (works)
    • Yubikey 5 NFC USB-C f/w 5.2.7 (works)
    • Yubikey Neo USB-A f/w 3.5.0 (works)
    • Yubikey Security Key f/w 5.4.3 (works) - FIDO Only
    • ykman -r ACS info output (while Yubikey is placed on NFC reader for several seconds):
      Device type: YubiKey 5 NFC
      Serial number: XXXYYY
      Firmware version: 5.1.1
      Form factor: Keychain (USB-A)
      NFC transport is enabled.
      
      Applications    USB             NFC
      OTP             Enabled         Enabled
      FIDO U2F        Enabled         Enabled
      FIDO2           Enabled         Enabled
      OATH            Enabled         Enabled
      PIV             Enabled         Enabled
      OpenPGP         Enabled         Enabled
      YubiHSM Auth    Not available   Not available
      
    • You will need to ensure that the NFC transport on your Yubikey has been enabled (it is by default), or you will need to reconfigure using ykman config nfc --enable-all while connected to a USB port.
  • ACS ACR122U-A9 (f/w: 2.4.1)
    • usbconfig -v list output (truncated)
      ugen1.5: <ACS ACR122U PICC Interface> at usbus1, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (200mA)
      
        bLength = 0x0012
        bDescriptorType = 0x0001
        bcdUSB = 0x0110
        bDeviceClass = 0x0000  <Probed by interface class>
        bDeviceSubClass = 0x0000
        bDeviceProtocol = 0x0000
        bMaxPacketSize0 = 0x0008
        idVendor = 0x072f
        idProduct = 0x2200
        bcdDevice = 0x0214
        iManufacturer = 0x0001  <ACS>
        iProduct = 0x0002  <ACR122U PICC Interface>
        iSerialNumber = 0x0000  <no string>
        bNumConfigurations = 0x0001
      
    • You can check to see if your NFC reader is supported by pcscd here: https://ccid.apdu.fr/ccid/section.html
@debdrup
Copy link

debdrup commented Feb 17, 2024

Would you be interested in formatting this in AsciiDoc (which is similar to MarkDown), and getting this into the official FreeBSD documentation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment