hid-u2fzero.c (8731B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * U2F Zero LED and RNG driver 4 * 5 * Copyright 2018 Andrej Shadura <andrew@shadura.me> 6 * Loosely based on drivers/hid/hid-led.c 7 * and drivers/usb/misc/chaoskey.c 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation, version 2. 12 */ 13 14#include <linux/hid.h> 15#include <linux/hidraw.h> 16#include <linux/hw_random.h> 17#include <linux/leds.h> 18#include <linux/module.h> 19#include <linux/mutex.h> 20#include <linux/usb.h> 21 22#include "usbhid/usbhid.h" 23#include "hid-ids.h" 24 25#define DRIVER_SHORT "u2fzero" 26 27#define HID_REPORT_SIZE 64 28 29enum hw_revision { 30 HW_U2FZERO, 31 HW_NITROKEY_U2F, 32}; 33 34struct hw_revision_config { 35 u8 rng_cmd; 36 u8 wink_cmd; 37 const char *name; 38}; 39 40static const struct hw_revision_config hw_configs[] = { 41 [HW_U2FZERO] = { 42 .rng_cmd = 0x21, 43 .wink_cmd = 0x24, 44 .name = "U2F Zero", 45 }, 46 [HW_NITROKEY_U2F] = { 47 .rng_cmd = 0xc0, 48 .wink_cmd = 0xc2, 49 .name = "NitroKey U2F", 50 }, 51}; 52 53/* We only use broadcast (CID-less) messages */ 54#define CID_BROADCAST 0xffffffff 55 56struct u2f_hid_msg { 57 u32 cid; 58 union { 59 struct { 60 u8 cmd; 61 u8 bcnth; 62 u8 bcntl; 63 u8 data[HID_REPORT_SIZE - 7]; 64 } init; 65 struct { 66 u8 seq; 67 u8 data[HID_REPORT_SIZE - 5]; 68 } cont; 69 }; 70} __packed; 71 72struct u2f_hid_report { 73 u8 report_type; 74 struct u2f_hid_msg msg; 75} __packed; 76 77#define U2F_HID_MSG_LEN(f) (size_t)(((f).init.bcnth << 8) + (f).init.bcntl) 78 79struct u2fzero_device { 80 struct hid_device *hdev; 81 struct urb *urb; /* URB for the RNG data */ 82 struct led_classdev ldev; /* Embedded struct for led */ 83 struct hwrng hwrng; /* Embedded struct for hwrng */ 84 char *led_name; 85 char *rng_name; 86 u8 *buf_out; 87 u8 *buf_in; 88 struct mutex lock; 89 bool present; 90 kernel_ulong_t hw_revision; 91}; 92 93static int u2fzero_send(struct u2fzero_device *dev, struct u2f_hid_report *req) 94{ 95 int ret; 96 97 mutex_lock(&dev->lock); 98 99 memcpy(dev->buf_out, req, sizeof(struct u2f_hid_report)); 100 101 ret = hid_hw_output_report(dev->hdev, dev->buf_out, 102 sizeof(struct u2f_hid_msg)); 103 104 mutex_unlock(&dev->lock); 105 106 if (ret < 0) 107 return ret; 108 109 return ret == sizeof(struct u2f_hid_msg) ? 0 : -EMSGSIZE; 110} 111 112struct u2fzero_transfer_context { 113 struct completion done; 114 int status; 115}; 116 117static void u2fzero_read_callback(struct urb *urb) 118{ 119 struct u2fzero_transfer_context *ctx = urb->context; 120 121 ctx->status = urb->status; 122 complete(&ctx->done); 123} 124 125static int u2fzero_recv(struct u2fzero_device *dev, 126 struct u2f_hid_report *req, 127 struct u2f_hid_msg *resp) 128{ 129 int ret; 130 struct hid_device *hdev = dev->hdev; 131 struct u2fzero_transfer_context ctx; 132 133 mutex_lock(&dev->lock); 134 135 memcpy(dev->buf_out, req, sizeof(struct u2f_hid_report)); 136 137 dev->urb->context = &ctx; 138 init_completion(&ctx.done); 139 140 ret = usb_submit_urb(dev->urb, GFP_NOIO); 141 if (unlikely(ret)) { 142 hid_err(hdev, "usb_submit_urb failed: %d", ret); 143 goto err; 144 } 145 146 ret = hid_hw_output_report(dev->hdev, dev->buf_out, 147 sizeof(struct u2f_hid_msg)); 148 149 if (ret < 0) { 150 hid_err(hdev, "hid_hw_output_report failed: %d", ret); 151 goto err; 152 } 153 154 ret = (wait_for_completion_timeout( 155 &ctx.done, msecs_to_jiffies(USB_CTRL_SET_TIMEOUT))); 156 if (ret == 0) { 157 usb_kill_urb(dev->urb); 158 hid_err(hdev, "urb submission timed out"); 159 } else { 160 ret = dev->urb->actual_length; 161 memcpy(resp, dev->buf_in, ret); 162 } 163 164err: 165 mutex_unlock(&dev->lock); 166 167 return ret; 168} 169 170static int u2fzero_blink(struct led_classdev *ldev) 171{ 172 struct u2fzero_device *dev = container_of(ldev, 173 struct u2fzero_device, ldev); 174 struct u2f_hid_report req = { 175 .report_type = 0, 176 .msg.cid = CID_BROADCAST, 177 .msg.init = { 178 .cmd = hw_configs[dev->hw_revision].wink_cmd, 179 .bcnth = 0, 180 .bcntl = 0, 181 .data = {0}, 182 } 183 }; 184 return u2fzero_send(dev, &req); 185} 186 187static int u2fzero_brightness_set(struct led_classdev *ldev, 188 enum led_brightness brightness) 189{ 190 ldev->brightness = LED_OFF; 191 if (brightness) 192 return u2fzero_blink(ldev); 193 else 194 return 0; 195} 196 197static int u2fzero_rng_read(struct hwrng *rng, void *data, 198 size_t max, bool wait) 199{ 200 struct u2fzero_device *dev = container_of(rng, 201 struct u2fzero_device, hwrng); 202 struct u2f_hid_report req = { 203 .report_type = 0, 204 .msg.cid = CID_BROADCAST, 205 .msg.init = { 206 .cmd = hw_configs[dev->hw_revision].rng_cmd, 207 .bcnth = 0, 208 .bcntl = 0, 209 .data = {0}, 210 } 211 }; 212 struct u2f_hid_msg resp; 213 int ret; 214 size_t actual_length; 215 /* valid packets must have a correct header */ 216 int min_length = offsetof(struct u2f_hid_msg, init.data); 217 218 if (!dev->present) { 219 hid_dbg(dev->hdev, "device not present"); 220 return 0; 221 } 222 223 ret = u2fzero_recv(dev, &req, &resp); 224 225 /* ignore errors or packets without data */ 226 if (ret < min_length) 227 return 0; 228 229 /* only take the minimum amount of data it is safe to take */ 230 actual_length = min3((size_t)ret - min_length, 231 U2F_HID_MSG_LEN(resp), max); 232 233 memcpy(data, resp.init.data, actual_length); 234 235 return actual_length; 236} 237 238static int u2fzero_init_led(struct u2fzero_device *dev, 239 unsigned int minor) 240{ 241 dev->led_name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL, 242 "%s%u", DRIVER_SHORT, minor); 243 if (dev->led_name == NULL) 244 return -ENOMEM; 245 246 dev->ldev.name = dev->led_name; 247 dev->ldev.max_brightness = LED_ON; 248 dev->ldev.flags = LED_HW_PLUGGABLE; 249 dev->ldev.brightness_set_blocking = u2fzero_brightness_set; 250 251 return devm_led_classdev_register(&dev->hdev->dev, &dev->ldev); 252} 253 254static int u2fzero_init_hwrng(struct u2fzero_device *dev, 255 unsigned int minor) 256{ 257 dev->rng_name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL, 258 "%s-rng%u", DRIVER_SHORT, minor); 259 if (dev->rng_name == NULL) 260 return -ENOMEM; 261 262 dev->hwrng.name = dev->rng_name; 263 dev->hwrng.read = u2fzero_rng_read; 264 dev->hwrng.quality = 1; 265 266 return devm_hwrng_register(&dev->hdev->dev, &dev->hwrng); 267} 268 269static int u2fzero_fill_in_urb(struct u2fzero_device *dev) 270{ 271 struct hid_device *hdev = dev->hdev; 272 struct usb_device *udev; 273 struct usbhid_device *usbhid = hdev->driver_data; 274 unsigned int pipe_in; 275 struct usb_host_endpoint *ep; 276 277 if (dev->hdev->bus != BUS_USB) 278 return -EINVAL; 279 280 udev = hid_to_usb_dev(hdev); 281 282 if (!usbhid->urbout || !usbhid->urbin) 283 return -ENODEV; 284 285 ep = usb_pipe_endpoint(udev, usbhid->urbin->pipe); 286 if (!ep) 287 return -ENODEV; 288 289 dev->urb = usb_alloc_urb(0, GFP_KERNEL); 290 if (!dev->urb) 291 return -ENOMEM; 292 293 pipe_in = (usbhid->urbin->pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); 294 295 usb_fill_int_urb(dev->urb, 296 udev, 297 pipe_in, 298 dev->buf_in, 299 HID_REPORT_SIZE, 300 u2fzero_read_callback, 301 NULL, 302 ep->desc.bInterval); 303 304 return 0; 305} 306 307static int u2fzero_probe(struct hid_device *hdev, 308 const struct hid_device_id *id) 309{ 310 struct u2fzero_device *dev; 311 unsigned int minor; 312 int ret; 313 314 if (!hid_is_usb(hdev)) 315 return -EINVAL; 316 317 dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL); 318 if (dev == NULL) 319 return -ENOMEM; 320 321 dev->hw_revision = id->driver_data; 322 323 dev->buf_out = devm_kmalloc(&hdev->dev, 324 sizeof(struct u2f_hid_report), GFP_KERNEL); 325 if (dev->buf_out == NULL) 326 return -ENOMEM; 327 328 dev->buf_in = devm_kmalloc(&hdev->dev, 329 sizeof(struct u2f_hid_msg), GFP_KERNEL); 330 if (dev->buf_in == NULL) 331 return -ENOMEM; 332 333 ret = hid_parse(hdev); 334 if (ret) 335 return ret; 336 337 dev->hdev = hdev; 338 hid_set_drvdata(hdev, dev); 339 mutex_init(&dev->lock); 340 341 ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); 342 if (ret) 343 return ret; 344 345 u2fzero_fill_in_urb(dev); 346 347 dev->present = true; 348 349 minor = ((struct hidraw *) hdev->hidraw)->minor; 350 351 ret = u2fzero_init_led(dev, minor); 352 if (ret) { 353 hid_hw_stop(hdev); 354 return ret; 355 } 356 357 hid_info(hdev, "%s LED initialised\n", hw_configs[dev->hw_revision].name); 358 359 ret = u2fzero_init_hwrng(dev, minor); 360 if (ret) { 361 hid_hw_stop(hdev); 362 return ret; 363 } 364 365 hid_info(hdev, "%s RNG initialised\n", hw_configs[dev->hw_revision].name); 366 367 return 0; 368} 369 370static void u2fzero_remove(struct hid_device *hdev) 371{ 372 struct u2fzero_device *dev = hid_get_drvdata(hdev); 373 374 mutex_lock(&dev->lock); 375 dev->present = false; 376 mutex_unlock(&dev->lock); 377 378 hid_hw_stop(hdev); 379 usb_poison_urb(dev->urb); 380 usb_free_urb(dev->urb); 381} 382 383static const struct hid_device_id u2fzero_table[] = { 384 { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, 385 USB_DEVICE_ID_U2F_ZERO), 386 .driver_data = HW_U2FZERO }, 387 { HID_USB_DEVICE(USB_VENDOR_ID_CLAY_LOGIC, 388 USB_DEVICE_ID_NITROKEY_U2F), 389 .driver_data = HW_NITROKEY_U2F }, 390 { } 391}; 392MODULE_DEVICE_TABLE(hid, u2fzero_table); 393 394static struct hid_driver u2fzero_driver = { 395 .name = "hid-" DRIVER_SHORT, 396 .probe = u2fzero_probe, 397 .remove = u2fzero_remove, 398 .id_table = u2fzero_table, 399}; 400 401module_hid_driver(u2fzero_driver); 402 403MODULE_LICENSE("GPL"); 404MODULE_AUTHOR("Andrej Shadura <andrew@shadura.me>"); 405MODULE_DESCRIPTION("U2F Zero LED and RNG driver");