fido_assert_user_name returns NULL if there is a single resident credential
codingllama opened this issue · 3 comments
What version of libfido2 are you using?
1.11.0
What operating system are you running?
macOS 12.4
What application are you using in conjunction with libfido2?
Reproducible using libfido2 directly, see attached toy program.
How does the problem manifest itself?
fido_assert_user_name returns NULL if there is a single statement in the assertion. If there is more than one statement user names are returned.
The same applies to other user information, such as fido_assert_user_display_name and fido_assert_user_icon. Based on the current documentation it's hard to say whether this is working as intended.
Note that the use case in question is passwordless, so there are no allowed credentials set.
Is the problem reproducible?
Yes
What are the steps that lead to the problem?
- Register a single resident credential for the RPID
- Run the toy program, output shows NULL
- Register an additional resident credential for the RPID
- Run the toy program, output now shows user names
Does the problem happen with different authenticators?
Seems consistent with Yubico authenticators (5ci and Bio).
Please include the output of fido2-token -L
.
fido2-token -L
$ fido2-token -L ioreg://4294969044: vendor=0x1050, product=0x0406 (Yubico YubiKey FIDO+CCID) ioreg://4294977891: vendor=0x1050, product=0x0406 (Yubico YubiKey FIDO+CCID)
Please include the output of fido2-token -I
.
fido2-token -I
$ fido2-token -I ioreg://4294977891 proto: 0x02 major: 0x05 minor: 0x04 build: 0x03 caps: 0x05 (wink, cbor, msg) version strings: U2F_V2, FIDO_2_0, FIDO_2_1_PRE extension strings: credProtect, hmac-secret transport strings: usb, lightning algorithms: es256 (public-key), eddsa (public-key) aaguid: c5ef55ffad9a4b9fb580adebafe026d0 options: rk, up, noplat, clientPin, credentialMgmtPreview maxmsgsiz: 1200 maxcredcntlst: 8 maxcredlen: 128 maxlargeblob: 0 fwversion: 0x50403 pin protocols: 2, 1 pin retries: 8 uv retries: undefined
Please include the output of FIDO_DEBUG=1
.
FIDO_DEBUG=1
$ FIDO_DEBUG=1 ./pin run_manifest: found 2 hid devices Device #0: [ioreg://4294977891] [Yubico] [YubiKey FIDO+CCID] Device #1: [ioreg://4294969044] [Yubico] [YubiKey FIDO+CCID] Using device [ioreg://4294977891] fido_tx: dev=0x6000038083f0, cmd=0x06 fido_tx: buf=0x6000038083f0, len=8 0000: 32 d1 0b 5d dd 71 5a f5 fido_rx: dev=0x6000038083f0, cmd=0x06, ms=-1 rx_preamble: buf=0x7ff7b71e6d50, len=64 0000: ff ff ff ff 86 00 11 32 d1 0b 5d dd 71 5a f5 2f 0016: b6 cd f1 02 05 04 03 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=0x6000038083f8, len=17 0000: 32 d1 0b 5d dd 71 5a f5 2f b6 cd f1 02 05 04 03 0016: 05 fido_dev_get_cbor_info_tx: dev=0x6000038083f0 fido_tx: dev=0x6000038083f0, cmd=0x10 fido_tx: buf=0x7ff7b71e6590, len=1 0000: 04 fido_dev_get_cbor_info_rx: dev=0x6000038083f0, ci=0x600003d04000, ms=-1 fido_rx: dev=0x6000038083f0, cmd=0x10, ms=-1 rx_preamble: buf=0x7ff7b71e6510, len=64 0000: 2f b6 cd f1 90 00 d2 00 ac 01 83 66 55 32 46 5f 0016: 56 32 68 46 49 44 4f 5f 32 5f 30 6c 46 49 44 4f 0032: 5f 32 5f 31 5f 50 52 45 02 82 6b 63 72 65 64 50 0048: 72 6f 74 65 63 74 6b 68 6d 61 63 2d 73 65 63 72 rx: payload_len=210 rx: buf=0x7ff7b71e6510, len=64 0000: 2f b6 cd f1 00 65 74 03 50 c5 ef 55 ff ad 9a 4b 0016: 9f b5 80 ad eb af e0 26 d0 04 a5 62 72 6b f5 62 0032: 75 70 f5 64 70 6c 61 74 f4 69 63 6c 69 65 6e 74 0048: 50 69 6e f5 75 63 72 65 64 65 6e 74 69 61 6c 4d rx: buf=0x7ff7b71e6510, len=64 0000: 2f b6 cd f1 01 67 6d 74 50 72 65 76 69 65 77 f5 0016: 05 19 04 b0 06 82 02 01 07 08 08 18 80 09 82 63 0032: 75 73 62 69 6c 69 67 68 74 6e 69 6e 67 0a 82 a2 0048: 63 61 6c 67 26 64 74 79 70 65 6a 70 75 62 6c 69 rx: buf=0x7ff7b71e6510, len=64 0000: 2f b6 cd f1 02 63 2d 6b 65 79 a2 63 61 6c 67 27 0016: 64 74 79 70 65 6a 70 75 62 6c 69 63 2d 6b 65 79 0032: 0d 04 0e 1a 00 05 04 03 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=0x7ff7b71e6590, len=210 0000: 00 ac 01 83 66 55 32 46 5f 56 32 68 46 49 44 4f 0016: 5f 32 5f 30 6c 46 49 44 4f 5f 32 5f 31 5f 50 52 0032: 45 02 82 6b 63 72 65 64 50 72 6f 74 65 63 74 6b 0048: 68 6d 61 63 2d 73 65 63 72 65 74 03 50 c5 ef 55 0064: ff ad 9a 4b 9f b5 80 ad eb af e0 26 d0 04 a5 62 0080: 72 6b f5 62 75 70 f5 64 70 6c 61 74 f4 69 63 6c 0096: 69 65 6e 74 50 69 6e f5 75 63 72 65 64 65 6e 74 0112: 69 61 6c 4d 67 6d 74 50 72 65 76 69 65 77 f5 05 0128: 19 04 b0 06 82 02 01 07 08 08 18 80 09 82 63 75 0144: 73 62 69 6c 69 67 68 74 6e 69 6e 67 0a 82 a2 63 0160: 61 6c 67 26 64 74 79 70 65 6a 70 75 62 6c 69 63 0176: 2d 6b 65 79 a2 63 61 6c 67 27 64 74 79 70 65 6a 0192: 70 75 62 6c 69 63 2d 6b 65 79 0d 04 0e 1a 00 05 0208: 04 03 parse_reply_element: cbor type fido_dev_open_rx: FIDO_MAXMSG=2048, maxmsgsiz=1200 Running fake assertion for RPID zarquon fido_dev_authkey_tx: dev=0x6000038083f0 fido_tx: dev=0x6000038083f0, cmd=0x10 fido_tx: buf=0x6000008140a0, len=6 0000: 06 a2 01 02 02 02 fido_dev_authkey_rx: dev=0x6000038083f0, authkey=0x600001f1c000, ms=4999 fido_rx: dev=0x6000038083f0, cmd=0x10, ms=4999 rx_preamble: buf=0x7ff7b71e5c60, len=64 0000: 2f b6 cd f1 90 00 51 00 a1 01 a5 01 02 03 38 18 0016: 20 01 21 58 20 e7 7e c6 e5 7c 77 f1 68 02 af ef 0032: c1 37 37 3e fa a2 26 d9 b4 89 df f7 1e 11 0b 68 0048: d8 a6 ef fb 82 22 58 20 69 27 42 9c 7e c0 85 1c rx: payload_len=81 rx: buf=0x7ff7b71e5c60, len=64 0000: 2f b6 cd f1 00 04 19 c4 36 f5 eb 96 e4 61 f9 58 0016: 19 c6 a6 46 40 04 ef ad 64 9f e8 dd 92 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=0x7ff7b71e5cf0, len=81 0000: 00 a1 01 a5 01 02 03 38 18 20 01 21 58 20 e7 7e 0016: c6 e5 7c 77 f1 68 02 af ef c1 37 37 3e fa a2 26 0032: d9 b4 89 df f7 1e 11 0b 68 d8 a6 ef fb 82 22 58 0048: 20 69 27 42 9c 7e c0 85 1c 04 19 c4 36 f5 eb 96 0064: e4 61 f9 58 19 c6 a6 46 40 04 ef ad 64 9f e8 dd 0080: 92 fido_tx: dev=0x6000038083f0, cmd=0x10 fido_tx: buf=0x600002400080, len=120 0000: 06 a4 01 02 02 05 03 a5 01 02 03 38 18 20 01 21 0016: 58 20 da cc be 95 d4 79 0b 34 fa e5 ae 4c 22 4b 0032: 9f 77 b2 a0 77 f7 45 77 2e a6 28 c7 a4 c1 f1 59 0048: a3 cb 22 58 20 cf 13 04 9f e5 a9 47 93 07 9b 29 0064: f5 c7 bf e4 95 9c 0e 3b 3d 46 73 35 6c ef d7 a1 0080: 6f 75 00 01 d5 06 58 20 29 7b 00 f3 8b ae 57 4e 0096: d0 ac eb 51 85 df b0 93 d3 8e f3 e7 41 7f 8f 4c 0112: 97 b5 a0 f3 db 73 cd 38 fido_rx: dev=0x6000038083f0, cmd=0x10, ms=4992 rx_preamble: buf=0x7ff7b71e5c40, len=64 0000: 2f b6 cd f1 90 00 35 00 a1 02 58 30 99 30 44 50 0016: 02 7e 38 e4 d4 da 4d 36 d8 24 3c a6 6d b1 e5 72 0032: e7 d9 fc 43 b5 a4 28 63 1b ac 97 bc 9c 0c b8 f7 0048: 18 0d 0a 5d 45 7c 33 f5 a6 60 ae 88 00 00 00 00 rx: payload_len=53 fido_rx: buf=0x7ff7b71e5d00, len=53 0000: 00 a1 02 58 30 99 30 44 50 02 7e 38 e4 d4 da 4d 0016: 36 d8 24 3c a6 6d b1 e5 72 e7 d9 fc 43 b5 a4 28 0032: 63 1b ac 97 bc 9c 0c b8 f7 18 0d 0a 5d 45 7c 33 0048: f5 a6 60 ae 88 fido_tx: dev=0x6000038083f0, cmd=0x10 fido_tx: buf=0x600002e04000, len=89 0000: 02 a5 01 67 7a 61 72 71 75 6f 6e 02 58 20 84 e0 0016: c0 ea fa a9 5a 34 c2 93 f2 78 ac 52 e4 5c e5 37 0032: ba b5 e7 52 a0 0e 69 59 a1 3a e1 03 b6 5a 05 a1 0048: 62 75 70 f5 06 58 20 19 5c 87 fc a8 7b 51 2b 49 0064: 29 0c f9 36 28 e7 a9 b4 54 de fa 5c eb 3c 75 ad 0080: 07 f2 86 d5 5f 3c 47 07 02 fido_rx: dev=0x6000038083f0, cmd=0x10, ms=4909 rx_preamble: buf=0x7ff7b71e6550, len=64 0000: 2f b6 cd f1 90 00 e7 00 a4 01 a2 62 69 64 58 30 0016: 09 86 28 be 01 fd 40 5b 96 5f 3a 1f c4 d6 df f9 0032: 2f f5 6e 98 2c bc f9 0d 15 02 35 a1 5a 60 f1 59 0048: 3d 78 ae 5d 53 7e 89 1a 9e af 82 e0 b0 80 b0 38 rx: payload_len=231 rx: buf=0x7ff7b71e6550, len=64 0000: 2f b6 cd f1 00 64 74 79 70 65 6a 70 75 62 6c 69 0016: 63 2d 6b 65 79 02 58 25 3a 57 e8 a8 fb 6b 38 ad 0032: 74 db 90 30 1b 94 1b 56 ab 07 a7 dc 5a 19 a1 41 0048: 27 29 39 0c f3 59 f7 06 05 00 00 02 92 03 58 48 rx: buf=0x7ff7b71e6550, len=64 0000: 2f b6 cd f1 01 30 46 02 21 00 89 ad 07 29 d3 ec 0016: 5b b3 b3 17 0c b0 d1 67 f1 10 2a 66 ae 42 3a 53 0032: a4 01 e8 0a 0a 30 22 ed 1d 13 02 21 00 a6 cf b3 0048: a7 b6 fd 47 fe 71 58 7c ed 22 26 ea d9 68 3e ed rx: buf=0x7ff7b71e6550, len=64 0000: 2f b6 cd f1 02 f7 9f a3 46 91 9d ce 13 ce cf 61 0016: 82 ce 04 a1 62 69 64 58 24 32 61 30 65 36 30 63 0032: 34 2d 65 66 62 33 2d 34 61 34 32 2d 38 36 63 35 0048: 2d 34 37 34 33 62 63 39 37 63 32 33 63 00 00 00 fido_rx: buf=0x7ff7b71e6610, len=231 0000: 00 a4 01 a2 62 69 64 58 30 09 86 28 be 01 fd 40 0016: 5b 96 5f 3a 1f c4 d6 df f9 2f f5 6e 98 2c bc f9 0032: 0d 15 02 35 a1 5a 60 f1 59 3d 78 ae 5d 53 7e 89 0048: 1a 9e af 82 e0 b0 80 b0 38 64 74 79 70 65 6a 70 0064: 75 62 6c 69 63 2d 6b 65 79 02 58 25 3a 57 e8 a8 0080: fb 6b 38 ad 74 db 90 30 1b 94 1b 56 ab 07 a7 dc 0096: 5a 19 a1 41 27 29 39 0c f3 59 f7 06 05 00 00 02 0112: 92 03 58 48 30 46 02 21 00 89 ad 07 29 d3 ec 5b 0128: b3 b3 17 0c b0 d1 67 f1 10 2a 66 ae 42 3a 53 a4 0144: 01 e8 0a 0a 30 22 ed 1d 13 02 21 00 a6 cf b3 a7 0160: b6 fd 47 fe 71 58 7c ed 22 26 ea d9 68 3e ed f7 0176: 9f a3 46 91 9d ce 13 ce cf 61 82 ce 04 a1 62 69 0192: 64 58 24 32 61 30 65 36 30 63 34 2d 65 66 62 33 0208: 2d 34 61 34 32 2d 38 36 63 35 2d 34 37 34 33 62 0224: 63 39 37 63 32 33 63 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=0x600000404180, len=37 fido_tx: dev=0x6000038083f0, cmd=0x11 fido_tx: buf=0x0, len=0 Got 1 assertions user = (null)
Repro program.
repro program
#include <stdio.h>
#include <string.h>
#include <fido.h>
const int kExitFailure = EXIT_FAILURE;
// NOTE: change consts below as appropriate.
const char *kDevPath = "ioreg://4294977891";
const char *rpid = "zarquon";
const char *pin = "12345";
int runOnDevice(const fido_dev_info_t *info) {
if (info == NULL) {
return kExitFailure;
}
printf("Using device [%s]\n", fido_dev_info_path(info));
fido_dev_t *dev = fido_dev_new_with_info(info);
if (dev == NULL) {
return kExitFailure;
}
int r;
if ((r = fido_dev_open_with_info(dev)) != FIDO_OK) {
return r;
}
const unsigned char cdh[32] = "00000000000000000000000000000000";
fido_assert_t *ass = fido_assert_new();
if (r == FIDO_OK)
r = fido_assert_set_clientdata(ass, cdh, 32);
if (r == FIDO_OK)
r = fido_assert_set_rp(ass, rpid);
if (r == FIDO_OK)
r = fido_assert_set_up(ass, FIDO_OPT_TRUE);
if (r == FIDO_OK)
r = fido_assert_set_uv(ass, FIDO_OPT_TRUE);
if (r == FIDO_OK)
r = fido_dev_set_timeout(dev, /* ms= */ 5000);
if (r == FIDO_OK) {
printf("Running fake assertion for RPID %s\n", rpid);
r = fido_dev_get_assert(dev, ass, pin);
}
fido_dev_cancel(dev);
fido_dev_close(dev);
fido_dev_free(&dev);
if (r != FIDO_OK) {
fido_assert_free(&ass);
return r;
}
size_t count = fido_assert_count(ass);
printf("Got %zu assertions\n", count);
for (size_t i = 0; i < count; i++) {
printf("\tuser = %s\n", fido_assert_user_name(ass, i));
}
fido_assert_free(&ass);
return 0;
}
int main() {
fido_init(0);
const size_t kMaxDevs = 64;
fido_dev_info_t *infos = fido_dev_info_new(kMaxDevs);
if (infos == NULL) {
return kExitFailure;
}
size_t nInfos = 0;
fido_dev_info_manifest(infos, kMaxDevs, &nInfos); // always returns FIDO_OK
if (nInfos == 0) {
return kExitFailure;
}
const fido_dev_info_t *tInfo = NULL;
for (size_t i = 0; i < nInfos; i++) {
const fido_dev_info_t *info = fido_dev_info_ptr(infos, i);
if (info == NULL) {
continue;
}
const char *path = fido_dev_info_path(info);
const char *mstr = fido_dev_info_manufacturer_string(info);
const char *pinfo = fido_dev_info_product_string(info);
printf("Device #%zu: [%s] [%s] [%s]\n", i, path, mstr, pinfo);
if (strcmp(kDevPath, path) == 0) {
tInfo = info;
}
}
int r = runOnDevice(tInfo);
if (r != FIDO_OK) {
fprintf(stderr, "libfido error %d: %s\n", r, fido_strerr(r));
}
fido_dev_info_free(&infos, nInfos);
return r;
}
As said in the issue, not sure if this is WAI, but I appreciate the feedback nonetheless.
Hi,
Sounds like this is working as intended. When an authenticator has a single discoverable credential for a specific relying party, it returns the user ID field only (retrievable using the fido_assert_user_id_{ptr,len}()
functions). For the multiple accounts per RP case, it also returns the other fields (unless the authenticator has an internal mechanism for selecting which credential to use). For further details, please see the specification's authenticatorGetAssertion
response structure [1], specifically the user (0x04) member.
Thanks @LDVG for the quick reply and @martelletto for the man update.