Statistics
| Branch: | Revision:

root / hw / ccid-card-emulated.c @ 927d4878

History | View | Annotate | Download (18.5 kB)

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 "char/char.h"
36
#include "monitor/monitor.h"
37
#include "hw/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
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
    EnumTable *table, uint32_t not_found_value)
473
{
474
    uint32_t ret = not_found_value;
475

    
476
    while (table->name != NULL) {
477
        if (strcmp(table->name, str) == 0) {
478
            ret = table->value;
479
            break;
480
        }
481
        table++;
482
    }
483
    return ret;
484
}
485

    
486
static int emulated_initfn(CCIDCardState *base)
487
{
488
    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
489
    VCardEmulError ret;
490
    EnumTable *ptable;
491

    
492
    QSIMPLEQ_INIT(&card->event_list);
493
    QSIMPLEQ_INIT(&card->guest_apdu_list);
494
    qemu_mutex_init(&card->event_list_mutex);
495
    qemu_mutex_init(&card->vreader_mutex);
496
    qemu_mutex_init(&card->handle_apdu_mutex);
497
    qemu_cond_init(&card->handle_apdu_cond);
498
    card->reader = NULL;
499
    card->quit_apdu_thread = 0;
500
    if (init_pipe_signaling(card) < 0) {
501
        return -1;
502
    }
503
    card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0);
504
    if (card->backend == 0) {
505
        printf("unknown backend, must be one of:\n");
506
        for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
507
            printf("%s\n", ptable->name);
508
        }
509
        return -1;
510
    }
511

    
512
    /* TODO: a passthru backened that works on local machine. third card type?*/
513
    if (card->backend == BACKEND_CERTIFICATES) {
514
        if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
515
            ret = emulated_initialize_vcard_from_certificates(card);
516
        } else {
517
            printf("%s: you must provide all three certs for"
518
                   " certificates backend\n", EMULATED_DEV_NAME);
519
            return -1;
520
        }
521
    } else {
522
        if (card->backend != BACKEND_NSS_EMULATED) {
523
            printf("%s: bad backend specified. The options are:\n%s (default),"
524
                " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME,
525
                BACKEND_CERTIFICATES_NAME);
526
            return -1;
527
        }
528
        if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
529
            printf("%s: unexpected cert parameters to nss emulated backend\n",
530
                   EMULATED_DEV_NAME);
531
            return -1;
532
        }
533
        /* default to mirroring the local hardware readers */
534
        ret = wrap_vcard_emul_init(NULL);
535
    }
536
    if (ret != VCARD_EMUL_OK) {
537
        printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
538
        return -1;
539
    }
540
    qemu_thread_create(&card->event_thread_id, event_thread, card,
541
                       QEMU_THREAD_JOINABLE);
542
    qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card,
543
                       QEMU_THREAD_JOINABLE);
544
    return 0;
545
}
546

    
547
static int emulated_exitfn(CCIDCardState *base)
548
{
549
    EmulatedState *card = DO_UPCAST(EmulatedState, base, 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
    return 0;
565
}
566

    
567
static Property emulated_card_properties[] = {
568
    DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
569
    DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
570
    DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
571
    DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
572
    DEFINE_PROP_STRING("db", EmulatedState, db),
573
    DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
574
    DEFINE_PROP_END_OF_LIST(),
575
};
576

    
577
static void emulated_class_initfn(ObjectClass *klass, void *data)
578
{
579
    DeviceClass *dc = DEVICE_CLASS(klass);
580
    CCIDCardClass *cc = CCID_CARD_CLASS(klass);
581

    
582
    cc->initfn = emulated_initfn;
583
    cc->exitfn = emulated_exitfn;
584
    cc->get_atr = emulated_get_atr;
585
    cc->apdu_from_guest = emulated_apdu_from_guest;
586
    dc->desc = "emulated smartcard";
587
    dc->props = emulated_card_properties;
588
}
589

    
590
static 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,
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)