]>
Commit | Line | Data |
---|---|---|
111a38b0 RR |
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.LIB file in the top-level directory. | |
6 | */ | |
7 | ||
7a685896 AL |
8 | #ifdef G_LOG_DOMAIN |
9 | #undef G_LOG_DOMAIN | |
10 | #endif | |
11 | #define G_LOG_DOMAIN "libcacard" | |
12 | #include <glib.h> | |
13 | ||
111a38b0 | 14 | #include "qemu-common.h" |
1de7afc9 | 15 | #include "qemu/thread.h" |
111a38b0 RR |
16 | |
17 | #include "vcard.h" | |
18 | #include "vcard_emul.h" | |
19 | #include "card_7816.h" | |
20 | #include "vreader.h" | |
21 | #include "vevent.h" | |
7a685896 AL |
22 | #include "cac.h" /* just for debugging defines */ |
23 | ||
24 | #define LIBCACARD_LOG_DOMAIN "libcacard" | |
111a38b0 RR |
25 | |
26 | struct VReaderStruct { | |
27 | int reference_count; | |
28 | VCard *card; | |
29 | char *name; | |
30 | vreader_id_t id; | |
31 | QemuMutex lock; | |
32 | VReaderEmul *reader_private; | |
33 | VReaderEmulFree reader_private_free; | |
34 | }; | |
35 | ||
7a685896 AL |
36 | /* |
37 | * Debug helpers | |
38 | */ | |
39 | ||
40 | static const char * | |
41 | apdu_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 | ||
111a38b0 RR |
96 | /* manage locking */ |
97 | static inline void | |
98 | vreader_lock(VReader *reader) | |
99 | { | |
100 | qemu_mutex_lock(&reader->lock); | |
101 | } | |
102 | ||
103 | static inline void | |
104 | vreader_unlock(VReader *reader) | |
105 | { | |
106 | qemu_mutex_unlock(&reader->lock); | |
107 | } | |
108 | ||
109 | /* | |
110 | * vreader constructor | |
111 | */ | |
112 | VReader * | |
113 | vreader_new(const char *name, VReaderEmul *private, | |
114 | VReaderEmulFree private_free) | |
115 | { | |
116 | VReader *reader; | |
117 | ||
78a4b8d2 | 118 | reader = g_new(VReader, 1); |
111a38b0 RR |
119 | qemu_mutex_init(&reader->lock); |
120 | reader->reference_count = 1; | |
be168af8 | 121 | reader->name = g_strdup(name); |
111a38b0 RR |
122 | 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 */ | |
130 | VReader* | |
131 | vreader_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 */ | |
143 | void | |
144 | vreader_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); | |
155 | if (reader->card) { | |
156 | vcard_free(reader->card); | |
157 | } | |
158 | if (reader->name) { | |
7267c094 | 159 | g_free(reader->name); |
111a38b0 RR |
160 | } |
161 | if (reader->reader_private_free) { | |
162 | reader->reader_private_free(reader->reader_private); | |
163 | } | |
7267c094 | 164 | g_free(reader); |
111a38b0 RR |
165 | } |
166 | ||
167 | static VCard * | |
168 | vreader_get_card(VReader *reader) | |
169 | { | |
170 | VCard *card; | |
171 | ||
172 | vreader_lock(reader); | |
173 | card = vcard_reference(reader->card); | |
174 | vreader_unlock(reader); | |
175 | return card; | |
176 | } | |
177 | ||
178 | VReaderStatus | |
179 | vreader_card_is_present(VReader *reader) | |
180 | { | |
181 | VCard *card = vreader_get_card(reader); | |
182 | ||
183 | if (card == NULL) { | |
184 | return VREADER_NO_CARD; | |
185 | } | |
186 | vcard_free(card); | |
187 | return VREADER_OK; | |
188 | } | |
189 | ||
190 | vreader_id_t | |
191 | vreader_get_id(VReader *reader) | |
192 | { | |
193 | if (reader == NULL) { | |
194 | return (vreader_id_t)-1; | |
195 | } | |
196 | return reader->id; | |
197 | } | |
198 | ||
199 | VReaderStatus | |
200 | vreader_set_id(VReader *reader, vreader_id_t id) | |
201 | { | |
202 | if (reader == NULL) { | |
203 | return VREADER_NO_CARD; | |
204 | } | |
205 | reader->id = id; | |
206 | return VREADER_OK; | |
207 | } | |
208 | ||
209 | const char * | |
210 | vreader_get_name(VReader *reader) | |
211 | { | |
212 | if (reader == NULL) { | |
213 | return NULL; | |
214 | } | |
215 | return reader->name; | |
216 | } | |
217 | ||
218 | VReaderEmul * | |
219 | vreader_get_private(VReader *reader) | |
220 | { | |
221 | return reader->reader_private; | |
222 | } | |
223 | ||
224 | static VReaderStatus | |
225 | vreader_reset(VReader *reader, VCardPower power, unsigned char *atr, int *len) | |
226 | { | |
227 | VCard *card = vreader_get_card(reader); | |
228 | ||
229 | if (card == NULL) { | |
230 | return VREADER_NO_CARD; | |
231 | } | |
232 | /* | |
233 | * clean up our state | |
234 | */ | |
235 | vcard_reset(card, power); | |
236 | if (atr) { | |
237 | vcard_get_atr(card, atr, len); | |
238 | } | |
239 | vcard_free(card); /* free our reference */ | |
240 | return VREADER_OK; | |
241 | } | |
242 | ||
243 | VReaderStatus | |
244 | vreader_power_on(VReader *reader, unsigned char *atr, int *len) | |
245 | { | |
246 | return vreader_reset(reader, VCARD_POWER_ON, atr, len); | |
247 | } | |
248 | ||
249 | VReaderStatus | |
250 | vreader_power_off(VReader *reader) | |
251 | { | |
252 | return vreader_reset(reader, VCARD_POWER_OFF, NULL, 0); | |
253 | } | |
254 | ||
255 | ||
256 | VReaderStatus | |
257 | vreader_xfr_bytes(VReader *reader, | |
258 | unsigned char *send_buf, int send_buf_len, | |
259 | unsigned char *receive_buf, int *receive_buf_len) | |
260 | { | |
261 | VCardAPDU *apdu; | |
262 | VCardResponse *response = NULL; | |
263 | VCardStatus card_status; | |
264 | unsigned short status; | |
265 | VCard *card = vreader_get_card(reader); | |
266 | ||
267 | if (card == NULL) { | |
268 | return VREADER_NO_CARD; | |
269 | } | |
270 | ||
271 | apdu = vcard_apdu_new(send_buf, send_buf_len, &status); | |
272 | if (apdu == NULL) { | |
273 | response = vcard_make_response(status); | |
274 | card_status = VCARD_DONE; | |
275 | } else { | |
8e25c274 | 276 | g_debug("%s: CLS=0x%x,INS=0x%x,P1=0x%x,P2=0x%x,Lc=%d,Le=%d %s", |
7a685896 AL |
277 | __func__, apdu->a_cla, apdu->a_ins, apdu->a_p1, apdu->a_p2, |
278 | apdu->a_Lc, apdu->a_Le, apdu_ins_to_string(apdu->a_ins)); | |
111a38b0 | 279 | card_status = vcard_process_apdu(card, apdu, &response); |
7a685896 | 280 | if (response) { |
8e25c274 | 281 | g_debug("%s: status=%d sw1=0x%x sw2=0x%x len=%d (total=%d)", |
7a685896 AL |
282 | __func__, response->b_status, response->b_sw1, |
283 | response->b_sw2, response->b_len, response->b_total_len); | |
284 | } | |
111a38b0 | 285 | } |
f33a984d | 286 | assert(card_status == VCARD_DONE && response); |
fa5912a1 MA |
287 | int size = MIN(*receive_buf_len, response->b_total_len); |
288 | memcpy(receive_buf, response->b_data, size); | |
289 | *receive_buf_len = size; | |
111a38b0 RR |
290 | vcard_response_delete(response); |
291 | vcard_apdu_delete(apdu); | |
292 | vcard_free(card); /* free our reference */ | |
293 | return VREADER_OK; | |
294 | } | |
295 | ||
296 | struct VReaderListStruct { | |
297 | VReaderListEntry *head; | |
298 | VReaderListEntry *tail; | |
299 | }; | |
300 | ||
301 | struct VReaderListEntryStruct { | |
302 | VReaderListEntry *next; | |
303 | VReaderListEntry *prev; | |
304 | VReader *reader; | |
305 | }; | |
306 | ||
307 | ||
308 | static VReaderListEntry * | |
309 | vreader_list_entry_new(VReader *reader) | |
310 | { | |
311 | VReaderListEntry *new_reader_list_entry; | |
312 | ||
78a4b8d2 | 313 | new_reader_list_entry = g_new0(VReaderListEntry, 1); |
111a38b0 RR |
314 | new_reader_list_entry->reader = vreader_reference(reader); |
315 | return new_reader_list_entry; | |
316 | } | |
317 | ||
318 | static void | |
319 | vreader_list_entry_delete(VReaderListEntry *entry) | |
320 | { | |
321 | if (entry == NULL) { | |
322 | return; | |
323 | } | |
324 | vreader_free(entry->reader); | |
7267c094 | 325 | g_free(entry); |
111a38b0 RR |
326 | } |
327 | ||
328 | ||
329 | static VReaderList * | |
330 | vreader_list_new(void) | |
331 | { | |
332 | VReaderList *new_reader_list; | |
333 | ||
78a4b8d2 | 334 | new_reader_list = g_new0(VReaderList, 1); |
111a38b0 RR |
335 | return new_reader_list; |
336 | } | |
337 | ||
338 | void | |
339 | vreader_list_delete(VReaderList *list) | |
340 | { | |
341 | VReaderListEntry *current_entry; | |
1687a089 | 342 | VReaderListEntry *next_entry; |
111a38b0 RR |
343 | for (current_entry = vreader_list_get_first(list); current_entry; |
344 | current_entry = next_entry) { | |
345 | next_entry = vreader_list_get_next(current_entry); | |
346 | vreader_list_entry_delete(current_entry); | |
347 | } | |
348 | list->head = NULL; | |
349 | list->tail = NULL; | |
7267c094 | 350 | g_free(list); |
111a38b0 RR |
351 | } |
352 | ||
353 | ||
354 | VReaderListEntry * | |
355 | vreader_list_get_first(VReaderList *list) | |
356 | { | |
357 | return list ? list->head : NULL; | |
358 | } | |
359 | ||
360 | VReaderListEntry * | |
361 | vreader_list_get_next(VReaderListEntry *current) | |
362 | { | |
363 | return current ? current->next : NULL; | |
364 | } | |
365 | ||
366 | VReader * | |
367 | vreader_list_get_reader(VReaderListEntry *entry) | |
368 | { | |
369 | return entry ? vreader_reference(entry->reader) : NULL; | |
370 | } | |
371 | ||
372 | static void | |
373 | vreader_queue(VReaderList *list, VReaderListEntry *entry) | |
374 | { | |
375 | if (entry == NULL) { | |
376 | return; | |
377 | } | |
378 | entry->next = NULL; | |
379 | entry->prev = list->tail; | |
380 | if (list->head) { | |
381 | list->tail->next = entry; | |
382 | } else { | |
383 | list->head = entry; | |
384 | } | |
385 | list->tail = entry; | |
386 | } | |
387 | ||
388 | static void | |
389 | vreader_dequeue(VReaderList *list, VReaderListEntry *entry) | |
390 | { | |
391 | if (entry == NULL) { | |
392 | return; | |
393 | } | |
394 | if (entry->next == NULL) { | |
395 | list->tail = entry->prev; | |
396 | } else if (entry->prev == NULL) { | |
397 | list->head = entry->next; | |
398 | } else { | |
399 | entry->prev->next = entry->next; | |
400 | entry->next->prev = entry->prev; | |
401 | } | |
402 | if ((list->tail == NULL) || (list->head == NULL)) { | |
403 | list->head = list->tail = NULL; | |
404 | } | |
405 | entry->next = entry->prev = NULL; | |
406 | } | |
407 | ||
408 | static VReaderList *vreader_list; | |
409 | static QemuMutex vreader_list_mutex; | |
410 | ||
411 | static void | |
412 | vreader_list_init(void) | |
413 | { | |
414 | vreader_list = vreader_list_new(); | |
415 | qemu_mutex_init(&vreader_list_mutex); | |
416 | } | |
417 | ||
418 | static void | |
419 | vreader_list_lock(void) | |
420 | { | |
421 | qemu_mutex_lock(&vreader_list_mutex); | |
422 | } | |
423 | ||
424 | static void | |
425 | vreader_list_unlock(void) | |
426 | { | |
427 | qemu_mutex_unlock(&vreader_list_mutex); | |
428 | } | |
429 | ||
430 | static VReaderList * | |
431 | vreader_copy_list(VReaderList *list) | |
432 | { | |
1687a089 MT |
433 | VReaderList *new_list; |
434 | VReaderListEntry *current_entry; | |
111a38b0 RR |
435 | |
436 | new_list = vreader_list_new(); | |
437 | if (new_list == NULL) { | |
438 | return NULL; | |
439 | } | |
440 | for (current_entry = vreader_list_get_first(list); current_entry; | |
441 | current_entry = vreader_list_get_next(current_entry)) { | |
442 | VReader *reader = vreader_list_get_reader(current_entry); | |
443 | VReaderListEntry *new_entry = vreader_list_entry_new(reader); | |
444 | ||
445 | vreader_free(reader); | |
446 | vreader_queue(new_list, new_entry); | |
447 | } | |
448 | return new_list; | |
449 | } | |
450 | ||
451 | VReaderList * | |
452 | vreader_get_reader_list(void) | |
453 | { | |
454 | VReaderList *new_reader_list; | |
455 | ||
456 | vreader_list_lock(); | |
457 | new_reader_list = vreader_copy_list(vreader_list); | |
458 | vreader_list_unlock(); | |
459 | return new_reader_list; | |
460 | } | |
461 | ||
462 | VReader * | |
463 | vreader_get_reader_by_id(vreader_id_t id) | |
464 | { | |
465 | VReader *reader = NULL; | |
1687a089 | 466 | VReaderListEntry *current_entry; |
111a38b0 RR |
467 | |
468 | if (id == (vreader_id_t) -1) { | |
469 | return NULL; | |
470 | } | |
471 | ||
472 | vreader_list_lock(); | |
473 | for (current_entry = vreader_list_get_first(vreader_list); current_entry; | |
474 | current_entry = vreader_list_get_next(current_entry)) { | |
475 | VReader *creader = vreader_list_get_reader(current_entry); | |
476 | if (creader->id == id) { | |
477 | reader = creader; | |
478 | break; | |
479 | } | |
480 | vreader_free(creader); | |
481 | } | |
482 | vreader_list_unlock(); | |
483 | return reader; | |
484 | } | |
485 | ||
486 | VReader * | |
487 | vreader_get_reader_by_name(const char *name) | |
488 | { | |
489 | VReader *reader = NULL; | |
1687a089 | 490 | VReaderListEntry *current_entry; |
111a38b0 RR |
491 | |
492 | vreader_list_lock(); | |
493 | for (current_entry = vreader_list_get_first(vreader_list); current_entry; | |
494 | current_entry = vreader_list_get_next(current_entry)) { | |
495 | VReader *creader = vreader_list_get_reader(current_entry); | |
496 | if (strcmp(creader->name, name) == 0) { | |
497 | reader = creader; | |
498 | break; | |
499 | } | |
500 | vreader_free(creader); | |
501 | } | |
502 | vreader_list_unlock(); | |
503 | return reader; | |
504 | } | |
505 | ||
506 | /* called from card_emul to initialize the readers */ | |
507 | VReaderStatus | |
508 | vreader_add_reader(VReader *reader) | |
509 | { | |
510 | VReaderListEntry *reader_entry; | |
511 | ||
512 | reader_entry = vreader_list_entry_new(reader); | |
513 | if (reader_entry == NULL) { | |
514 | return VREADER_OUT_OF_MEMORY; | |
515 | } | |
516 | vreader_list_lock(); | |
517 | vreader_queue(vreader_list, reader_entry); | |
518 | vreader_list_unlock(); | |
519 | vevent_queue_vevent(vevent_new(VEVENT_READER_INSERT, reader, NULL)); | |
520 | return VREADER_OK; | |
521 | } | |
522 | ||
523 | ||
524 | VReaderStatus | |
525 | vreader_remove_reader(VReader *reader) | |
526 | { | |
527 | VReaderListEntry *current_entry; | |
528 | ||
529 | vreader_list_lock(); | |
530 | for (current_entry = vreader_list_get_first(vreader_list); current_entry; | |
531 | current_entry = vreader_list_get_next(current_entry)) { | |
532 | if (current_entry->reader == reader) { | |
533 | break; | |
534 | } | |
535 | } | |
536 | vreader_dequeue(vreader_list, current_entry); | |
537 | vreader_list_unlock(); | |
538 | vreader_list_entry_delete(current_entry); | |
539 | vevent_queue_vevent(vevent_new(VEVENT_READER_REMOVE, reader, NULL)); | |
540 | return VREADER_OK; | |
541 | } | |
542 | ||
543 | /* | |
544 | * Generate VEVENT_CARD_INSERT or VEVENT_CARD_REMOVE based on vreader | |
545 | * state. Separated from vreader_insert_card to allow replaying events | |
546 | * for a given state. | |
547 | */ | |
548 | void | |
549 | vreader_queue_card_event(VReader *reader) | |
550 | { | |
551 | vevent_queue_vevent(vevent_new( | |
552 | reader->card ? VEVENT_CARD_INSERT : VEVENT_CARD_REMOVE, reader, | |
553 | reader->card)); | |
554 | } | |
555 | ||
556 | /* | |
557 | * insert/remove a new card. for removal, card == NULL | |
558 | */ | |
559 | VReaderStatus | |
560 | vreader_insert_card(VReader *reader, VCard *card) | |
561 | { | |
562 | vreader_lock(reader); | |
563 | if (reader->card) { | |
564 | /* decrement reference count */ | |
565 | vcard_free(reader->card); | |
566 | reader->card = NULL; | |
567 | } | |
568 | reader->card = vcard_reference(card); | |
569 | vreader_unlock(reader); | |
570 | vreader_queue_card_event(reader); | |
571 | return VREADER_OK; | |
572 | } | |
573 | ||
574 | /* | |
575 | * initialize all the static reader structures | |
576 | */ | |
577 | void | |
578 | vreader_init(void) | |
579 | { | |
580 | vreader_list_init(); | |
581 | } | |
582 |