Skip to content

Instantly share code, notes, and snippets.

@hackerb9
Last active August 29, 2022 06:43
Show Gist options
  • Save hackerb9/4abd1484c48c857b4c4b73f4fc9c8e7d to your computer and use it in GitHub Desktop.
Save hackerb9/4abd1484c48c857b4c4b73f4fc9c8e7d to your computer and use it in GitHub Desktop.
Detect U2F (FIDO2) USB security keys by reading the hidraw report descriptor
/*
* Was originally u2f_hidraw_id.c,
* Copyright (c) 2014-2015 Andrew Lutomirski
*
* Mangled into isu2f.c by hackerb9 in 2022 as a demonstration for firejail.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h> /* fprintf() */
#include <string.h> /* strlen() */
#include <fcntl.h> /* open() */
#include <unistd.h> /* read(), close() */
#include <linux/hid.h> /* HID_MAX_DESCRIPTOR_SIZE */
#define HID_RPTDESC_FIRST_BYTE_LONG_ITEM 0xfe
#define HID_RPTDESC_TYPE_GLOBAL 0x1
#define HID_RPTDESC_TYPE_LOCAL 0x2
#define HID_RPTDESC_GLOBAL_ITEM_USAGE_PAGE 0x0
#define HID_RPTDESC_LOCAL_ITEM_USAGE 0x0
int main(int argc, char **argv)
{
char *path = NULL;
unsigned char desc[HID_MAX_DESCRIPTOR_SIZE];
int desclen;
int fd = -1;
int i;
int ret = 1;
unsigned int usage_page = 0;
int is_u2f_token = 0;
if (argc < 2) {
fprintf(stderr, "Usage: isu2f /sys/class/hidraw/*/device/report_descriptor\n");
return 1;
}
while (*(++argv)) {
path = *argv;
is_u2f_token = 0;
fd = open(path, O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
perror(path);
continue;
}
desclen = read(fd, desc, sizeof(desc));
if (desclen < 0) {
perror(path);
continue;
/* XXX Maybe should handle EINTR or short reads */
}
if (desclen == 0) {
fprintf(stderr, "%s: Empty\n", path);
continue;
}
/* Parse the report descriptor. */
for (i = 0; i < desclen; ) {
/*
* The first byte of the report descriptor is a tag, a type,
* and a code that helps determine the size.
*/
unsigned char tag = desc[i] >> 4;
unsigned char type = (desc[i] >> 2) & 0x3;
unsigned char sizecode = desc[i] & 0x3;
int size, j;
unsigned int value = 0;
if (desc[i] == HID_RPTDESC_FIRST_BYTE_LONG_ITEM) {
/* Long item; skip it. */
if (i + 1 >= desclen) {
fprintf(stderr, "%s: Bad report descriptor: EOF when expecting long_item length.\n", path);
break;
}
i += (desc[i+1] + 3); /* Can't overflow. */
continue;
}
size = (sizecode < 3 ? sizecode : 4);
if (i + 1 + size > desclen) {
fprintf(stderr, "%s: Bad report descriptor: EOF when expecting item length.\n", path);
i += 1 + size;
continue;
}
for (j = 0; j < size; j++)
value |= (desc[i + 1 + j] << 8*j);
if (type == HID_RPTDESC_TYPE_GLOBAL &&
tag == HID_RPTDESC_GLOBAL_ITEM_USAGE_PAGE)
usage_page = value;
/*
* Detect U2F tokens. See:
* https://fidoalliance.org/specs/fido-u2f-HID-protocol-v1.0-rd-20141008.pdf
* http://www.usb.org/developers/hidpage/HUTRR48.pdf
*/
if (type == HID_RPTDESC_TYPE_LOCAL &&
tag == HID_RPTDESC_LOCAL_ITEM_USAGE) {
if (usage_page == 0xf1d0 && value == 0x1) {
is_u2f_token = 1;
break;
}
}
i += 1 + size;
}
/* Fit in 80 cols: lop off "/report_descriptor" */
int l=strlen(path);
if (l>18 && (strcmp(path+l-18, "/report_descriptor") == 0))
path[l-18] = '\0';
printf("%s: %s\n", path,
(is_u2f_token)?
"Yup, this is a U2F_TOKEN":
"Nope, not a U2F_TOKEN");
ret = 0;
if (fd != -1)
close(fd);
} /* Matches 'while (++argv) {...' */
if (fd != -1)
close(fd);
return ret;
}
@hackerb9
Copy link
Author

hackerb9 commented Aug 29, 2022

Note: This returns true to the shell if any U2F keys were found. False, if none are plugged in.

@hackerb9
Copy link
Author

Note 2: While only tested with USB, this would likely work with bluetooth as well since it uses the same HID format.

@hackerb9
Copy link
Author

Compilation:

cc -o isu2f isu2f.c

Usage

isu2f  /sys/class/hidraw/*/device/report_descriptor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment