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
counter_increment(struct u2f_emu_vdev_counter * vdev_counter)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
counter_read(struct u2f_emu_vdev_counter * vdev_counter)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
u2f_emulated_reset(U2FEmulatedState * key)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
u2f_pending_out_add(U2FEmulatedState * key,const uint8_t packet[U2FHID_PACKET_SIZE])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
u2f_pending_out_get(U2FEmulatedState * key)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
u2f_emulated_recv_from_guest(U2FKeyState * base,const uint8_t packet[U2FHID_PACKET_SIZE])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
u2f_emulated_thread(void * arg)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
u2f_emulated_read(const char * path,char * buffer,size_t buffer_len)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
u2f_emulated_setup_counter(const char * path,struct synced_counter * counter)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
u2f_emulated_setup_vdev_manualy(U2FEmulatedState * key)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
u2f_emulated_event_handler(EventNotifier * notifier)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
u2f_emulated_realize(U2FKeyState * base,Error ** errp)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
u2f_emulated_unrealize(U2FKeyState * base)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
u2f_emulated_class_init(ObjectClass * klass,void * data)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
u2f_key_emulated_register_types(void)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