OpenBSD Journal

Cryptographic Signing using ssh-keygen(1) with a FIDO Authenticator

Contributed by rueda on from the token-effort dept.


Hitherto, releases of the fwobac software (which underlies Undeadly) have been unsigned. This is overdue for change, so for the latest release [version 1.7], we are providing a digital signature. As signing is being performed manually, why not employ an additional [hardware] factor?

signify(1) does not support the use of FIDO authenticators. However, recent versions of OpenSSH do support signing using the [under-appreciated] -Y sign option of ssh-keygen(1), and with the recent addition of FIDO authenticator support to OpenSSH [as reported previously], we have a means (using tools in base OpenBSD) of using a hardware factor when signing files.

Selecting a FIDO Authenticator

While many FIDO authenticator products [from many vendors] are available, those on hand are both from Yubico:

$ usbdevs | grep Yubi
addr 06: 1050:0120 Yubico, Security Key by Yubico
addr 07: 1050:0407 Yubico, YubiKey OTP+FIDO+CCID

The "Security Key":

In comparison, the other device, a YubiKey 5:

Whilst the "Security Key" is perfectly adequate for the task, we opt to use the YubiKey. Having selected a FIDO authenticator, we unplug the other device.


To establish multiple factors for authentication, we opt to use a non-resident key, and use a passphrase for the private "key handle". This gives:

  • Things we have:
    • the FIDO Authenticator
    • the file containing the encrypted key handle
  • Things we know:
    • the passphrase for the encrypted key handle

Creating a Signing Key

Firstly, we need to create a signing key if we don't already have one.

With the FIDO authenticator attached:

$ KF="${HOME}/.ssh/id_rueda_undeadly_signing_ed25519-sk"
$ CMT="rueda - Undeadly signing"
$ ssh-keygen -C "${CMT}" -f "${KF}" -t ed25519-sk
Generating public/private ed25519-sk key pair.
You may need to touch your authenticator to authorize key generation.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/rueda/.ssh/id_rueda_undeadly_signing_ed25519-sk
Your public key has been saved in /home/rueda/.ssh/
The key fingerprint is:
SHA256:NUtLWRrVRWkN3yeywFQ6EPC4KKkZN4/UZxsO4Hqc1fc rueda - Undeadly signing
The key's randomart image is:
+[ED25519-SK 256]-+
|      ..o.oo+..+=|
|       o + *  .+o|
|  .   . . % . o +|
| . + o . + * o ..|
|. B = * S o .    |
| O B = + .       |
|+ = . o   E      |
| .               |
|                 |

For the sake of illustration, we view the public key:

$ fold "${KF}.pub" AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEaZ0MPwa
TYU/ipMe8NR4U+zXpZzxuGaMTat7cMLsJYVAAAABHNzaDo= rueda - Undeadly signing

Creating an "Allowed Signers" File

Signature verification is not performed directly against the public key file; rather, we [or those performing verification] must prepare a file in "allowed signers" format:

$ ID=""
$ AS="undeadly_allowed_signers"
$ echo "${ID} namespaces=\"file\" $(awk '{print $1,$2}' ${KF}.pub)" >> "${AS}"

Note that there may be more than one key permitted to sign in this context, so we append to the file, rather than overwriting it.

For the sake of illustration, we view the file:

$ fold -w 72 "${AS}" namespaces="file" AAAAGnNrLXN

As the aim of this exercise is for others to be able to verify our signatures, we share the allowed signers file. For the sake of diversity, we share the public key file elsewhere.


With the FIDO authenticator attached, we sign using:

$ RF="fwobac-1.7.tar.gz"
$ ssh-keygen -Y sign -f "${KF}" -n "file" "${RF}"
Enter passphrase:
Signing file fwobac-1.7.tar.gz
Confirm user presence for key ED25519-SK SHA256:NUtLWRrVRWkN3yeywFQ6EPC4KKkZN4/UZxsO4Hqc1fc
Write signature to fwobac-1.7.tar.gz.sig

For the sake of illustration, we view the signature:

$ cat "${RF}.sig"


As an illustration and sanity check we verify (that the the signature is valid and by an allowed signer, and that the file matches the signature):

$ ssh-keygen -Y verify -f "${AS}" \
    -I "${ID}" -n "file" -s "${RF}.sig" < "${RF}"
Good "file" signature for with ED25519-SK key SHA256:NUtLWRrVRWkN3yeywFQ6EPC4KKkZN4/UZxsO4Hqc1fc

If we are not concerned which of multiple allowed signers has created the signature, a more general approach is:

$ ssh-keygen -Y verify -f "${AS}" \
    -I $(ssh-keygen -Y find-principals -s "${RF}.sig" -f "${AS}") \
    -n "file" -s "${RF}.sig" < "${RF}"
Good "file" signature for with ED25519-SK key SHA256:NUtLWRrVRWkN3yeywFQ6EPC4KKkZN4/UZxsO4Hqc1fc


Many thanks to Damien Miller (djm@)!

(Comments are closed)

  1. By jwrt (jwrghti) on has 1.2-1.6 tarballs, but only the signature of 1.7



Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]