xref: /openbmc/qemu/hw/usb/u2f.c (revision d328fef93ae757a0dd65ed786a4086e27952eef3)
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