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