u2f-emulated.c (11644B)
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 */ 39struct 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 48static 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 60static 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 66typedef struct U2FEmulatedState U2FEmulatedState; 67 68#define PENDING_OUT_NUM 32 69 70struct 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 104static 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 111static 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 127static 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 142static 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 156static 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 197static 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 214static 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 241static 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 279static 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 298static 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 346static 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 372static 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 381static 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 393static 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 400static void u2f_key_emulated_register_types(void) 401{ 402 type_register_static(&u2f_key_emulated_info); 403} 404 405type_init(u2f_key_emulated_register_types)