/* * 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; }