danstiner / rust-u2f

U2F security token emulator written in Rust
Apache License 2.0
293 stars 43 forks source link

Support for ed25519 keys #82

Open egor-duda opened 2 years ago

egor-duda commented 2 years ago

I've successfully created ecdsa-sk key with ssh-keygen -t ecdsa-sk command using softu2f service. Approval notification appears and key is successfully generated But when I try to create key ed25519-sk key with ssh-keygen -t ed25519-sk, ssh-keygen returns Key enrollment failed: invalid format error, and no notification appears. Is it because ed25519 keys are not supported, or I'm doing something wrong?

Logs:

deo@bld03:~$ ~/local/bin/ssh-keygen -t ecdsa-sk -f test-ecdsa-sk
Generating public/private ecdsa-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 test-ecdsa-sk
Your public key has been saved in test-ecdsa-sk.pub
The key fingerprint is:
SHA256:ZaPbThQihbkYsKaT48gsjLNyd7uiX/vUCZJd4jTuLiM deo@bld03
The key's randomart image is:
+-[ECDSA-SK 256]--+
|  ..   o.        |
|   .. o.         |                                                                                           
|  o  o..= *      |                                                                                           
| +  . .B O o     |                                                                                           
|=     o S .      |                                                                                           
|Bo     o * .     |                                                                                           
|==    . + =      |                                                                                           
|oo. E.++ o       |                                                                                           
|o..+.++*o .      |                                                                                           
+----[SHA256]-----+                                                                                           
deo@bld03:~$ ~/local/bin/ssh-keygen -t ed25519-sk -f test-ed25519-sk
Generating public/private ed25519-sk key pair.                                                                
You may need to touch your authenticator to authorize key generation.                                         
Key enrollment failed: invalid format

systemctl status softu2f.service
● softu2f.service - Software-only U2F Emulation Service
     Loaded: loaded (/etc/systemd/system/softu2f.service; static)
     Active: active (running) since Tue 2021-12-28 17:30:45 MSK; 1min 29s ago
TriggeredBy: ● softu2f.socket
   Main PID: 471 (system-daemon)
      Tasks: 2 (limit: 1094)
     Memory: 5.1M
        CPU: 27ms
     CGroup: /system.slice/softu2f.service
             └─471 /usr/lib/softu2f/system-daemon

systemctl --user status softu2f.service
● softu2f.service - Software-only U2F Emulation Service
     Loaded: loaded (/etc/xdg/systemd/user/softu2f.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2021-12-28 17:30:45 MSK; 2min 42s ago
   Main PID: 463 (user-daemon)
      Tasks: 3 (limit: 1094)
     Memory: 10.1M
        CPU: 93ms
     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/softu2f.service
             └─463 /usr/lib/softu2f/user-daemon

journalctl -u softu2f.service
Dec 28 17:30:45 bld03 systemd[1]: Started Software-only U2F Emulation Service.
Dec 28 17:30:45 bld03 system-daemon[471]: Dec 28 17:30:45.173 INFO starting SoftU2F system daemon, version: 0.4.2
Dec 28 17:30:45 bld03 system-daemon[471]: Dec 28 17:30:45.193 DEBG accepting connection, peer_cred: Ok(UCred { uid: 1000, gid: 1000 }), peer_addr: Ok((unnamed)), local_addr: Ok("/run/softu2f/>
Dec 28 17:30:45 bld03 system-daemon[471]: Dec 28 17:30:45.195 DEBG Future::poll, result: Ok(NotReady), device_id: m4d0LB4RyvwLR4B_FBcKK
Dec 28 17:30:45 bld03 system-daemon[471]: Dec 28 17:30:45.196 INFO Creating virtual U2F device, name: SoftU2F Linux (deo@bld03), device_id: m4d0LB4RyvwLR4B_FBcKK
Dec 28 17:30:45 bld03 system-daemon[471]: Dec 28 17:30:45.224 DEBG Sending create device event, uhid_device: SoftU2F Linux (deo@bld03), device_id: m4d0LB4RyvwLR4B_FBcKK
Dec 28 17:30:45 bld03 system-daemon[471]: Dec 28 17:30:45.224 DEBG Sent create device event, uhid_device: SoftU2F Linux (deo@bld03), device_id: m4d0LB4RyvwLR4B_FBcKK
Dec 28 17:30:45 bld03 system-daemon[471]: Dec 28 17:30:45.224 DEBG Future::poll, result: Ok(NotReady), device_id: m4d0LB4RyvwLR4B_FBcKK
[... lots of duplicate lines supressed ...]

journalctl --user -u softu2f.service
Dec 28 17:30:45 bld03 systemd[454]: Started Software-only U2F Emulation Service.
Dec 28 17:30:45 bld03 user-daemon[463]: Dec 28 17:30:45.120 INFO Starting virtual Universal 2nd Factor device user daemon, version: 0.4.2
Dec 28 17:30:45 bld03 user-daemon[463]: Dec 28 17:30:45.134 DEBG Opening socket, path: /run/softu2f/softu2f.sock
Dec 28 17:30:45 bld03 user-daemon[463]: Dec 28 17:30:45.145 DEBG Sending create device request, request: CreateDeviceRequest
Dec 28 17:30:45 bld03 user-daemon[463]: Dec 28 17:30:45.226 INFO Virtual U2F device created, device_id: m4d0LB4RyvwLR4B_FBcKK
Dec 28 17:30:45 bld03 user-daemon[463]: Dec 28 17:30:45.233 INFO Loaded configuration file, path: /home/deo/.config/rustu2f/config.json
Dec 28 17:30:45 bld03 user-daemon[463]: Dec 28 17:30:45.234 WARN Storing secrets in an unencrypted file, dir: /home/deo/.local/share/rustu2f
Dec 28 17:30:45 bld03 user-daemon[463]: Dec 28 17:30:45.234 INFO Ready to authenticate
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.424 DEBG Begin transaction, payload_len: 8, command: Init, channel_id: 0xFFFFFFFF
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.424 DEBG Received payload, len: 8
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.424 DEBG RequestMessage::Init, new_channel_id: 0x000001
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.425 DEBG Begin transaction, payload_len: 73, command: Msg, channel_id: 0x000001
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.425 DEBG Payload incomplete, receive_len: 57, payload_len: 73
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.426 DEBG Received payload, len: 73
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.426 DEBG RequestMessage::EncapsulatedRequest, data.len: 73
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.426 DEBG Registration request, app: 4wYQ6KFiEVlg/h7CI+ZSnJ9LboAgDcteXDIcivHisb8=
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.426 DEBG register
Dec 28 17:31:10 bld03 user-daemon[463]: Dec 28 17:31:10.426 DEBG test_user_presence, message: Register with site
Dec 28 17:31:12 bld03 user-daemon[463]: Dec 28 17:31:12.709 DEBG test_user_presence, user_present: true, action: approve
Dec 28 17:31:12 bld03 user-daemon[463]: Dec 28 17:31:12.746 INFO Registered, app: 4wYQ6KFiEVlg/h7CI+ZSnJ9LboAgDcteXDIcivHisb8=
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.056 DEBG Begin transaction, payload_len: 8, command: Init, channel_id: 0xFFFFFFFF
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.056 DEBG Received payload, len: 8
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.056 DEBG RequestMessage::Init, new_channel_id: 0x000002
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.057 DEBG Begin transaction, payload_len: 73, command: Msg, channel_id: 0x000002
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.057 DEBG Payload incomplete, receive_len: 57, payload_len: 73
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.058 DEBG Received payload, len: 73
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.058 DEBG RequestMessage::EncapsulatedRequest, data.len: 73
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.058 DEBG Registration request, app: 4wYQ6KFiEVlg/h7CI+ZSnJ9LboAgDcteXDIcivHisb8=
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.058 DEBG register
Dec 28 17:31:19 bld03 user-daemon[463]: Dec 28 17:31:19.058 DEBG test_user_presence, message: Register with site
Dec 28 17:31:20 bld03 user-daemon[463]: Dec 28 17:31:20.630 DEBG test_user_presence, user_present: true, action: approve
Dec 28 17:31:20 bld03 user-daemon[463]: Dec 28 17:31:20.664 INFO Registered, app: 4wYQ6KFiEVlg/h7CI+ZSnJ9LboAgDcteXDIcivHisb8=
Dec 28 17:31:32 bld03 user-daemon[463]: Dec 28 17:31:32.734 DEBG Begin transaction, payload_len: 8, command: Init, channel_id: 0xFFFFFFFF
Dec 28 17:31:32 bld03 user-daemon[463]: Dec 28 17:31:32.735 DEBG Received payload, len: 8
Dec 28 17:31:32 bld03 user-daemon[463]: Dec 28 17:31:32.735 DEBG RequestMessage::Init, new_channel_id: 0x000003
danstiner commented 2 years ago

Neat, I had not heard of ssh-keygen -t ecdsa-sk and it's cool that works with this tool.

That said, I would not recommend doing this. Properly securing ssh keys is beyond the scope of discussing in a GitHub issue, but in short this tool does not provide additional security for your ssh keys. On your machine, there seems to not be a keychain so this program is falling back to storing secrets in ~/.local/share/rustu2f, which is no more secure than the ~/.ssh directory being used by ssh for the actual keys. In fact, it is worse because it forces use of the arguably problematic ecdsa algorithm (https://wiki.archlinux.org/title/SSH_keys#ECDSA)

If you had a compatible keychain program (e.g. Gnome Keyring), this tool would store keys in the keychain which is arguably better. But I think that is pointless because Gnome Keyring can directly act as an ssh agent instead of this extra step of using -sk keys. (https://wiki.gnome.org/Projects/GnomeKeyring/Ssh). So there is no case where the tool would be providing meaningful extra security. Please use a hardware token if you need the additional security benefits.

I don't know why ed25519-sk does not work. Adding -vvv is often useful for more verbose logs to debug ssh issues. I'd accept a PR to add support for ed25519 if it was reasonably small, but I suspect it will require substantial changes to support the newer FIDO2 protocol, which is a big project I don't have much interest in at this time (see #50)

egor-duda commented 2 years ago

Thanks for prompt response!

I'm not planning to use softu2f as an additional security feature, as I fully understand it doesn't add anything to ordinary ssh keys security-wise.

My rationale for using softu2f is testing and development -- I'm trying to implement -sk keys support in dropbear (I've already implemented ecdsa-sk part, there's a PR pending in dropbear repo). Unfortunately, my hardware token's firmware supports only ecdsa keys, so I want to use softu2f for testing and debugging ed25519-sk keys support for dropbear

I'll try to look into this a bit deeper. As far as I can see from rust-u2f code, it mentions ecdsa only in attestation code, where it uses hardcoded ecdsa certs. Is this a place where ecdsa support (and lack of ed25519 support) might be coming from? Or should I look elsewhere?

danstiner commented 2 years ago

Development and testing are exactly the intended use cases! Sorry to be brusque, had issues with people incorrectly using this tool in the past and complaining so I try to be upfront about limitations.

Looked a bit closer since you have such a cool use case, but unfortunately U2F definitely only supports ecdsa. So this tool has basically the same limitations as your hardware token. Only the newer FIDO2 protocol allows specifying different key types.

I'm not exactly sure what it would take to support FIDO2, but it's a fair bit more than new certs. It'd be a rewrite of the u2f-core crate to support FIDO2 operations, plus a small change in the u2fhid-protocol crate to support CBOR, plus some smaller changes throughout the rest of the project. It's something I've considered doing, but I'm already in the middle of a rewrite to start using modern async/await syntax (#81) and this is just a hobby project :)

Sorry to not be of more help, good luck on your project.

Findings

(documenting for posterity)

This verbose keygen outputs shows the virtual device is found, but there is an invalid argument error that comes from a line in the u2f_register function of the fido2 lib that checks for ecdsa. This is done for backwards compatibility. You can use the fido2 library to talk to U2F keys, but the library will check the options you are using are actually supported by the older U2F keys/protocol: https://github.com/Yubico/libfido2/blob/980654105d2123932e895c7f7cd740f6a7909e08/src/u2f.c#L657

ssh-keygen -v -t ed25519-sk 
Generating public/private ed25519-sk key pair.
You may need to touch your authenticator to authorize key generation.
debug1: start_helper: starting /usr/local/libexec/ssh-sk-helper 
debug1: sshsk_enroll: provider "internal", device "(null)", application "ssh:", userid "(null)", flags 0x01, challenge len 0
debug1: sshsk_enroll: using random challenge
debug1: sk_probe: 1 device(s) detected
debug1: sk_probe: selecting sk by touch
debug1: ssh_sk_enroll: using device /dev/hidraw0
debug1: ssh_sk_enroll: fido_dev_make_cred: FIDO_ERR_INVALID_ARGUMENT
debug1: sshsk_enroll: provider "internal" failure -1
debug1: ssh-sk-helper: Enrollment failed: invalid format
debug1: main: reply len 8
debug1: client_converse: helper returned error -4
Key enrollment failed: invalid format

The relevant part of the U2F spec is the register messages. The request message has no way to select a key type and the response specifies the key/signature is to be ECDSA: https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-request-message---u2f_register

Also a note that I had to update to libfido2 version 1.8.0 before I could use even the ecdsa-sk keygen, prior versions fail when trying to retrieve USB device attributes that do not exist for the "fake" UHID devices this tool creates: https://github.com/Yubico/libfido2/commit/6117603260fb55ba4ea3f515d3801e5ba6669aa5

egor-duda commented 2 years ago

Great write-up, thanks!

It seems that the task is indeed much bigger than I initially thought. I wonder if it would be possible to use OpenSK project's code as a template/inspiration for implementing CTAP2 protocol. Although, incidentally, OpenSK itself doesn't support ed25519 keys yet :) Will try to take a bit deeper look into it.