flynn / u2f

Go packages that provide communication with FIDO U2F tokens over USB
Other
89 stars 23 forks source link

HyperFIDO Pro Mini ctap2token: CBOR error: CTAP2_ERR_INVALID_CBOR #14

Closed rgl closed 3 years ago

rgl commented 3 years ago

I'm trying a HyperFIDO Pro Mini authenticator (amazon buy link) with the https://github.com/flynn/u2f/tree/webauthn branch that is being worked on by @daeMOn63 at https://github.com/flynn/u2f/pull/12 and its failed with a CBOR error.

I've tried the ctap2token example as:

git clone -b webauthn https://github.com/flynn/u2f.git
cd u2f
go run ctap2token/example/main.go

Which returned:

Token info:
&ctap2token.GetInfoResponse{Versions:[]string{"U2F_V2", "FIDO_2_0", "FIDO_2_1_PRE"}, Extensions:[]string{"credProtect", "hmac-secret"}, AAGUID:[]uint8{0x9f, 0x77, 0xe2, 0x79, 0xa6, 0xe2, 0x4d, 0x58, 0xb7, 0x0, 0x31, 0xe5, 0x94, 0x3c, 0x6a, 0x98}, Options:ctap2token.AuthenticatorOptions{"clientPin":false, "credentialMgmtPreview":true, "plat":false, "rk":true, "up":true}, MaxMsgSize:0x800, PinProtocol:[]uint{0x1}}
Sending makeCredential request, please press authenticator button...
Successfully created credential
MakeCredentials signature is valid!
credentialID: d8ac1cf85bbecfb6a3affebdd0...
Sending GetAssertion request, please press authenticator button...
panic: ctap2token: CBOR error: CTAP2_ERR_INVALID_CBOR

goroutine 1 [running]:
main.main()
    /home/rgl/webauthn/u2f/ctap2token/example/main.go:137 +0x1433
exit status 2

I pressed the button once and it go thru the first step successfully; but when it reached the second step of asking me to press the button, it failed with the CBOR error before I pressed the button a second time.

Can you help me troubleshoot this? Is there something else I should try?

daeMOn63 commented 3 years ago

I have one of those as well (probably an older version than yours, it doesn't list the FIDO_2_1_PRE version) and also have issues with it. Things seem a little better on your side by at least getting a valid error code, I'm getting a 0x10 error at the exact same spot, which isn't even part of the spec. :shrug:

I don't have many ideas about what to do from here. I did try modifying the GetAssertionRequest parameters and CBOR encoding options without getting any luck. I've also captured USB traffic from the token on a WebAuthn flow from the browser - but they still use U2F/CTAP1 so this didn't help.

Maybe the fact that this specific token isn't FIDO2 certified gives us some hints (only the Pro version seems certified for FIDO2. The mini is only for U2F)

from https://fidoalliance.org/certification/fido-certified-products/, searching for all Hypersecu Information Systems, Inc. products: image

I didn't encounter issues running this example on a wide range of other tokens so I'm really clueless here. My only advice would be to stick to U2F/CTAP1 protocol for now, which seems to work fine with this token.

rgl commented 3 years ago

My authenticator is the new Pro Mini version (not the Mini version). It is supposed to be FIDO2 compliant. It seems to work with https://webauthn.io/, but I'm not sure if its a FIDO2-only site. By any chance, was this the site you've used? Do you known which version of fido is it using?

Can you guide/point me in capturing the usb traffic (in Ubuntu or Windows)? Maybe that would help troubleshooting this?

BTW, I'm just starting to slowly learn about CTAP2/webauthn, so please bear with me :)

daeMOn63 commented 3 years ago

Indeed, the Pro version is supposed to be compliant.

So to be a bit more specific, the website is not really in play here, we have:

token <--- USB ---> browser <--- HTTP ---> webauthn.io 

which means it's the browser's responsibility to talk with the token and handle the U2F / CTAP2 protocols. I'm mainly testing in Linux, and Firefox / Chrome seems to only use the old U2F (or also called CTAP1) protocol. Windows browsers were using CTAP2 I think, I don't exactly remember what I've tested there.

To capture USB, you can go with Wireshark (see https://wiki.wireshark.org/CaptureSetup/USB). Identify your device bus and ID with lsusb (bus correspond to the usbmonX interface, and you can filter the packets on the specific device ID)

I've also pushed a debug branch webauthn_debug, which might be simpler than capturing USB. It would be great if you could switch on it, retry running the example and share the output.

rgl commented 3 years ago

Thank you for the details!

Please see the webauthn_debug branch generated log.txt log file.

Please see the hyperfidopromini.pcapng.gz wireshark usb capture file. I've tried this with the z4yx/u2f_fido2_dissector.lua dissector by copying it to ~/.local/lib/wireshark/plugins and modifying to use my authenticator USB VID/PID:

--usb_table:add(0x10500407,ctap_proto) -- VID/PID of Yubikey
usb_table:add(0x2ccf0854,ctap_proto) -- VID/PID of HS HyperFIDO

But I not really known how to interpret most of the capture (the capture starts when I insert the authenticator in the usb port and stops after the example program panics).

daeMOn63 commented 3 years ago

Thanks for the logs! I didn't spot anything there, but I think I managed to fix it. Could you please checkout https://github.com/flynn/u2f/pull/15 and retry?

I booted up my Windows VM and managed to capture USB between the token and the browser while interacting with webauthn.io, and as I supposed before, Windows browsers use the CTAP2 protocol. The webauthn flow did work there, so all left to do was to retrieve the GetAssertion request from the capture, and compare it with the one made in the example code. It appeared that the transports field was not set in the browser scenario. I removed it and managed to get my HyperSecu mini to work. Hopefully, your Pro version fails for the same reason. :crossed_fingers:

rgl commented 3 years ago

It now works! Thank you!

I'm not yet sure why, but the example application sometimes asks for a PIN. I will try to dig into CTAP2 protocol to known when a authenticator might require a PIN :-)

rgl commented 3 years ago

Actually, the application asks for the PIN when I do not press the authenticator button after some seconds. Is that expected? Or should this "error" out in some other way?

daeMOn63 commented 3 years ago

This looks like to be again a feature proper to the HyperSecu tokens. While timing out waiting for user presence, tokens are expected to return a CTAP2_ERR_ACTION_TIMEOUTerror. HyperSecu mini seems to return a CTAP2_ERR_PIN_REQUIRED instead, which then triggers the condition to ask for a user pin :shrug:

See updated example in https://github.com/flynn/u2f/commit/840ab5f7207620bf26324e150b81f9e075691db0 that catch it and avoid asking for a pin when it's not set. This isn't great but I can't do much more here.

rgl commented 3 years ago

I see, something is kinda broken with it.

With your change, this is now more understandable. Thanks :-)