Closed darkdragon-001 closed 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?
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?
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).
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?
Here's a video showing how it works for me. https://user-images.githubusercontent.com/33375/127883213-cb25073f-f488-4d46-948e-8e5d4912fcbd.mp4
This video also includes the log output from tpm-fido: https://user-images.githubusercontent.com/33375/127884721-17c55083-fbe7-47b6-997e-9a44dbcbbd0a.mp4
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.
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
Thanks for your explanation! Do you have any idea what goes wrong with the browser?
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))
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
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.
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?
Works like a charm :heart_eyes: Thank you so much for your quick responses and debugging!
I added a few more debug outputs, and it fails in
pinentry.go:113
witherr == "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 with
invalid key: invalid key handle (key handle size: 20)`. Any help appreciated!Fedora 34, Gnome, TPM 2.0, Lenovo T490