2 * U2F USB Passthru device.
4 * Copyright (c) 2020 César Belley <cesar.belley@lse.epita.fr>
5 * Written by César Belley <cesar.belley@lse.epita.fr>
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
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"
33 #include "migration/vmstate.h"
40 #include <linux/hidraw.h>
41 #include <sys/ioctl.h>
44 #define BROADCAST_CID 0xFFFFFFFF
45 #define TRANSACTION_TIMEOUT 120000
52 /* Nonce for broadcast isolation */
53 uint8_t nonce
[NONCE_SIZE
];
56 typedef struct U2FPassthruState U2FPassthruState
;
58 #define CURRENT_TRANSACTIONS_NUM 4
60 struct U2FPassthruState
{
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
;
73 /* Transaction time checking */
74 int64_t last_transaction_time
;
78 #define TYPE_U2F_PASSTHRU "u2f-passthru"
79 #define PASSTHRU_U2F_KEY(obj) \
80 OBJECT_CHECK(U2FPassthruState, (obj), TYPE_U2F_PASSTHRU)
82 /* Init packet sizes */
83 #define PACKET_INIT_HEADER_SIZE 7
84 #define PACKET_INIT_DATA_SIZE (U2FHID_PACKET_SIZE - PACKET_INIT_HEADER_SIZE)
86 /* Cont packet sizes */
87 #define PACKET_CONT_HEADER_SIZE 5
88 #define PACKET_CONT_DATA_SIZE (U2FHID_PACKET_SIZE - PACKET_CONT_HEADER_SIZE)
95 uint8_t data
[PACKET_INIT_DATA_SIZE
];
98 static inline uint32_t packet_get_cid(const void *packet
)
100 return *((uint32_t *)packet
);
103 static inline bool packet_is_init(const void *packet
)
105 return ((uint8_t *)packet
)[4] & (1 << 7);
108 static inline uint16_t packet_init_get_bcnt(
109 const struct packet_init
*packet_init
)
112 bcnt
|= packet_init
->bcnth
<< 8;
113 bcnt
|= packet_init
->bcntl
;
118 static void u2f_passthru_reset(U2FPassthruState
*key
)
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;
128 static void u2f_timeout_check(void *opaque
)
130 U2FPassthruState
*key
= opaque
;
131 int64_t time
= qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
);
133 if (time
> key
->last_transaction_time
+ TRANSACTION_TIMEOUT
) {
134 u2f_passthru_reset(key
);
136 timer_mod(&key
->timer
, time
+ TRANSACTION_TIMEOUT
/ 4);
140 static int u2f_transaction_get_index(U2FPassthruState
*key
, uint32_t cid
)
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
) {
152 static struct transaction
*u2f_transaction_get(U2FPassthruState
*key
,
155 int index
= u2f_transaction_get_index(key
, cid
);
159 return &key
->current_transactions
[index
];
162 static struct transaction
*u2f_transaction_get_from_nonce(U2FPassthruState
*key
,
163 const uint8_t nonce
[NONCE_SIZE
])
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
,
171 return &key
->current_transactions
[index
];
177 static void u2f_transaction_close(U2FPassthruState
*key
, uint32_t cid
)
179 int index
, next_index
;
180 index
= u2f_transaction_get_index(key
, cid
);
184 next_index
= (index
+ 1) % CURRENT_TRANSACTIONS_NUM
;
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
));
193 next_index
= (index
+ 1) % CURRENT_TRANSACTIONS_NUM
;
196 key
->current_transactions_end
= index
;
197 --key
->current_transactions_num
;
199 if (key
->current_transactions_num
== 0) {
200 u2f_passthru_reset(key
);
204 static void u2f_transaction_add(U2FPassthruState
*key
, uint32_t cid
,
205 const uint8_t nonce
[NONCE_SIZE
])
208 struct transaction
*transaction
;
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
);
218 index
= key
->current_transactions_end
;
219 key
->current_transactions_end
= (index
+ 1) % CURRENT_TRANSACTIONS_NUM
;
220 ++key
->current_transactions_num
;
223 transaction
= &key
->current_transactions
[index
];
224 transaction
->cid
= cid
;
225 transaction
->resp_bcnt
= 0;
226 transaction
->resp_size
= 0;
230 memcpy(transaction
->nonce
, nonce
, NONCE_SIZE
);
234 static void u2f_passthru_read(void *opaque
);
236 static void u2f_transaction_start(U2FPassthruState
*key
,
237 const struct packet_init
*packet_init
)
242 if (packet_init
->cid
== BROADCAST_CID
) {
243 u2f_transaction_add(key
, packet_init
->cid
, packet_init
->data
);
245 u2f_transaction_add(key
, packet_init
->cid
, NULL
);
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);
255 key
->last_transaction_time
= time
;
258 static void u2f_passthru_recv_from_host(U2FPassthruState
*key
,
259 const uint8_t packet
[U2FHID_PACKET_SIZE
])
261 struct transaction
*transaction
;
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
)) {
271 packet_init
= (struct packet_init
*)packet
;
272 transaction
= u2f_transaction_get_from_nonce(key
, packet_init
->data
);
274 transaction
= u2f_transaction_get(key
, cid
);
277 /* Ignore no started transaction */
278 if (transaction
== NULL
) {
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
;
287 if (packet_init
->cid
== BROADCAST_CID
) {
288 /* Nonce checking for legitimate response */
289 if (memcmp(transaction
->nonce
, packet_init
->data
, NONCE_SIZE
)
295 transaction
->resp_size
+= PACKET_CONT_DATA_SIZE
;
298 /* Transaction end check */
299 if (transaction
->resp_size
>= transaction
->resp_bcnt
) {
300 u2f_transaction_close(key
, cid
);
302 u2f_send_to_guest(&key
->base
, packet
);
305 static void u2f_passthru_read(void *opaque
)
307 U2FPassthruState
*key
= opaque
;
308 U2FKeyState
*base
= &key
->base
;
309 uint8_t packet
[2 * U2FHID_PACKET_SIZE
];
312 /* Full size base queue check */
313 if (base
->pending_in_num
>= U2FHID_PENDING_IN_NUM
) {
317 ret
= read(key
->hidraw_fd
, packet
, sizeof(packet
));
320 if (base
->dev
.attached
) {
321 usb_device_detach(&base
->dev
);
322 u2f_passthru_reset(key
);
326 if (ret
!= U2FHID_PACKET_SIZE
) {
329 u2f_passthru_recv_from_host(key
, packet
);
332 static void u2f_passthru_recv_from_guest(U2FKeyState
*base
,
333 const uint8_t packet
[U2FHID_PACKET_SIZE
])
335 U2FPassthruState
*key
= PASSTHRU_U2F_KEY(base
);
336 uint8_t host_packet
[U2FHID_PACKET_SIZE
+ 1];
339 if (packet_is_init(packet
)) {
340 u2f_transaction_start(key
, (struct packet_init
*)packet
);
344 memcpy(host_packet
+ 1, packet
, U2FHID_PACKET_SIZE
);
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
);
353 static bool u2f_passthru_is_u2f_device(int fd
)
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) */
362 /* Get report descriptor size */
363 ret
= ioctl(fd
, HIDIOCGRDESCSIZE
, &rdesc_size
);
364 if (ret
< 0 || rdesc_size
< sizeof(u2f_hid_report_desc_header
)) {
368 /* Get report descriptor */
369 memset(&rdesc
, 0x0, sizeof(rdesc
));
370 rdesc
.size
= rdesc_size
;
371 ret
= ioctl(fd
, HIDIOCGRDESC
, &rdesc
);
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;
381 #ifdef CONFIG_LIBUDEV
382 static int u2f_passthru_open_from_device(struct udev_device
*device
)
384 const char *devnode
= udev_device_get_devnode(device
);
386 int fd
= qemu_open_old(devnode
, O_RDWR
);
389 } else if (!u2f_passthru_is_u2f_device(fd
)) {
396 static int u2f_passthru_open_from_enumerate(struct udev
*udev
,
397 struct udev_enumerate
*enumerate
)
399 struct udev_list_entry
*devices
, *entry
;
402 ret
= udev_enumerate_scan_devices(enumerate
);
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
);
412 if (syspath
== NULL
) {
416 device
= udev_device_new_from_syspath(udev
, syspath
);
417 if (device
== NULL
) {
421 fd
= u2f_passthru_open_from_device(device
);
422 udev_device_unref(device
);
430 static int u2f_passthru_open_from_scan(void)
433 struct udev_enumerate
*enumerate
;
441 enumerate
= udev_enumerate_new(udev
);
442 if (enumerate
== NULL
) {
447 ret
= udev_enumerate_add_match_subsystem(enumerate
, "hidraw");
449 fd
= u2f_passthru_open_from_enumerate(udev
, enumerate
);
452 udev_enumerate_unref(enumerate
);
459 static void u2f_passthru_unrealize(U2FKeyState
*base
)
461 U2FPassthruState
*key
= PASSTHRU_U2F_KEY(base
);
463 u2f_passthru_reset(key
);
464 qemu_close(key
->hidraw_fd
);
467 static void u2f_passthru_realize(U2FKeyState
*base
, Error
**errp
)
469 U2FPassthruState
*key
= PASSTHRU_U2F_KEY(base
);
472 if (key
->hidraw
== NULL
) {
473 #ifdef CONFIG_LIBUDEV
474 fd
= u2f_passthru_open_from_scan();
476 error_setg(errp
, "%s: Failed to find a U2F USB device",
481 error_setg(errp
, "%s: Missing hidraw", TYPE_U2F_PASSTHRU
);
485 fd
= qemu_open_old(key
->hidraw
, O_RDWR
);
487 error_setg(errp
, "%s: Failed to open %s", TYPE_U2F_PASSTHRU
,
492 if (!u2f_passthru_is_u2f_device(fd
)) {
494 error_setg(errp
, "%s: Passed hidraw does not represent "
495 "a U2F HID device", TYPE_U2F_PASSTHRU
);
500 u2f_passthru_reset(key
);
503 static int u2f_passthru_post_load(void *opaque
, int version_id
)
505 U2FPassthruState
*key
= opaque
;
506 u2f_passthru_reset(key
);
510 static const VMStateDescription u2f_passthru_vmstate
= {
511 .name
= "u2f-key-passthru",
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()
521 static Property u2f_passthru_properties
[] = {
522 DEFINE_PROP_STRING("hidraw", U2FPassthruState
, hidraw
),
523 DEFINE_PROP_END_OF_LIST(),
526 static void u2f_passthru_class_init(ObjectClass
*klass
, void *data
)
528 DeviceClass
*dc
= DEVICE_CLASS(klass
);
529 U2FKeyClass
*kc
= U2F_KEY_CLASS(klass
);
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 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
540 static const TypeInfo u2f_key_passthru_info
= {
541 .name
= TYPE_U2F_PASSTHRU
,
542 .parent
= TYPE_U2F_KEY
,
543 .instance_size
= sizeof(U2FPassthruState
),
544 .class_init
= u2f_passthru_class_init
547 static void u2f_key_passthru_register_types(void)
549 type_register_static(&u2f_key_passthru_info
);
552 type_init(u2f_key_passthru_register_types
)