psanford / tpm-fido

A WebAuthn/U2F token protected by a TPM (Go/Linux)
MIT License
299 stars 17 forks source link

Can't get this working #1

Closed darkdragon-001 closed 3 years ago

darkdragon-001 commented 3 years ago

I added a few more debug outputs, and it fails in pinentry.go:113 with err == "pinentry: inappropriate ioctl for device"'. When I comment out the pinentry check (this is just for user confirmation and is not getting any input string, right?), registration works but authentication fails withinvalid key: invalid key handle (key handle size: 20)`. Any help appreciated!

Fedora 34, Gnome, TPM 2.0, Lenovo T490

psanford commented 3 years ago

pinentry is for user presence confirmation. Do you know what package is currently providing pinentry on your system? This is what mine looks like on ubuntu 20.04:

$ update-alternatives --display pinentry
pinentry - auto mode
  link best version is /usr/bin/pinentry-gnome3
  link currently points to /usr/bin/pinentry-gnome3
  link pinentry is /usr/bin/pinentry
  slave pinentry.1.gz is /usr/share/man/man1/pinentry.1.gz
/usr/bin/pinentry-gnome3 - priority 90
  slave pinentry.1.gz: /usr/share/man/man1/pinentry-gnome3.1.gz
/usr/bin/pinentry-gtk-2 - priority 85
  slave pinentry.1.gz: /usr/share/man/man1/pinentry-gtk-2.1.gz

The invalid key handle error happens when you get a keyhandle back from the site you've registered at and tpm-fido can't decode it because its not the correct format. I could image that happening on a site where you've registered multiple keys, but I wouldn't expect that to cause an actual problem, it would fail trying to auth with key handles for other keys but it should succeed when it gets the correct key handle.

Are you seeing that issue on multiple sites, or is it just one? Can you test on https://webauthn.io/ to see if it works there?

darkdragon-001 commented 3 years ago

I am also using pinentry-gnome3 and just testing on https://webauthn.io/. Do I somehow need to clear my browser storage between (unsuccessful) trials? Furthermore, I am running via sudo to access /dev/tpm0. Is this the correct approach?

psanford commented 3 years ago

Running as sudo will prevent pinentry from displaying to your user. I just pushed a change to default to use /dev/tpmrm0 instead of /dev/tpm0. At least on ubuntu, tpmrm0 has more lax permissions, allowing users in the tss group to access it. If thats also how it works on fedora you can add your user to the tss group and then run it without elevated privileges. Or you could try chgrp'ing the device temporarily to group that includes your user.

The docs weren't very clear, but you also need permission to access /dev/uhid, so be sure to check its permissions as well. (I just pushed a small update to the readme that hopefully makes that more clear).

darkdragon-001 commented 3 years ago

Thanks a lot! With your updated readme (it's also tss group on Fedora), no errors appear any more and registrations seems successful. Just the udev rule doesn't work, but manually changing it works. Just with authentication, I think I have to debug a little more, since it doesn't show any log output and the site does nothing after clicking Login. What should happen when pressing the login button?

psanford commented 3 years ago

Here's a video showing how it works for me. https://user-images.githubusercontent.com/33375/127883213-cb25073f-f488-4d46-948e-8e5d4912fcbd.mp4

psanford commented 3 years ago

This video also includes the log output from tpm-fido: https://user-images.githubusercontent.com/33375/127884721-17c55083-fbe7-47b6-997e-9a44dbcbbd0a.mp4

darkdragon-001 commented 3 years ago

Thanks for your videos :ok_hand: Obviously, registration is already failing then for me since the Success! Now try logging in :-) message is not shown...

I was debugging a bit further and noticed that browsers don't accept my response: Chromium: DOMException: The operation either timed out or was not allowed. See: https://www.w3.org/TR/webauthn-2/#sctn-privacy-considerations-client. Firefox: DOMException: The operation failed for an unknown transient reason

Also I noted that the timeout of 750 ms might be a bit small to click the pinentry button :see_no_evil: That's why there are always multiple RegisterCmd received.

psanford commented 3 years ago

The protocol is designed to have a short timeout with the browser retrying. On a physical key you don't notice because you can press the button at any time (but the reason the key blinks is that register command is being called over and over).

In order to support the short timeout but also not have a UI that flashes on and off, we have some special code that manages the pinentry UI separately from the actual FIDO HID requests: https://github.com/psanford/tpm-fido/blob/master/pinentry/pinentry.go#L79

darkdragon-001 commented 3 years ago

Thanks for your explanation! Do you have any idea what goes wrong with the browser?

psanford commented 3 years ago

Hard to say without more information. Can you apply the following patch to add some debug logs and then share the resulting logs after testing again?

diff --git a/fidohid/fidohid.go b/fidohid/fidohid.go
index 8c72def..21c9b71 100644
--- a/fidohid/fidohid.go
+++ b/fidohid/fidohid.go
@@ -458,6 +458,7 @@ func (t *SoftToken) WriteResponse(ctx context.Context, evt AuthEvent, data []byt
 }

 func writeRespose(d *uhid.Device, chanID uint32, cmd CmdType, data []byte, status uint16) error {
+       log.Printf("Write response: chan=%d cmd=%s status=%d data=%x", chanID, cmd, status, data)

        initial := true
        pktSize := initialPacketDataLen
diff --git a/tpmfido.go b/tpmfido.go
index 3c86b6b..72de7cb 100644
--- a/tpmfido.go
+++ b/tpmfido.go
@@ -80,6 +80,8 @@ func (s *server) run() {

                req := evt.Req

+               log.Printf("got req: %+v\n", req)
+
                if req.Command == fidoauth.CmdAuthenticate {
                        log.Printf("got AuthenticateCmd site=%s", sitesignatures.FromAppParam(req.Authenticate.ApplicationParam))
darkdragon-001 commented 3 years ago

See log below.

2021/08/03 23:25:48 Write response: chan=4294967295 cmd=CmdInit status=0 data=9e55163c732f74cc000000010201000000
2021/08/03 23:25:48 unsuppoted cmd: CmdCbor 16
2021/08/03 23:25:48 Write response: chan=1 cmd=CmdCbor status=27904 data=
2021/08/03 23:25:48 got req: &{Command:1 Param1:3 Param2:0 Size:64 Data:[195 44 38 106 113 37 202 144 35 150 123 11 148 53 62 1 183 153 188 68 11 153 121 107 67 73 52 55 178 62 45 175 116 166 234 146 19 201 156 47 116 178 36 146 179 32 207 64 38 42 148 193 169 80 160 57 127 41 37 11 96 132 30 240 0 0] Register:0xc0000cc540 Authenticate:}
2021/08/03 23:25:48 got RegisterCmd site=webauthn.io
2021/08/03 23:25:49 Write response: chan=1 cmd=CmdMsg status=27013 data=
2021/08/03 23:25:49 got req: &{Command:1 Param1:3 Param2:0 Size:64 Data:[195 44 38 106 113 37 202 144 35 150 123 11 148 53 62 1 183 153 188 68 11 153 121 107 67 73 52 55 178 62 45 175 116 166 234 146 19 201 156 47 116 178 36 146 179 32 207 64 38 42 148 193 169 80 160 57 127 41 37 11 96 132 30 240 0 0] Register:0xc00001a1c0 Authenticate:}
2021/08/03 23:25:49 got RegisterCmd site=webauthn.io
2021/08/03 23:25:50 Write response: chan=1 cmd=CmdMsg status=36864 data=05044b1c822a26f625b4475ba35f9b2e2e83f80b6dc3a9d89810c265d10d9aa7e871b6b191a28d3c6372c0e277c1f5717dbe998811572355990f19edae7ee842715e1754504d4649444f0000007e0020e196c9208d80fb09d603cfc68e0e5fca2ce9de4d601bcdd810180556901efa22001078b1ee86cd92bb2db6770d53619bed9cc9d52face71730ffa5400dc6f669e83f87e83868721a3f37910c2b6038c1cc453efeebce139a6cdc65bdd435528c95630628b855c0bda1c63d42108ed3e05f3e44b32d18ef45552fc5b554504d4649444f000000580023000b00040072000000100018000b0003001000204b1c822a26f625b4475ba35f9b2e2e83f80b6dc3a9d89810c265d10d9aa7e8710020b6b191a28d3c6372c0e277c1f5717dbe998811572355990f19edae7ee842715e54504d4649444f000000205f3c15d163f9b9a25a240f513107f9229334f2063fe60dd737bc06d390dec8253082017e30820124a003020102020101300a06082a8648ce3d040302303c3111300f06035504030c08536f66742055324631143012060355040a0c0b47697448756220496e632e3111300f060355040b0c085365637572697479301e170d3137303732363230303930385a170d3237303732343230303930385a303c3111300f06035504030c08536f66742055324631143012060355040a0c0b47697448756220496e632e3111300f060355040b0c0853656375726974793059301306072a8648ce3d020106082a8648ce3d03010703420004f69cab24144bb4ef87f70f231c5cd4f57804acf8e0c6b2b3e352183d80391f6bd279d26a4c836474e6c2da2393ffac1d50346c5c23906557933ecb93ff6eded1a31730153013060b2b0601040182e51c020101040403020308300a06082a8648ce3d0403020348003045022100fe221d97b8eaea12bb9f4214850f481765b5e095935ea1a3d66d0fb16f39f722022064d7dc2f5c6c382af765f5786a39b0b14a974528ef7ddf2102151b884ad4417a3046022100b7fd8dd400082798eccabab987a340f5cec69d01b9ac1c7dbbefce36ae3f52f00221009612064127c79f05bb5edb9af19e3b1f6934e6570dc83bf3ea7619a992399aa8
psanford commented 3 years ago

I see the problem. Your TPM's private key handle is 126 bytes vs mine is only 94 bytes. That small bit extra is enough to overflow the keyhandle field in the U2F register response payload (https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-response-message-success).

I should be able to trim out some extra bytes from the keyhandle payload to get it down under size limit. I'll also add an error check for that condition for the future.

psanford commented 3 years ago

I just pushed a change to the main branch that I think should fix this issue for you. Can you try it out and let me know?

darkdragon-001 commented 3 years ago

Works like a charm :heart_eyes: Thank you so much for your quick responses and debugging!