xref: /openbmc/qemu/hw/usb/ccid-card-emulated.c (revision 09a274d8)
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(, EmulEvent) event_list;
123     QemuMutex event_list_mutex;
124     QemuThread event_thread_id;
125     VReader *reader;
126     QSIMPLEQ_HEAD(, 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 static void clean_event_notifier(EmulatedState *card)
413 {
414     event_notifier_set_handler(&card->notifier, NULL);
415     event_notifier_cleanup(&card->notifier);
416 }
417 
418 #define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
419 #define CERTIFICATES_ARGS_TEMPLATE\
420     "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
421 
422 static int wrap_vcard_emul_init(VCardEmulOptions *options)
423 {
424     static int called;
425     static int options_was_null;
426 
427     if (called) {
428         if ((options == NULL) != options_was_null) {
429             printf("%s: warning: running emulated with certificates"
430                    " and emulated side by side is not supported\n",
431                    __func__);
432             return VCARD_EMUL_FAIL;
433         }
434         vcard_emul_replay_insertion_events();
435         return VCARD_EMUL_OK;
436     }
437     options_was_null = (options == NULL);
438     called = 1;
439     return vcard_emul_init(options);
440 }
441 
442 static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
443 {
444     char emul_args[200];
445     VCardEmulOptions *options = NULL;
446 
447     snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
448         card->db ? card->db : CERTIFICATES_DEFAULT_DB,
449         card->cert1, card->cert2, card->cert3);
450     options = vcard_emul_options(emul_args);
451     if (options == NULL) {
452         printf("%s: warning: not using certificates due to"
453                " initialization error\n", __func__);
454     }
455     return wrap_vcard_emul_init(options);
456 }
457 
458 typedef struct EnumTable {
459     const char *name;
460     uint32_t value;
461 } EnumTable;
462 
463 static const EnumTable backend_enum_table[] = {
464     {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
465     {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
466     {NULL, 0},
467 };
468 
469 static uint32_t parse_enumeration(char *str,
470     const EnumTable *table, uint32_t not_found_value)
471 {
472     uint32_t ret = not_found_value;
473 
474     if (str == NULL)
475         return 0;
476 
477     while (table->name != NULL) {
478         if (strcmp(table->name, str) == 0) {
479             ret = table->value;
480             break;
481         }
482         table++;
483     }
484     return ret;
485 }
486 
487 static void emulated_realize(CCIDCardState *base, Error **errp)
488 {
489     EmulatedState *card = EMULATED_CCID_CARD(base);
490     VCardEmulError ret;
491     const EnumTable *ptable;
492 
493     QSIMPLEQ_INIT(&card->event_list);
494     QSIMPLEQ_INIT(&card->guest_apdu_list);
495     qemu_mutex_init(&card->event_list_mutex);
496     qemu_mutex_init(&card->vreader_mutex);
497     qemu_mutex_init(&card->handle_apdu_mutex);
498     qemu_cond_init(&card->handle_apdu_cond);
499     card->reader = NULL;
500     card->quit_apdu_thread = 0;
501     if (init_event_notifier(card, errp) < 0) {
502         goto out1;
503     }
504 
505     card->backend = 0;
506     if (card->backend_str) {
507         card->backend = parse_enumeration(card->backend_str,
508                                           backend_enum_table, 0);
509     }
510 
511     if (card->backend == 0) {
512         error_setg(errp, "backend must be one of:");
513         for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
514             error_append_hint(errp, "%s\n", ptable->name);
515         }
516         goto out2;
517     }
518 
519     /* TODO: a passthru backened that works on local machine. third card type?*/
520     if (card->backend == BACKEND_CERTIFICATES) {
521         if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
522             ret = emulated_initialize_vcard_from_certificates(card);
523         } else {
524             error_setg(errp, "%s: you must provide all three certs for"
525                        " certificates backend", TYPE_EMULATED_CCID);
526             goto out2;
527         }
528     } else {
529         if (card->backend != BACKEND_NSS_EMULATED) {
530             error_setg(errp, "%s: bad backend specified. The options are:%s"
531                        " (default), %s.", TYPE_EMULATED_CCID,
532                        BACKEND_NSS_EMULATED_NAME, BACKEND_CERTIFICATES_NAME);
533             goto out2;
534         }
535         if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
536             error_setg(errp, "%s: unexpected cert parameters to nss emulated "
537                        "backend", TYPE_EMULATED_CCID);
538             goto out2;
539         }
540         /* default to mirroring the local hardware readers */
541         ret = wrap_vcard_emul_init(NULL);
542     }
543     if (ret != VCARD_EMUL_OK) {
544         error_setg(errp, "%s: failed to initialize vcard", TYPE_EMULATED_CCID);
545         goto out2;
546     }
547     qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
548                        card, QEMU_THREAD_JOINABLE);
549     qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
550                        card, QEMU_THREAD_JOINABLE);
551 
552     return;
553 
554 out2:
555     clean_event_notifier(card);
556 out1:
557     qemu_cond_destroy(&card->handle_apdu_cond);
558     qemu_mutex_destroy(&card->handle_apdu_mutex);
559     qemu_mutex_destroy(&card->vreader_mutex);
560     qemu_mutex_destroy(&card->event_list_mutex);
561 }
562 
563 static void emulated_unrealize(CCIDCardState *base, Error **errp)
564 {
565     EmulatedState *card = EMULATED_CCID_CARD(base);
566     VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
567 
568     vevent_queue_vevent(vevent); /* stop vevent thread */
569     qemu_thread_join(&card->event_thread_id);
570 
571     card->quit_apdu_thread = 1; /* stop handle_apdu thread */
572     qemu_cond_signal(&card->handle_apdu_cond);
573     qemu_thread_join(&card->apdu_thread_id);
574 
575     clean_event_notifier(card);
576     /* threads exited, can destroy all condvars/mutexes */
577     qemu_cond_destroy(&card->handle_apdu_cond);
578     qemu_mutex_destroy(&card->handle_apdu_mutex);
579     qemu_mutex_destroy(&card->vreader_mutex);
580     qemu_mutex_destroy(&card->event_list_mutex);
581 }
582 
583 static Property emulated_card_properties[] = {
584     DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
585     DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
586     DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
587     DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
588     DEFINE_PROP_STRING("db", EmulatedState, db),
589     DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
590     DEFINE_PROP_END_OF_LIST(),
591 };
592 
593 static void emulated_class_initfn(ObjectClass *klass, void *data)
594 {
595     DeviceClass *dc = DEVICE_CLASS(klass);
596     CCIDCardClass *cc = CCID_CARD_CLASS(klass);
597 
598     cc->realize = emulated_realize;
599     cc->unrealize = emulated_unrealize;
600     cc->get_atr = emulated_get_atr;
601     cc->apdu_from_guest = emulated_apdu_from_guest;
602     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
603     dc->desc = "emulated smartcard";
604     dc->props = emulated_card_properties;
605 }
606 
607 static const TypeInfo emulated_card_info = {
608     .name          = TYPE_EMULATED_CCID,
609     .parent        = TYPE_CCID_CARD,
610     .instance_size = sizeof(EmulatedState),
611     .class_init    = emulated_class_initfn,
612 };
613 
614 static void ccid_card_emulated_register_types(void)
615 {
616     type_register_static(&emulated_card_info);
617 }
618 
619 type_init(ccid_card_emulated_register_types)
620