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