blob: 9725f46a743e8f70bd15d6fcc0f9896a795b68f2 [file] [log] [blame]
Robert Relyea111a38b2010-11-28 16:36:38 +02001/*
2 * emulate the reader
3 *
4 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
5 * See the COPYING.LIB file in the top-level directory.
6 */
7
Alon Levy7a685892013-03-05 15:32:19 +02008#ifdef G_LOG_DOMAIN
9#undef G_LOG_DOMAIN
10#endif
11#define G_LOG_DOMAIN "libcacard"
Alon Levy7a685892013-03-05 15:32:19 +020012
Paolo Bonzini28507a42015-04-27 12:34:18 +020013#include "glib-compat.h"
14
15#include <string.h>
Robert Relyea111a38b2010-11-28 16:36:38 +020016
17#include "vcard.h"
18#include "vcard_emul.h"
19#include "card_7816.h"
20#include "vreader.h"
21#include "vevent.h"
Alon Levy7a685892013-03-05 15:32:19 +020022#include "cac.h" /* just for debugging defines */
23
24#define LIBCACARD_LOG_DOMAIN "libcacard"
Robert Relyea111a38b2010-11-28 16:36:38 +020025
26struct VReaderStruct {
27 int reference_count;
28 VCard *card;
29 char *name;
30 vreader_id_t id;
Michael Tokarevfd25c0e2014-05-08 12:30:48 +040031 CompatGMutex lock;
Robert Relyea111a38b2010-11-28 16:36:38 +020032 VReaderEmul *reader_private;
33 VReaderEmulFree reader_private_free;
34};
35
Alon Levy7a685892013-03-05 15:32:19 +020036/*
37 * Debug helpers
38 */
39
40static const char *
41apdu_ins_to_string(int ins)
42{
43 switch (ins) {
44 case VCARD7816_INS_MANAGE_CHANNEL:
45 return "manage channel";
46 case VCARD7816_INS_EXTERNAL_AUTHENTICATE:
47 return "external authenticate";
48 case VCARD7816_INS_GET_CHALLENGE:
49 return "get challenge";
50 case VCARD7816_INS_INTERNAL_AUTHENTICATE:
51 return "internal authenticate";
52 case VCARD7816_INS_ERASE_BINARY:
53 return "erase binary";
54 case VCARD7816_INS_READ_BINARY:
55 return "read binary";
56 case VCARD7816_INS_WRITE_BINARY:
57 return "write binary";
58 case VCARD7816_INS_UPDATE_BINARY:
59 return "update binary";
60 case VCARD7816_INS_READ_RECORD:
61 return "read record";
62 case VCARD7816_INS_WRITE_RECORD:
63 return "write record";
64 case VCARD7816_INS_UPDATE_RECORD:
65 return "update record";
66 case VCARD7816_INS_APPEND_RECORD:
67 return "append record";
68 case VCARD7816_INS_ENVELOPE:
69 return "envelope";
70 case VCARD7816_INS_PUT_DATA:
71 return "put data";
72 case VCARD7816_INS_GET_DATA:
73 return "get data";
74 case VCARD7816_INS_SELECT_FILE:
75 return "select file";
76 case VCARD7816_INS_VERIFY:
77 return "verify";
78 case VCARD7816_INS_GET_RESPONSE:
79 return "get response";
80 case CAC_GET_PROPERTIES:
81 return "get properties";
82 case CAC_GET_ACR:
83 return "get acr";
84 case CAC_READ_BUFFER:
85 return "read buffer";
86 case CAC_UPDATE_BUFFER:
87 return "update buffer";
88 case CAC_SIGN_DECRYPT:
89 return "sign decrypt";
90 case CAC_GET_CERTIFICATE:
91 return "get certificate";
92 }
93 return "unknown";
94}
95
Robert Relyea111a38b2010-11-28 16:36:38 +020096/* manage locking */
97static inline void
98vreader_lock(VReader *reader)
99{
Michael Tokarevfd25c0e2014-05-08 12:30:48 +0400100 g_mutex_lock(&reader->lock);
Robert Relyea111a38b2010-11-28 16:36:38 +0200101}
102
103static inline void
104vreader_unlock(VReader *reader)
105{
Michael Tokarevfd25c0e2014-05-08 12:30:48 +0400106 g_mutex_unlock(&reader->lock);
Robert Relyea111a38b2010-11-28 16:36:38 +0200107}
108
109/*
110 * vreader constructor
111 */
112VReader *
113vreader_new(const char *name, VReaderEmul *private,
114 VReaderEmulFree private_free)
115{
116 VReader *reader;
117
Michael Tokarev78a4b8d2014-05-08 19:51:01 +0400118 reader = g_new(VReader, 1);
Michael Tokarevfd25c0e2014-05-08 12:30:48 +0400119 g_mutex_init(&reader->lock);
Robert Relyea111a38b2010-11-28 16:36:38 +0200120 reader->reference_count = 1;
Markus Armbrusterbe168af2013-01-22 11:08:04 +0100121 reader->name = g_strdup(name);
Robert Relyea111a38b2010-11-28 16:36:38 +0200122 reader->card = NULL;
123 reader->id = (vreader_id_t)-1;
124 reader->reader_private = private;
125 reader->reader_private_free = private_free;
126 return reader;
127}
128
129/* get a reference */
130VReader*
131vreader_reference(VReader *reader)
132{
133 if (reader == NULL) {
134 return NULL;
135 }
136 vreader_lock(reader);
137 reader->reference_count++;
138 vreader_unlock(reader);
139 return reader;
140}
141
142/* free a reference */
143void
144vreader_free(VReader *reader)
145{
146 if (reader == NULL) {
147 return;
148 }
149 vreader_lock(reader);
150 if (reader->reference_count-- > 1) {
151 vreader_unlock(reader);
152 return;
153 }
154 vreader_unlock(reader);
Michael Tokarevfd25c0e2014-05-08 12:30:48 +0400155 g_mutex_clear(&reader->lock);
Robert Relyea111a38b2010-11-28 16:36:38 +0200156 if (reader->card) {
157 vcard_free(reader->card);
158 }
Markus Armbrusterec159932014-06-06 18:32:08 +0200159 g_free(reader->name);
Robert Relyea111a38b2010-11-28 16:36:38 +0200160 if (reader->reader_private_free) {
161 reader->reader_private_free(reader->reader_private);
162 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500163 g_free(reader);
Robert Relyea111a38b2010-11-28 16:36:38 +0200164}
165
166static VCard *
167vreader_get_card(VReader *reader)
168{
169 VCard *card;
170
171 vreader_lock(reader);
172 card = vcard_reference(reader->card);
173 vreader_unlock(reader);
174 return card;
175}
176
177VReaderStatus
178vreader_card_is_present(VReader *reader)
179{
180 VCard *card = vreader_get_card(reader);
181
182 if (card == NULL) {
183 return VREADER_NO_CARD;
184 }
185 vcard_free(card);
186 return VREADER_OK;
187}
188
189vreader_id_t
190vreader_get_id(VReader *reader)
191{
192 if (reader == NULL) {
193 return (vreader_id_t)-1;
194 }
195 return reader->id;
196}
197
198VReaderStatus
199vreader_set_id(VReader *reader, vreader_id_t id)
200{
201 if (reader == NULL) {
202 return VREADER_NO_CARD;
203 }
204 reader->id = id;
205 return VREADER_OK;
206}
207
208const char *
209vreader_get_name(VReader *reader)
210{
211 if (reader == NULL) {
212 return NULL;
213 }
214 return reader->name;
215}
216
217VReaderEmul *
218vreader_get_private(VReader *reader)
219{
220 return reader->reader_private;
221}
222
223static VReaderStatus
224vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len)
225{
226 VCard *card = vreader_get_card(reader);
227
228 if (card == NULL) {
229 return VREADER_NO_CARD;
230 }
231 /*
232 * clean up our state
233 */
234 vcard_reset(card, power);
235 if (atr) {
236 vcard_get_atr(card, atr, len);
237 }
238 vcard_free(card); /* free our reference */
239 return VREADER_OK;
240}
241
242VReaderStatus
243vreader_power_on(VReader *reader, unsigned char *atr, int *len)
244{
245 return vreader_reset(reader, VCARD_POWER_ON, atr, len);
246}
247
248VReaderStatus
249vreader_power_off(VReader *reader)
250{
251 return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0);
252}
253
254
255VReaderStatus
256vreader_xfr_bytes(VReader *reader,
257 unsigned char *send_buf, int send_buf_len,
258 unsigned char *receive_buf, int *receive_buf_len)
259{
260 VCardAPDU *apdu;
261 VCardResponse *response = NULL;
262 VCardStatus card_status;
263 unsigned short status;
264 VCard *card = vreader_get_card(reader);
265
266 if (card == NULL) {
267 return VREADER_NO_CARD;
268 }
269
270 apdu = vcard_apdu_new(send_buf, send_buf_len, &status);
271 if (apdu == NULL) {
272 response = vcard_make_response(status);
273 card_status = VCARD_DONE;
274 } else {
Alon Levy8e25c272014-05-05 17:41:32 +0300275 g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s",
Alon Levy7a685892013-03-05 15:32:19 +0200276 __func__, apdu->a_cla, apdu->a_ins, apdu->a_p1, apdu->a_p2,
277 apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->a_ins));
Robert Relyea111a38b2010-11-28 16:36:38 +0200278 card_status = vcard_process_apdu(card, apdu, &response);
Alon Levy7a685892013-03-05 15:32:19 +0200279 if (response) {
Alon Levy8e25c272014-05-05 17:41:32 +0300280 g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)",
Alon Levy7a685892013-03-05 15:32:19 +0200281 __func__, response->b_status, response->b_sw1,
282 response->b_sw2, response->b_len, response->b_total_len);
283 }
Robert Relyea111a38b2010-11-28 16:36:38 +0200284 }
Markus Armbrusterf33a9842014-05-23 13:24:36 +0200285 assert(card_status == VCARD_DONE && response);
Markus Armbrusterfa5912a2014-05-23 13:24:35 +0200286 int size = MIN(*receive_buf_len, response->b_total_len);
287 memcpy(receive_buf, response->b_data, size);
288 *receive_buf_len = size;
Robert Relyea111a38b2010-11-28 16:36:38 +0200289 vcard_response_delete(response);
290 vcard_apdu_delete(apdu);
291 vcard_free(card); /* free our reference */
292 return VREADER_OK;
293}
294
295struct VReaderListStruct {
296 VReaderListEntry *head;
297 VReaderListEntry *tail;
298};
299
300struct VReaderListEntryStruct {
301 VReaderListEntry *next;
302 VReaderListEntry *prev;
303 VReader *reader;
304};
305
306
307static VReaderListEntry *
308vreader_list_entry_new(VReader *reader)
309{
310 VReaderListEntry *new_reader_list_entry;
311
Michael Tokarev78a4b8d2014-05-08 19:51:01 +0400312 new_reader_list_entry = g_new0(VReaderListEntry, 1);
Robert Relyea111a38b2010-11-28 16:36:38 +0200313 new_reader_list_entry->reader = vreader_reference(reader);
314 return new_reader_list_entry;
315}
316
317static void
318vreader_list_entry_delete(VReaderListEntry *entry)
319{
320 if (entry == NULL) {
321 return;
322 }
323 vreader_free(entry->reader);
Anthony Liguori7267c092011-08-20 22:09:37 -0500324 g_free(entry);
Robert Relyea111a38b2010-11-28 16:36:38 +0200325}
326
327
328static VReaderList *
329vreader_list_new(void)
330{
331 VReaderList *new_reader_list;
332
Michael Tokarev78a4b8d2014-05-08 19:51:01 +0400333 new_reader_list = g_new0(VReaderList, 1);
Robert Relyea111a38b2010-11-28 16:36:38 +0200334 return new_reader_list;
335}
336
337void
338vreader_list_delete(VReaderList *list)
339{
340 VReaderListEntry *current_entry;
Michael Tokarev1687a082014-05-08 21:17:38 +0400341 VReaderListEntry *next_entry;
Robert Relyea111a38b2010-11-28 16:36:38 +0200342 for (current_entry = vreader_list_get_first(list); current_entry;
343 current_entry = next_entry) {
344 next_entry = vreader_list_get_next(current_entry);
345 vreader_list_entry_delete(current_entry);
346 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500347 g_free(list);
Robert Relyea111a38b2010-11-28 16:36:38 +0200348}
349
350
351VReaderListEntry *
352vreader_list_get_first(VReaderList *list)
353{
354 return list ? list->head : NULL;
355}
356
357VReaderListEntry *
358vreader_list_get_next(VReaderListEntry *current)
359{
360 return current ? current->next : NULL;
361}
362
363VReader *
364vreader_list_get_reader(VReaderListEntry *entry)
365{
366 return entry ? vreader_reference(entry->reader) : NULL;
367}
368
369static void
370vreader_queue(VReaderList *list, VReaderListEntry *entry)
371{
372 if (entry == NULL) {
373 return;
374 }
375 entry->next = NULL;
376 entry->prev = list->tail;
377 if (list->head) {
378 list->tail->next = entry;
379 } else {
380 list->head = entry;
381 }
382 list->tail = entry;
383}
384
385static void
386vreader_dequeue(VReaderList *list, VReaderListEntry *entry)
387{
388 if (entry == NULL) {
389 return;
390 }
391 if (entry->next == NULL) {
392 list->tail = entry->prev;
393 } else if (entry->prev == NULL) {
394 list->head = entry->next;
395 } else {
396 entry->prev->next = entry->next;
397 entry->next->prev = entry->prev;
398 }
399 if ((list->tail == NULL) || (list->head == NULL)) {
400 list->head = list->tail = NULL;
401 }
402 entry->next = entry->prev = NULL;
403}
404
405static VReaderList *vreader_list;
Michael Tokarevfd25c0e2014-05-08 12:30:48 +0400406static CompatGMutex vreader_list_mutex;
Robert Relyea111a38b2010-11-28 16:36:38 +0200407
408static void
409vreader_list_init(void)
410{
411 vreader_list = vreader_list_new();
Robert Relyea111a38b2010-11-28 16:36:38 +0200412}
413
414static void
415vreader_list_lock(void)
416{
Michael Tokarevfd25c0e2014-05-08 12:30:48 +0400417 g_mutex_lock(&vreader_list_mutex);
Robert Relyea111a38b2010-11-28 16:36:38 +0200418}
419
420static void
421vreader_list_unlock(void)
422{
Michael Tokarevfd25c0e2014-05-08 12:30:48 +0400423 g_mutex_unlock(&vreader_list_mutex);
Robert Relyea111a38b2010-11-28 16:36:38 +0200424}
425
426static VReaderList *
427vreader_copy_list(VReaderList *list)
428{
Michael Tokarev1687a082014-05-08 21:17:38 +0400429 VReaderList *new_list;
430 VReaderListEntry *current_entry;
Robert Relyea111a38b2010-11-28 16:36:38 +0200431
432 new_list = vreader_list_new();
433 if (new_list == NULL) {
434 return NULL;
435 }
436 for (current_entry = vreader_list_get_first(list); current_entry;
437 current_entry = vreader_list_get_next(current_entry)) {
438 VReader *reader = vreader_list_get_reader(current_entry);
439 VReaderListEntry *new_entry = vreader_list_entry_new(reader);
440
441 vreader_free(reader);
442 vreader_queue(new_list, new_entry);
443 }
444 return new_list;
445}
446
447VReaderList *
448vreader_get_reader_list(void)
449{
450 VReaderList *new_reader_list;
451
452 vreader_list_lock();
453 new_reader_list = vreader_copy_list(vreader_list);
454 vreader_list_unlock();
455 return new_reader_list;
456}
457
458VReader *
459vreader_get_reader_by_id(vreader_id_t id)
460{
461 VReader *reader = NULL;
Michael Tokarev1687a082014-05-08 21:17:38 +0400462 VReaderListEntry *current_entry;
Robert Relyea111a38b2010-11-28 16:36:38 +0200463
464 if (id == (vreader_id_t) -1) {
465 return NULL;
466 }
467
468 vreader_list_lock();
469 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
470 current_entry = vreader_list_get_next(current_entry)) {
471 VReader *creader = vreader_list_get_reader(current_entry);
472 if (creader->id == id) {
473 reader = creader;
474 break;
475 }
476 vreader_free(creader);
477 }
478 vreader_list_unlock();
479 return reader;
480}
481
482VReader *
483vreader_get_reader_by_name(const char *name)
484{
485 VReader *reader = NULL;
Michael Tokarev1687a082014-05-08 21:17:38 +0400486 VReaderListEntry *current_entry;
Robert Relyea111a38b2010-11-28 16:36:38 +0200487
488 vreader_list_lock();
489 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
490 current_entry = vreader_list_get_next(current_entry)) {
491 VReader *creader = vreader_list_get_reader(current_entry);
492 if (strcmp(creader->name, name) == 0) {
493 reader = creader;
494 break;
495 }
496 vreader_free(creader);
497 }
498 vreader_list_unlock();
499 return reader;
500}
501
502/* called from card_emul to initialize the readers */
503VReaderStatus
504vreader_add_reader(VReader *reader)
505{
506 VReaderListEntry *reader_entry;
507
508 reader_entry = vreader_list_entry_new(reader);
509 if (reader_entry == NULL) {
510 return VREADER_OUT_OF_MEMORY;
511 }
512 vreader_list_lock();
513 vreader_queue(vreader_list, reader_entry);
514 vreader_list_unlock();
515 vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL));
516 return VREADER_OK;
517}
518
519
520VReaderStatus
521vreader_remove_reader(VReader *reader)
522{
523 VReaderListEntry *current_entry;
524
525 vreader_list_lock();
526 for (current_entry = vreader_list_get_first(vreader_list); current_entry;
527 current_entry = vreader_list_get_next(current_entry)) {
528 if (current_entry->reader == reader) {
529 break;
530 }
531 }
532 vreader_dequeue(vreader_list, current_entry);
533 vreader_list_unlock();
534 vreader_list_entry_delete(current_entry);
535 vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL));
536 return VREADER_OK;
537}
538
539/*
540 * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader
541 * state. Separated from vreader_insert_card to allow replaying events
542 * for a given state.
543 */
544void
545vreader_queue_card_event(VReader *reader)
546{
547 vevent_queue_vevent(vevent_new(
548 reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader,
549 reader->card));
550}
551
552/*
553 * insert/remove a new card. for removal, card == NULL
554 */
555VReaderStatus
556vreader_insert_card(VReader *reader, VCard *card)
557{
558 vreader_lock(reader);
559 if (reader->card) {
560 /* decrement reference count */
561 vcard_free(reader->card);
562 reader->card = NULL;
563 }
564 reader->card = vcard_reference(card);
565 vreader_unlock(reader);
566 vreader_queue_card_event(reader);
567 return VREADER_OK;
568}
569
570/*
571 * initialize all the static reader structures
572 */
573void
574vreader_init(void)
575{
576 vreader_list_init();
577}
578