A plugin for OpenSSH to connect to FIDO/U2F security keys through native Windows Hello APIs.
OpenSSH version 8.2 added support for authentication using FIDO/U2F hardware security keys.
There are two new key type ecdsa-sk
and ed25519-sk
which can be used for this.
Communicating with keys is done through a helper app named ssh-sk-helper
(by default it is in /usr/lib/ssh
).
This helper has an internal implementation to connect to FIDO/U2F keys using libfido2 library and support connecting to keys via HID protocol on USB(no Bluetooth or other things).
ssh-sk-helper
also supports dynamically loaded middleware libraries to be used instead of internal implementation so you can connect to security keys through other ways.
Details about how to implement those middlewares are described in OpenSSH source in file PROTOCOL.u2f
.
Internal implementation works well in Windows. However, in Windows 10 version 1903 or higher, you need administrator privileges to be able to access any FIDO device, which means you need to run bash or other apps calling OpenSSH as administrator or they won't detect your keys, and this is painful.
Windows provides an API set called Windows Hello to access to FIDO/U2F keys without administrator privileges, these APIs are being used in major browsers(Chrome, Firefox, Edge) in Windows for JavaScript WebAuthn implementation. Windows Hello also supports other types of authenticators like internal TPM device(if they support generating ecdsa or ed25519 keys, they can be used instead of FIDO/U2F security keys).
So I created this middleware module for OpenSSH to access FIDO/U2F keys through Windows Hello APIs and make everything easier.
Compiled files of this project are available on GitHub releases. It is compiled for the MSYS environment(Git for Windows is using MSYS). For other environments like Cygwin please download the source code and compile it yourself.
Note: If you are using OpenSSH version 8.2p1, you need to install and configure(or compile) a modified ssh-sk-helper
, if you are using OpenSSH 8.3p1 or higher, it's not needed.
Copy this file wherever you want, PATH or LIB directory is preferred(e.g. /usr/bin
).
ssh
, ssh-keygen
, ssh-add
can use this module(sshd
could also use security keys but it's a little weird to do so).
To use in ssh
open ssh_config
(normally in /etc/ssh
) and add this:
Host *
SecurityKeyProvider winhello.dll
For use in ssh-keygen
use -w
argument like this:
ssh-keygen -t ecdsa-sk -w winhello.dll
And for use in ssh-add
use -S
command:
ssh-add -S winhello.dll ~/.ssh/id_ecdsa_sk
You can also set SSH_SK_PROVIDER
environment variable for ssh-keygen
and ssh-add
instead of argument method explained above, for example:
SSH_SK_PROVIDER=winhello.dll ssh-keygen -t ecdsa-sk
SSH_SK_PROVIDER=winhello.dll ssh-add ~/.ssh/id_ecdsa_sk
Use full path to winhello.dll
if it's not in bin or lib folders or if you get "file not found" error.
If you are downloading tarball:
./configure
make
If you are cloning from Git:
autoreconf --install
./configure
make
make install
will copy the DLL file properly into /usr/lib
but it also copies some static files for linking, those files are not needed because OpenSSH will use dlopen
to access to middlewares.
Due to some limitations in the version 8.2p1 of OpenSSH, to use this project you need to change some code inside OpenSSH ssh-sk-helper
binary(more detail about this on the next part).
The patch to these changes is available in this repository, also a binary version is provided.
This modified ssh-sk-helper
functionality is the same and you won't fill any differences when using it unless you want to use another module that expects the original interface.
ssh-sk-helper
hash the challenge before it sends it to the module, so in sk_enroll
and sk_sign
functions received challenge is hashed, but Windows requires receiving the plain challenge and hash it by itself, so currently we will hash data two times which cause failure in server verification.
I've changed ssh-sk.c
and removed hashing from it and moved it to sk-usbhid.c
and bumped API version to prevent other modules expecting original implementation to connect.
Copy ssh-sk-helper.exe
into /usr/lib/ssh
. You can either rename the original file in that directory or rename this one into something else before copying.
Remember if you just replace the original ssh-sk-helper.exe
it might be replaced with the original one later when you update your components(i.e. with MinGW updater, pacman, Cygwin updater, or updating "Git for Windows"). Also always create a backup of original components if you are going to replace them.
If /usr/lib/ssh/ssh-sk-helper.exe
is not the one required for this project(i.e. you installed the provided/compiled ssh-sk-helper
under a different name or you want to use the original one in some cases) use SSH_SK_HELPER
environment variable to call it whenever you want to use this projects module:
SSH_SK_HELPER=/usr/lib/ssh/custom_ssh-sk-helper.exe ssh ...
You can also set this environment variable in your shell init code(e.g. if you are using bash, add in ~/.bashrc
file)
export SSH_SK_HELPER=/usr/lib/ssh/custom_ssh-sk-helper.exe
Download OpenSSH 8.2p1 source code and apply the provided patch to it:
cd openssh-source
patch -p1 < ssh-sk-helper.patch
Then compile it according to your environment instructions.
After that, just copy ssh-sk-helper
and use it on your main installation of OpenSSH.
-
This module doesn't support
no-touch-required
option due to its support not available in Windows Hello APIs. -
Windows Hello API does not support empty user ID, so if you do not specify any user ID(using
-O user
option) this module uses a default user IDssh user
, this behavior is different from the internal implementation which uses empty user ID. -
Support for copying resident keys from security key is not available(yet), use internal implementation for this(do not add
-w
tossh-key
or-S
tossh-add
or use the wordinternal
as the path to middleware):ssh-keygen -K ssh-add -K OR ssh-keygen -K -w internal SSH_SK_PROVIDER=internal ssh-add -K
Be sure that you are running bash as administrator whenever you use internal implementation or you get "Device not found" error.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
OpenSSH project uses BSD license. Microsoft webauthn.h interface uses MIT license. This project is available through LGPLv3 license.