xref: /openbmc/qemu/hw/usb/u2f-passthru.c (revision 7e26c92b)
1 /*
2  * U2F USB Passthru device.
3  *
4  * Copyright (c) 2020 César Belley <cesar.belley@lse.epita.fr>
5  * Written by César Belley <cesar.belley@lse.epita.fr>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #include "qemu/osdep.h"
27 #include "qemu/module.h"
28 #include "qemu/main-loop.h"
29 #include "qemu/error-report.h"
30 #include "qapi/error.h"
31 #include "hw/qdev-properties.h"
32 #include "hw/usb.h"
33 #include "migration/vmstate.h"
34 
35 #include "u2f.h"
36 
37 #ifdef CONFIG_LIBUDEV
38 #include <libudev.h>
39 #endif
40 #include <linux/hidraw.h>
41 #include <sys/ioctl.h>
42 
43 #define NONCE_SIZE 8
44 #define BROADCAST_CID 0xFFFFFFFF
45 #define TRANSACTION_TIMEOUT 120000
46 
47 struct transaction {
48     uint32_t cid;
49     uint16_t resp_bcnt;
50     uint16_t resp_size;
51 
52     /* Nonce for broadcast isolation */
53     uint8_t nonce[NONCE_SIZE];
54 };
55 
56 typedef struct U2FPassthruState U2FPassthruState;
57 
58 #define CURRENT_TRANSACTIONS_NUM 4
59 
60 struct U2FPassthruState {
61     U2FKeyState base;
62 
63     /* Host device */
64     char *hidraw;
65     int hidraw_fd;
66 
67     /* Current Transactions */
68     struct transaction current_transactions[CURRENT_TRANSACTIONS_NUM];
69     uint8_t current_transactions_start;
70     uint8_t current_transactions_end;
71     uint8_t current_transactions_num;
72 
73     /* Transaction time checking */
74     int64_t last_transaction_time;
75     QEMUTimer timer;
76 };
77 
78 #define TYPE_U2F_PASSTHRU "u2f-passthru"
79 #define PASSTHRU_U2F_KEY(obj) \
80     OBJECT_CHECK(U2FPassthruState, (obj), TYPE_U2F_PASSTHRU)
81 
82 /* Init packet sizes */
83 #define PACKET_INIT_HEADER_SIZE 7
84 #define PACKET_INIT_DATA_SIZE (U2FHID_PACKET_SIZE - PACKET_INIT_HEADER_SIZE)
85 
86 /* Cont packet sizes */
87 #define PACKET_CONT_HEADER_SIZE 5
88 #define PACKET_CONT_DATA_SIZE (U2FHID_PACKET_SIZE - PACKET_CONT_HEADER_SIZE)
89 
90 struct packet_init {
91     uint32_t cid;
92     uint8_t cmd;
93     uint8_t bcnth;
94     uint8_t bcntl;
95     uint8_t data[PACKET_INIT_DATA_SIZE];
96 } QEMU_PACKED;
97 
98 static inline uint32_t packet_get_cid(const void *packet)
99 {
100     return *((uint32_t *)packet);
101 }
102 
103 static inline bool packet_is_init(const void *packet)
104 {
105     return ((uint8_t *)packet)[4] & (1 << 7);
106 }
107 
108 static inline uint16_t packet_init_get_bcnt(
109         const struct packet_init *packet_init)
110 {
111     uint16_t bcnt = 0;
112     bcnt |= packet_init->bcnth << 8;
113     bcnt |= packet_init->bcntl;
114 
115     return bcnt;
116 }
117 
118 static void u2f_passthru_reset(U2FPassthruState *key)
119 {
120     timer_del(&key->timer);
121     qemu_set_fd_handler(key->hidraw_fd, NULL, NULL, key);
122     key->last_transaction_time = 0;
123     key->current_transactions_start = 0;
124     key->current_transactions_end = 0;
125     key->current_transactions_num = 0;
126 }
127 
128 static void u2f_timeout_check(void *opaque)
129 {
130     U2FPassthruState *key = opaque;
131     int64_t time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
132 
133     if (time > key->last_transaction_time + TRANSACTION_TIMEOUT) {
134         u2f_passthru_reset(key);
135     } else {
136         timer_mod(&key->timer, time + TRANSACTION_TIMEOUT / 4);
137     }
138 }
139 
140 static int u2f_transaction_get_index(U2FPassthruState *key, uint32_t cid)
141 {
142     for (int i = 0; i < key->current_transactions_num; ++i) {
143         int index = (key->current_transactions_start + i)
144             % CURRENT_TRANSACTIONS_NUM;
145         if (cid == key->current_transactions[index].cid) {
146             return index;
147         }
148     }
149     return -1;
150 }
151 
152 static struct transaction *u2f_transaction_get(U2FPassthruState *key,
153                                                uint32_t cid)
154 {
155     int index = u2f_transaction_get_index(key, cid);
156     if (index < 0) {
157         return NULL;
158     }
159     return &key->current_transactions[index];
160 }
161 
162 static struct transaction *u2f_transaction_get_from_nonce(U2FPassthruState *key,
163                                 const uint8_t nonce[NONCE_SIZE])
164 {
165     for (int i = 0; i < key->current_transactions_num; ++i) {
166         int index = (key->current_transactions_start + i)
167             % CURRENT_TRANSACTIONS_NUM;
168         if (key->current_transactions[index].cid == BROADCAST_CID
169             && memcmp(nonce, key->current_transactions[index].nonce,
170                       NONCE_SIZE) == 0) {
171             return &key->current_transactions[index];
172         }
173     }
174     return NULL;
175 }
176 
177 static void u2f_transaction_close(U2FPassthruState *key, uint32_t cid)
178 {
179     int index, next_index;
180     index = u2f_transaction_get_index(key, cid);
181     if (index < 0) {
182         return;
183     }
184     next_index = (index + 1) % CURRENT_TRANSACTIONS_NUM;
185 
186     /* Rearrange to ensure the oldest is at the start position */
187     while (next_index != key->current_transactions_end) {
188         memcpy(&key->current_transactions[index],
189                &key->current_transactions[next_index],
190                sizeof(struct transaction));
191 
192         index = next_index;
193         next_index = (index + 1) % CURRENT_TRANSACTIONS_NUM;
194     }
195 
196     key->current_transactions_end = index;
197     --key->current_transactions_num;
198 
199     if (key->current_transactions_num == 0) {
200         u2f_passthru_reset(key);
201     }
202 }
203 
204 static void u2f_transaction_add(U2FPassthruState *key, uint32_t cid,
205                                 const uint8_t nonce[NONCE_SIZE])
206 {
207     uint8_t index;
208     struct transaction *transaction;
209 
210     if (key->current_transactions_num >= CURRENT_TRANSACTIONS_NUM) {
211         /* Close the oldest transaction */
212         index = key->current_transactions_start;
213         transaction = &key->current_transactions[index];
214         u2f_transaction_close(key, transaction->cid);
215     }
216 
217     /* Index */
218     index = key->current_transactions_end;
219     key->current_transactions_end = (index + 1) % CURRENT_TRANSACTIONS_NUM;
220     ++key->current_transactions_num;
221 
222     /* Transaction */
223     transaction = &key->current_transactions[index];
224     transaction->cid = cid;
225     transaction->resp_bcnt = 0;
226     transaction->resp_size = 0;
227 
228     /* Nonce */
229     if (nonce != NULL) {
230         memcpy(transaction->nonce, nonce, NONCE_SIZE);
231     }
232 }
233 
234 static void u2f_passthru_read(void *opaque);
235 
236 static void u2f_transaction_start(U2FPassthruState *key,
237                                   const struct packet_init *packet_init)
238 {
239     int64_t time;
240 
241     /* Transaction */
242     if (packet_init->cid == BROADCAST_CID) {
243         u2f_transaction_add(key, packet_init->cid, packet_init->data);
244     } else {
245         u2f_transaction_add(key, packet_init->cid, NULL);
246     }
247 
248     /* Time */
249     time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
250     if (key->last_transaction_time == 0) {
251         qemu_set_fd_handler(key->hidraw_fd, u2f_passthru_read, NULL, key);
252         timer_init_ms(&key->timer, QEMU_CLOCK_VIRTUAL, u2f_timeout_check, key);
253         timer_mod(&key->timer, time + TRANSACTION_TIMEOUT / 4);
254     }
255     key->last_transaction_time = time;
256 }
257 
258 static void u2f_passthru_recv_from_host(U2FPassthruState *key,
259                                     const uint8_t packet[U2FHID_PACKET_SIZE])
260 {
261     struct transaction *transaction;
262     uint32_t cid;
263 
264     /* Retrieve transaction */
265     cid = packet_get_cid(packet);
266     if (cid == BROADCAST_CID) {
267         struct packet_init *packet_init;
268         if (!packet_is_init(packet)) {
269             return;
270         }
271         packet_init = (struct packet_init *)packet;
272         transaction = u2f_transaction_get_from_nonce(key, packet_init->data);
273     } else {
274         transaction = u2f_transaction_get(key, cid);
275     }
276 
277     /* Ignore no started transaction */
278     if (transaction == NULL) {
279         return;
280     }
281 
282     if (packet_is_init(packet)) {
283         struct packet_init *packet_init = (struct packet_init *)packet;
284         transaction->resp_bcnt = packet_init_get_bcnt(packet_init);
285         transaction->resp_size = PACKET_INIT_DATA_SIZE;
286 
287         if (packet_init->cid == BROADCAST_CID) {
288             /* Nonce checking for legitimate response */
289             if (memcmp(transaction->nonce, packet_init->data, NONCE_SIZE)
290                 != 0) {
291                 return;
292             }
293         }
294     } else {
295         transaction->resp_size += PACKET_CONT_DATA_SIZE;
296     }
297 
298     /* Transaction end check */
299     if (transaction->resp_size >= transaction->resp_bcnt) {
300         u2f_transaction_close(key, cid);
301     }
302     u2f_send_to_guest(&key->base, packet);
303 }
304 
305 static void u2f_passthru_read(void *opaque)
306 {
307     U2FPassthruState *key = opaque;
308     U2FKeyState *base = &key->base;
309     uint8_t packet[2 * U2FHID_PACKET_SIZE];
310     int ret;
311 
312     /* Full size base queue check */
313     if (base->pending_in_num >= U2FHID_PENDING_IN_NUM) {
314         return;
315     }
316 
317     ret = read(key->hidraw_fd, packet, sizeof(packet));
318     if (ret < 0) {
319         /* Detach */
320         if (base->dev.attached) {
321             usb_device_detach(&base->dev);
322             u2f_passthru_reset(key);
323         }
324         return;
325     }
326     if (ret != U2FHID_PACKET_SIZE) {
327         return;
328     }
329     u2f_passthru_recv_from_host(key, packet);
330 }
331 
332 static void u2f_passthru_recv_from_guest(U2FKeyState *base,
333                                     const uint8_t packet[U2FHID_PACKET_SIZE])
334 {
335     U2FPassthruState *key = PASSTHRU_U2F_KEY(base);
336     uint8_t host_packet[U2FHID_PACKET_SIZE + 1];
337     ssize_t written;
338 
339     if (packet_is_init(packet)) {
340         u2f_transaction_start(key, (struct packet_init *)packet);
341     }
342 
343     host_packet[0] = 0;
344     memcpy(host_packet + 1, packet, U2FHID_PACKET_SIZE);
345 
346     written = write(key->hidraw_fd, host_packet, sizeof(host_packet));
347     if (written != sizeof(host_packet)) {
348         error_report("%s: Bad written size (req 0x%zu, val 0x%zd)",
349                      TYPE_U2F_PASSTHRU, sizeof(host_packet), written);
350     }
351 }
352 
353 static bool u2f_passthru_is_u2f_device(int fd)
354 {
355     int ret, rdesc_size;
356     struct hidraw_report_descriptor rdesc;
357     const uint8_t u2f_hid_report_desc_header[] = {
358         0x06, 0xd0, 0xf1, /* Usage Page (FIDO) */
359         0x09, 0x01,       /* Usage (FIDO) */
360     };
361 
362     /* Get report descriptor size */
363     ret = ioctl(fd, HIDIOCGRDESCSIZE, &rdesc_size);
364     if (ret < 0 || rdesc_size < sizeof(u2f_hid_report_desc_header)) {
365         return false;
366     }
367 
368     /* Get report descriptor */
369     memset(&rdesc, 0x0, sizeof(rdesc));
370     rdesc.size = rdesc_size;
371     ret = ioctl(fd, HIDIOCGRDESC, &rdesc);
372     if (ret < 0) {
373         return false;
374     }
375 
376     /* Header bytes cover specific U2F rdesc values */
377     return memcmp(u2f_hid_report_desc_header, rdesc.value,
378                   sizeof(u2f_hid_report_desc_header)) == 0;
379 }
380 
381 #ifdef CONFIG_LIBUDEV
382 static int u2f_passthru_open_from_device(struct udev_device *device)
383 {
384     const char *devnode = udev_device_get_devnode(device);
385 
386     int fd = qemu_open(devnode, O_RDWR);
387     if (fd < 0) {
388         return -1;
389     } else if (!u2f_passthru_is_u2f_device(fd)) {
390         qemu_close(fd);
391         return -1;
392     }
393     return fd;
394 }
395 
396 static int u2f_passthru_open_from_enumerate(struct udev *udev,
397                                             struct udev_enumerate *enumerate)
398 {
399     struct udev_list_entry *devices, *entry;
400     int ret, fd;
401 
402     ret = udev_enumerate_scan_devices(enumerate);
403     if (ret < 0) {
404         return -1;
405     }
406 
407     devices = udev_enumerate_get_list_entry(enumerate);
408     udev_list_entry_foreach(entry, devices) {
409         struct udev_device *device;
410         const char *syspath = udev_list_entry_get_name(entry);
411 
412         if (syspath == NULL) {
413             continue;
414         }
415 
416         device = udev_device_new_from_syspath(udev, syspath);
417         if (device == NULL) {
418             continue;
419         }
420 
421         fd = u2f_passthru_open_from_device(device);
422         udev_device_unref(device);
423         if (fd >= 0) {
424             return fd;
425         }
426     }
427     return -1;
428 }
429 
430 static int u2f_passthru_open_from_scan(void)
431 {
432     struct udev *udev;
433     struct udev_enumerate *enumerate;
434     int ret, fd = -1;
435 
436     udev = udev_new();
437     if (udev == NULL) {
438         return -1;
439     }
440 
441     enumerate = udev_enumerate_new(udev);
442     if (enumerate == NULL) {
443         udev_unref(udev);
444         return -1;
445     }
446 
447     ret = udev_enumerate_add_match_subsystem(enumerate, "hidraw");
448     if (ret >= 0) {
449         fd = u2f_passthru_open_from_enumerate(udev, enumerate);
450     }
451 
452     udev_enumerate_unref(enumerate);
453     udev_unref(udev);
454 
455     return fd;
456 }
457 #endif
458 
459 static void u2f_passthru_unrealize(U2FKeyState *base)
460 {
461     U2FPassthruState *key = PASSTHRU_U2F_KEY(base);
462 
463     u2f_passthru_reset(key);
464     qemu_close(key->hidraw_fd);
465 }
466 
467 static void u2f_passthru_realize(U2FKeyState *base, Error **errp)
468 {
469     U2FPassthruState *key = PASSTHRU_U2F_KEY(base);
470     int fd;
471 
472     if (key->hidraw == NULL) {
473 #ifdef CONFIG_LIBUDEV
474         fd = u2f_passthru_open_from_scan();
475         if (fd < 0) {
476             error_setg(errp, "%s: Failed to find a U2F USB device",
477                        TYPE_U2F_PASSTHRU);
478             return;
479         }
480 #else
481         error_setg(errp, "%s: Missing hidraw", TYPE_U2F_PASSTHRU);
482         return;
483 #endif
484     } else {
485         fd = qemu_open(key->hidraw, O_RDWR);
486         if (fd < 0) {
487             error_setg(errp, "%s: Failed to open %s", TYPE_U2F_PASSTHRU,
488                        key->hidraw);
489             return;
490         }
491 
492         if (!u2f_passthru_is_u2f_device(fd)) {
493             qemu_close(fd);
494             error_setg(errp, "%s: Passed hidraw does not represent "
495                        "a U2F HID device", TYPE_U2F_PASSTHRU);
496             return;
497         }
498     }
499     key->hidraw_fd = fd;
500     u2f_passthru_reset(key);
501 }
502 
503 static int u2f_passthru_post_load(void *opaque, int version_id)
504 {
505     U2FPassthruState *key = opaque;
506     u2f_passthru_reset(key);
507     return 0;
508 }
509 
510 static const VMStateDescription u2f_passthru_vmstate = {
511     .name = "u2f-key-passthru",
512     .version_id = 1,
513     .minimum_version_id = 1,
514     .post_load = u2f_passthru_post_load,
515     .fields = (VMStateField[]) {
516         VMSTATE_U2F_KEY(base, U2FPassthruState),
517         VMSTATE_END_OF_LIST()
518     }
519 };
520 
521 static Property u2f_passthru_properties[] = {
522     DEFINE_PROP_STRING("hidraw", U2FPassthruState, hidraw),
523     DEFINE_PROP_END_OF_LIST(),
524 };
525 
526 static void u2f_passthru_class_init(ObjectClass *klass, void *data)
527 {
528     DeviceClass *dc = DEVICE_CLASS(klass);
529     U2FKeyClass *kc = U2F_KEY_CLASS(klass);
530 
531     kc->realize = u2f_passthru_realize;
532     kc->unrealize = u2f_passthru_unrealize;
533     kc->recv_from_guest = u2f_passthru_recv_from_guest;
534     dc->desc = "QEMU U2F passthrough key";
535     dc->vmsd = &u2f_passthru_vmstate;
536     device_class_set_props(dc, u2f_passthru_properties);
537 }
538 
539 static const TypeInfo u2f_key_passthru_info = {
540     .name = TYPE_U2F_PASSTHRU,
541     .parent = TYPE_U2F_KEY,
542     .instance_size = sizeof(U2FPassthruState),
543     .class_init = u2f_passthru_class_init
544 };
545 
546 static void u2f_key_passthru_register_types(void)
547 {
548     type_register_static(&u2f_key_passthru_info);
549 }
550 
551 type_init(u2f_key_passthru_register_types)
552