qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 */
     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)