using hardware tokens to secure SSH, MS365 logins

i’ve done a bit of research, below – my understanding of the current state of affairs [ 2023-03 ]. i’m writing this while testing YubiKey 5 NFC, but consider different alternatives.


why: i’m considering an attack vector where malicious actor has remote control of my PC – can lift up arbitrary files [ including passphrase-protected private key used for ssh authentication ] & eavesdrop keystrokes [ including the passphrase typed when starting ssh agent ]. i’d like to have additional authentication factor protecting me against such a remote attack.

yubikey can help here by acting as one of the following:

  1. time-based code generator,
  2. PIV – cryptographic smartcard holding private keys for certificate signing,
  3. FIDO2/U2F token

2# and 3# are most suitable for protecting SSH. 2# has been used since at least 2015, is well documented but quite convoluted – requireing use of additional gpg-ssh agent running on the computer from which SSH connections are made.

FIDO2/U2F is a relative newcommer, was introduced in OpenSSH 8.2 from 2020. it sounds most tempting – i’ll focus on it below.

we have a choice of two placements of the the secret:

  • resident credentails [ also called discoverable ] – the private key is generated on and kept completely on the token; user needs to enter token-providing PIN with each SSH login; in this mode token can hold limited number of identities, 25 for yubikey 5 NFC,
  • non-resident or non-discoverable – private key handle, needed for SSH auth, is kept in the file system, can be protected by pass-phrase, rest of the secret is in the hardware token and cannot be easily extracted. both parts are needed to log in to remote server. each use of token will require touching it to confirm physical presence and – optionally – entering PIN. contrary to the resident credentials, non-resident can be used with endless number of servers/credentials.

the non-resident flow looks most interesting for my use case. the passphrase can be cached by ssh agent; assumign there’s no PIN requirement – ssh connection will require additional touch of the token – that’s as little friction as it can get, i think.

compatibility with this flow:

  • hardware token should support FIDO2/U2F – yubikey 5 NFC does,
  • current stable debian has OpenSSH 8.4 – we’re good on the server side,
  • openssh beta builds from Microsoft are even newer than that – it’s all you need to run SSH / SCP client from windows command line,
  • yubikey 5 in the FIDO2 role works fine both on stable debian and Win10, Win11 without need to install any drivers,
  • for putty – it’s more complicated; i’ve found two alternatives
    • use putty-cac fork of putty. it seems pretty lively, has support both for smartcards / PIV and FIDO2 flow, but it does not have support for passphrase protected private key handle stored in a file and used in the non-resident flow. if you’re using resident credentials or non-resident without passphrase protection – pageant from this fork can be used to supply authentication information to filezilla, winscp, git and other applications relying on putty’s agent,
    • use ssh-agent from recent version of openssh, winssh-pagent which exposes authentication to mainline putty and other apps like filezilla etc.

generation of non-resident credentials via openssh:

ssh-keygen -t ed25519-sk

-t specifies type of key, currently it can only be ecdsa-sk or ed25519-sk . ecdsa-sk is supported by every FIDO2 device i’ve found. ed25519-sk is likely to be backdoored but supported only by few token modesl.

during this process you can provide a pass-phrase protecting the private key handle that will be stored on a local disk or leave it empty.

you’ll also be asked to provide PIN protecting the token and to touch it.

once the command suceeds – it’ll produce two files: private key handle and a public key. the public key should be added to .ssh/authorized_keys on the servers where you want to be able to log in.

to log in – just run ssh -i path/to-private-key-handle name@server, provide pass-phrase if it was set, touch the bliking token and you’re in.

optionally you can run ssh-add path-to-private-key-handle and add the key to ssh-agent, it’ll cache it and its passphrase in memory so you don’t need to type it with each ssh login.

i’m not found of SSH agent forwarding, but it works pretty well also with the token. when you’ll be connecting from the jump-host to another machine – each time you’ll need to touch the bliking token.

presence of token can be forwarded via windows RDP in options > local resources > more: [x] WebAuthn (Windows Hello or security key). from remote computer you can as well use ssh [ if you’ve copied the file with private key handle ].

MS Office

looks like microsoft allows only the resident-key approach – where secret [ equivalent of login and password ] is stored on the token and protected only with a PIN. this works perfercetly fine under MS Windows, also via RDP. it does not work under Android and [according to what i’ve found, not tested] neither on iOS: see 1, 2, 3. which is a bummer.

facebook, google

seem to work just fine with windows and android.


results of an unexhaustive web research:

vendored25519-sk supportnotes
token2.comnot mentioned
trustkeynot mentioned
librem-keynot mentioned
feitiannot mentioned
tillitis.seeventually but not yetnewcommer open source & hardware
onlykey.ioyesopen source, user-upgradable firmware
nitrokey.comyes for nitrokey3 open source, user-upgradable firmware, in rust
solokeys.comyesopen source, user upgradable firmware, in rust
yubicoyes for keys with firmware >= 5.2.3non-upgradable firmware

other reviews from 2018:


listing resident credentials – e.g. ssh keys or ms365 login+passwords:

ykman fido credentials list

deleting such entry [ be carefull.. ]

ykman fido credentials delete 98780123...


  • have few keys or other backup access method – hardware keys can be lost/stolen, damaged, lose non-volatile memory, suffer bugs; you don’t want to lock yourself out completely if any of those happens,


out-of-scope – PIV [smartcard] flow with SSH:

Leave a Reply

Your email address will not be published. Required fields are marked *

(Spamcheck Enabled)