1bb014a81SCésar Belley /*
2bb014a81SCésar Belley * U2F USB device.
3bb014a81SCésar Belley *
4bb014a81SCésar Belley * Copyright (c) 2020 César Belley <cesar.belley@lse.epita.fr>
5bb014a81SCésar Belley * Written by César Belley <cesar.belley@lse.epita.fr>
6bb014a81SCésar Belley *
7bb014a81SCésar Belley * Permission is hereby granted, free of charge, to any person obtaining a copy
8bb014a81SCésar Belley * of this software and associated documentation files (the "Software"), to deal
9bb014a81SCésar Belley * in the Software without restriction, including without limitation the rights
10bb014a81SCésar Belley * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11bb014a81SCésar Belley * copies of the Software, and to permit persons to whom the Software is
12bb014a81SCésar Belley * furnished to do so, subject to the following conditions:
13bb014a81SCésar Belley *
14bb014a81SCésar Belley * The above copyright notice and this permission notice shall be included in
15bb014a81SCésar Belley * all copies or substantial portions of the Software.
16bb014a81SCésar Belley *
17bb014a81SCésar Belley * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18bb014a81SCésar Belley * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19bb014a81SCésar Belley * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20bb014a81SCésar Belley * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21bb014a81SCésar Belley * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22bb014a81SCésar Belley * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23bb014a81SCésar Belley * THE SOFTWARE.
24bb014a81SCésar Belley */
25bb014a81SCésar Belley
26bb014a81SCésar Belley #include "qemu/osdep.h"
27bb014a81SCésar Belley #include "qemu/module.h"
28bb014a81SCésar Belley #include "qapi/error.h"
29bb014a81SCésar Belley #include "hw/usb.h"
30bb014a81SCésar Belley #include "hw/usb/hid.h"
31bb014a81SCésar Belley #include "migration/vmstate.h"
32bb014a81SCésar Belley #include "desc.h"
33bb014a81SCésar Belley
34bb014a81SCésar Belley #include "u2f.h"
35bb014a81SCésar Belley
36bb014a81SCésar Belley /* U2F key Vendor / Product */
37bb014a81SCésar Belley #define U2F_KEY_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */
38bb014a81SCésar Belley #define U2F_KEY_PRODUCT_NUM 0x0005
39bb014a81SCésar Belley
40bb014a81SCésar Belley enum {
41bb014a81SCésar Belley STR_MANUFACTURER = 1,
42bb014a81SCésar Belley STR_PRODUCT,
43bb014a81SCésar Belley STR_SERIALNUMBER,
44bb014a81SCésar Belley STR_CONFIG,
45bb014a81SCésar Belley STR_INTERFACE
46bb014a81SCésar Belley };
47bb014a81SCésar Belley
48bb014a81SCésar Belley static const USBDescStrings desc_strings = {
49bb014a81SCésar Belley [STR_MANUFACTURER] = "QEMU",
50bb014a81SCésar Belley [STR_PRODUCT] = "U2F USB key",
51bb014a81SCésar Belley [STR_SERIALNUMBER] = "0",
52bb014a81SCésar Belley [STR_CONFIG] = "U2F key config",
53bb014a81SCésar Belley [STR_INTERFACE] = "U2F key interface"
54bb014a81SCésar Belley };
55bb014a81SCésar Belley
56bb014a81SCésar Belley static const USBDescIface desc_iface_u2f_key = {
57bb014a81SCésar Belley .bInterfaceNumber = 0,
58bb014a81SCésar Belley .bNumEndpoints = 2,
59bb014a81SCésar Belley .bInterfaceClass = USB_CLASS_HID,
60bb014a81SCésar Belley .bInterfaceSubClass = 0x0,
61bb014a81SCésar Belley .bInterfaceProtocol = 0x0,
62bb014a81SCésar Belley .ndesc = 1,
63bb014a81SCésar Belley .descs = (USBDescOther[]) {
64bb014a81SCésar Belley {
65bb014a81SCésar Belley /* HID descriptor */
66bb014a81SCésar Belley .data = (uint8_t[]) {
67bb014a81SCésar Belley 0x09, /* u8 bLength */
68bb014a81SCésar Belley USB_DT_HID, /* u8 bDescriptorType */
69bb014a81SCésar Belley 0x10, 0x01, /* u16 HID_class */
70bb014a81SCésar Belley 0x00, /* u8 country_code */
71bb014a81SCésar Belley 0x01, /* u8 num_descriptors */
72bb014a81SCésar Belley USB_DT_REPORT, /* u8 type: Report */
73bb014a81SCésar Belley 0x22, 0, /* u16 len */
74bb014a81SCésar Belley },
75bb014a81SCésar Belley },
76bb014a81SCésar Belley },
77bb014a81SCésar Belley .eps = (USBDescEndpoint[]) {
78bb014a81SCésar Belley {
79bb014a81SCésar Belley .bEndpointAddress = USB_DIR_IN | 0x01,
80bb014a81SCésar Belley .bmAttributes = USB_ENDPOINT_XFER_INT,
81bb014a81SCésar Belley .wMaxPacketSize = U2FHID_PACKET_SIZE,
82bb014a81SCésar Belley .bInterval = 0x05,
83bb014a81SCésar Belley }, {
84bb014a81SCésar Belley .bEndpointAddress = USB_DIR_OUT | 0x01,
85bb014a81SCésar Belley .bmAttributes = USB_ENDPOINT_XFER_INT,
86bb014a81SCésar Belley .wMaxPacketSize = U2FHID_PACKET_SIZE,
87bb014a81SCésar Belley .bInterval = 0x05,
88bb014a81SCésar Belley },
89bb014a81SCésar Belley },
90bb014a81SCésar Belley
91bb014a81SCésar Belley };
92bb014a81SCésar Belley
93bb014a81SCésar Belley static const USBDescDevice desc_device_u2f_key = {
94bb014a81SCésar Belley .bcdUSB = 0x0100,
95bb014a81SCésar Belley .bMaxPacketSize0 = U2FHID_PACKET_SIZE,
96bb014a81SCésar Belley .bNumConfigurations = 1,
97bb014a81SCésar Belley .confs = (USBDescConfig[]) {
98bb014a81SCésar Belley {
99bb014a81SCésar Belley .bNumInterfaces = 1,
100bb014a81SCésar Belley .bConfigurationValue = 1,
101bb014a81SCésar Belley .iConfiguration = STR_CONFIG,
102bb014a81SCésar Belley .bmAttributes = USB_CFG_ATT_ONE,
103bb014a81SCésar Belley .bMaxPower = 15,
104bb014a81SCésar Belley .nif = 1,
105bb014a81SCésar Belley .ifs = &desc_iface_u2f_key,
106bb014a81SCésar Belley },
107bb014a81SCésar Belley },
108bb014a81SCésar Belley };
109bb014a81SCésar Belley
110bb014a81SCésar Belley static const USBDesc desc_u2f_key = {
111bb014a81SCésar Belley .id = {
112bb014a81SCésar Belley .idVendor = U2F_KEY_VENDOR_NUM,
113bb014a81SCésar Belley .idProduct = U2F_KEY_PRODUCT_NUM,
114bb014a81SCésar Belley .bcdDevice = 0,
115bb014a81SCésar Belley .iManufacturer = STR_MANUFACTURER,
116bb014a81SCésar Belley .iProduct = STR_PRODUCT,
117bb014a81SCésar Belley .iSerialNumber = STR_SERIALNUMBER,
118bb014a81SCésar Belley },
119bb014a81SCésar Belley .full = &desc_device_u2f_key,
120bb014a81SCésar Belley .str = desc_strings,
121bb014a81SCésar Belley };
122bb014a81SCésar Belley
123bb014a81SCésar Belley static const uint8_t u2f_key_hid_report_desc[] = {
124bb014a81SCésar Belley 0x06, 0xd0, 0xf1, /* Usage Page (FIDO) */
125bb014a81SCésar Belley 0x09, 0x01, /* Usage (FIDO) */
126bb014a81SCésar Belley 0xa1, 0x01, /* Collection (HID Application) */
127bb014a81SCésar Belley 0x09, 0x20, /* Usage (FIDO data in) */
128bb014a81SCésar Belley 0x15, 0x00, /* Logical Minimum (0) */
129bb014a81SCésar Belley 0x26, 0xFF, 0x00, /* Logical Maximum (0xff) */
130bb014a81SCésar Belley 0x75, 0x08, /* Report Size (8) */
131bb014a81SCésar Belley 0x95, 0x40, /* Report Count (0x40) */
132bb014a81SCésar Belley 0x81, 0x02, /* Input (Data, Variable, Absolute) */
133bb014a81SCésar Belley 0x09, 0x21, /* Usage (FIDO data out) */
134bb014a81SCésar Belley 0x15, 0x00, /* Logical Minimum (0) */
135bb014a81SCésar Belley 0x26, 0xFF, 0x00, /* Logical Maximum (0xFF) */
136bb014a81SCésar Belley 0x75, 0x08, /* Report Size (8) */
137bb014a81SCésar Belley 0x95, 0x40, /* Report Count (0x40) */
138bb014a81SCésar Belley 0x91, 0x02, /* Output (Data, Variable, Absolute) */
139bb014a81SCésar Belley 0xC0 /* End Collection */
140bb014a81SCésar Belley };
141bb014a81SCésar Belley
u2f_key_reset(U2FKeyState * key)142bb014a81SCésar Belley static void u2f_key_reset(U2FKeyState *key)
143bb014a81SCésar Belley {
144bb014a81SCésar Belley key->pending_in_start = 0;
145bb014a81SCésar Belley key->pending_in_end = 0;
146bb014a81SCésar Belley key->pending_in_num = 0;
147bb014a81SCésar Belley }
148bb014a81SCésar Belley
u2f_key_handle_reset(USBDevice * dev)149bb014a81SCésar Belley static void u2f_key_handle_reset(USBDevice *dev)
150bb014a81SCésar Belley {
151bb014a81SCésar Belley U2FKeyState *key = U2F_KEY(dev);
152bb014a81SCésar Belley
153bb014a81SCésar Belley u2f_key_reset(key);
154bb014a81SCésar Belley }
155bb014a81SCésar Belley
u2f_key_handle_control(USBDevice * dev,USBPacket * p,int request,int value,int index,int length,uint8_t * data)156bb014a81SCésar Belley static void u2f_key_handle_control(USBDevice *dev, USBPacket *p,
157bb014a81SCésar Belley int request, int value, int index, int length, uint8_t *data)
158bb014a81SCésar Belley {
159bb014a81SCésar Belley U2FKeyState *key = U2F_KEY(dev);
160bb014a81SCésar Belley int ret;
161bb014a81SCésar Belley
162bb014a81SCésar Belley ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
163bb014a81SCésar Belley if (ret >= 0) {
164bb014a81SCésar Belley return;
165bb014a81SCésar Belley }
166bb014a81SCésar Belley
167bb014a81SCésar Belley switch (request) {
168bb014a81SCésar Belley case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
169bb014a81SCésar Belley switch (value >> 8) {
170bb014a81SCésar Belley case 0x22:
171bb014a81SCésar Belley memcpy(data, u2f_key_hid_report_desc,
172bb014a81SCésar Belley sizeof(u2f_key_hid_report_desc));
173bb014a81SCésar Belley p->actual_length = sizeof(u2f_key_hid_report_desc);
174bb014a81SCésar Belley break;
175bb014a81SCésar Belley default:
176bb014a81SCésar Belley goto fail;
177bb014a81SCésar Belley }
178bb014a81SCésar Belley break;
179bb014a81SCésar Belley case HID_GET_IDLE:
180bb014a81SCésar Belley data[0] = key->idle;
181bb014a81SCésar Belley p->actual_length = 1;
182bb014a81SCésar Belley break;
183bb014a81SCésar Belley case HID_SET_IDLE:
184bb014a81SCésar Belley key->idle = (uint8_t)(value >> 8);
185bb014a81SCésar Belley break;
186bb014a81SCésar Belley default:
187bb014a81SCésar Belley fail:
188bb014a81SCésar Belley p->status = USB_RET_STALL;
189bb014a81SCésar Belley break;
190bb014a81SCésar Belley }
191bb014a81SCésar Belley
192bb014a81SCésar Belley }
193bb014a81SCésar Belley
u2f_key_recv_from_guest(U2FKeyState * key,USBPacket * p)194bb014a81SCésar Belley static void u2f_key_recv_from_guest(U2FKeyState *key, USBPacket *p)
195bb014a81SCésar Belley {
196bb014a81SCésar Belley U2FKeyClass *kc = U2F_KEY_GET_CLASS(key);
197bb014a81SCésar Belley uint8_t packet[U2FHID_PACKET_SIZE];
198bb014a81SCésar Belley
199bb014a81SCésar Belley if (kc->recv_from_guest == NULL || p->iov.size != U2FHID_PACKET_SIZE) {
200bb014a81SCésar Belley return;
201bb014a81SCésar Belley }
202bb014a81SCésar Belley
203bb014a81SCésar Belley usb_packet_copy(p, packet, p->iov.size);
204bb014a81SCésar Belley kc->recv_from_guest(key, packet);
205bb014a81SCésar Belley }
206bb014a81SCésar Belley
u2f_pending_in_add(U2FKeyState * key,const uint8_t packet[U2FHID_PACKET_SIZE])207bb014a81SCésar Belley static void u2f_pending_in_add(U2FKeyState *key,
208bb014a81SCésar Belley const uint8_t packet[U2FHID_PACKET_SIZE])
209bb014a81SCésar Belley {
210bb014a81SCésar Belley uint8_t index;
211bb014a81SCésar Belley
212bb014a81SCésar Belley if (key->pending_in_num >= U2FHID_PENDING_IN_NUM) {
213bb014a81SCésar Belley return;
214bb014a81SCésar Belley }
215bb014a81SCésar Belley
216bb014a81SCésar Belley index = key->pending_in_end;
217bb014a81SCésar Belley key->pending_in_end = (index + 1) % U2FHID_PENDING_IN_NUM;
218bb014a81SCésar Belley ++key->pending_in_num;
219bb014a81SCésar Belley
220bb014a81SCésar Belley memcpy(key->pending_in[index], packet, U2FHID_PACKET_SIZE);
221bb014a81SCésar Belley }
222bb014a81SCésar Belley
u2f_pending_in_get(U2FKeyState * key)223bb014a81SCésar Belley static uint8_t *u2f_pending_in_get(U2FKeyState *key)
224bb014a81SCésar Belley {
225bb014a81SCésar Belley uint8_t index;
226bb014a81SCésar Belley
227bb014a81SCésar Belley if (key->pending_in_num == 0) {
228bb014a81SCésar Belley return NULL;
229bb014a81SCésar Belley }
230bb014a81SCésar Belley
231bb014a81SCésar Belley index = key->pending_in_start;
232bb014a81SCésar Belley key->pending_in_start = (index + 1) % U2FHID_PENDING_IN_NUM;
233bb014a81SCésar Belley --key->pending_in_num;
234bb014a81SCésar Belley
235bb014a81SCésar Belley return key->pending_in[index];
236bb014a81SCésar Belley }
237bb014a81SCésar Belley
u2f_key_handle_data(USBDevice * dev,USBPacket * p)238bb014a81SCésar Belley static void u2f_key_handle_data(USBDevice *dev, USBPacket *p)
239bb014a81SCésar Belley {
240bb014a81SCésar Belley U2FKeyState *key = U2F_KEY(dev);
241bb014a81SCésar Belley uint8_t *packet_in;
242bb014a81SCésar Belley
243bb014a81SCésar Belley /* Endpoint number check */
244bb014a81SCésar Belley if (p->ep->nr != 1) {
245bb014a81SCésar Belley p->status = USB_RET_STALL;
246bb014a81SCésar Belley return;
247bb014a81SCésar Belley }
248bb014a81SCésar Belley
249bb014a81SCésar Belley switch (p->pid) {
250bb014a81SCésar Belley case USB_TOKEN_OUT:
251bb014a81SCésar Belley u2f_key_recv_from_guest(key, p);
252bb014a81SCésar Belley break;
253bb014a81SCésar Belley case USB_TOKEN_IN:
254bb014a81SCésar Belley packet_in = u2f_pending_in_get(key);
255bb014a81SCésar Belley if (packet_in == NULL) {
256bb014a81SCésar Belley p->status = USB_RET_NAK;
257bb014a81SCésar Belley return;
258bb014a81SCésar Belley }
259bb014a81SCésar Belley usb_packet_copy(p, packet_in, U2FHID_PACKET_SIZE);
260bb014a81SCésar Belley break;
261bb014a81SCésar Belley default:
262bb014a81SCésar Belley p->status = USB_RET_STALL;
263bb014a81SCésar Belley break;
264bb014a81SCésar Belley }
265bb014a81SCésar Belley }
266bb014a81SCésar Belley
u2f_send_to_guest(U2FKeyState * key,const uint8_t packet[U2FHID_PACKET_SIZE])267bb014a81SCésar Belley void u2f_send_to_guest(U2FKeyState *key,
268bb014a81SCésar Belley const uint8_t packet[U2FHID_PACKET_SIZE])
269bb014a81SCésar Belley {
270bb014a81SCésar Belley u2f_pending_in_add(key, packet);
271bb014a81SCésar Belley usb_wakeup(key->ep, 0);
272bb014a81SCésar Belley }
273bb014a81SCésar Belley
u2f_key_unrealize(USBDevice * dev)274bb014a81SCésar Belley static void u2f_key_unrealize(USBDevice *dev)
275bb014a81SCésar Belley {
276bb014a81SCésar Belley U2FKeyState *key = U2F_KEY(dev);
277bb014a81SCésar Belley U2FKeyClass *kc = U2F_KEY_GET_CLASS(key);
278bb014a81SCésar Belley
279bb014a81SCésar Belley if (kc->unrealize != NULL) {
280bb014a81SCésar Belley kc->unrealize(key);
281bb014a81SCésar Belley }
282bb014a81SCésar Belley }
283bb014a81SCésar Belley
u2f_key_realize(USBDevice * dev,Error ** errp)284bb014a81SCésar Belley static void u2f_key_realize(USBDevice *dev, Error **errp)
285bb014a81SCésar Belley {
286bb014a81SCésar Belley U2FKeyState *key = U2F_KEY(dev);
287bb014a81SCésar Belley U2FKeyClass *kc = U2F_KEY_GET_CLASS(key);
288bb014a81SCésar Belley Error *local_err = NULL;
289bb014a81SCésar Belley
290bb014a81SCésar Belley usb_desc_create_serial(dev);
291bb014a81SCésar Belley usb_desc_init(dev);
292bb014a81SCésar Belley u2f_key_reset(key);
293bb014a81SCésar Belley
294bb014a81SCésar Belley if (kc->realize != NULL) {
295bb014a81SCésar Belley kc->realize(key, &local_err);
296bb014a81SCésar Belley if (local_err != NULL) {
297bb014a81SCésar Belley error_propagate(errp, local_err);
298bb014a81SCésar Belley return;
299bb014a81SCésar Belley }
300bb014a81SCésar Belley }
301bb014a81SCésar Belley key->ep = usb_ep_get(dev, USB_TOKEN_IN, 1);
302bb014a81SCésar Belley }
303bb014a81SCésar Belley
304bb014a81SCésar Belley const VMStateDescription vmstate_u2f_key = {
305bb014a81SCésar Belley .name = "u2f-key",
306bb014a81SCésar Belley .version_id = 1,
307bb014a81SCésar Belley .minimum_version_id = 1,
308*3abedf29SRichard Henderson .fields = (const VMStateField[]) {
309bb014a81SCésar Belley VMSTATE_USB_DEVICE(dev, U2FKeyState),
310bb014a81SCésar Belley VMSTATE_UINT8(idle, U2FKeyState),
311bb014a81SCésar Belley VMSTATE_UINT8_2DARRAY(pending_in, U2FKeyState,
312bb014a81SCésar Belley U2FHID_PENDING_IN_NUM, U2FHID_PACKET_SIZE),
313bb014a81SCésar Belley VMSTATE_UINT8(pending_in_start, U2FKeyState),
314bb014a81SCésar Belley VMSTATE_UINT8(pending_in_end, U2FKeyState),
315bb014a81SCésar Belley VMSTATE_UINT8(pending_in_num, U2FKeyState),
316bb014a81SCésar Belley VMSTATE_END_OF_LIST()
317bb014a81SCésar Belley }
318bb014a81SCésar Belley };
319bb014a81SCésar Belley
u2f_key_class_init(ObjectClass * klass,void * data)320bb014a81SCésar Belley static void u2f_key_class_init(ObjectClass *klass, void *data)
321bb014a81SCésar Belley {
322bb014a81SCésar Belley DeviceClass *dc = DEVICE_CLASS(klass);
323bb014a81SCésar Belley USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
324bb014a81SCésar Belley
325bb014a81SCésar Belley uc->product_desc = "QEMU U2F USB key";
326bb014a81SCésar Belley uc->usb_desc = &desc_u2f_key;
327bb014a81SCésar Belley uc->handle_reset = u2f_key_handle_reset;
328bb014a81SCésar Belley uc->handle_control = u2f_key_handle_control;
329bb014a81SCésar Belley uc->handle_data = u2f_key_handle_data;
330bb014a81SCésar Belley uc->handle_attach = usb_desc_attach;
331bb014a81SCésar Belley uc->realize = u2f_key_realize;
332bb014a81SCésar Belley uc->unrealize = u2f_key_unrealize;
333bb014a81SCésar Belley dc->desc = "QEMU U2F key";
334bb014a81SCésar Belley dc->vmsd = &vmstate_u2f_key;
335bb014a81SCésar Belley }
336bb014a81SCésar Belley
337bb014a81SCésar Belley static const TypeInfo u2f_key_info = {
338bb014a81SCésar Belley .name = TYPE_U2F_KEY,
339bb014a81SCésar Belley .parent = TYPE_USB_DEVICE,
340bb014a81SCésar Belley .instance_size = sizeof(U2FKeyState),
341bb014a81SCésar Belley .abstract = true,
342bb014a81SCésar Belley .class_size = sizeof(U2FKeyClass),
343bb014a81SCésar Belley .class_init = u2f_key_class_init,
344bb014a81SCésar Belley };
345bb014a81SCésar Belley
u2f_key_register_types(void)346bb014a81SCésar Belley static void u2f_key_register_types(void)
347bb014a81SCésar Belley {
348bb014a81SCésar Belley type_register_static(&u2f_key_info);
349bb014a81SCésar Belley }
350bb014a81SCésar Belley
351bb014a81SCésar Belley type_init(u2f_key_register_types)
352