diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 15:35:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 15:35:18 +0000 |
commit | b750101eb236130cf056c675997decbac904cc49 (patch) | |
tree | a5df1a06754bdd014cb975c051c83b01c9a97532 /src/udev/fido_id/fido_id_desc.c | |
parent | Initial commit. (diff) | |
download | systemd-b750101eb236130cf056c675997decbac904cc49.tar.xz systemd-b750101eb236130cf056c675997decbac904cc49.zip |
Adding upstream version 252.22.upstream/252.22
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/udev/fido_id/fido_id_desc.c')
-rw-r--r-- | src/udev/fido_id/fido_id_desc.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/udev/fido_id/fido_id_desc.c b/src/udev/fido_id/fido_id_desc.c new file mode 100644 index 0000000..2dfa759 --- /dev/null +++ b/src/udev/fido_id/fido_id_desc.c @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* Inspired by Andrew Lutomirski's 'u2f-hidraw-policy.c' */ + +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include "fido_id_desc.h" + +#define HID_RPTDESC_FIRST_BYTE_LONG_ITEM 0xfeu +#define HID_RPTDESC_TYPE_GLOBAL 0x1u +#define HID_RPTDESC_TYPE_LOCAL 0x2u +#define HID_RPTDESC_TAG_USAGE_PAGE 0x0u +#define HID_RPTDESC_TAG_USAGE 0x0u + +/* + * HID usage for FIDO CTAP1 ("U2F") and CTAP2 security tokens. + * https://fidoalliance.org/specs/fido-u2f-v1.0-ps-20141009/fido-u2f-u2f_hid.h-v1.0-ps-20141009.txt + * https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#usb-discovery + * https://www.usb.org/sites/default/files/hutrr48.pdf + */ +#define FIDO_FULL_USAGE_CTAPHID 0xf1d00001u + +/* + * Parses a HID report descriptor and identifies FIDO CTAP1 ("U2F")/CTAP2 security tokens based on their + * declared usage. + * A positive return value indicates that the report descriptor belongs to a FIDO security token. + * https://www.usb.org/sites/default/files/documents/hid1_11.pdf (Section 6.2.2) + */ +int is_fido_security_token_desc(const uint8_t *desc, size_t desc_len) { + uint32_t usage = 0; + + for (size_t pos = 0; pos < desc_len; ) { + uint8_t tag, type, size_code; + size_t size; + uint32_t value; + + /* Report descriptors consists of short items (1-5 bytes) and long items (3-258 bytes). */ + if (desc[pos] == HID_RPTDESC_FIRST_BYTE_LONG_ITEM) { + /* No long items are defined in the spec; skip them. + * The length of the data in a long item is contained in the byte after the long + * item tag. The header consists of three bytes: special long item tag, length, + * actual tag. */ + if (pos + 1 >= desc_len) + return -EINVAL; + pos += desc[pos + 1] + 3; + continue; + } + + /* The first byte of a short item encodes tag, type and size. */ + tag = desc[pos] >> 4; /* Bits 7 to 4 */ + type = (desc[pos] >> 2) & 0x3; /* Bits 3 and 2 */ + size_code = desc[pos] & 0x3; /* Bits 1 and 0 */ + /* Size is coded as follows: + * 0 -> 0 bytes, 1 -> 1 byte, 2 -> 2 bytes, 3 -> 4 bytes + */ + size = size_code < 3 ? size_code : 4; + /* Consume header byte. */ + pos++; + + /* Extract the item value coded on size bytes. */ + if (pos + size > desc_len) + return -EINVAL; + value = 0; + for (size_t i = 0; i < size; i++) + value |= (uint32_t) desc[pos + i] << (8 * i); + /* Consume value bytes. */ + pos += size; + + if (type == HID_RPTDESC_TYPE_GLOBAL && tag == HID_RPTDESC_TAG_USAGE_PAGE) { + /* A usage page is a 16 bit value coded on at most 16 bits. */ + if (size > 2) + return -EINVAL; + /* A usage page sets the upper 16 bits of a following usage. */ + usage = (value & 0x0000ffffu) << 16; + } + + if (type == HID_RPTDESC_TYPE_LOCAL && tag == HID_RPTDESC_TAG_USAGE) { + /* A usage is a 32 bit value, but is prepended with the current usage page if + * coded on less than 4 bytes (that is, at most 2 bytes). */ + if (size == 4) + usage = value; + else + usage = (usage & 0xffff0000u) | (value & 0x0000ffffu); + if (usage == FIDO_FULL_USAGE_CTAPHID) + return 1; + } + } + + return 0; +} |