diff options
Diffstat (limited to 'drivers/hid/hid-u2fzero.c')
-rw-r--r-- | drivers/hid/hid-u2fzero.c | 55 |
1 files changed, 42 insertions, 13 deletions
diff --git a/drivers/hid/hid-u2fzero.c b/drivers/hid/hid-u2fzero.c index d70cd3d7f583..31ea7fc69916 100644 --- a/drivers/hid/hid-u2fzero.c +++ b/drivers/hid/hid-u2fzero.c @@ -26,6 +26,30 @@ #define HID_REPORT_SIZE 64 +enum hw_revision { + HW_U2FZERO, + HW_NITROKEY_U2F, +}; + +struct hw_revision_config { + u8 rng_cmd; + u8 wink_cmd; + const char *name; +}; + +static const struct hw_revision_config hw_configs[] = { + [HW_U2FZERO] = { + .rng_cmd = 0x21, + .wink_cmd = 0x24, + .name = "U2F Zero", + }, + [HW_NITROKEY_U2F] = { + .rng_cmd = 0xc0, + .wink_cmd = 0xc2, + .name = "NitroKey U2F", + }, +}; + /* We only use broadcast (CID-less) messages */ #define CID_BROADCAST 0xffffffff @@ -52,10 +76,6 @@ struct u2f_hid_report { #define U2F_HID_MSG_LEN(f) (size_t)(((f).init.bcnth << 8) + (f).init.bcntl) -/* Custom extensions to the U2FHID protocol */ -#define U2F_CUSTOM_GET_RNG 0x21 -#define U2F_CUSTOM_WINK 0x24 - struct u2fzero_device { struct hid_device *hdev; struct urb *urb; /* URB for the RNG data */ @@ -67,6 +87,7 @@ struct u2fzero_device { u8 *buf_in; struct mutex lock; bool present; + kernel_ulong_t hw_revision; }; static int u2fzero_send(struct u2fzero_device *dev, struct u2f_hid_report *req) @@ -132,7 +153,7 @@ static int u2fzero_recv(struct u2fzero_device *dev, ret = (wait_for_completion_timeout( &ctx.done, msecs_to_jiffies(USB_CTRL_SET_TIMEOUT))); - if (ret < 0) { + if (ret == 0) { usb_kill_urb(dev->urb); hid_err(hdev, "urb submission timed out"); } else { @@ -154,7 +175,7 @@ static int u2fzero_blink(struct led_classdev *ldev) .report_type = 0, .msg.cid = CID_BROADCAST, .msg.init = { - .cmd = U2F_CUSTOM_WINK, + .cmd = hw_configs[dev->hw_revision].wink_cmd, .bcnth = 0, .bcntl = 0, .data = {0}, @@ -182,7 +203,7 @@ static int u2fzero_rng_read(struct hwrng *rng, void *data, .report_type = 0, .msg.cid = CID_BROADCAST, .msg.init = { - .cmd = U2F_CUSTOM_GET_RNG, + .cmd = hw_configs[dev->hw_revision].rng_cmd, .bcnth = 0, .bcntl = 0, .data = {0}, @@ -191,6 +212,8 @@ static int u2fzero_rng_read(struct hwrng *rng, void *data, struct u2f_hid_msg resp; int ret; size_t actual_length; + /* valid packets must have a correct header */ + int min_length = offsetof(struct u2f_hid_msg, init.data); if (!dev->present) { hid_dbg(dev->hdev, "device not present"); @@ -200,12 +223,12 @@ static int u2fzero_rng_read(struct hwrng *rng, void *data, ret = u2fzero_recv(dev, &req, &resp); /* ignore errors or packets without data */ - if (ret < offsetof(struct u2f_hid_msg, init.data)) + if (ret < min_length) return 0; /* only take the minimum amount of data it is safe to take */ - actual_length = min3((size_t)ret - offsetof(struct u2f_hid_msg, - init.data), U2F_HID_MSG_LEN(resp), max); + actual_length = min3((size_t)ret - min_length, + U2F_HID_MSG_LEN(resp), max); memcpy(data, resp.init.data, actual_length); @@ -295,6 +318,8 @@ static int u2fzero_probe(struct hid_device *hdev, if (dev == NULL) return -ENOMEM; + dev->hw_revision = id->driver_data; + dev->buf_out = devm_kmalloc(&hdev->dev, sizeof(struct u2f_hid_report), GFP_KERNEL); if (dev->buf_out == NULL) @@ -329,7 +354,7 @@ static int u2fzero_probe(struct hid_device *hdev, return ret; } - hid_info(hdev, "U2F Zero LED initialised\n"); + hid_info(hdev, "%s LED initialised\n", hw_configs[dev->hw_revision].name); ret = u2fzero_init_hwrng(dev, minor); if (ret) { @@ -337,7 +362,7 @@ static int u2fzero_probe(struct hid_device *hdev, return ret; } - hid_info(hdev, "U2F Zero RNG initialised\n"); + hid_info(hdev, "%s RNG initialised\n", hw_configs[dev->hw_revision].name); return 0; } @@ -357,7 +382,11 @@ static void u2fzero_remove(struct hid_device *hdev) static const struct hid_device_id u2fzero_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, - USB_DEVICE_ID_U2F_ZERO) }, + USB_DEVICE_ID_U2F_ZERO), + .driver_data = HW_U2FZERO }, + { HID_USB_DEVICE(USB_VENDOR_ID_CLAY_LOGIC, + USB_DEVICE_ID_NITROKEY_U2F), + .driver_data = HW_NITROKEY_U2F }, { } }; MODULE_DEVICE_TABLE(hid, u2fzero_table); |