xref: /openbmc/qemu/hw/usb/u2f-emulated.c (revision b86c6ba6)
1 /*
2  * U2F USB Emulated 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/thread.h"
29 #include "qemu/main-loop.h"
30 #include "qapi/error.h"
31 #include "hw/usb.h"
32 #include "hw/qdev-properties.h"
33 
34 #include <u2f-emu/u2f-emu.h>
35 
36 #include "u2f.h"
37 
38 /* Counter which sync with a file */
39 struct synced_counter {
40     /* Emulated device counter */
41     struct u2f_emu_vdev_counter vdev_counter;
42 
43     /* Private attributes */
44     uint32_t value;
45     FILE *fp;
46 };
47 
48 static void counter_increment(struct u2f_emu_vdev_counter *vdev_counter)
49 {
50     struct synced_counter *counter = (struct synced_counter *)vdev_counter;
51     ++counter->value;
52 
53     /* Write back */
54     if (fseek(counter->fp, 0, SEEK_SET) == -1) {
55         return;
56     }
57     fprintf(counter->fp, "%u\n", counter->value);
58 }
59 
60 static uint32_t counter_read(struct u2f_emu_vdev_counter *vdev_counter)
61 {
62     struct synced_counter *counter = (struct synced_counter *)vdev_counter;
63     return counter->value;
64 }
65 
66 typedef struct U2FEmulatedState U2FEmulatedState;
67 
68 #define PENDING_OUT_NUM 32
69 
70 struct U2FEmulatedState {
71     U2FKeyState base;
72 
73     /* U2F virtual emulated device */
74     u2f_emu_vdev *vdev;
75     QemuMutex vdev_mutex;
76 
77     /* Properties */
78     char *dir;
79     char *cert;
80     char *privkey;
81     char *entropy;
82     char *counter;
83     struct synced_counter synced_counter;
84 
85     /* Pending packets received from the guest */
86     uint8_t pending_out[PENDING_OUT_NUM][U2FHID_PACKET_SIZE];
87     uint8_t pending_out_start;
88     uint8_t pending_out_end;
89     uint8_t pending_out_num;
90     QemuMutex pending_out_mutex;
91 
92     /* Emulation thread and sync */
93     QemuCond key_cond;
94     QemuMutex key_mutex;
95     QemuThread key_thread;
96     bool stop_thread;
97     EventNotifier notifier;
98 };
99 
100 #define TYPE_U2F_EMULATED "u2f-emulated"
101 #define EMULATED_U2F_KEY(obj) \
102     OBJECT_CHECK(U2FEmulatedState, (obj), TYPE_U2F_EMULATED)
103 
104 static void u2f_emulated_reset(U2FEmulatedState *key)
105 {
106     key->pending_out_start = 0;
107     key->pending_out_end = 0;
108     key->pending_out_num = 0;
109 }
110 
111 static void u2f_pending_out_add(U2FEmulatedState *key,
112                                 const uint8_t packet[U2FHID_PACKET_SIZE])
113 {
114     int index;
115 
116     if (key->pending_out_num >= PENDING_OUT_NUM) {
117         return;
118     }
119 
120     index = key->pending_out_end;
121     key->pending_out_end = (index + 1) % PENDING_OUT_NUM;
122     ++key->pending_out_num;
123 
124     memcpy(&key->pending_out[index], packet, U2FHID_PACKET_SIZE);
125 }
126 
127 static uint8_t *u2f_pending_out_get(U2FEmulatedState *key)
128 {
129     int index;
130 
131     if (key->pending_out_num == 0) {
132         return NULL;
133     }
134 
135     index  = key->pending_out_start;
136     key->pending_out_start = (index + 1) % PENDING_OUT_NUM;
137     --key->pending_out_num;
138 
139     return key->pending_out[index];
140 }
141 
142 static void u2f_emulated_recv_from_guest(U2FKeyState *base,
143                                     const uint8_t packet[U2FHID_PACKET_SIZE])
144 {
145     U2FEmulatedState *key = EMULATED_U2F_KEY(base);
146 
147     qemu_mutex_lock(&key->pending_out_mutex);
148     u2f_pending_out_add(key, packet);
149     qemu_mutex_unlock(&key->pending_out_mutex);
150 
151     qemu_mutex_lock(&key->key_mutex);
152     qemu_cond_signal(&key->key_cond);
153     qemu_mutex_unlock(&key->key_mutex);
154 }
155 
156 static void *u2f_emulated_thread(void* arg)
157 {
158     U2FEmulatedState *key = arg;
159     uint8_t packet[U2FHID_PACKET_SIZE];
160     uint8_t *packet_out = NULL;
161 
162 
163     while (true) {
164         /* Wait signal */
165         qemu_mutex_lock(&key->key_mutex);
166         qemu_cond_wait(&key->key_cond, &key->key_mutex);
167         qemu_mutex_unlock(&key->key_mutex);
168 
169         /* Exit thread check */
170         if (key->stop_thread) {
171             key->stop_thread = false;
172             break;
173         }
174 
175         qemu_mutex_lock(&key->pending_out_mutex);
176         packet_out = u2f_pending_out_get(key);
177         if (packet_out == NULL) {
178             qemu_mutex_unlock(&key->pending_out_mutex);
179             continue;
180         }
181         memcpy(packet, packet_out, U2FHID_PACKET_SIZE);
182         qemu_mutex_unlock(&key->pending_out_mutex);
183 
184         qemu_mutex_lock(&key->vdev_mutex);
185         u2f_emu_vdev_send(key->vdev, U2F_EMU_USB, packet,
186                           U2FHID_PACKET_SIZE);
187 
188         /* Notify response */
189         if (u2f_emu_vdev_has_response(key->vdev, U2F_EMU_USB)) {
190             event_notifier_set(&key->notifier);
191         }
192         qemu_mutex_unlock(&key->vdev_mutex);
193     }
194     return NULL;
195 }
196 
197 static ssize_t u2f_emulated_read(const char *path, char *buffer,
198                                  size_t buffer_len)
199 {
200     int fd;
201     ssize_t ret;
202 
203     fd = qemu_open_old(path, O_RDONLY);
204     if (fd < 0) {
205         return -1;
206     }
207 
208     ret = read(fd, buffer, buffer_len);
209     close(fd);
210 
211     return ret;
212 }
213 
214 static bool u2f_emulated_setup_counter(const char *path,
215                                        struct synced_counter *counter)
216 {
217     int fd, ret;
218     FILE *fp;
219 
220     fd = qemu_open_old(path, O_RDWR);
221     if (fd < 0) {
222         return false;
223     }
224     fp = fdopen(fd, "r+");
225     if (fp == NULL) {
226         close(fd);
227         return false;
228     }
229     ret = fscanf(fp, "%u", &counter->value);
230     if (ret == EOF) {
231         fclose(fp);
232         return false;
233     }
234     counter->fp = fp;
235     counter->vdev_counter.counter_increment = counter_increment;
236     counter->vdev_counter.counter_read = counter_read;
237 
238     return true;
239 }
240 
241 static u2f_emu_rc u2f_emulated_setup_vdev_manualy(U2FEmulatedState *key)
242 {
243     ssize_t ret;
244     char cert_pem[4096], privkey_pem[2048];
245     struct u2f_emu_vdev_setup setup_info;
246 
247     /* Certificate */
248     ret = u2f_emulated_read(key->cert, cert_pem, sizeof(cert_pem));
249     if (ret < 0) {
250         return -1;
251     }
252 
253     /* Private key */
254     ret = u2f_emulated_read(key->privkey, privkey_pem, sizeof(privkey_pem));
255     if (ret < 0) {
256         return -1;
257     }
258 
259     /* Entropy */
260     ret = u2f_emulated_read(key->entropy, (char *)&setup_info.entropy,
261                             sizeof(setup_info.entropy));
262     if (ret < 0) {
263         return -1;
264     }
265 
266     /* Counter */
267     if (!u2f_emulated_setup_counter(key->counter, &key->synced_counter)) {
268         return -1;
269     }
270 
271     /* Setup */
272     setup_info.certificate = cert_pem;
273     setup_info.private_key = privkey_pem;
274     setup_info.counter = (struct u2f_emu_vdev_counter *)&key->synced_counter;
275 
276     return u2f_emu_vdev_new(&key->vdev, &setup_info);
277 }
278 
279 static void u2f_emulated_event_handler(EventNotifier *notifier)
280 {
281     U2FEmulatedState *key = container_of(notifier, U2FEmulatedState, notifier);
282     size_t packet_size;
283     uint8_t *packet_in = NULL;
284 
285     event_notifier_test_and_clear(&key->notifier);
286     qemu_mutex_lock(&key->vdev_mutex);
287     while (u2f_emu_vdev_has_response(key->vdev, U2F_EMU_USB)) {
288         packet_size = u2f_emu_vdev_get_response(key->vdev, U2F_EMU_USB,
289                                                 &packet_in);
290         if (packet_size == U2FHID_PACKET_SIZE) {
291             u2f_send_to_guest(&key->base, packet_in);
292         }
293         u2f_emu_vdev_free_response(packet_in);
294     }
295     qemu_mutex_unlock(&key->vdev_mutex);
296 }
297 
298 static void u2f_emulated_realize(U2FKeyState *base, Error **errp)
299 {
300     U2FEmulatedState *key = EMULATED_U2F_KEY(base);
301     u2f_emu_rc rc;
302 
303     if (key->cert != NULL || key->privkey != NULL || key->entropy != NULL
304         || key->counter != NULL) {
305         if (key->cert != NULL && key->privkey != NULL
306             && key->entropy != NULL && key->counter != NULL) {
307             rc = u2f_emulated_setup_vdev_manualy(key);
308         } else {
309             error_setg(errp, "%s: cert, priv, entropy and counter "
310                        "parameters must be provided to manually configure "
311                        "the emulated device", TYPE_U2F_EMULATED);
312             return;
313         }
314     } else if (key->dir != NULL) {
315         rc = u2f_emu_vdev_new_from_dir(&key->vdev, key->dir);
316     } else {
317         rc = u2f_emu_vdev_new_ephemeral(&key->vdev);
318     }
319 
320     if (rc != U2F_EMU_OK) {
321         error_setg(errp, "%s: Failed to setup the key", TYPE_U2F_EMULATED);
322         return;
323     }
324 
325     if (event_notifier_init(&key->notifier, false) < 0) {
326         error_setg(errp, "%s: Failed to initialize notifier",
327                    TYPE_U2F_EMULATED);
328         return;
329     }
330     /* Notifier */
331     event_notifier_set_handler(&key->notifier, u2f_emulated_event_handler);
332 
333     /* Synchronization */
334     qemu_cond_init(&key->key_cond);
335     qemu_mutex_init(&key->vdev_mutex);
336     qemu_mutex_init(&key->pending_out_mutex);
337     qemu_mutex_init(&key->key_mutex);
338     u2f_emulated_reset(key);
339 
340     /* Thread */
341     key->stop_thread = false;
342     qemu_thread_create(&key->key_thread, "u2f-key", u2f_emulated_thread,
343                        key, QEMU_THREAD_JOINABLE);
344 }
345 
346 static void u2f_emulated_unrealize(U2FKeyState *base)
347 {
348     U2FEmulatedState *key = EMULATED_U2F_KEY(base);
349 
350     /* Thread */
351     key->stop_thread = true;
352     qemu_cond_signal(&key->key_cond);
353     qemu_thread_join(&key->key_thread);
354 
355     /* Notifier */
356     event_notifier_set_handler(&key->notifier, NULL);
357     event_notifier_cleanup(&key->notifier);
358 
359     /* Synchronization */
360     qemu_cond_destroy(&key->key_cond);
361     qemu_mutex_destroy(&key->vdev_mutex);
362     qemu_mutex_destroy(&key->key_mutex);
363     qemu_mutex_destroy(&key->pending_out_mutex);
364 
365     /* Vdev */
366     u2f_emu_vdev_free(key->vdev);
367     if (key->synced_counter.fp != NULL) {
368         fclose(key->synced_counter.fp);
369     }
370 }
371 
372 static Property u2f_emulated_properties[] = {
373     DEFINE_PROP_STRING("dir", U2FEmulatedState, dir),
374     DEFINE_PROP_STRING("cert", U2FEmulatedState, cert),
375     DEFINE_PROP_STRING("privkey", U2FEmulatedState, privkey),
376     DEFINE_PROP_STRING("entropy", U2FEmulatedState, entropy),
377     DEFINE_PROP_STRING("counter", U2FEmulatedState, counter),
378     DEFINE_PROP_END_OF_LIST(),
379 };
380 
381 static void u2f_emulated_class_init(ObjectClass *klass, void *data)
382 {
383     DeviceClass *dc = DEVICE_CLASS(klass);
384     U2FKeyClass *kc = U2F_KEY_CLASS(klass);
385 
386     kc->realize = u2f_emulated_realize;
387     kc->unrealize = u2f_emulated_unrealize;
388     kc->recv_from_guest = u2f_emulated_recv_from_guest;
389     dc->desc = "QEMU U2F emulated key";
390     device_class_set_props(dc, u2f_emulated_properties);
391 }
392 
393 static const TypeInfo u2f_key_emulated_info = {
394     .name = TYPE_U2F_EMULATED,
395     .parent = TYPE_U2F_KEY,
396     .instance_size = sizeof(U2FEmulatedState),
397     .class_init = u2f_emulated_class_init
398 };
399 
400 static void u2f_key_emulated_register_types(void)
401 {
402     type_register_static(&u2f_key_emulated_info);
403 }
404 
405 type_init(u2f_key_emulated_register_types)
406