seabios: update binaries to release 1.9.0
[qemu/ar7.git] / hw / usb / ccid-card-emulated.c
blob869a63c5b7c93522b73a8ff678c3bba008f5d462
1 /*
2 * CCID Card Device. Emulated card.
4 * Copyright (c) 2011 Red Hat.
5 * Written by Alon Levy.
7 * This code is licensed under the GNU LGPL, version 2 or later.
8 */
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.
14 * Usage 1: standard, mirror hardware reader+card:
15 * qemu .. -usb -device usb-ccid -device ccid-card-emulated
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
25 * If you use a non default db for the certificates you can specify it using
26 * the db parameter.
29 #include <eventt.h>
30 #include <vevent.h>
31 #include <vreader.h>
32 #include <vcard_emul.h>
34 #include "qemu/thread.h"
35 #include "sysemu/char.h"
36 #include "ccid.h"
38 #define DPRINTF(card, lvl, fmt, ...) \
39 do {\
40 if (lvl <= card->debug) {\
41 printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
42 } \
43 } while (0)
45 #define EMULATED_DEV_NAME "ccid-card-emulated"
47 #define BACKEND_NSS_EMULATED_NAME "nss-emulated"
48 #define BACKEND_CERTIFICATES_NAME "certificates"
50 enum {
51 BACKEND_NSS_EMULATED = 1,
52 BACKEND_CERTIFICATES
55 #define DEFAULT_BACKEND BACKEND_NSS_EMULATED
57 typedef struct EmulatedState EmulatedState;
59 enum {
60 EMUL_READER_INSERT = 0,
61 EMUL_READER_REMOVE,
62 EMUL_CARD_INSERT,
63 EMUL_CARD_REMOVE,
64 EMUL_GUEST_APDU,
65 EMUL_RESPONSE_APDU,
66 EMUL_ERROR,
69 static const char *emul_event_to_string(uint32_t emul_event)
71 switch (emul_event) {
72 case EMUL_READER_INSERT:
73 return "EMUL_READER_INSERT";
74 case EMUL_READER_REMOVE:
75 return "EMUL_READER_REMOVE";
76 case EMUL_CARD_INSERT:
77 return "EMUL_CARD_INSERT";
78 case EMUL_CARD_REMOVE:
79 return "EMUL_CARD_REMOVE";
80 case EMUL_GUEST_APDU:
81 return "EMUL_GUEST_APDU";
82 case EMUL_RESPONSE_APDU:
83 return "EMUL_RESPONSE_APDU";
84 case EMUL_ERROR:
85 return "EMUL_ERROR";
87 return "UNKNOWN";
90 typedef struct EmulEvent {
91 QSIMPLEQ_ENTRY(EmulEvent) entry;
92 union {
93 struct {
94 uint32_t type;
95 } gen;
96 struct {
97 uint32_t type;
98 uint64_t code;
99 } error;
100 struct {
101 uint32_t type;
102 uint32_t len;
103 uint8_t data[];
104 } data;
105 } p;
106 } EmulEvent;
108 #define MAX_ATR_SIZE 40
109 struct EmulatedState {
110 CCIDCardState base;
111 uint8_t debug;
112 char *backend_str;
113 uint32_t backend;
114 char *cert1;
115 char *cert2;
116 char *cert3;
117 char *db;
118 uint8_t atr[MAX_ATR_SIZE];
119 uint8_t atr_length;
120 QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
121 QemuMutex event_list_mutex;
122 QemuThread event_thread_id;
123 VReader *reader;
124 QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
125 QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
126 QemuMutex handle_apdu_mutex;
127 QemuCond handle_apdu_cond;
128 EventNotifier notifier;
129 int quit_apdu_thread;
130 QemuThread apdu_thread_id;
133 static void emulated_apdu_from_guest(CCIDCardState *base,
134 const uint8_t *apdu, uint32_t len)
136 EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
137 EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
139 assert(event);
140 event->p.data.type = EMUL_GUEST_APDU;
141 event->p.data.len = len;
142 memcpy(event->p.data.data, apdu, len);
143 qemu_mutex_lock(&card->vreader_mutex);
144 QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
145 qemu_mutex_unlock(&card->vreader_mutex);
146 qemu_mutex_lock(&card->handle_apdu_mutex);
147 qemu_cond_signal(&card->handle_apdu_cond);
148 qemu_mutex_unlock(&card->handle_apdu_mutex);
151 static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
153 EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
155 *len = card->atr_length;
156 return card->atr;
159 static void emulated_push_event(EmulatedState *card, EmulEvent *event)
161 qemu_mutex_lock(&card->event_list_mutex);
162 QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
163 qemu_mutex_unlock(&card->event_list_mutex);
164 event_notifier_set(&card->notifier);
167 static void emulated_push_type(EmulatedState *card, uint32_t type)
169 EmulEvent *event = g_new(EmulEvent, 1);
171 assert(event);
172 event->p.gen.type = type;
173 emulated_push_event(card, event);
176 static void emulated_push_error(EmulatedState *card, uint64_t code)
178 EmulEvent *event = g_new(EmulEvent, 1);
180 assert(event);
181 event->p.error.type = EMUL_ERROR;
182 event->p.error.code = code;
183 emulated_push_event(card, event);
186 static void emulated_push_data_type(EmulatedState *card, uint32_t type,
187 const uint8_t *data, uint32_t len)
189 EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
191 assert(event);
192 event->p.data.type = type;
193 event->p.data.len = len;
194 memcpy(event->p.data.data, data, len);
195 emulated_push_event(card, event);
198 static void emulated_push_reader_insert(EmulatedState *card)
200 emulated_push_type(card, EMUL_READER_INSERT);
203 static void emulated_push_reader_remove(EmulatedState *card)
205 emulated_push_type(card, EMUL_READER_REMOVE);
208 static void emulated_push_card_insert(EmulatedState *card,
209 const uint8_t *atr, uint32_t len)
211 emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
214 static void emulated_push_card_remove(EmulatedState *card)
216 emulated_push_type(card, EMUL_CARD_REMOVE);
219 static void emulated_push_response_apdu(EmulatedState *card,
220 const uint8_t *apdu, uint32_t len)
222 emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
225 #define APDU_BUF_SIZE 270
226 static void *handle_apdu_thread(void* arg)
228 EmulatedState *card = arg;
229 uint8_t recv_data[APDU_BUF_SIZE];
230 int recv_len;
231 VReaderStatus reader_status;
232 EmulEvent *event;
234 while (1) {
235 qemu_mutex_lock(&card->handle_apdu_mutex);
236 qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
237 qemu_mutex_unlock(&card->handle_apdu_mutex);
238 if (card->quit_apdu_thread) {
239 card->quit_apdu_thread = 0; /* debugging */
240 break;
242 qemu_mutex_lock(&card->vreader_mutex);
243 while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
244 event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
245 assert((unsigned long)event > 1000);
246 QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
247 if (event->p.data.type != EMUL_GUEST_APDU) {
248 DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
249 g_free(event);
250 continue;
252 if (card->reader == NULL) {
253 DPRINTF(card, 1, "reader is NULL\n");
254 g_free(event);
255 continue;
257 recv_len = sizeof(recv_data);
258 reader_status = vreader_xfr_bytes(card->reader,
259 event->p.data.data, event->p.data.len,
260 recv_data, &recv_len);
261 DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
262 if (reader_status == VREADER_OK) {
263 emulated_push_response_apdu(card, recv_data, recv_len);
264 } else {
265 emulated_push_error(card, reader_status);
267 g_free(event);
269 qemu_mutex_unlock(&card->vreader_mutex);
271 return NULL;
274 static void *event_thread(void *arg)
276 int atr_len = MAX_ATR_SIZE;
277 uint8_t atr[MAX_ATR_SIZE];
278 VEvent *event = NULL;
279 EmulatedState *card = arg;
281 while (1) {
282 const char *reader_name;
284 event = vevent_wait_next_vevent();
285 if (event == NULL || event->type == VEVENT_LAST) {
286 break;
288 if (event->type != VEVENT_READER_INSERT) {
289 if (card->reader == NULL && event->reader != NULL) {
290 /* Happens after device_add followed by card remove or insert.
291 * XXX: create synthetic add_reader events if vcard_emul_init
292 * already called, which happens if device_del and device_add
293 * are called */
294 card->reader = vreader_reference(event->reader);
295 } else {
296 if (event->reader != card->reader) {
297 fprintf(stderr,
298 "ERROR: wrong reader: quiting event_thread\n");
299 break;
303 switch (event->type) {
304 case VEVENT_READER_INSERT:
305 /* TODO: take a specific reader. i.e. track which reader
306 * we are seeing here, check it is the one we want (the first,
307 * or by a particular name), and ignore if we don't want it.
309 reader_name = vreader_get_name(event->reader);
310 if (card->reader != NULL) {
311 DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
312 vreader_get_name(card->reader), reader_name);
313 qemu_mutex_lock(&card->vreader_mutex);
314 vreader_free(card->reader);
315 qemu_mutex_unlock(&card->vreader_mutex);
316 emulated_push_reader_remove(card);
318 qemu_mutex_lock(&card->vreader_mutex);
319 DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
320 card->reader = vreader_reference(event->reader);
321 qemu_mutex_unlock(&card->vreader_mutex);
322 emulated_push_reader_insert(card);
323 break;
324 case VEVENT_READER_REMOVE:
325 DPRINTF(card, 2, " READER REMOVE: %s\n",
326 vreader_get_name(event->reader));
327 qemu_mutex_lock(&card->vreader_mutex);
328 vreader_free(card->reader);
329 card->reader = NULL;
330 qemu_mutex_unlock(&card->vreader_mutex);
331 emulated_push_reader_remove(card);
332 break;
333 case VEVENT_CARD_INSERT:
334 /* get the ATR (intended as a response to a power on from the
335 * reader */
336 atr_len = MAX_ATR_SIZE;
337 vreader_power_on(event->reader, atr, &atr_len);
338 card->atr_length = (uint8_t)atr_len;
339 DPRINTF(card, 2, " CARD INSERT\n");
340 emulated_push_card_insert(card, atr, atr_len);
341 break;
342 case VEVENT_CARD_REMOVE:
343 DPRINTF(card, 2, " CARD REMOVE\n");
344 emulated_push_card_remove(card);
345 break;
346 case VEVENT_LAST: /* quit */
347 vevent_delete(event);
348 return NULL;
349 break;
350 default:
351 break;
353 vevent_delete(event);
355 return NULL;
358 static void card_event_handler(EventNotifier *notifier)
360 EmulatedState *card = container_of(notifier, EmulatedState, notifier);
361 EmulEvent *event, *next;
363 event_notifier_test_and_clear(&card->notifier);
364 qemu_mutex_lock(&card->event_list_mutex);
365 QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
366 DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
367 switch (event->p.gen.type) {
368 case EMUL_RESPONSE_APDU:
369 ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
370 event->p.data.len);
371 break;
372 case EMUL_READER_INSERT:
373 ccid_card_ccid_attach(&card->base);
374 break;
375 case EMUL_READER_REMOVE:
376 ccid_card_ccid_detach(&card->base);
377 break;
378 case EMUL_CARD_INSERT:
379 assert(event->p.data.len <= MAX_ATR_SIZE);
380 card->atr_length = event->p.data.len;
381 memcpy(card->atr, event->p.data.data, card->atr_length);
382 ccid_card_card_inserted(&card->base);
383 break;
384 case EMUL_CARD_REMOVE:
385 ccid_card_card_removed(&card->base);
386 break;
387 case EMUL_ERROR:
388 ccid_card_card_error(&card->base, event->p.error.code);
389 break;
390 default:
391 DPRINTF(card, 2, "unexpected event\n");
392 break;
394 g_free(event);
396 QSIMPLEQ_INIT(&card->event_list);
397 qemu_mutex_unlock(&card->event_list_mutex);
400 static int init_event_notifier(EmulatedState *card)
402 if (event_notifier_init(&card->notifier, false) < 0) {
403 DPRINTF(card, 2, "event notifier creation failed\n");
404 return -1;
406 event_notifier_set_handler(&card->notifier, card_event_handler);
407 return 0;
410 #define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
411 #define CERTIFICATES_ARGS_TEMPLATE\
412 "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
414 static int wrap_vcard_emul_init(VCardEmulOptions *options)
416 static int called;
417 static int options_was_null;
419 if (called) {
420 if ((options == NULL) != options_was_null) {
421 printf("%s: warning: running emulated with certificates"
422 " and emulated side by side is not supported\n",
423 __func__);
424 return VCARD_EMUL_FAIL;
426 vcard_emul_replay_insertion_events();
427 return VCARD_EMUL_OK;
429 options_was_null = (options == NULL);
430 called = 1;
431 return vcard_emul_init(options);
434 static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
436 char emul_args[200];
437 VCardEmulOptions *options = NULL;
439 snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
440 card->db ? card->db : CERTIFICATES_DEFAULT_DB,
441 card->cert1, card->cert2, card->cert3);
442 options = vcard_emul_options(emul_args);
443 if (options == NULL) {
444 printf("%s: warning: not using certificates due to"
445 " initialization error\n", __func__);
447 return wrap_vcard_emul_init(options);
450 typedef struct EnumTable {
451 const char *name;
452 uint32_t value;
453 } EnumTable;
455 static const EnumTable backend_enum_table[] = {
456 {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
457 {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
458 {NULL, 0},
461 static uint32_t parse_enumeration(char *str,
462 const EnumTable *table, uint32_t not_found_value)
464 uint32_t ret = not_found_value;
466 if (str == NULL)
467 return 0;
469 while (table->name != NULL) {
470 if (strcmp(table->name, str) == 0) {
471 ret = table->value;
472 break;
474 table++;
476 return ret;
479 static int emulated_initfn(CCIDCardState *base)
481 EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
482 VCardEmulError ret;
483 const EnumTable *ptable;
485 QSIMPLEQ_INIT(&card->event_list);
486 QSIMPLEQ_INIT(&card->guest_apdu_list);
487 qemu_mutex_init(&card->event_list_mutex);
488 qemu_mutex_init(&card->vreader_mutex);
489 qemu_mutex_init(&card->handle_apdu_mutex);
490 qemu_cond_init(&card->handle_apdu_cond);
491 card->reader = NULL;
492 card->quit_apdu_thread = 0;
493 if (init_event_notifier(card) < 0) {
494 return -1;
497 card->backend = 0;
498 if (card->backend_str) {
499 card->backend = parse_enumeration(card->backend_str,
500 backend_enum_table, 0);
503 if (card->backend == 0) {
504 printf("backend must be one of:\n");
505 for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
506 printf("%s\n", ptable->name);
508 return -1;
511 /* TODO: a passthru backened that works on local machine. third card type?*/
512 if (card->backend == BACKEND_CERTIFICATES) {
513 if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
514 ret = emulated_initialize_vcard_from_certificates(card);
515 } else {
516 printf("%s: you must provide all three certs for"
517 " certificates backend\n", EMULATED_DEV_NAME);
518 return -1;
520 } else {
521 if (card->backend != BACKEND_NSS_EMULATED) {
522 printf("%s: bad backend specified. The options are:\n%s (default),"
523 " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME,
524 BACKEND_CERTIFICATES_NAME);
525 return -1;
527 if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
528 printf("%s: unexpected cert parameters to nss emulated backend\n",
529 EMULATED_DEV_NAME);
530 return -1;
532 /* default to mirroring the local hardware readers */
533 ret = wrap_vcard_emul_init(NULL);
535 if (ret != VCARD_EMUL_OK) {
536 printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
537 return -1;
539 qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
540 card, QEMU_THREAD_JOINABLE);
541 qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
542 card, QEMU_THREAD_JOINABLE);
543 return 0;
546 static int emulated_exitfn(CCIDCardState *base)
548 EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
549 VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
551 vevent_queue_vevent(vevent); /* stop vevent thread */
552 qemu_thread_join(&card->event_thread_id);
554 card->quit_apdu_thread = 1; /* stop handle_apdu thread */
555 qemu_cond_signal(&card->handle_apdu_cond);
556 qemu_thread_join(&card->apdu_thread_id);
558 /* threads exited, can destroy all condvars/mutexes */
559 qemu_cond_destroy(&card->handle_apdu_cond);
560 qemu_mutex_destroy(&card->handle_apdu_mutex);
561 qemu_mutex_destroy(&card->vreader_mutex);
562 qemu_mutex_destroy(&card->event_list_mutex);
563 return 0;
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(),
576 static void emulated_class_initfn(ObjectClass *klass, void *data)
578 DeviceClass *dc = DEVICE_CLASS(klass);
579 CCIDCardClass *cc = CCID_CARD_CLASS(klass);
581 cc->initfn = emulated_initfn;
582 cc->exitfn = emulated_exitfn;
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;
590 static const TypeInfo emulated_card_info = {
591 .name = EMULATED_DEV_NAME,
592 .parent = TYPE_CCID_CARD,
593 .instance_size = sizeof(EmulatedState),
594 .class_init = emulated_class_initfn,
597 static void ccid_card_emulated_register_types(void)
599 type_register_static(&emulated_card_info);
602 type_init(ccid_card_emulated_register_types)