2 * U2F USB Emulated device.
4 * Copyright (c) 2020 César Belley <cesar.belley@lse.epita.fr>
5 * Written by César Belley <cesar.belley@lse.epita.fr>
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
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"
32 #include "hw/qdev-properties.h"
34 #include <u2f-emu/u2f-emu.h>
38 /* Counter which sync with a file */
39 struct synced_counter
{
40 /* Emulated device counter */
41 struct u2f_emu_vdev_counter vdev_counter
;
43 /* Private attributes */
48 static void counter_increment(struct u2f_emu_vdev_counter
*vdev_counter
)
50 struct synced_counter
*counter
= (struct synced_counter
*)vdev_counter
;
54 if (fseek(counter
->fp
, 0, SEEK_SET
) == -1) {
57 fprintf(counter
->fp
, "%u\n", counter
->value
);
60 static uint32_t counter_read(struct u2f_emu_vdev_counter
*vdev_counter
)
62 struct synced_counter
*counter
= (struct synced_counter
*)vdev_counter
;
63 return counter
->value
;
66 typedef struct U2FEmulatedState U2FEmulatedState
;
68 #define PENDING_OUT_NUM 32
70 struct U2FEmulatedState
{
73 /* U2F virtual emulated device */
83 struct synced_counter synced_counter
;
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
;
92 /* Emulation thread and sync */
95 QemuThread key_thread
;
97 EventNotifier notifier
;
100 #define TYPE_U2F_EMULATED "u2f-emulated"
101 #define EMULATED_U2F_KEY(obj) \
102 OBJECT_CHECK(U2FEmulatedState, (obj), TYPE_U2F_EMULATED)
104 static void u2f_emulated_reset(U2FEmulatedState
*key
)
106 key
->pending_out_start
= 0;
107 key
->pending_out_end
= 0;
108 key
->pending_out_num
= 0;
111 static void u2f_pending_out_add(U2FEmulatedState
*key
,
112 const uint8_t packet
[U2FHID_PACKET_SIZE
])
116 if (key
->pending_out_num
>= PENDING_OUT_NUM
) {
120 index
= key
->pending_out_end
;
121 key
->pending_out_end
= (index
+ 1) % PENDING_OUT_NUM
;
122 ++key
->pending_out_num
;
124 memcpy(&key
->pending_out
[index
], packet
, U2FHID_PACKET_SIZE
);
127 static uint8_t *u2f_pending_out_get(U2FEmulatedState
*key
)
131 if (key
->pending_out_num
== 0) {
135 index
= key
->pending_out_start
;
136 key
->pending_out_start
= (index
+ 1) % PENDING_OUT_NUM
;
137 --key
->pending_out_num
;
139 return key
->pending_out
[index
];
142 static void u2f_emulated_recv_from_guest(U2FKeyState
*base
,
143 const uint8_t packet
[U2FHID_PACKET_SIZE
])
145 U2FEmulatedState
*key
= EMULATED_U2F_KEY(base
);
147 qemu_mutex_lock(&key
->pending_out_mutex
);
148 u2f_pending_out_add(key
, packet
);
149 qemu_mutex_unlock(&key
->pending_out_mutex
);
151 qemu_mutex_lock(&key
->key_mutex
);
152 qemu_cond_signal(&key
->key_cond
);
153 qemu_mutex_unlock(&key
->key_mutex
);
156 static void *u2f_emulated_thread(void* arg
)
158 U2FEmulatedState
*key
= arg
;
159 uint8_t packet
[U2FHID_PACKET_SIZE
];
160 uint8_t *packet_out
= NULL
;
165 qemu_mutex_lock(&key
->key_mutex
);
166 qemu_cond_wait(&key
->key_cond
, &key
->key_mutex
);
167 qemu_mutex_unlock(&key
->key_mutex
);
169 /* Exit thread check */
170 if (key
->stop_thread
) {
171 key
->stop_thread
= false;
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
);
181 memcpy(packet
, packet_out
, U2FHID_PACKET_SIZE
);
182 qemu_mutex_unlock(&key
->pending_out_mutex
);
184 qemu_mutex_lock(&key
->vdev_mutex
);
185 u2f_emu_vdev_send(key
->vdev
, U2F_EMU_USB
, packet
,
188 /* Notify response */
189 if (u2f_emu_vdev_has_response(key
->vdev
, U2F_EMU_USB
)) {
190 event_notifier_set(&key
->notifier
);
192 qemu_mutex_unlock(&key
->vdev_mutex
);
197 static ssize_t
u2f_emulated_read(const char *path
, char *buffer
,
203 fd
= qemu_open_old(path
, O_RDONLY
);
208 ret
= read(fd
, buffer
, buffer_len
);
214 static bool u2f_emulated_setup_counter(const char *path
,
215 struct synced_counter
*counter
)
220 fd
= qemu_open_old(path
, O_RDWR
);
224 fp
= fdopen(fd
, "r+");
229 ret
= fscanf(fp
, "%u", &counter
->value
);
235 counter
->vdev_counter
.counter_increment
= counter_increment
;
236 counter
->vdev_counter
.counter_read
= counter_read
;
241 static u2f_emu_rc
u2f_emulated_setup_vdev_manualy(U2FEmulatedState
*key
)
244 char cert_pem
[4096], privkey_pem
[2048];
245 struct u2f_emu_vdev_setup setup_info
;
248 ret
= u2f_emulated_read(key
->cert
, cert_pem
, sizeof(cert_pem
));
254 ret
= u2f_emulated_read(key
->privkey
, privkey_pem
, sizeof(privkey_pem
));
260 ret
= u2f_emulated_read(key
->entropy
, (char *)&setup_info
.entropy
,
261 sizeof(setup_info
.entropy
));
267 if (!u2f_emulated_setup_counter(key
->counter
, &key
->synced_counter
)) {
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
;
276 return u2f_emu_vdev_new(&key
->vdev
, &setup_info
);
279 static void u2f_emulated_event_handler(EventNotifier
*notifier
)
281 U2FEmulatedState
*key
= container_of(notifier
, U2FEmulatedState
, notifier
);
283 uint8_t *packet_in
= NULL
;
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
,
290 if (packet_size
== U2FHID_PACKET_SIZE
) {
291 u2f_send_to_guest(&key
->base
, packet_in
);
293 u2f_emu_vdev_free_response(packet_in
);
295 qemu_mutex_unlock(&key
->vdev_mutex
);
298 static void u2f_emulated_realize(U2FKeyState
*base
, Error
**errp
)
300 U2FEmulatedState
*key
= EMULATED_U2F_KEY(base
);
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
);
309 error_setg(errp
, "%s: cert, priv, entropy and counter "
310 "parameters must be provided to manualy configure "
311 "the emulated device", TYPE_U2F_EMULATED
);
314 } else if (key
->dir
!= NULL
) {
315 rc
= u2f_emu_vdev_new_from_dir(&key
->vdev
, key
->dir
);
317 rc
= u2f_emu_vdev_new_ephemeral(&key
->vdev
);
320 if (rc
!= U2F_EMU_OK
) {
321 error_setg(errp
, "%s: Failed to setup the key", TYPE_U2F_EMULATED
);
325 if (event_notifier_init(&key
->notifier
, false) < 0) {
326 error_setg(errp
, "%s: Failed to initialize notifier",
331 event_notifier_set_handler(&key
->notifier
, u2f_emulated_event_handler
);
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
);
341 key
->stop_thread
= false;
342 qemu_thread_create(&key
->key_thread
, "u2f-key", u2f_emulated_thread
,
343 key
, QEMU_THREAD_JOINABLE
);
346 static void u2f_emulated_unrealize(U2FKeyState
*base
)
348 U2FEmulatedState
*key
= EMULATED_U2F_KEY(base
);
351 key
->stop_thread
= true;
352 qemu_cond_signal(&key
->key_cond
);
353 qemu_thread_join(&key
->key_thread
);
356 event_notifier_set_handler(&key
->notifier
, NULL
);
357 event_notifier_cleanup(&key
->notifier
);
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
);
366 u2f_emu_vdev_free(key
->vdev
);
367 if (key
->synced_counter
.fp
!= NULL
) {
368 fclose(key
->synced_counter
.fp
);
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(),
381 static void u2f_emulated_class_init(ObjectClass
*klass
, void *data
)
383 DeviceClass
*dc
= DEVICE_CLASS(klass
);
384 U2FKeyClass
*kc
= U2F_KEY_CLASS(klass
);
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
);
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
400 static void u2f_key_emulated_register_types(void)
402 type_register_static(&u2f_key_emulated_info
);
405 type_init(u2f_key_emulated_register_types
)