assert without -p still triggers userPresence check on authenticator
restena-sw opened this issue · 3 comments
What version of libfido2 are you using?
master (cf85116)
What operating system are you running?
Debian 11
What application are you using in conjunction with libfido2?
examples/cred & examples/assert
How does the problem manifest itself?
After successful registration of a credential, subsequent assert for the credential always triggers the blink&wait on the authenticator even if the the "-p" command-line option is NOT set.
Is the problem reproducible?
Yes.
What are the steps that lead to the problem?
Example:
./cred -t es256 -k 12345 -r /dev/hidraw6
./assert 12345 /dev/hidraw6
Does the problem happen with different authenticators?
On two different Yubico products at least (Yubikey 5C, no PIN set; Yubikey Bio, PIN set + fingerprint enrolled).
Please include the output of fido2-token -L
.
fido2-token -L
# fido2-token -L /dev/hidraw4: vendor=0x1050, product=0x0402 (Yubico YubiKey FIDO) /dev/hidraw6: vendor=0x1050, product=0x0407 (Yubico YubiKey OTP+FIDO+CCID)
Please include the output of fido2-token -I
.
fido2-token -I
# fido2-token -I /dev/hidraw4 proto: 0x02 major: 0x05 minor: 0x05 build: 0x06 caps: 0x05 (wink, cbor, msg) version strings: U2F_V2, FIDO_2_0, FIDO_2_1_PRE, FIDO_2_1 extension strings: credProtect, hmac-secret, largeBlobKey, credBlob, minPinLength aaguid: d8522d9f575b486688a9ba99fa02f35b options: rk, up, uv, noplat, uvToken, alwaysUv, credMgmt, authnrCfg, bioEnroll, clientPin, largeBlobs, pinUvAuthToken, setMinPINLength, nomakeCredUvNotRqd, credentialMgmtPreview, userVerificationMgmtPreview maxmsgsiz: 1200 maxcredcntlst: 8 maxcredlen: 128 fwversion: 0x50506 pin protocols: 2, 1 pin retries: 8 uv retries: 3 sensor type: 1 (touch) max samples: 16 # fido2-token -I /dev/hidraw6 proto: 0x02 major: 0x05 minor: 0x01 build: 0x02 caps: 0x05 (wink, cbor, msg) version strings: U2F_V2, FIDO_2_0 extension strings: hmac-secret aaguid: cb69481e8ff7403993ec0a2729a154a8 options: rk, up, noplat, noclientPin maxmsgsiz: 1200 maxcredcntlst: 0 maxcredlen: 0 fwversion: 0x0 pin protocols: 1 pin retries: undefined uv retries: undefined
Please include the output of FIDO_DEBUG=1
.
FIDO_DEBUG=1
# FIDO_DEBUG=1 ./examples/assert 12345 /dev/hidraw6 fido_tx: dev=0x55d3159c7320, cmd=0x06 fido_tx: buf=0x55d3159c7320, len=8 0000: a4 ae 30 1e bc c2 fb 0e fido_rx: dev=0x55d3159c7320, cmd=0x06, ms=-1 rx_preamble: buf=0x7ffe9d2c7e40, len=64 0000: ff ff ff ff 86 00 11 a4 ae 30 1e bc c2 fb 0e 01 0016: 21 00 0a 02 05 01 02 05 00 00 00 00 00 00 00 00 0032: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 rx: payload_len=17 fido_rx: buf=0x55d3159c7328, len=17 0000: a4 ae 30 1e bc c2 fb 0e 01 21 00 0a 02 05 01 02 0016: 05 fido_dev_get_cbor_info_tx: dev=0x55d3159c7320 fido_tx: dev=0x55d3159c7320, cmd=0x10 fido_tx: buf=0x7ffe9d2c7e97, len=1 0000: 04 fido_dev_get_cbor_info_rx: dev=0x55d3159c7320, ci=0x55d3159c7470, ms=-1 fido_rx: dev=0x55d3159c7320, cmd=0x10, ms=-1 rx_preamble: buf=0x7ffe9d2c7db0, len=64 0000: 01 21 00 0a 90 00 56 00 a6 01 82 66 55 32 46 5f 0016: 56 32 68 46 49 44 4f 5f 32 5f 30 02 81 6b 68 6d 0032: 61 63 2d 73 65 63 72 65 74 03 50 cb 69 48 1e 8f 0048: f7 40 39 93 ec 0a 27 29 a1 54 a8 04 a4 62 72 6b rx: payload_len=86 rx: buf=0x7ffe9d2c7db0, len=64 0000: 01 21 00 0a 00 f5 62 75 70 f5 64 70 6c 61 74 f4 0016: 69 63 6c 69 65 6e 74 50 69 6e f4 05 19 04 b0 06 0032: 81 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fido_rx: buf=0x55d3159c7570, len=86 0000: 00 a6 01 82 66 55 32 46 5f 56 32 68 46 49 44 4f 0016: 5f 32 5f 30 02 81 6b 68 6d 61 63 2d 73 65 63 72 0032: 65 74 03 50 cb 69 48 1e 8f f7 40 39 93 ec 0a 27 0048: 29 a1 54 a8 04 a4 62 72 6b f5 62 75 70 f5 64 70 0064: 6c 61 74 f4 69 63 6c 69 65 6e 74 50 69 6e f4 05 0080: 19 04 b0 06 81 01 fido_dev_open_rx: FIDO_MAXMSG=2048, maxmsgsiz=1200 fido_tx: dev=0x55d3159c7320, cmd=0x10 fido_tx: buf=0x55d3159c7f30, len=48 0000: 02 a2 01 69 6c 6f 63 61 6c 68 6f 73 74 02 58 20 0016: a2 fe ee a3 57 46 c3 8f 60 3e 6e 0d 6b 75 30 d9 0032: c9 43 88 22 5a 69 60 1a 19 9d eb 0a 05 59 4b 36 fido_rx: dev=0x55d3159c7320, cmd=0x10, ms=-1 rx_preamble: buf=0x7ffe9d2c7e00, len=64 0000: 01 21 00 0a 90 00 c2 00 a4 01 a2 62 69 64 50 9b 0016: 8b 5f 1d 1b c8 91 14 d6 8b 9b 2a 3d e2 7c 19 64 0032: 74 79 70 65 6a 70 75 62 6c 69 63 2d 6b 65 79 02 0048: 58 25 49 96 0d e5 88 0e 8c 68 74 34 17 0f 64 76 rx: payload_len=194 rx: buf=0x7ffe9d2c7e00, len=64 0000: 01 21 00 0a 00 60 5b 8f e4 ae b9 a2 86 32 c7 99 0016: 5c f3 ba 83 1d 97 63 01 00 00 03 d0 03 58 48 30 0032: 46 02 21 00 bd 9b fa a6 bb 3a 6e 99 12 c4 ee 27 0048: 57 60 23 ef 0c 9d c9 1a 25 45 62 62 c3 32 4e 93 rx: buf=0x7ffe9d2c7e00, len=64 0000: 01 21 00 0a 01 88 3a 00 a3 02 21 00 b7 20 5d 1e 0016: f3 3e fe a3 98 80 bb 2a 57 ac 02 c7 96 61 01 db 0032: cd 3b 7c 0c ed 99 01 d8 5f 94 76 8d 04 a1 62 69 0048: 64 58 20 78 1c 78 60 ad 88 d2 63 32 62 2a f1 74 rx: buf=0x7ffe9d2c7e00, len=64 0000: 01 21 00 0a 02 5d ed b2 e7 a4 2b 44 89 29 39 c5 0016: 56 64 01 27 0d bb c4 49 00 00 00 00 00 00 00 00 0032: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fido_rx: buf=0x55d3159c86b0, len=194 0000: 00 a4 01 a2 62 69 64 50 9b 8b 5f 1d 1b c8 91 14 0016: d6 8b 9b 2a 3d e2 7c 19 64 74 79 70 65 6a 70 75 0032: 62 6c 69 63 2d 6b 65 79 02 58 25 49 96 0d e5 88 0048: 0e 8c 68 74 34 17 0f 64 76 60 5b 8f e4 ae b9 a2 0064: 86 32 c7 99 5c f3 ba 83 1d 97 63 01 00 00 03 d0 0080: 03 58 48 30 46 02 21 00 bd 9b fa a6 bb 3a 6e 99 0096: 12 c4 ee 27 57 60 23 ef 0c 9d c9 1a 25 45 62 62 0112: c3 32 4e 93 88 3a 00 a3 02 21 00 b7 20 5d 1e f3 0128: 3e fe a3 98 80 bb 2a 57 ac 02 c7 96 61 01 db cd 0144: 3b 7c 0c ed 99 01 d8 5f 94 76 8d 04 a1 62 69 64 0160: 58 20 78 1c 78 60 ad 88 d2 63 32 62 2a f1 74 5d 0176: ed b2 e7 a4 2b 44 89 29 39 c5 56 64 01 27 0d bb 0192: c4 49 adjust_assert_count: cbor_type adjust_assert_count: cbor_type adjust_assert_count: cbor_type adjust_assert_count: cbor_type cbor_decode_assert_authdata: buf=0x55d3159c81a0, len=37 assert: fopen: No such file or directory assert: read_ec_pubkey
Remark
Inspecting the code, I realised that options.up simply remains unset when the "-p" parameter is not supplied to assert - which then may explain the observed behaviour because options.up is spec'ed as true by default in the CTAP2 spec.
In code, up
is initialised to false, is not changed during parameter parsing if -p is unset, and setting the actual CTAP2 parameter happens inside a if (up &&
conditional, which is skipped when the parameter is unset.
I changed the source to always set fido_assert_set_up() like this in assert.c line 151:
if ((r = fido_assert_set_up(assert, up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK)
to make options.up always explicitly set; but that did not change the observed behaviour. (authenticators still wait for user interaction)
So, I suspect, in addition to the code issue of falling back to spec defaults rather than explicitly setting to false, there might be an actual issue with Yubikey firmwares in that they do not honour the request not to execute userPresence checks.
Hi,
examples/assert.c:151 controls the behavior of the assertion verification, not the request itself. You have the corresponding code for the request sent to the authenticator at examples/assert.c:297. Making your modifications there should get you your desired behavior. We've deliberately not included UP=false
in the example; the -p
flag simply enforces that the user presence flag is set in the returned authenticator data.
For more control over the various options, you may want to experiment with fido2-assert
instead. For example:
$ fido2-assert -G -i assert_param -t up=false /dev/hidraw7 | fido2-assert -V pubkey es256
$ echo $?
0
Ah, that's very helpful indeed!
-
It's more of a documentation bug in the examples/ then. The README states for "assert":
The -p option requests that the user be present.
It would be more correct to state `The -p option verifies that the authenticator asserted that the user was present." -
I've modified line 297, and yes: it does yield the desired behaviour (immediate auth transaction without user interaction). There is only one oddity I noticed when running with FIDO_DEBUG=1:
# FIDO_DEBUG=1 ./assert 12345 /dev/hidraw2
fido_tx: dev=0x5585d47bf320, cmd=0x06
fido_tx: buf=0x5585d47bf320, len=8
0000: d3 7b 9e ee d9 3c e7 07
fido_rx: dev=0x5585d47bf320, cmd=0x06, ms=-1
rx_preamble: buf=0x7ffd5290f870, len=64
0000: ff ff ff ff 86 00 11 d3 7b 9e ee d9 3c e7 07 01
0016: 22 00 04 02 05 01 02 05 00 00 00 00 00 00 00 00
0032: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
rx: payload_len=17
fido_rx: buf=0x5585d47bf328, len=17
0000: d3 7b 9e ee d9 3c e7 07 01 22 00 04 02 05 01 02
0016: 05
fido_dev_get_cbor_info_tx: dev=0x5585d47bf320
fido_tx: dev=0x5585d47bf320, cmd=0x10
fido_tx: buf=0x7ffd5290f8c7, len=1
0000: 04
fido_dev_get_cbor_info_rx: dev=0x5585d47bf320, ci=0x5585d47bf470, ms=-1
fido_rx: dev=0x5585d47bf320, cmd=0x10, ms=-1
rx_preamble: buf=0x7ffd5290f7e0, len=64
0000: 01 22 00 04 90 00 56 00 a6 01 82 66 55 32 46 5f
0016: 56 32 68 46 49 44 4f 5f 32 5f 30 02 81 6b 68 6d
0032: 61 63 2d 73 65 63 72 65 74 03 50 cb 69 48 1e 8f
0048: f7 40 39 93 ec 0a 27 29 a1 54 a8 04 a4 62 72 6b
rx: payload_len=86
rx: buf=0x7ffd5290f7e0, len=64
0000: 01 22 00 04 00 f5 62 75 70 f5 64 70 6c 61 74 f4
0016: 69 63 6c 69 65 6e 74 50 69 6e f4 05 19 04 b0 06
0032: 81 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
fido_rx: buf=0x5585d47bf570, len=86
0000: 00 a6 01 82 66 55 32 46 5f 56 32 68 46 49 44 4f
0016: 5f 32 5f 30 02 81 6b 68 6d 61 63 2d 73 65 63 72
0032: 65 74 03 50 cb 69 48 1e 8f f7 40 39 93 ec 0a 27
0048: 29 a1 54 a8 04 a4 62 72 6b f5 62 75 70 f5 64 70
0064: 6c 61 74 f4 69 63 6c 69 65 6e 74 50 69 6e f4 05
0080: 19 04 b0 06 81 01
fido_dev_open_rx: FIDO_MAXMSG=2048, maxmsgsiz=1200
fido_tx: dev=0x5585d47bf320, cmd=0x10
fido_tx: buf=0x5585d47c0190, len=54
0000: 02 a3 01 69 6c 6f 63 61 6c 68 6f 73 74 02 58 20
0016: a2 fe ee a3 57 46 c3 8f 60 3e 6e 0d 6b 75 30 d9
0032: c9 43 88 22 5a 69 60 1a 19 9d eb 0a 05 59 4b 36
0048: 05 a1 62 75 70 f4
fido_rx: dev=0x5585d47bf320, cmd=0x10, ms=-1
rx_preamble: buf=0x7ffd5290f830, len=64
0000: 01 22 00 04 90 00 c1 00 a4 01 a2 62 69 64 50 87
0016: 9c c5 20 6d a3 db ef 96 d5 13 e7 8d 8d b1 80 64
0032: 74 79 70 65 6a 70 75 62 6c 69 63 2d 6b 65 79 02
0048: 58 25 49 96 0d e5 88 0e 8c 68 74 34 17 0f 64 76
rx: payload_len=193
rx: buf=0x7ffd5290f830, len=64
0000: 01 22 00 04 00 60 5b 8f e4 ae b9 a2 86 32 c7 99
0016: 5c f3 ba 83 1d 97 63 00 00 00 03 d5 03 58 47 30
0032: 45 02 21 00 de 70 a5 ff 4d a4 d8 5e 35 d8 34 7e
0048: 3b 8f 9d f3 f6 32 01 7e cd 0c 08 5e 51 7e a1 62
rx: buf=0x7ffd5290f830, len=64
0000: 01 22 00 04 01 17 a9 9d 2d 02 20 69 c6 8b 5c bf
0016: b7 b0 ca b9 82 a1 c8 b6 3a 4c d1 ec 5b 69 29 07
0032: 36 fa 45 f9 af 7f f0 3f 4e ea 01 04 a1 62 69 64
0048: 58 20 78 1c 78 60 ad 88 d2 63 32 62 2a f1 74 5d
rx: buf=0x7ffd5290f830, len=64
0000: 01 22 00 04 02 ed b2 e7 a4 2b 44 89 29 39 c5 56
0016: 64 01 27 0d bb c4 49 00 00 00 00 00 00 00 00 00
0032: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0048: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
fido_rx: buf=0x5585d47c06b0, len=193
0000: 00 a4 01 a2 62 69 64 50 87 9c c5 20 6d a3 db ef
0016: 96 d5 13 e7 8d 8d b1 80 64 74 79 70 65 6a 70 75
0032: 62 6c 69 63 2d 6b 65 79 02 58 25 49 96 0d e5 88
0048: 0e 8c 68 74 34 17 0f 64 76 60 5b 8f e4 ae b9 a2
0064: 86 32 c7 99 5c f3 ba 83 1d 97 63 00 00 00 03 d5
0080: 03 58 47 30 45 02 21 00 de 70 a5 ff 4d a4 d8 5e
0096: 35 d8 34 7e 3b 8f 9d f3 f6 32 01 7e cd 0c 08 5e
0112: 51 7e a1 62 17 a9 9d 2d 02 20 69 c6 8b 5c bf b7
0128: b0 ca b9 82 a1 c8 b6 3a 4c d1 ec 5b 69 29 07 36
0144: fa 45 f9 af 7f f0 3f 4e ea 01 04 a1 62 69 64 58
0160: 20 78 1c 78 60 ad 88 d2 63 32 62 2a f1 74 5d ed
0176: b2 e7 a4 2b 44 89 29 39 c5 56 64 01 27 0d bb c4
0192: 49
adjust_assert_count: cbor_type
adjust_assert_count: cbor_type
adjust_assert_count: cbor_type
adjust_assert_count: cbor_type
cbor_decode_assert_authdata: buf=0x5585d47bf5a0, len=37
cbor_decode_assert_authdata: buf=0x5585d47d9550, len=37
fido_check_flags: flags=00
fido_check_flags: up=1, uv=0
fido_get_signed_hash: cose_alg=-7
Note the two lines
fido_check_flags: flags=00
fido_check_flags: up=1, uv=0
The assertion did correctly not set userPresence, but the lib function fido_check_flags was called with up=1 anyway? And then doesn't fail?
It's more of a documentation bug in the examples/ then. The README states for "assert": The -p option requests that the user be present. It would be more correct to state `The -p option verifies that the authenticator asserted that the user was present."
We'll give it a look and see if we can improve it. Thank you!
Note the two lines
fido_check_flags: flags=00 fido_check_flags: up=1, uv=0
The assertion did correctly not set userPresence, but the lib function fido_check_flags was called with up=1 anyway? And then doesn't fail?
up=1
is FIDO_OPT_FALSE
. To verify that that the user presence flag has been set by the authenticator, fido_assert_set_up()
must be called with FIDO_OPT_TRUE
before fido_assert_verify()
is called.
$ export FIDO_DEBUG=1
$ fido2-assert -G -i assert_param -t up=false /dev/hidraw7 | fido2-assert -V -p pubkey es256
...
fido_check_flags: flags=00
fido_check_flags: up=2, uv=0
fido_check_flags: CTAP_AUTHDATA_USER_PRESENT
fido_assert_verify: fido_check_flags
fido2-assert: fido_assert_verify: FIDO_ERR_INVALID_PARAM
$ echo $?
1