Mailing List Archive

U2F support in OpenSSH HEAD
Hi,

As of this morning, OpenSSH now has experimental U2F/FIDO support, with
U2F being added as a new key type "sk-ecdsa-sha2-nistp256@openssh.com"
or "ecdsa-sk" for short (the "sk" stands for "security key").

If you're not familiar with U2F, this is an open standard for making
inexpensive hardware security tokens. These are easily the cheapest way
for users to get a hardware-backed keypair and there is a good range of
vendors who sell them including Yubico, Feitian, Thetis and Kensington.
Hardware-backed keys offer the benefit of being considerably more
difficult to steal - an attacker typically has to steal the physical
token (or at least persistent access to it) in order to steal the key.

Since there are a number of ways to talk to U2F devices, including USB,
Bluetooth and NFC, we didn't want to burden OpenSSH with a bunch of
dependencies. Instead we've delegated the task of communicating with the
tokens to a small middleware library that is loaded in a manner similar
to the existing PKCS#11 support.

We've written a basic middleware for Yubico's libfido2 that is capable
of talking to any standard USB HID U2F or FIDO2 token. The middleware
source is hosted in the libfido2 tree, so building that and OpenSSH HEAD
is sufficient to get started.

Some quickstart instructions:

1. Build and install OpenSSH

If you're using OpenBSD, then you can use a snapshot release dated
after 2019-11-01 and it will have an OpenSSH with the necessary
support.

If you're on another operating system then you'll need to clone portable
OpenSSH from https://github.com/openssh/openssh-portable and follow
the build instructions in README,md. U2F support adds no additional
dependencies to this step.

2. Build libfido2:

If you're on OpenBSD, the see my recent posts to the ports@ mailing
list for libfido2 and its dependencies. Hopefully these will be added
to the ports tree soon.

Otherwise, you'll need to install libfido2's dependencies and
libfido2 HEAD yourself by cloning https://github.com/Yubico/libfido2
and following its build instructions. libfido2 will install a
${libdir}/libsk-libfido2.so shared object - that's the middleware you
need for the subsequent steps.

The existing middleware is pretty basic: it will attempt to locate and
use the first U2F token it finds attached via USB. It's therefore likely
to get confused if you happen to have more than one token attached to
your machine.

libfido2 includes support for OpenBSD, Linux, OS X and Windows (though
I expect more work will be needed on the OpenSSH side for to get Windows
going).

3. Generate a key.

The OpenSSH tools use the $SSH_SK_PROVIDER environment variable to
point to the middleware, though all tools that support security keys
accept dedicated command-line or configuration options (e.g. ssh_config
SecurityKeyProvider). This provider needs to be available for key
generation and signing (e.g. pubkey authentication) operations.

$ SSH_SK_PROVIDER=/path/to/libsk-libfido2.so
$ export SSH_SK_PROVIDER
$ ssh-keygen -t ecdsa-sk

You will typically need to tap your token to confirm the keygen
operation, but once complete this will yield a keypair at
~/.ssh/id_ecdsa_sk. It can be used much like any other key -
id_ecdsa_sk.pub can be copied to a server's authorized_keys file and
can be used for authentication, Note that the server only verifies
signatures, so it doesn't need to communicate with tokens.

The id_ecdsa_sk private key generated in this step is basically a U2F
"key handle" that is combined with a per-token secret to yield the real
public key. Theft or disclosure of the on-disk id_ecdsa_sk private
key alone should yield attackers the ability to authenticate using a
U2F token - they must steal the hardware itself (or access to it at
least). Moreover, the default mode for key creation requires the user
demonstrate physical presence for each signature operation, typically by
tapping the token. This makes theft-of-use more difficult and easy to
detect.

In any case, ssh-keygen will prompt for a passphrase for the on-disk
private key file for U2F keys as usual and this passphrase may be used
as an additional layer of protection.

4. Authenticate using a U2F token

This step is very straightforward; append the public key to
authorized_keys as you would normally. Note that U2F keys are a new
OpenSSH key type, so the server must support it too.

The only other requirement is that ssh(1) have access to the
middleware library. If you set the $SSH_SK_PROVIDER environment above
then you're already done, but otherwise you might want to use the
SecurityKeyProvider option in your configuration or on the command-line
to point ssh at the middleware.

At authentication time, you will need to tap your token to confirm the
private key signing operation.

5. Add a U2F key to a ssh-agent.

U2F keys may be added to ssh-agent just like any other key. The only
additional requirements are 1) that the agent supports the new key type,
2) the middleware library and physical token must be present on the host
running the agent (much like PKCS#11), 3) that ssh-add be told the path
to the middleware library (via the environment or using the -S option)
and 4) that the middleware library be situated at a whitelisted path
(see the documentation for ssh-agent's -P option).

If you've set the environment variable and have installed
libsk-libfido.so to a common system library directory like /usr/lib or
/usr/local/lib then it will be covered by the default whitelist and you
can just proceed to add the key like any other:

ssh-add ~/.ssh/id_ecdsa_sk

You'll still need to tap the key for each authentication operation. I'll
look at adding support for reminding the user via ssh-askpass soon.

**

There's some more detail on the new key format and other technical
aspects of the feature in the PROTOCOL.u2f file in the OpenSSH source
distribution.

We chose to add U2F devices to the SSH protocol as keys rather than
as another more web-like authentication methods because SSH users are
familiar with keys and there are many tools that support them. It was
not possible to enable U2F keys using the existing SSH ECDSA key format
because, despite U2F devices using ECDSA for signatures, the signature
format differs from the plain signatures used in SSH by including some
additional fields.

I'm pretty excited about this feature so please give it a try and let
me know your feedback. I'm happy to answer any questions you might have.

Cheers,
Damien Miller

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Fri, 1 Nov 2019 19:36:16 +1100 (AEDT)
Damien Miller <djm@mindrot.org> wrote:

> Theft or disclosure of the on-disk id_ecdsa_sk private
> key alone should yield attackers the ability to authenticate using a
> U2F token

Just to clarify: I assume that should read "should *not* yield"?

(Great stuff, by the way.)

Christian
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Fri, 1 Nov 2019, Christian Kandeler wrote:

> On Fri, 1 Nov 2019 19:36:16 +1100 (AEDT)
> Damien Miller <djm@mindrot.org> wrote:
>
> > Theft or disclosure of the on-disk id_ecdsa_sk private
> > key alone should yield attackers the ability to authenticate using a
> > U2F token
>
> Just to clarify: I assume that should read "should *not* yield"?

your right - that was a great place for a grammatical error...

-d
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On 11/1/19 4:36 AM, Damien Miller wrote:
> new key type "sk-ecdsa-sha2-nistp256@openssh.com"

Was ECDSA with NIST P-256 strictly necessary, or would Ed25519 be
possible as well?

Thanks,
- Joe

--
Joseph S. Testa II
Founder & Principal Security Consultant
Positron Security
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
I've had a patch on the bugzilla for a while related to U2F with
support for a few additional settings such as providing a path to a
specific key to use instead of the first one found and setting if user
presence is required when using the key. Is there any objection to
folding those parts in if appropriate?

Joseph, to offer comment on NIST P-256. There was originally quite a
limited subset of support in U2F, originally ES256 or RS256. There's
since been more added (Ed25519 appears to be one of them at a cursory
glance). If you take a look at param.h in the libfido2 repository
you'll see the list of supported algorithm constants (COSE_*). From
personal experience though I've had a few different brands of
pure-u2f-only tokens and never seen support for anything other than
P-256 in the wild. Yubicos U2F only keys for example are currently
listed on their site as only having P-256 support. I imagine
multi-purpose keys might have more expansive support though. RS256
also appears to be marked as deprecated.

On Sat, Nov 2, 2019 at 7:54 PM Joseph S. Testa II
<jtesta@positronsecurity.com> wrote:
>
> On 11/1/19 4:36 AM, Damien Miller wrote:
> > new key type "sk-ecdsa-sha2-nistp256@openssh.com"
>
> Was ECDSA with NIST P-256 strictly necessary, or would Ed25519 be
> possible as well?
>
> Thanks,
> - Joe
>
> --
> Joseph S. Testa II
> Founder & Principal Security Consultant
> Positron Security
> _______________________________________________
> openssh-unix-dev mailing list
> openssh-unix-dev@mindrot.org
> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
Joseph S. Testa II <jtesta@positronsecurity.com> writes:

> On 11/1/19 4:36 AM, Damien Miller wrote:
> > new key type "sk-ecdsa-sha2-nistp256@openssh.com"
>
> Was ECDSA with NIST P-256 strictly necessary, or would Ed25519 be
> possible as well?

I would guess that it largely comes down to support of the algoirthms in
the hardware keys and the libfido2 library.

Some tokens built on top of TPM 2.0 hardware may only support ECDSA or
RSA....

YubiKey 5.2.3 enhancements to FIDO 2 Support recently announced
(on October 22, 2019)
URL: https://support.yubico.com/support/solutions/articles/15000027138-yubikey-5-2-3-enhancements-to-fido-2-support

| Additional Encryption Algorithms
|
| To ensure a high level of security for the FIDO2 authentication
| credentials, the supported encryption algorithms have been updated.
| Support for the Ed25519 curve has been added, while support for RSA keys
| has been removed.

This makes sense in that the new NISP FIPS 186-5 draft does provide for
EdDSA with both 25519 and 448 curves and YubiKey is something the US Fed
folks are in favor of using for some places where CAC cards are not as
desirable to use.

Right now, the libfido2 library seems to support ECDSA P-256 with
SHA-256 and PKCS#1.5 2048-bit RSA with SHA-256.

Given that the US Federal Government is mandating RSA-PSS for most
everything rather than PKCS#1.5 RSA, the odds are good that RSA
support will be going down in a lot of places.

I suspect that both ECDSA P256 and ECDSA P384 are supported on many PIV
Smart Card devices.

I fully expect to see EdDSA 25519 based devices eventually.

-- Mark
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Sat, 2 Nov 2019, Joseph S. Testa II wrote:

> On 11/1/19 4:36 AM, Damien Miller wrote:
> > new key type "sk-ecdsa-sha2-nistp256@openssh.com"
>
> Was ECDSA with NIST P-256 strictly necessary,

Yes, it is the only key type specified for U2F.

> or would Ed25519 be possible as well?

I think Ed25519 might be specified for FIDO2, if so we'll look at adding
it in the future.

-d

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Sat, 2 Nov 2019, Jordan J wrote:

> I've had a patch on the bugzilla for a while related to U2F with
> support for a few additional settings such as providing a path to a
> specific key to use instead of the first one found

This would need to be implemented in the middleware library, either
the one in libfido/tools/sk-libfido2.c or another.

> and setting if user
> presence is required when using the key. Is there any objection to
> folding those parts in if appropriate?

That's possible already: at keygen time, the default is to require
user presence for signatures but you can overide this by passing the
"-x 0" flag. This is currently undocumented, and I'll hopefully soon
get around to documenting it and making it accept mnemonic string
instead of raw U2F flags.

At authentication time, I've got a patch almost ready to require
user presence that I hope to commit next week.

-d
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
> That's possible already: at keygen time, the default is to require
> user presence for signatures but you can overide this by passing the
> "-x 0" flag. This is currently undocumented, and I'll hopefully soon
> get around to documenting it and making it accept mnemonic string
> instead of raw U2F flags.

I can make a quick pull request to update it to be a mnemonic if
you're interested. I'm looking around and testing the U2F support at
the moment anyway.
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
With regards to the middleware library Damien, was there a reason in
particular you used fido_dev_force_u2f(dev)?

Incidentally, I made that pull request while I as looking about.

On Sun, Nov 3, 2019 at 6:30 PM Jordan J <jordandev678@gmail.com> wrote:
>
> > That's possible already: at keygen time, the default is to require
> > user presence for signatures but you can overide this by passing the
> > "-x 0" flag. This is currently undocumented, and I'll hopefully soon
> > get around to documenting it and making it accept mnemonic string
> > instead of raw U2F flags.
>
> I can make a quick pull request to update it to be a mnemonic if
> you're interested. I'm looking around and testing the U2F support at
> the moment anyway.
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Fri, 1 Nov 2019, Damien Miller wrote:

> Hi,
>
> As of this morning, OpenSSH now has experimental U2F/FIDO support, with
> U2F being added as a new key type "sk-ecdsa-sha2-nistp256@openssh.com"
> or "ecdsa-sk" for short (the "sk" stands for "security key").

An update on this: I've just committed internal support for U2F/FIDO2
security keys to OpenSSH. If ./configure can find a compatible libfido2
then it will be used automatically, with no additional configuration
required in OpenSSH tools. You should use libfido2 HEAD for now until
they make their next release.

Practically, this means that you can just run "ssh-keygen -t ecdsa-sk"
and it will work without fiddling with middleware binaries, etc.

Please give this a try - security key support is a substantial change and
it really needs testing ahead of the next release.

-d
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On 2019-11-14, Damien Miller <djm@mindrot.org> wrote:
> Please give this a try - security key support is a substantial change and
> it really needs testing ahead of the next release.

Hi Damien,

Thanks for working on security key support, this is a really nice
feature to have in openssh.

My non-FIDO2 security key (YubiKey NEO) doesn't work with the latest
changes to openssh and libfido2, failing with `try_device:
fido_dev_get_assert: FIDO_ERR_USER_PRESENCE_REQUIRED`. I'm not sure if
this is a problem in libfido2 or sk-usbhid.c (I also reported this
issue at https://github.com/Yubico/libfido2/issues/73).

Is try_device incompatible with U2F keys? It seems to me to be trying
to detect the presence of a key handle using an assert with up=0, but
that causes the U2F codepath in libfido2 to return an error
FIDO_ERR_USER_PRESENCE_REQUIRED.

I believe that since try_device is only trying to find the device with
the key, FIDO_ERR_USER_PRESENCE_REQUIRED should be ignored here, since
that seems to indicate that the key lookup succeeded, but
authentication was not attempted. I attached a diff that makes this
change and it seems to fix my issue.
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Thu, 14 Nov 2019, Michael Forney wrote:

> On 2019-11-14, Damien Miller <djm@mindrot.org> wrote:
> > Please give this a try - security key support is a substantial change and
> > it really needs testing ahead of the next release.
>
> Hi Damien,
>
> Thanks for working on security key support, this is a really nice
> feature to have in openssh.
>
> My non-FIDO2 security key (YubiKey NEO) doesn't work with the latest
> changes to openssh and libfido2, failing with `try_device:
> fido_dev_get_assert: FIDO_ERR_USER_PRESENCE_REQUIRED`. I'm not sure if
> this is a problem in libfido2 or sk-usbhid.c (I also reported this
> issue at https://github.com/Yubico/libfido2/issues/73).
>
> Is try_device incompatible with U2F keys? It seems to me to be trying
> to detect the presence of a key handle using an assert with up=0, but
> that causes the U2F codepath in libfido2 to return an error
> FIDO_ERR_USER_PRESENCE_REQUIRED.
>
> I believe that since try_device is only trying to find the device with
> the key, FIDO_ERR_USER_PRESENCE_REQUIRED should be ignored here, since
> that seems to indicate that the key lookup succeeded, but
> authentication was not attempted. I attached a diff that makes this
> change and it seems to fix my issue.

Thanks for testing this!

Does this patch help? If you're able to test multiple U2F-only keys in
a host then that would be ideal - you'll be able to see whether ssh is
trying each device if you run it in verbose mode (i.e. ssh -vvv ...)

Basically, I want to make sure that FIDO_ERR_USER_PRESENCE_REQUIRED is
returned only when a token actually claims a key handle, and not all the
time...

diff --git a/sk-usbhid.c b/sk-usbhid.c
index 63c7cb2..8758e2d 100644
--- a/sk-usbhid.c
+++ b/sk-usbhid.c
@@ -197,6 +197,10 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
}
r = fido_dev_get_assert(dev, assert, NULL);
skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
+ if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
+ /* U2F tokens may return this */
+ r = FIDO_OK;
+ }
out:
fido_assert_free(&assert);

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On 2019-11-14, Damien Miller <djm@mindrot.org> wrote:
> Thanks for testing this!
>
> Does this patch help? If you're able to test multiple U2F-only keys in
> a host then that would be ideal - you'll be able to see whether ssh is
> trying each device if you run it in verbose mode (i.e. ssh -vvv ...)

Yep, this patch works too:

debug1: skdebug: found 1 device(s)
debug1: skdebug: trying device 0: /dev/hidraw0
debug1: skdebug: fido_dev_get_assert: FIDO_ERR_USER_PRESENCE_REQUIRED
debug1: skdebug: found key
debug1: Authentication succeeded (publickey).
Authenticated to localhost ([::1]:22).

and without the key plugged in:

debug1: skdebug: found 0 device(s)
debug1: skdebug: couldn't find device for key handle
debug1: sshsk_sign: sk_sign failed with code -1
debug1: identity_sign: sshkey_sign: unexpected internal error
sign_and_send_pubkey: signing failed: unexpected internal error

Unfortunately I only have the one key to test with.

> Basically, I want to make sure that FIDO_ERR_USER_PRESENCE_REQUIRED is
> returned only when a token actually claims a key handle, and not all the
> time...

Yeah, this crossed my mind after I sent the diff. Your patch looks good :)
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Thu, 13 Nov 2019, Michael Forney wrote:

> On 2019-11-14, Damien Miller <djm@mindrot.org> wrote:
> > Thanks for testing this!
> >
> > Does this patch help? If you're able to test multiple U2F-only keys in
> > a host then that would be ideal - you'll be able to see whether ssh is
> > trying each device if you run it in verbose mode (i.e. ssh -vvv ...)
>
> Yep, this patch works too:
>
> debug1: skdebug: found 1 device(s)
> debug1: skdebug: trying device 0: /dev/hidraw0
> debug1: skdebug: fido_dev_get_assert: FIDO_ERR_USER_PRESENCE_REQUIRED
> debug1: skdebug: found key
> debug1: Authentication succeeded (publickey).
> Authenticated to localhost ([::1]:22).
>
> and without the key plugged in:
>
> debug1: skdebug: found 0 device(s)
> debug1: skdebug: couldn't find device for key handle
> debug1: sshsk_sign: sk_sign failed with code -1
> debug1: identity_sign: sshkey_sign: unexpected internal error
> sign_and_send_pubkey: signing failed: unexpected internal error
>
> Unfortunately I only have the one key to test with.
>
> > Basically, I want to make sure that FIDO_ERR_USER_PRESENCE_REQUIRED is
> > returned only when a token actually claims a key handle, and not all the
> > time...
>
> Yeah, this crossed my mind after I sent the diff. Your patch looks good :)

Thanks to my compulsive hoarding of technology that I should have disposed
of, I found an old U2F security key and managed to test it. U2F tokens
(well, mine anyway) return FIDO_ERR_NO_CREDENTIALS as expected.

I'll commit the patch.

-d
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Fri, 15 Nov 2019, Damien Miller wrote:

> On Fri, 1 Nov 2019, Damien Miller wrote:
>
> > Hi,
> >
> > As of this morning, OpenSSH now has experimental U2F/FIDO support, with
> > U2F being added as a new key type "sk-ecdsa-sha2-nistp256@openssh.com"
> > or "ecdsa-sk" for short (the "sk" stands for "security key").
>
> An update on this: I've just committed internal support for U2F/FIDO2
> security keys to OpenSSH. If ./configure can find a compatible libfido2
> then it will be used automatically, with no additional configuration
> required in OpenSSH tools. You should use libfido2 HEAD for now until
> they make their next release.
>
> Practically, this means that you can just run "ssh-keygen -t ecdsa-sk"
> and it will work without fiddling with middleware binaries, etc.
>
> Please give this a try - security key support is a substantial change and
> it really needs testing ahead of the next release.

One more note: you'll need to pass --with-security-key-builtin to
configure to enable the built-in security key support. If it finds
the libraries that it depends on then you should see something like:

U2F/FIDO support: built-in

In configure's final summary.

-d
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
That works for me. I noticed though that if you use
--with-security-key-builtin and it can't find the library to actually
use the builtin it's not treated as an error. Perhaps it should be
given the explicit indication that it's expected?

I've also updated the pull request on github that switches it from a
number to mnemonic flags to apply cleanly to the current master and
update the ssh-keygen manpage. I can also send it though another
medium instead of github if that's preferred?

On Fri, Nov 15, 2019 at 5:14 AM Damien Miller <djm@mindrot.org> wrote:
>
> On Fri, 15 Nov 2019, Damien Miller wrote:
>
> > On Fri, 1 Nov 2019, Damien Miller wrote:
> >
> > > Hi,
> > >
> > > As of this morning, OpenSSH now has experimental U2F/FIDO support, with
> > > U2F being added as a new key type "sk-ecdsa-sha2-nistp256@openssh.com"
> > > or "ecdsa-sk" for short (the "sk" stands for "security key").
> >
> > An update on this: I've just committed internal support for U2F/FIDO2
> > security keys to OpenSSH. If ./configure can find a compatible libfido2
> > then it will be used automatically, with no additional configuration
> > required in OpenSSH tools. You should use libfido2 HEAD for now until
> > they make their next release.
> >
> > Practically, this means that you can just run "ssh-keygen -t ecdsa-sk"
> > and it will work without fiddling with middleware binaries, etc.
> >
> > Please give this a try - security key support is a substantial change and
> > it really needs testing ahead of the next release.
>
> One more note: you'll need to pass --with-security-key-builtin to
> configure to enable the built-in security key support. If it finds
> the libraries that it depends on then you should see something like:
>
> U2F/FIDO support: built-in
>
> In configure's final summary.
>
> -d
> _______________________________________________
> openssh-unix-dev mailing list
> openssh-unix-dev@mindrot.org
> https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Fri, 15 Nov 2019, Jordan J wrote:

> That works for me. I noticed though that if you use
> --with-security-key-builtin and it can't find the library to actually
> use the builtin it's not treated as an error. Perhaps it should be
> given the explicit indication that it's expected?
>
> I've also updated the pull request on github that switches it from a
> number to mnemonic flags to apply cleanly to the current master and
> update the ssh-keygen manpage. I can also send it though another
> medium instead of github if that's preferred?

I'm still figuring out what to do with the -x option because there are
other u2f/fido2 things that are likely to be needed there.

-d
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
Hi Damien,

On Nov 14, 2019, at 3:26 PM, Damien Miller <djm@mindrot.org> wrote:
> On Fri, 1 Nov 2019, Damien Miller wrote:
>> As of this morning, OpenSSH now has experimental U2F/FIDO support, with
>> U2F being added as a new key type "sk-ecdsa-sha2-nistp256@openssh.com"
>> or "ecdsa-sk" for short (the "sk" stands for "security key").
>
> An update on this: I've just committed internal support for U2F/FIDO2
> security keys to OpenSSH. If ./configure can find a compatible libfido2
> then it will be used automatically, with no additional configuration
> required in OpenSSH tools. You should use libfido2 HEAD for now until
> they make their next release.
>
> Practically, this means that you can just run "ssh-keygen -t ecdsa-sk"
> and it will work without fiddling with middleware binaries, etc.
>
> Please give this a try - security key support is a substantial change and
> it really needs testing ahead of the next release.


I’ve been following this work with great interest, as I’ve been looking to add this support to my Python “AsyncSSH” package. I got a chance to look more closely at this over the last few days, and I’ve now got an initial implementation working and interoperating with OpenSSH-portable HEAD!

As part of my testing, I’ve been experimenting with not only plan SK keys, but also various combinations of creating certificates of SK keys signed by non-SK CA keys and vice-versa. I’ve generally been able to get OpenSSH to work with certificates of SK keys to work when signed with either non-SK or SK CAs. However, I haven’t been able to get OpenSSH to work when signing a non-SK key with an SK CA. I haven’t dug into the OpenSSH code to figure out what might be going wrong here, but I wanted to let you know about it.

These keys work fine when I use OpenSSH as a client to talk to my AsyncSSH server with this support, and AsyncSSH can use these keys successfully to talk to itself, so I think the problem is specifically in the OpenSSH server-side support for this case. Creating a certificate for an SK key signed by an SK CA works fine when OpenSSH is the server with either itself or AsyncSSH as the client. So, you’ll need to specifically try a non-SK key signed by an SK CA.


One other thing I wanted to ask you about was whether you had any plans to support SK keys as host keys. Your current PROTOCOL.u2f file says that these keys “are not used for host-based user authentication or server host key authentication”. However, I think there are a few use cases where this could make sense.

One use case is for reverse-direction connections, such as NETCONF “Call Home” described in RFC 8071. I know this isn’t something OpenSSH supports yet, but I recently added such support to AsyncSSH. See https://asyncssh.readthedocs.io/en/latest/#reverse-direction-example <https://asyncssh.readthedocs.io/en/latest/#reverse-direction-example> for more details. Basically, this use case involves a client running a process that makes an outbound TCP connection to a server but then using the resulting TCP connection once it is set up to authentication the remote server as a “user” and the client as a “host”, reversing the normal SSH direction and allowing the remote server to run commands on the local system. So, in the case of security keys, you’d create an SK server host key, and when you make the outbound connection and begin the key exchange, you’d hit the user presence button on the security key to perform the signing operation with the server host key and allow the reverse connection to be established.

A second use case would be to simply use a security key with user presence disabled as a more secure key store than just keeping a private key on the local disk of an SSH server. As long as the security key was present, the SSH server could accept new connections. However, you could remove the key at any time to disable this function, and there would be no concern about the key being remotely stolen from the server — someone would need physical access to steal the security key and need the enrollment information for that to do them any good.

The same argument can be applied to using a security key for host-based user authentication, and there you could even leave user presence enabled.


Finally, I noticed a few minor things in the PROTOCOL.u2f doc that didn’t look right. Specifically, that doc says:
> In addition to the message to be signed, the U2F signature operation
> requires a few additional parameters:
>
> byte control bits (e.g. "user presence required" flag)
> byte[32] SHA256(message)
> byte[32] SHA256(application)
> byte key_handle length
> byte[] key_handle

This isn’t really the format that these parameters are provided during a signing operation, though, at least not to the middleware library documented later in the doc. You may just want to leave this part of the description out, or at least sync it up a bit better with that later description. For instance, the key handle length is a size_t there, not a single byte, and the “control bits” is later called “flags”. The arguments are also in a different order, and there’s a missing argument which specified the key type (“alg”).
Following this you show the signed blob as:
> This signature is signed over a blob that consists of:
>
> byte[32] SHA256(application)
> byte flags (including "user present", extensions present)
> uint32 counter
> byte[] extensions
> byte[32] SHA256(message)
How would the “extensions” be encoded here, though, and how would the hardware know where they end and the SHA256 of the message begins? The doc mentions an “extensions present” flag, but I don’t see that defined.
Just after this, you show the signature returned from the U2F hardware as:
> The signature returned from U2F hardware takes the following format:
>
> byte flags (including "user present")
> uint32 counter
> byte[32] ecdsa_signature (in X9.62 format).
The signature is more than 32 bytes here, though. The middleware library returns the signature as an (r, s) pair, where each is a 32-byte string value that is later converted to integers and then encoded as a pair of MPInts. I suspect the hardware might be returning (r, s) as DER encoded in some cases and that the middleware library is hiding that, but either way the text above isn’t quite right.
Later, in the description of the sk_enroll() call, you show a “challenge” argument, but it’s not clear how that’s used. Are you doing anything with that today? I tried looking in various online docs about U2F/FIDO to see if it was described there, but I couldn’t really find anything that matched up with that. Most of what I found was much too high-level, or focused on things like the Javascript APIs in the browser and not the underlying code talking to the hardware tokens.
Thanks for all your work on this! I look forward to doing more testing on this as I fill out things like key enrollment and talking to an SSH agent process. I’ll report back here if I run into any issues with that.
--
Ron Frederick
ronf@timeheart.net



_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
On Mon, 2 Dec 2019, Ron Frederick wrote:

> Hi Damien,
>
> I’ve been following this work with great interest, as I’ve been
> looking to add this support to my Python “AsyncSSH” package. I got a
> chance to look more closely at this over the last few days, and I’ve
> now got an initial implementation working and interoperating with
> OpenSSH-portable HEAD!

Excellent - that's really good news.

> As part of my testing, I’ve been experimenting with not only plan SK
> keys, but also various combinations of creating certificates of SK
> keys signed by non-SK CA keys and vice-versa. I’ve generally been
> able to get OpenSSH to work with certificates of SK keys to work when
> signed with either non-SK or SK CAs. However, I haven’t been able to
> get OpenSSH to work when signing a non-SK key with an SK CA. I haven’t
> dug into the OpenSSH code to figure out what might be going wrong
> here, but I wanted to let you know about it.

It looks like I neglected to add the SK algorithms to the server's
CASignatureAlgorithms list. I'll fix that now.

> One other thing I wanted to ask you about was whether you had any
> plans to support SK keys as host keys. Your current PROTOCOL.u2f file
> says that these keys “are not used for host-based user authentication
> or server host key authentication”. However, I think there are a few
> use cases where this could make sense.

It wasn't something we'd really considered, but it wouldn't be very
hard to add. I'll look at it.

> One use case is for reverse-direction connections, such as NETCONF
> “Call Home” described in RFC 8071. I know this isn’t something OpenSSH
> supports yet, but I recently added such support to AsyncSSH. See
> https://asyncssh.readthedocs.io/en/latest/#reverse-direction-example
> <https://asyncssh.readthedocs.io/en/latest/#reverse-direction-example>
> for more details. Basically, this use case involves a client running
> a process that makes an outbound TCP connection to a server but then
> using the resulting TCP connection once it is set up to authentication
> the remote server as a “user” and the client as a “host”, reversing
> the normal SSH direction and allowing the remote server to run
> commands on the local system. So, in the case of security keys,
> you’d create an SK server host key, and when you make the outbound
> connection and begin the key exchange, you’d hit the user presence
> button on the security key to perform the signing operation with the
> server host key and allow the reverse connection to be established.

I'm not sure that I'm ready to add support to sshd for prompting the
user to touch their security key, I think it's too confusing as we've
never intended sshd to be run interactively.

> A second use case would be to simply use a security key with user
> presence disabled as a more secure key store than just keeping a
> private key on the local disk of an SSH server. As long as the
> security key was present, the SSH server could accept new connections.
> However, you could remove the key at any time to disable this
> function, and there would be no concern about the key being remotely
> stolen from the server — someone would need physical access to steal
> the security key and need the enrollment information for that to do
> them any good.

This is good motivation - we'd probably want to require that security
keys do not require user presence for this case.

> Finally, I noticed a few minor things in the PROTOCOL.u2f doc that
> didn’t look right. Specifically, that doc says:
>
> > In addition to the message to be signed, the U2F signature operation
> > requires a few additional parameters:
> >
> > byte control bits (e.g. "user presence required" flag)
> > byte[32] SHA256(message)
> > byte[32] SHA256(application)
> > byte key_handle length
> > byte[] key_handle
>
> This isn’t really the format that these parameters are provided during
> a signing operation, though, at least not to the middleware library
> documented later in the doc. You may just want to leave this part of
> the description out, or at least sync it up a bit better with that
> later description. For instance, the key handle length is a size_t
> there, not a single byte, and the “control bits” is later called
> “flags”. The arguments are also in a different order, and there’s a
> missing argument which specified the key type (“alg”).

AFAIK this is how things appear on the wire to a U2F token, but yeah
it's probably superfluous here.

> Following this you show the signed blob as:
>
> > This signature is signed over a blob that consists of:
> >
> > byte[32] SHA256(application)
> > byte flags (including "user present", extensions present)
> > uint32 counter
> > byte[] extensions
> > byte[32] SHA256(message)
>
> How would the “extensions” be encoded here, though, and how would the
> hardware know where they end and the SHA256 of the message begins?
> The doc mentions an “extensions present” flag, but I don’t see that
> defined.

extensions are only possible for FIDO2 keys and nothing we've defined
requests them (if they did, they'd break the signature). I mentioned it
there because that's where they'll go in the future if we ever support
them.

> Just after this, you show the signature returned from the U2F hardware
> as:
>
> > The signature returned from U2F hardware takes the following format:
> >
> > byte flags (including "user present")
> > uint32 counter
> > byte[32] ecdsa_signature (in X9.62 format).
>
> The signature is more than 32 bytes here, though. The middleware
> library returns the signature as an (r, s) pair, where each is a
> 32-byte string value that is later converted to integers and then
> encoded as a pair of MPInts. I suspect the hardware might be returning
> (r, s) as DER encoded in some cases and that the middleware library is
> hiding that, but either way the text above isn’t quite right.

Yes, it's DER encoded. I'll adjust the docs.

> Later, in the description of the sk_enroll() call, you show a
> “challenge” argument, but it’s not clear how that’s used. Are you
> doing anything with that today? I tried looking in various online docs
> about U2F/FIDO to see if it was described there, but I couldn’t really
> find anything that matched up with that. Most of what I found was much
> too high-level, or focused on things like the Javascript APIs in the
> browser and not the underlying code talking to the hardware tokens.

The challenge can be used as part of a workflow that uses the attestation
information coming back from the security key. The attestation object can
be used to prove that a particular key is hosted in hardware, typically
down to manufacturer/batch granularity. The challenge is used to ensure
that attestations are not subject to replay.

We don't disclose the attestation in the public key as it gives away a
bit too much identifying data, but I have plans to optionally write it
out as a sidecar to the private key.

> Thanks for all your work on this! I look forward to doing more testing
> on this as I fill out things like key enrollment and talking to an SSH
> agent process. I’ll report back here if I run into any issues with
> that.

Thanks for porting it to another SSH implementation. I should mention
that there's a small chance that some of the formats might change before
we make a release with this code in it, but I'll try to let you know if
this happens.

-d
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
Re: U2F support in OpenSSH HEAD [ In reply to ]
Hi Damien,

Thanks for following up!

On Dec 10, 2019, at 2:10 PM, Damien Miller <djm@mindrot.org> wrote:
> On Mon, 2 Dec 2019, Ron Frederick wrote:
>> As part of my testing, I’ve been experimenting with not only plan SK
>> keys, but also various combinations of creating certificates of SK
>> keys signed by non-SK CA keys and vice-versa. I’ve generally been
>> able to get OpenSSH to work with certificates of SK keys to work when
>> signed with either non-SK or SK CAs. However, I haven’t been able to
>> get OpenSSH to work when signing a non-SK key with an SK CA. I haven’t
>> dug into the OpenSSH code to figure out what might be going wrong
>> here, but I wanted to let you know about it.
>
> It looks like I neglected to add the SK algorithms to the server's
> CASignatureAlgorithms list. I'll fix that now.

Ah, great! Once you have a fix, I’d be happy to give it a try again here.


>> One other thing I wanted to ask you about was whether you had any
>> plans to support SK keys as host keys. Your current PROTOCOL.u2f file
>> says that these keys “are not used for host-based user authentication
>> or server host key authentication”. However, I think there are a few
>> use cases where this could make sense.
>
> It wasn't something we'd really considered, but it wouldn't be very
> hard to add. I'll look at it.

Thanks!


>> One use case is for reverse-direction connections, such as NETCONF
>> “Call Home” described in RFC 8071. I know this isn’t something OpenSSH
>> supports yet, but I recently added such support to AsyncSSH. See
>> https://asyncssh.readthedocs.io/en/latest/#reverse-direction-example
>> <https://asyncssh.readthedocs.io/en/latest/#reverse-direction-example>
>> for more details. Basically, this use case involves a client running
>> a process that makes an outbound TCP connection to a server but then
>> using the resulting TCP connection once it is set up to authentication
>> the remote server as a “user” and the client as a “host”, reversing
>> the normal SSH direction and allowing the remote server to run
>> commands on the local system. So, in the case of security keys,
>> you’d create an SK server host key, and when you make the outbound
>> connection and begin the key exchange, you’d hit the user presence
>> button on the security key to perform the signing operation with the
>> server host key and allow the reverse connection to be established.
>
> I'm not sure that I'm ready to add support to sshd for prompting the
> user to touch their security key, I think it's too confusing as we've
> never intended sshd to be run interactively.

Agreed on this point. In the case of the reverse direction support, it’s actually a “client” application that ends up validating the host key, as it’s the thing making the outbound TCP connection in this case. The “server” that’s listening for new TCP connections would still be non-interactive, and so that’s where you’d actually want to use client keys that don’t require prompting, either by using non-SK keys or using SK keys with the presence requirement turned off.


>> A second use case would be to simply use a security key with user
>> presence disabled as a more secure key store than just keeping a
>> private key on the local disk of an SSH server. As long as the
>> security key was present, the SSH server could accept new connections.
>> However, you could remove the key at any time to disable this
>> function, and there would be no concern about the key being remotely
>> stolen from the server — someone would need physical access to steal
>> the security key and need the enrollment information for that to do
>> them any good.
>
> This is good motivation - we'd probably want to require that security
> keys do not require user presence for this case.

For regular sshd listening for new connections, I think requiring that would make sense.


>> Finally, I noticed a few minor things in the PROTOCOL.u2f doc that
>> didn’t look right. Specifically, that doc says:
>>
>>> In addition to the message to be signed, the U2F signature operation
>>> requires a few additional parameters:
>>>
>>> byte control bits (e.g. "user presence required" flag)
>>> byte[32] SHA256(message)
>>> byte[32] SHA256(application)
>>> byte key_handle length
>>> byte[] key_handle
>>
>> This isn’t really the format that these parameters are provided during
>> a signing operation, though, at least not to the middleware library
>> documented later in the doc. You may just want to leave this part of
>> the description out, or at least sync it up a bit better with that
>> later description. For instance, the key handle length is a size_t
>> there, not a single byte, and the “control bits” is later called
>> “flags”. The arguments are also in a different order, and there’s a
>> missing argument which specified the key type (“alg”).
>
> AFAIK this is how things appear on the wire to a U2F token, but yeah
> it's probably superfluous here.

I must admit I haven’t looked closely at the FIDO protocol itself. For now, I’ve only focused on your middleware library and what it expects as arguments and returns as a result. That might be something worth documenting in PROTOCOL.u2f, as that’s the thing people are most likely to either want to implement if they have their own security keys that don’t work with libsk-libfido2 or to call into if they are writing alternate SSH Implementations which want to use that library as I did.


>> Following this you show the signed blob as:
>>
>>> This signature is signed over a blob that consists of:
>>>
>>> byte[32] SHA256(application)
>>> byte flags (including "user present", extensions present)
>>> uint32 counter
>>> byte[] extensions
>>> byte[32] SHA256(message)
>>
>> How would the “extensions” be encoded here, though, and how would the
>> hardware know where they end and the SHA256 of the message begins?
>> The doc mentions an “extensions present” flag, but I don’t see that
>> defined.
>
> extensions are only possible for FIDO2 keys and nothing we've defined
> requests them (if they did, they'd break the signature). I mentioned it
> there because that's where they'll go in the future if we ever support
> them.

My main concern on this was not finding a definition for the “extensions present” flag in the current code, or knowing how the length of the extensions might be encoded. Without that, there’s no way to future-proof my current implementation. I suppose I could do something like extract the last 32 bytes of the blob and use that as a the signature, ignoring any bytes in between but that’s not something usually done when parsing SSH “packets".


>> Just after this, you show the signature returned from the U2F hardware
>> as:
>>
>>> The signature returned from U2F hardware takes the following format:
>>>
>>> byte flags (including "user present")
>>> uint32 counter
>>> byte[32] ecdsa_signature (in X9.62 format).
>>
>> The signature is more than 32 bytes here, though. The middleware
>> library returns the signature as an (r, s) pair, where each is a
>> 32-byte string value that is later converted to integers and then
>> encoded as a pair of MPInts. I suspect the hardware might be returning
>> (r, s) as DER encoded in some cases and that the middleware library is
>> hiding that, but either way the text above isn’t quite right.
>
> Yes, it's DER encoded. I'll adjust the docs.

Ok. When going through your middleware API, though, you don’t actually see the DER encoding. That library converts the output from the hardware into a byte string big-endian representation of the r & s integers values in the ECDSA case, or puts the Ed25519 signature into the r value, with s being left empty. That might be something you’d want to document as well, in a section about the middleware API.


>> Later, in the description of the sk_enroll() call, you show a
>> “challenge” argument, but it’s not clear how that’s used. Are you
>> doing anything with that today? I tried looking in various online docs
>> about U2F/FIDO to see if it was described there, but I couldn’t really
>> find anything that matched up with that. Most of what I found was much
>> too high-level, or focused on things like the Javascript APIs in the
>> browser and not the underlying code talking to the hardware tokens.
>
> The challenge can be used as part of a workflow that uses the attestation
> information coming back from the security key. The attestation object can
> be used to prove that a particular key is hosted in hardware, typically
> down to manufacturer/batch granularity. The challenge is used to ensure
> that attestations are not subject to replay.
>
> We don't disclose the attestation in the public key as it gives away a
> bit too much identifying data, but I have plans to optionally write it
> out as a sidecar to the private key.

Yeah - I like that choice to keep the attestation response out of the encoded keys, but still make it available to callers who want it.

I just wasn’t sure what to pass in for the challenge when calling sk_enroll(). It turned out that I needed to pass in a 32-byte block, which I’m guessing would generally be a SHA256 hash of some challenge data. It worked fine to pass 32 null bytes, but it didn’t work if I passed in anything which wasn’t that length.


>> Thanks for all your work on this! I look forward to doing more testing
>> on this as I fill out things like key enrollment and talking to an SSH
>> agent process. I’ll report back here if I run into any issues with
>> that.
>
> Thanks for porting it to another SSH implementation. I should mention
> that there's a small chance that some of the formats might change before
> we make a release with this code in it, but I'll try to let you know if
> this happens.


Completely understood, and I actually included a caveat about exactly that in my check-in notice when I pushed this to my “develop” branch on Github. I’d be more than happy to make any changes needed to stay in sync with OpenSSH, and plan on waiting until you have a released version of this before I cut my own release so there are no interoperability problems between the two implementations.
--
Ron Frederick
ronf@timeheart.net



_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev