betrusted-io / xous-core

The Xous microkernel
Apache License 2.0
530 stars 85 forks source link

U2F registration fails (FIDO2 works) #498

Open DigitalBrains1 opened 8 months ago

DigitalBrains1 commented 8 months ago

This issue report stems from this comment. While FIDO2 works fine, it seems the older U2F fails where a different device, a NitroKey 3, works fine.

I installed libu2f-server and libu2f-host, simply by installing the Debian bookworm/stable packages, versions 1.1.0-4+b1 (u2f-server) and 1.1.10-3 (u2f-host).

These two programs should allow you to register a U2F device and have it validate authentication challenges, and it works with the Nitrokey 3. However, with the Precursor, it cannot be registered, the u2f-host program that talks to the device gives an error

error (-2): error in transport layer

Here is how to reproduce, and I also included USB traffic dumps for both Precursor and Nitrokey.

Generate challenge

The following invocation will make u2f-server generate a registration challenge, save the key handle to keyhandle-precursor.dat and the user key to userkey-precursor.dat:

$ u2f-server -aregister -o https://example.org -i https://example.org -k keyhandle-precursor.dat -p userkey-precursor.dat

This will print to stdout some JSON:

{ "challenge": "-736B0R1cxJXorY77D3dp1T3ovnvj5pppwGAt-xxQmE", "version": "U2F_V2", "appId": "https:\/\/example.org" }

Note that for exact reproduction, you can make it reuse that exact challenge again by passing it in with -c "[...challenge...]" as such:

$ u2f-server -aregister -o https://digitalbrains.com -i https://digitalbrains.com -k keyhandle-precursor.dat -p userkey-precursor.dat -c "-736B0R1cxJXorY77D3dp1T3ovnvj5pppwGAt-xxQmE"

Pass challenge to Precursor

Invoke u2f-host as:

$ u2f-host -aregister -o https://example.org

and then copy-paste the JSON output by u2f-server on stdin of the u2f-host process. End with a newline and EOF (Ctrl-D).

The Precursor will now prompt: image

Clicking accept will make u2f-host error out:

error (-2): error in transport layer

at which point you cannot continue with registration. The USB conversation between u2f-host and the Precursor, as captured by Wireshark, should be this: precursor-u2f-register-fail.pcapng.gz

Pass challenge to Nitrokey

Again, invoke u2f-host as:

$ u2f-host -aregister -o https://digitalbrains.com

and then copy-paste the JSON output by u2f-server on stdin of the u2f-host process. End with a newline and EOF (Ctrl-D). I used the exact same challenge as for the Precursor.

The Nitrokey starts to blink, touch it.

u2f-host outputs some JSON on stdout:

{ "registrationData": "BQTjF9hE8yPDZdhLuLcPmZSotCH942Alte4MQRhmjifdh6huMTdPLVXFC9uJNaPs8NH4vTx8PQC3Px8nNZ5z0wj_tqMAWJIDZkGxCfKIG-fb0TrB_pvHyT6m_vFFndxkYmCtXohO--CnlBtGJYLXaJ5KnHZIG93eqbRZSHnx0PbSRfT6F2p7wuITYF8xOPz4XyzYfUV4rhJv_3btbHT8dwJS4VglAtBBzGdM1_2q6np2fD33p0kPF66mIm26GziBEwTFBCOhQAjAbvbJK-6l-ZFOsiATRKQ7XwFMRsY2Gfs3Ir8TzJG0AlDc-I7Rmgx0C1dRv-oIPbLnMIICLjCCAdSgAwIBAgIEAMzMzDAKBggqhkjOPQQDAjA5MQswCQYDVQQGEwJERTEWMBQGA1UECgwNTml0cm9rZXkgR21iSDESMBAGA1UEAwwJRklETyBDQSAzMCAXDTIyMDQwNjExMjUyOFoYDzIwNzIwMzI0MTEyNTI4WjBtMQswCQYDVQQGEwJERTEWMBQGA1UECgwNTml0cm9rZXkgR21iSDEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEiMCAGA1UEAwwZTml0cm9rZXkgRklETyBBdHRlc3RhdGlvbjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCq6VUCC4Of2hGSyM7O9_uw4B_-pcLgYnFLQllKGO5wmK1I9sNNMpW-ubz52uyMOMUr7hbuuiZBZZj-dBD0ijaCjgZMwgZAwHQYDVR0OBBYEFDOBXdHoZV9fBKa27eCRiBPdwhnJMB8GA1UdIwQYMBaAFMFz5URWwMhuWGifn2LOKMiRlXYkMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMCEGCysGAQQBguUcAQEEBBIEEOyZ2xnNH0wGoqmUDxemowswEwYLKwYBBAGC5RwCAQEEBAMCBDAwCgYIKoZIzj0EAwIDSAAwRQIhAIcFpLaFPfU3XV-pA0ePZrpdukN06yOAijhpXnzGHO8IAiA8-1RKaNurtgplX5IYG4V9pPYcTgrVvdzfOmHZDS_JqDBGAiEAnpEA3G9YicGaha1ZjaSnC2qITmDXUfcD1yxhloDSOj8CIQDcfPNwX9DA6KOvs_MQACHc6BxWOX59PP_A5-RuuA98EA", "clientData": "eyAiY2hhbGxlbmdlIjogIi03MzZCMFIxY3hKWG9yWTc3RDNkcDFUM292bnZqNXBwcHdHQXQteHhRbUUiLCAib3JpZ2luIjogImh0dHBzOlwvXC9leGFtcGxlLm9yZyIsICJ0eXAiOiAibmF2aWdhdG9yLmlkLmZpbmlzaEVucm9sbG1lbnQiIH0" }

(I did it twice with the same challenge. registrationData changed, clientData stayed the same)

I am hoping that the following capture by Wireshark is the correct conversation for this exact response: nitrokey-u2f-success.pcapng.gz

Finish registration of Nitrokey

Paste the JSON that u2f-host outputted on stdin of the still running u2f-server process, ending in newline and EOF. u2f-host will reply:

Registration successful

and will save the credentials in the two files: key handle and user key.

Authenticate with Nitrokey

Very similar to the steps we did up to now, but instead of -aregister we now do -aauthenticate and the files are now input instead of output.

$ u2f-server -aauthenticate -o https://digitalbrains.com -i https://digitalbrains.com -k keyhandle-nitrokey.dat -p userkey-nitrokey.dat 

gives us some JSON:

{ "keyHandle": "owBYkgNmQbEJ8ogb59vROsH-m8fJPqb-8UWd3GRiYK1eiE774KeUG0Ylgtdonkqcdkgb3d6ptFlIefHQ9tJF9PoXanvC4hNgXzE4_PhfLNh9RXiuEm__du1sdPx3AlLhWCUC0EHMZ0zX_arqenZ8PfenSQ8XrqYibbobOIETBMUEI6FACMBu9skr7qX5kU6yIBNEpDtfAUxGxjYZ-zcivxPMkbQCUNz4jtGaDHQLV1G_6gg9suc", "version": "U2F_V2", "challenge": "Ni590tN3zf-MJmkZD9cArRXH5P5tetfAWWvv6YRF9sw", "appId": "https:\/\/example.org" }
u2f-host -aauthenticate  -o https://example.org

Paste the JSON from u2f-server into u2f-host as before, touch the Nitrokey, and u2f-host will output the challenge response:

{ "signatureData": "AQAAAIcwRgIhAPatcIRyUp7u8wpf7BKZGLvcQ8YtWiA6FWBp1BKr5VzBAiEA-SKkkF6bDijVNnStKFycqrWsPm_2ARO07IhpuV2HnxY", "clientData": "eyAiY2hhbGxlbmdlIjogIk5pNTkwdE4zemYtTUpta1pEOWNBclJYSDVQNXRldGZBV1d2djZZUkY5c3ciLCAib3JpZ2luIjogImh0dHBzOlwvXC9leGFtcGxlLm9yZyIsICJ0eXAiOiAibmF2aWdhdG9yLmlkLmdldEFzc2VydGlvbiIgfQ", "keyHandle": "owBYkgNmQbEJ8ogb59vROsH-m8fJPqb-8UWd3GRiYK1eiE774KeUG0Ylgtdonkqcdkgb3d6ptFlIefHQ9tJF9PoXanvC4hNgXzE4_PhfLNh9RXiuEm__du1sdPx3AlLhWCUC0EHMZ0zX_arqenZ8PfenSQ8XrqYibbobOIETBMUEI6FACMBu9skr7qX5kU6yIBNEpDtfAUxGxjYZ-zcivxPMkbQCUNz4jtGaDHQLV1G_6gg9suc" }

Paste that back again to u2f-server and it will say:

Successful authentication, counter: 135, user presence 1

I suspect that with all this data, people might be able to pose as the https://example.org server to my Nitrokey. But that server is not going to exist and it seems like a weird attacker model anyway; what should protect me from people posing as example.org is a signed SSL certificate, not this exchange above. Still, I decided not to use a real hostname.

DigitalBrains1 commented 8 months ago

Ah. This is with latest bleeding edge:

ver xous
Xous version: v0.9.15-459-g38855960
Thu, 01 Feb 2024 13:55:23 +0800

But it doesn't work with the stable release either. I just thought you'd prefer testing with bleeding edge.

bunnie commented 8 months ago

Thank you for the incredibly detailed notes. This will help debugging it more later.

As I mentioned elsewhere, I might de-prioritize this until this actually is a blocker for someone's workflow -- at the moment slogging through upgrading the crypto APIs to support the Signal client effort.

DigitalBrains1 commented 8 months ago

Yes, in practice the places where I actually use Precursor with FIDO work fine, so this issue might not be a problem for anyone.

at the moment slogging through upgrading the crypto APIs to support the Signal client effort.

Operator: We get signal. Captain: What ! Operator: Main screen turn on.

:-D Good luck!

bunnie commented 8 months ago

image