xref: /openbmc/qemu/hw/usb/ccid-card-emulated.c (revision 429d3ae2)
1 /*
2  * CCID Card Device. Emulated card.
3  *
4  * Copyright (c) 2011 Red Hat.
5  * Written by Alon Levy.
6  *
7  * This code is licensed under the GNU LGPL, version 2 or later.
8  */
9 
10 /*
11  * It can be used to provide access to the local hardware in a non exclusive
12  * way, or it can use certificates. It requires the usb-ccid bus.
13  *
14  * Usage 1: standard, mirror hardware reader+card:
15  * qemu .. -usb -device usb-ccid -device ccid-card-emulated
16  *
17  * Usage 2: use certificates, no hardware required
18  * one time: create the certificates:
19  *  for i in 1 2 3; do
20  *      certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
21  *  done
22  * qemu .. -usb -device usb-ccid \
23  *  -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
24  *
25  * If you use a non default db for the certificates you can specify it using
26  * the db parameter.
27  */
28 
29 #include "qemu/osdep.h"
30 #include <libcacard.h>
31 
32 #include "qemu/thread.h"
33 #include "qemu/main-loop.h"
34 #include "ccid.h"
35 #include "qapi/error.h"
36 
37 #define DPRINTF(card, lvl, fmt, ...) \
38 do {\
39     if (lvl <= card->debug) {\
40         printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
41     } \
42 } while (0)
43 
44 
45 #define TYPE_EMULATED_CCID "ccid-card-emulated"
46 #define EMULATED_CCID_CARD(obj) \
47     OBJECT_CHECK(EmulatedState, (obj), TYPE_EMULATED_CCID)
48 
49 #define BACKEND_NSS_EMULATED_NAME "nss-emulated"
50 #define BACKEND_CERTIFICATES_NAME "certificates"
51 
52 enum {
53     BACKEND_NSS_EMULATED = 1,
54     BACKEND_CERTIFICATES
55 };
56 
57 #define DEFAULT_BACKEND BACKEND_NSS_EMULATED
58 
59 typedef struct EmulatedState EmulatedState;
60 
61 enum {
62     EMUL_READER_INSERT = 0,
63     EMUL_READER_REMOVE,
64     EMUL_CARD_INSERT,
65     EMUL_CARD_REMOVE,
66     EMUL_GUEST_APDU,
67     EMUL_RESPONSE_APDU,
68     EMUL_ERROR,
69 };
70 
71 static const char *emul_event_to_string(uint32_t emul_event)
72 {
73     switch (emul_event) {
74     case EMUL_READER_INSERT:
75         return "EMUL_READER_INSERT";
76     case EMUL_READER_REMOVE:
77         return "EMUL_READER_REMOVE";
78     case EMUL_CARD_INSERT:
79         return "EMUL_CARD_INSERT";
80     case EMUL_CARD_REMOVE:
81         return "EMUL_CARD_REMOVE";
82     case EMUL_GUEST_APDU:
83         return "EMUL_GUEST_APDU";
84     case EMUL_RESPONSE_APDU:
85         return "EMUL_RESPONSE_APDU";
86     case EMUL_ERROR:
87         return "EMUL_ERROR";
88     }
89     return "UNKNOWN";
90 }
91 
92 typedef struct EmulEvent {
93     QSIMPLEQ_ENTRY(EmulEvent) entry;
94     union {
95         struct {
96             uint32_t type;
97         } gen;
98         struct {
99             uint32_t type;
100             uint64_t code;
101         } error;
102         struct {
103             uint32_t type;
104             uint32_t len;
105             uint8_t data[];
106         } data;
107     } p;
108 } EmulEvent;
109 
110 #define MAX_ATR_SIZE 40
111 struct EmulatedState {
112     CCIDCardState base;
113     uint8_t  debug;
114     char    *backend_str;
115     uint32_t backend;
116     char    *cert1;
117     char    *cert2;
118     char    *cert3;
119     char    *db;
120     uint8_t  atr[MAX_ATR_SIZE];
121     uint8_t  atr_length;
122     QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
123     QemuMutex event_list_mutex;
124     QemuThread event_thread_id;
125     VReader *reader;
126     QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
127     QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
128     QemuMutex handle_apdu_mutex;
129     QemuCond handle_apdu_cond;
130     EventNotifier notifier;
131     int      quit_apdu_thread;
132     QemuThread apdu_thread_id;
133 };
134 
135 static void emulated_apdu_from_guest(CCIDCardState *base,
136     const uint8_t *apdu, uint32_t len)
137 {
138     EmulatedState *card = EMULATED_CCID_CARD(base);
139     EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
140 
141     assert(event);
142     event->p.data.type = EMUL_GUEST_APDU;
143     event->p.data.len = len;
144     memcpy(event->p.data.data, apdu, len);
145     qemu_mutex_lock(&card->vreader_mutex);
146     QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
147     qemu_mutex_unlock(&card->vreader_mutex);
148     qemu_mutex_lock(&card->handle_apdu_mutex);
149     qemu_cond_signal(&card->handle_apdu_cond);
150     qemu_mutex_unlock(&card->handle_apdu_mutex);
151 }
152 
153 static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
154 {
155     EmulatedState *card = EMULATED_CCID_CARD(base);
156 
157     *len = card->atr_length;
158     return card->atr;
159 }
160 
161 static void emulated_push_event(EmulatedState *card, EmulEvent *event)
162 {
163     qemu_mutex_lock(&card->event_list_mutex);
164     QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
165     qemu_mutex_unlock(&card->event_list_mutex);
166     event_notifier_set(&card->notifier);
167 }
168 
169 static void emulated_push_type(EmulatedState *card, uint32_t type)
170 {
171     EmulEvent *event = g_new(EmulEvent, 1);
172 
173     assert(event);
174     event->p.gen.type = type;
175     emulated_push_event(card, event);
176 }
177 
178 static void emulated_push_error(EmulatedState *card, uint64_t code)
179 {
180     EmulEvent *event = g_new(EmulEvent, 1);
181 
182     assert(event);
183     event->p.error.type = EMUL_ERROR;
184     event->p.error.code = code;
185     emulated_push_event(card, event);
186 }
187 
188 static void emulated_push_data_type(EmulatedState *card, uint32_t type,
189     const uint8_t *data, uint32_t len)
190 {
191     EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
192 
193     assert(event);
194     event->p.data.type = type;
195     event->p.data.len = len;
196     memcpy(event->p.data.data, data, len);
197     emulated_push_event(card, event);
198 }
199 
200 static void emulated_push_reader_insert(EmulatedState *card)
201 {
202     emulated_push_type(card, EMUL_READER_INSERT);
203 }
204 
205 static void emulated_push_reader_remove(EmulatedState *card)
206 {
207     emulated_push_type(card, EMUL_READER_REMOVE);
208 }
209 
210 static void emulated_push_card_insert(EmulatedState *card,
211     const uint8_t *atr, uint32_t len)
212 {
213     emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
214 }
215 
216 static void emulated_push_card_remove(EmulatedState *card)
217 {
218     emulated_push_type(card, EMUL_CARD_REMOVE);
219 }
220 
221 static void emulated_push_response_apdu(EmulatedState *card,
222     const uint8_t *apdu, uint32_t len)
223 {
224     emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
225 }
226 
227 #define APDU_BUF_SIZE 270
228 static void *handle_apdu_thread(void* arg)
229 {
230     EmulatedState *card = arg;
231     uint8_t recv_data[APDU_BUF_SIZE];
232     int recv_len;
233     VReaderStatus reader_status;
234     EmulEvent *event;
235 
236     while (1) {
237         qemu_mutex_lock(&card->handle_apdu_mutex);
238         qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
239         qemu_mutex_unlock(&card->handle_apdu_mutex);
240         if (card->quit_apdu_thread) {
241             card->quit_apdu_thread = 0; /* debugging */
242             break;
243         }
244         qemu_mutex_lock(&card->vreader_mutex);
245         while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
246             event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
247             assert((unsigned long)event > 1000);
248             QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
249             if (event->p.data.type != EMUL_GUEST_APDU) {
250                 DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
251                 g_free(event);
252                 continue;
253             }
254             if (card->reader == NULL) {
255                 DPRINTF(card, 1, "reader is NULL\n");
256                 g_free(event);
257                 continue;
258             }
259             recv_len = sizeof(recv_data);
260             reader_status = vreader_xfr_bytes(card->reader,
261                     event->p.data.data, event->p.data.len,
262                     recv_data, &recv_len);
263             DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
264             if (reader_status == VREADER_OK) {
265                 emulated_push_response_apdu(card, recv_data, recv_len);
266             } else {
267                 emulated_push_error(card, reader_status);
268             }
269             g_free(event);
270         }
271         qemu_mutex_unlock(&card->vreader_mutex);
272     }
273     return NULL;
274 }
275 
276 static void *event_thread(void *arg)
277 {
278     int atr_len = MAX_ATR_SIZE;
279     uint8_t atr[MAX_ATR_SIZE];
280     VEvent *event = NULL;
281     EmulatedState *card = arg;
282 
283     while (1) {
284         const char *reader_name;
285 
286         event = vevent_wait_next_vevent();
287         if (event == NULL || event->type == VEVENT_LAST) {
288             break;
289         }
290         if (event->type != VEVENT_READER_INSERT) {
291             if (card->reader == NULL && event->reader != NULL) {
292                 /* Happens after device_add followed by card remove or insert.
293                  * XXX: create synthetic add_reader events if vcard_emul_init
294                  * already called, which happens if device_del and device_add
295                  * are called */
296                 card->reader = vreader_reference(event->reader);
297             } else {
298                 if (event->reader != card->reader) {
299                     fprintf(stderr,
300                         "ERROR: wrong reader: quiting event_thread\n");
301                     break;
302                 }
303             }
304         }
305         switch (event->type) {
306         case VEVENT_READER_INSERT:
307             /* TODO: take a specific reader. i.e. track which reader
308              * we are seeing here, check it is the one we want (the first,
309              * or by a particular name), and ignore if we don't want it.
310              */
311             reader_name = vreader_get_name(event->reader);
312             if (card->reader != NULL) {
313                 DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
314                     vreader_get_name(card->reader), reader_name);
315                 qemu_mutex_lock(&card->vreader_mutex);
316                 vreader_free(card->reader);
317                 qemu_mutex_unlock(&card->vreader_mutex);
318                 emulated_push_reader_remove(card);
319             }
320             qemu_mutex_lock(&card->vreader_mutex);
321             DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
322             card->reader = vreader_reference(event->reader);
323             qemu_mutex_unlock(&card->vreader_mutex);
324             emulated_push_reader_insert(card);
325             break;
326         case VEVENT_READER_REMOVE:
327             DPRINTF(card, 2, " READER REMOVE: %s\n",
328                     vreader_get_name(event->reader));
329             qemu_mutex_lock(&card->vreader_mutex);
330             vreader_free(card->reader);
331             card->reader = NULL;
332             qemu_mutex_unlock(&card->vreader_mutex);
333             emulated_push_reader_remove(card);
334             break;
335         case VEVENT_CARD_INSERT:
336             /* get the ATR (intended as a response to a power on from the
337              * reader */
338             atr_len = MAX_ATR_SIZE;
339             vreader_power_on(event->reader, atr, &atr_len);
340             card->atr_length = (uint8_t)atr_len;
341             DPRINTF(card, 2, " CARD INSERT\n");
342             emulated_push_card_insert(card, atr, atr_len);
343             break;
344         case VEVENT_CARD_REMOVE:
345             DPRINTF(card, 2, " CARD REMOVE\n");
346             emulated_push_card_remove(card);
347             break;
348         case VEVENT_LAST: /* quit */
349             vevent_delete(event);
350             return NULL;
351             break;
352         default:
353             break;
354         }
355         vevent_delete(event);
356     }
357     return NULL;
358 }
359 
360 static void card_event_handler(EventNotifier *notifier)
361 {
362     EmulatedState *card = container_of(notifier, EmulatedState, notifier);
363     EmulEvent *event, *next;
364 
365     event_notifier_test_and_clear(&card->notifier);
366     qemu_mutex_lock(&card->event_list_mutex);
367     QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
368         DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
369         switch (event->p.gen.type) {
370         case EMUL_RESPONSE_APDU:
371             ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
372                 event->p.data.len);
373             break;
374         case EMUL_READER_INSERT:
375             ccid_card_ccid_attach(&card->base);
376             break;
377         case EMUL_READER_REMOVE:
378             ccid_card_ccid_detach(&card->base);
379             break;
380         case EMUL_CARD_INSERT:
381             assert(event->p.data.len <= MAX_ATR_SIZE);
382             card->atr_length = event->p.data.len;
383             memcpy(card->atr, event->p.data.data, card->atr_length);
384             ccid_card_card_inserted(&card->base);
385             break;
386         case EMUL_CARD_REMOVE:
387             ccid_card_card_removed(&card->base);
388             break;
389         case EMUL_ERROR:
390             ccid_card_card_error(&card->base, event->p.error.code);
391             break;
392         default:
393             DPRINTF(card, 2, "unexpected event\n");
394             break;
395         }
396         g_free(event);
397     }
398     QSIMPLEQ_INIT(&card->event_list);
399     qemu_mutex_unlock(&card->event_list_mutex);
400 }
401 
402 static int init_event_notifier(EmulatedState *card, Error **errp)
403 {
404     if (event_notifier_init(&card->notifier, false) < 0) {
405         error_setg(errp, "ccid-card-emul: event notifier creation failed");
406         return -1;
407     }
408     event_notifier_set_handler(&card->notifier, card_event_handler);
409     return 0;
410 }
411 
412 #define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
413 #define CERTIFICATES_ARGS_TEMPLATE\
414     "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
415 
416 static int wrap_vcard_emul_init(VCardEmulOptions *options)
417 {
418     static int called;
419     static int options_was_null;
420 
421     if (called) {
422         if ((options == NULL) != options_was_null) {
423             printf("%s: warning: running emulated with certificates"
424                    " and emulated side by side is not supported\n",
425                    __func__);
426             return VCARD_EMUL_FAIL;
427         }
428         vcard_emul_replay_insertion_events();
429         return VCARD_EMUL_OK;
430     }
431     options_was_null = (options == NULL);
432     called = 1;
433     return vcard_emul_init(options);
434 }
435 
436 static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
437 {
438     char emul_args[200];
439     VCardEmulOptions *options = NULL;
440 
441     snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
442         card->db ? card->db : CERTIFICATES_DEFAULT_DB,
443         card->cert1, card->cert2, card->cert3);
444     options = vcard_emul_options(emul_args);
445     if (options == NULL) {
446         printf("%s: warning: not using certificates due to"
447                " initialization error\n", __func__);
448     }
449     return wrap_vcard_emul_init(options);
450 }
451 
452 typedef struct EnumTable {
453     const char *name;
454     uint32_t value;
455 } EnumTable;
456 
457 static const EnumTable backend_enum_table[] = {
458     {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
459     {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
460     {NULL, 0},
461 };
462 
463 static uint32_t parse_enumeration(char *str,
464     const EnumTable *table, uint32_t not_found_value)
465 {
466     uint32_t ret = not_found_value;
467 
468     if (str == NULL)
469         return 0;
470 
471     while (table->name != NULL) {
472         if (strcmp(table->name, str) == 0) {
473             ret = table->value;
474             break;
475         }
476         table++;
477     }
478     return ret;
479 }
480 
481 static void emulated_realize(CCIDCardState *base, Error **errp)
482 {
483     EmulatedState *card = EMULATED_CCID_CARD(base);
484     VCardEmulError ret;
485     const EnumTable *ptable;
486 
487     QSIMPLEQ_INIT(&card->event_list);
488     QSIMPLEQ_INIT(&card->guest_apdu_list);
489     qemu_mutex_init(&card->event_list_mutex);
490     qemu_mutex_init(&card->vreader_mutex);
491     qemu_mutex_init(&card->handle_apdu_mutex);
492     qemu_cond_init(&card->handle_apdu_cond);
493     card->reader = NULL;
494     card->quit_apdu_thread = 0;
495     if (init_event_notifier(card, errp) < 0) {
496         return;
497     }
498 
499     card->backend = 0;
500     if (card->backend_str) {
501         card->backend = parse_enumeration(card->backend_str,
502                                           backend_enum_table, 0);
503     }
504 
505     if (card->backend == 0) {
506         error_setg(errp, "backend must be one of:");
507         for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
508             error_append_hint(errp, "%s\n", ptable->name);
509         }
510         return;
511     }
512 
513     /* TODO: a passthru backened that works on local machine. third card type?*/
514     if (card->backend == BACKEND_CERTIFICATES) {
515         if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
516             ret = emulated_initialize_vcard_from_certificates(card);
517         } else {
518             error_setg(errp, "%s: you must provide all three certs for"
519                        " certificates backend", TYPE_EMULATED_CCID);
520             return;
521         }
522     } else {
523         if (card->backend != BACKEND_NSS_EMULATED) {
524             error_setg(errp, "%s: bad backend specified. The options are:%s"
525                        " (default), %s.", TYPE_EMULATED_CCID,
526                        BACKEND_NSS_EMULATED_NAME, BACKEND_CERTIFICATES_NAME);
527             return;
528         }
529         if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
530             error_setg(errp, "%s: unexpected cert parameters to nss emulated "
531                        "backend", TYPE_EMULATED_CCID);
532             return;
533         }
534         /* default to mirroring the local hardware readers */
535         ret = wrap_vcard_emul_init(NULL);
536     }
537     if (ret != VCARD_EMUL_OK) {
538         error_setg(errp, "%s: failed to initialize vcard", TYPE_EMULATED_CCID);
539         return;
540     }
541     qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
542                        card, QEMU_THREAD_JOINABLE);
543     qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
544                        card, QEMU_THREAD_JOINABLE);
545 }
546 
547 static void emulated_unrealize(CCIDCardState *base, Error **errp)
548 {
549     EmulatedState *card = EMULATED_CCID_CARD(base);
550     VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
551 
552     vevent_queue_vevent(vevent); /* stop vevent thread */
553     qemu_thread_join(&card->event_thread_id);
554 
555     card->quit_apdu_thread = 1; /* stop handle_apdu thread */
556     qemu_cond_signal(&card->handle_apdu_cond);
557     qemu_thread_join(&card->apdu_thread_id);
558 
559     /* threads exited, can destroy all condvars/mutexes */
560     qemu_cond_destroy(&card->handle_apdu_cond);
561     qemu_mutex_destroy(&card->handle_apdu_mutex);
562     qemu_mutex_destroy(&card->vreader_mutex);
563     qemu_mutex_destroy(&card->event_list_mutex);
564 }
565 
566 static Property emulated_card_properties[] = {
567     DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
568     DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
569     DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
570     DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
571     DEFINE_PROP_STRING("db", EmulatedState, db),
572     DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
573     DEFINE_PROP_END_OF_LIST(),
574 };
575 
576 static void emulated_class_initfn(ObjectClass *klass, void *data)
577 {
578     DeviceClass *dc = DEVICE_CLASS(klass);
579     CCIDCardClass *cc = CCID_CARD_CLASS(klass);
580 
581     cc->realize = emulated_realize;
582     cc->unrealize = emulated_unrealize;
583     cc->get_atr = emulated_get_atr;
584     cc->apdu_from_guest = emulated_apdu_from_guest;
585     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
586     dc->desc = "emulated smartcard";
587     dc->props = emulated_card_properties;
588 }
589 
590 static const TypeInfo emulated_card_info = {
591     .name          = TYPE_EMULATED_CCID,
592     .parent        = TYPE_CCID_CARD,
593     .instance_size = sizeof(EmulatedState),
594     .class_init    = emulated_class_initfn,
595 };
596 
597 static void ccid_card_emulated_register_types(void)
598 {
599     type_register_static(&emulated_card_info);
600 }
601 
602 type_init(ccid_card_emulated_register_types)
603