From 955d4f76efc1f0e5669bded5361c65553109f1d6 Mon Sep 17 00:00:00 2001 From: Radoslav Gerganov Date: Wed, 6 Mar 2019 11:47:04 +0200 Subject: [PATCH 1/2] Add support for hidg devices on Linux There is a HID gadget driver on Linux which provides emulation of USB HID devices. This could be very useful for testing the Solo firmware without actual hardware, using only a Linux box. This patch adds a command line argument which specifies whether the existing UDP backing should be used or the new one which reads and writes to /dev/hidg0. Testing done: 1. Created HID device with configfs 2. Started "./main -b hidg" as root 3. Successfully executed Webauthn registration and authentication on the same Linux machine Closes: #122 --- fido2/main.c | 38 +++++++++++++++++++++++++++++++++++- pc/app.h | 3 +++ pc/device.c | 55 ++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 83 insertions(+), 13 deletions(-) diff --git a/fido2/main.c b/fido2/main.c index 0ed2d90..0faa7b1 100644 --- a/fido2/main.c +++ b/fido2/main.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "cbor.h" #include "device.h" @@ -19,10 +21,44 @@ #if !defined(TEST) -int main() +bool use_udp = true; + +void usage(const char * cmd) +{ + fprintf(stderr, "Usage: %s [-b udp|hidg]\n", cmd); + fprintf(stderr, " -b backing implementation: udp(default) or hidg\n"); + exit(1); +} + +int main(int argc, char *argv[]) { uint8_t hidmsg[64]; uint32_t t1 = 0; + int opt; + + while ((opt = getopt(argc, argv, "b:")) != -1) + { + switch (opt) + { + case 'b': + if (strcmp("udp", optarg) == 0) + { + use_udp = true; + } + else if (strcmp("hidg", optarg) == 0) + { + use_udp = false; + } + else + { + usage(argv[0]); + } + break; + default: + usage(argv[0]); + break; + } + } set_logging_mask( /*0*/ diff --git a/pc/app.h b/pc/app.h index 8d15715..b5e8bd2 100644 --- a/pc/app.h +++ b/pc/app.h @@ -7,6 +7,7 @@ #ifndef SRC_APP_H_ #define SRC_APP_H_ +#include #define USING_DEV_BOARD @@ -20,6 +21,8 @@ void printing_init(); +extern bool use_udp; + // 0xRRGGBB #define LED_INIT_VALUE 0x000800 #define LED_WINK_VALUE 0x000008 diff --git a/pc/device.c b/pc/device.c index c3b4673..a789228 100644 --- a/pc/device.c +++ b/pc/device.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "device.h" #include "cbor.h" @@ -118,12 +119,6 @@ void udp_send(int fd, uint8_t * buf, int size) } } -void udp_close(int fd) -{ - close(fd); -} - - uint32_t millis() { @@ -134,18 +129,42 @@ uint32_t millis() } -static int serverfd = 0; +static int fd = 0; void usbhid_init() { - // just bridge to UDP for now for pure software testing - serverfd = udp_server(); + if (use_udp) + { + fd = udp_server(); + } + else + { + fd = open("/dev/hidg0", O_RDWR); + if (fd < 0) + { + perror("hidg open"); + exit(1); + } + } } // Receive 64 byte USB HID message, don't block, return size of packet, return 0 if nothing int usbhid_recv(uint8_t * msg) { - int l = udp_recv(serverfd, msg, HID_MESSAGE_SIZE); + int l = 0; + if (use_udp) + { + l = udp_recv(fd, msg, HID_MESSAGE_SIZE); + } + else + { + l = read(fd, msg, HID_MESSAGE_SIZE); /* Flawfinder: ignore */ + if (l < 0) + { + perror("hidg read"); + exit(1); + } + } uint8_t magic_cmd[] = "\xac\x10\x52\xca\x95\xe5\x69\xde\x69\xe0\x2e\xbf" "\xf3\x33\x48\x5f\x13\xf9\xb2\xda\x34\xc5\xa8\xa3" "\x40\x52\x66\x97\xa9\xab\x2e\x0b\x39\x4d\x8d\x04" @@ -166,12 +185,23 @@ int usbhid_recv(uint8_t * msg) // Send 64 byte USB HID message void usbhid_send(uint8_t * msg) { - udp_send(serverfd, msg, HID_MESSAGE_SIZE); + if (use_udp) + { + udp_send(fd, msg, HID_MESSAGE_SIZE); + } + else + { + if (write(fd, msg, HID_MESSAGE_SIZE) < 0) + { + perror("hidg write"); + exit(1); + } + } } void usbhid_close() { - udp_close(serverfd); + close(fd); } void int_handler(int i) @@ -185,6 +215,7 @@ void device_init() { signal(SIGINT, int_handler); + printf1(TAG_GREEN, "Using %s backing\n", use_udp ? "UDP" : "hidg"); usbhid_init(); authenticator_initialize(); From 6a288243c1f80a578f14741a69e869784f4d7d20 Mon Sep 17 00:00:00 2001 From: Nicolas Stalder Date: Thu, 7 Mar 2019 01:24:43 +0100 Subject: [PATCH 2/2] Add Makefile for installing a HID gadget The Makefile has targets for building, installing and uninstalling a HID gadget which acts as FIDO2 authenticator. Tested on Ubuntu 18.04 but should work on other distros as well. The only assumption being made is that kernel source is available at /usr/src/linux-source-$(KERNEL_VERSION).tar.bz2. A possible improvement would be to have a configure script which finds the correct kernel source archive. --- tools/gadgetfs/Makefile | 65 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 tools/gadgetfs/Makefile diff --git a/tools/gadgetfs/Makefile b/tools/gadgetfs/Makefile new file mode 100644 index 0000000..a9beca3 --- /dev/null +++ b/tools/gadgetfs/Makefile @@ -0,0 +1,65 @@ +TOP := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +KERNEL_FULL_VERSION := $(shell uname -r) +KERNEL_VERSION := $(shell uname -r | grep -o "^[^-]*") +KERNEL_MAJOR := $(shell uname -r | cut -d. -f1) +KERNEL_MINOR := $(shell uname -r | cut -d. -f2) + +MANUFACTURER = "Solo" +SERIAL = "1234567890" +IDVENDOR = "0x0483" +IDPRODUCT = "0xa2ca" +PRODUCT = "Solo Software Authenticator" +CONFIGFS = /sys/kernel/config +CONFIGFS_FIDO2 = $(CONFIGFS)/usb_gadget/fido2 + +obj-m := dummy_hcd.o +KVERSION := $(shell uname -r) +SHELL := /bin/bash + +all: dummy_hcd.ko + +install: dummy_hcd.ko + modprobe libcomposite + insmod dummy_hcd.ko + mkdir -p $(CONFIGFS_FIDO2) + mkdir -p $(CONFIGFS_FIDO2)/configs/c.1 + mkdir -p $(CONFIGFS_FIDO2)/functions/hid.usb0 + echo 0 > $(CONFIGFS_FIDO2)/functions/hid.usb0/protocol + echo 0 > $(CONFIGFS_FIDO2)/functions/hid.usb0/subclass + echo 64 > $(CONFIGFS_FIDO2)/functions/hid.usb0/report_length + echo -ne "\x06\xd0\xf1\x09\x01\xa1\x01\x09\x20\x15\x00\x26\xff\x00\x75\x08\x95\x40\x81\x02\x09\x21\x15\x00\x26\xff\x00\x75\x08\x95\x40\x91\x02\xc0" > $(CONFIGFS_FIDO2)/functions/hid.usb0/report_desc + mkdir $(CONFIGFS_FIDO2)/strings/0x409 + mkdir $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409 + echo $(IDPRODUCT) > $(CONFIGFS_FIDO2)/idProduct + echo $(IDVENDOR) > $(CONFIGFS_FIDO2)/idVendor + echo $(SERIAL) > $(CONFIGFS_FIDO2)/strings/0x409/serialnumber + echo $(MANUFACTURER) > $(CONFIGFS_FIDO2)/strings/0x409/manufacturer + echo $(PRODUCT) > $(CONFIGFS_FIDO2)/strings/0x409/product + echo "Configuration 1" > $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409/configuration + echo 120 > $(CONFIGFS_FIDO2)/configs/c.1/MaxPower + ln -s $(CONFIGFS_FIDO2)/functions/hid.usb0 $(CONFIGFS_FIDO2)/configs/c.1 + echo "dummy_udc.0" > $(CONFIGFS_FIDO2)/UDC + +uninstall: + echo "" > $(CONFIGFS_FIDO2)/UDC + rm $(CONFIGFS_FIDO2)/configs/c.1/hid.usb0 + rmdir $(CONFIGFS_FIDO2)/configs/c.1/strings/0x409 + rmdir $(CONFIGFS_FIDO2)/configs/c.1 + rmdir $(CONFIGFS_FIDO2)/functions/hid.usb0 + rmdir $(CONFIGFS_FIDO2)/strings/0x409 + rmdir $(CONFIGFS_FIDO2) + rmmod dummy_hcd.ko + +dummy_hcd.ko: dummy_hcd.c + $(MAKE) -C /lib/modules/$(KERNEL_FULL_VERSION)/build M=$(TOP) modules + +dummy_hcd.c: /usr/src/linux-source-$(KERNEL_VERSION).tar.bz2 + tar -xvf $^ linux-source-$(KERNEL_VERSION)/drivers/usb/gadget/udc/dummy_hcd.c + cp linux-source-$(KERNEL_VERSION)/drivers/usb/gadget/udc/dummy_hcd.c $@ + +clean: + $(MAKE) -C /lib/modules/$(KERNEL_FULL_VERSION)/build M=$(TOP) clean + rm -rf linux-source-$(KERNEL_VERSION) + rm -f dummy_hcd.c + +