2 * Tester for VSCARD protocol, client side.
4 * Can be used with ccid-card-passthru.
6 * Copyright (c) 2011 Red Hat.
7 * Written by Alon Levy.
9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 * See the COPYING.LIB file in the top-level directory.
18 #include "qemu-common.h"
19 #include "qemu/thread.h"
20 #include "qemu/sockets.h"
22 #include "vscard_common.h"
25 #include "vcard_emul.h"
36 for (i
= 0; i
< nSize
; i
++) {
37 printf("%02X ", arrBytes
[i
]);
44 printf("vscclient [-c <certname> .. -e <emul_args> -d <level>%s] "
48 printf(" -p use passthrough mode\n");
55 static GIOChannel
*channel_socket
;
56 static GByteArray
*socket_to_send
;
57 static QemuMutex socket_to_send_lock
;
58 static guint socket_tag
;
61 update_socket_watch(gboolean out
);
64 do_socket_send(GIOChannel
*source
,
65 GIOCondition condition
,
71 g_return_val_if_fail(socket_to_send
->len
!= 0, FALSE
);
72 g_return_val_if_fail(condition
& G_IO_OUT
, FALSE
);
74 g_io_channel_write_chars(channel_socket
,
75 (gchar
*)socket_to_send
->data
, socket_to_send
->len
, &bw
, &err
);
77 g_error("Error while sending socket %s", err
->message
);
80 g_byte_array_remove_range(socket_to_send
, 0, bw
);
82 if (socket_to_send
->len
== 0) {
83 update_socket_watch(FALSE
);
90 socket_prepare_sending(gpointer user_data
)
92 update_socket_watch(TRUE
);
104 VSCMsgHeader mhHeader
;
106 qemu_mutex_lock(&socket_to_send_lock
);
109 printf("sending type=%d id=%u, len =%u (0x%x)\n",
110 type
, reader_id
, length
, length
);
113 mhHeader
.type
= htonl(type
);
114 mhHeader
.reader_id
= 0;
115 mhHeader
.length
= htonl(length
);
116 g_byte_array_append(socket_to_send
, (guint8
*)&mhHeader
, sizeof(mhHeader
));
117 g_byte_array_append(socket_to_send
, (guint8
*)msg
, length
);
118 g_idle_add(socket_prepare_sending
, NULL
);
120 qemu_mutex_unlock(&socket_to_send_lock
);
125 static VReader
*pending_reader
;
126 static QemuMutex pending_reader_lock
;
127 static QemuCond pending_reader_condition
;
129 #define MAX_ATR_LEN 40
131 event_thread(void *arg
)
133 unsigned char atr
[MAX_ATR_LEN
];
134 int atr_len
= MAX_ATR_LEN
;
135 VEvent
*event
= NULL
;
136 unsigned int reader_id
;
140 const char *reader_name
;
142 event
= vevent_wait_next_vevent();
146 reader_id
= vreader_get_id(event
->reader
);
147 if (reader_id
== VSCARD_UNDEFINED_READER_ID
&&
148 event
->type
!= VEVENT_READER_INSERT
) {
149 /* ignore events from readers qemu has rejected */
150 /* if qemu is still deciding on this reader, wait to see if need to
151 * forward this event */
152 qemu_mutex_lock(&pending_reader_lock
);
153 if (!pending_reader
|| (pending_reader
!= event
->reader
)) {
154 /* wasn't for a pending reader, this reader has already been
155 * rejected by qemu */
156 qemu_mutex_unlock(&pending_reader_lock
);
157 vevent_delete(event
);
160 /* this reader hasn't been told its status from qemu yet, wait for
162 while (pending_reader
!= NULL
) {
163 qemu_cond_wait(&pending_reader_condition
, &pending_reader_lock
);
165 qemu_mutex_unlock(&pending_reader_lock
);
166 /* now recheck the id */
167 reader_id
= vreader_get_id(event
->reader
);
168 if (reader_id
== VSCARD_UNDEFINED_READER_ID
) {
169 /* this reader was rejected */
170 vevent_delete(event
);
173 /* reader was accepted, now forward the event */
175 switch (event
->type
) {
176 case VEVENT_READER_INSERT
:
177 /* tell qemu to insert a new CCID reader */
178 /* wait until qemu has responded to our first reader insert
179 * before we send a second. That way we won't confuse the responses
181 qemu_mutex_lock(&pending_reader_lock
);
182 while (pending_reader
!= NULL
) {
183 qemu_cond_wait(&pending_reader_condition
, &pending_reader_lock
);
185 pending_reader
= vreader_reference(event
->reader
);
186 qemu_mutex_unlock(&pending_reader_lock
);
187 reader_name
= vreader_get_name(event
->reader
);
189 printf(" READER INSERT: %s\n", reader_name
);
191 send_msg(VSC_ReaderAdd
,
192 reader_id
, /* currerntly VSCARD_UNDEFINED_READER_ID */
193 NULL
, 0 /* TODO reader_name, strlen(reader_name) */);
195 case VEVENT_READER_REMOVE
:
196 /* future, tell qemu that an old CCID reader has been removed */
198 printf(" READER REMOVE: %u\n", reader_id
);
200 send_msg(VSC_ReaderRemove
, reader_id
, NULL
, 0);
202 case VEVENT_CARD_INSERT
:
203 /* get the ATR (intended as a response to a power on from the
205 atr_len
= MAX_ATR_LEN
;
206 vreader_power_on(event
->reader
, atr
, &atr_len
);
207 /* ATR call functions as a Card Insert event */
209 printf(" CARD INSERT %u: ", reader_id
);
210 print_byte_array(atr
, atr_len
);
212 send_msg(VSC_ATR
, reader_id
, atr
, atr_len
);
214 case VEVENT_CARD_REMOVE
:
217 printf(" CARD REMOVE %u:\n", reader_id
);
219 send_msg(VSC_CardRemove
, reader_id
, NULL
, 0);
224 vevent_delete(event
);
231 get_id_from_string(char *string
, unsigned int default_id
)
233 unsigned int id
= atoi(string
);
235 /* don't accidentally swith to zero because no numbers have been supplied */
236 if ((id
== 0) && *string
!= '0') {
243 on_host_init(VSCMsgHeader
*mhHeader
, VSCMsgInit
*incoming
)
245 uint32_t *capabilities
= (incoming
->capabilities
);
246 int num_capabilities
=
247 1 + ((mhHeader
->length
- sizeof(VSCMsgInit
)) / sizeof(uint32_t));
249 QemuThread thread_id
;
251 incoming
->version
= ntohl(incoming
->version
);
252 if (incoming
->version
!= VSCARD_VERSION
) {
254 printf("warning: host has version %d, we have %d\n",
255 verbose
, VSCARD_VERSION
);
258 if (incoming
->magic
!= VSCARD_MAGIC
) {
259 printf("unexpected magic: got %d, expected %d\n",
260 incoming
->magic
, VSCARD_MAGIC
);
263 for (i
= 0 ; i
< num_capabilities
; ++i
) {
264 capabilities
[i
] = ntohl(capabilities
[i
]);
266 /* Future: check capabilities */
267 /* remove whatever reader might be left in qemu,
268 * in case of an unclean previous exit. */
269 send_msg(VSC_ReaderRemove
, VSCARD_MINIMAL_READER_ID
, NULL
, 0);
270 /* launch the event_thread. This will trigger reader adds for all the
271 * existing readers */
272 qemu_thread_create(&thread_id
, event_thread
, NULL
, 0);
282 #define APDUBufSize 270
285 do_socket_read(GIOChannel
*source
,
286 GIOCondition condition
,
292 uint8_t pbRecvBuffer
[APDUBufSize
];
293 static uint8_t pbSendBuffer
[APDUBufSize
];
294 VReaderStatus reader_status
;
295 VReader
*reader
= NULL
;
296 static VSCMsgHeader mhHeader
;
297 VSCMsgError
*error_msg
;
301 static gsize br
, to_read
;
302 static int state
= STATE_HEADER
;
304 if (state
== STATE_HEADER
&& to_read
== 0) {
305 buf
= (gchar
*)&mhHeader
;
306 to_read
= sizeof(mhHeader
);
310 g_io_channel_read_chars(source
, (gchar
*)buf
, to_read
, &br
, &err
);
312 g_error("error while reading: %s", err
->message
);
321 if (state
== STATE_HEADER
) {
322 mhHeader
.type
= ntohl(mhHeader
.type
);
323 mhHeader
.reader_id
= ntohl(mhHeader
.reader_id
);
324 mhHeader
.length
= ntohl(mhHeader
.length
);
326 printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n",
327 mhHeader
.type
, mhHeader
.reader_id
, mhHeader
.length
,
330 switch (mhHeader
.type
) {
335 buf
= (gchar
*)pbSendBuffer
;
336 to_read
= mhHeader
.length
;
337 state
= STATE_MESSAGE
;
340 fprintf(stderr
, "Unexpected message of type 0x%X\n", mhHeader
.type
);
345 if (state
== STATE_MESSAGE
) {
346 switch (mhHeader
.type
) {
349 printf(" recv APDU: ");
350 print_byte_array(pbSendBuffer
, mhHeader
.length
);
352 /* Transmit received APDU */
353 dwSendLength
= mhHeader
.length
;
354 dwRecvLength
= sizeof(pbRecvBuffer
);
355 reader
= vreader_get_reader_by_id(mhHeader
.reader_id
);
356 reader_status
= vreader_xfr_bytes(reader
,
357 pbSendBuffer
, dwSendLength
,
358 pbRecvBuffer
, &dwRecvLength
);
359 if (reader_status
== VREADER_OK
) {
360 mhHeader
.length
= dwRecvLength
;
362 printf(" send response: ");
363 print_byte_array(pbRecvBuffer
, mhHeader
.length
);
365 send_msg(VSC_APDU
, mhHeader
.reader_id
,
366 pbRecvBuffer
, dwRecvLength
);
368 rv
= reader_status
; /* warning: not meaningful */
369 send_msg(VSC_Error
, mhHeader
.reader_id
, &rv
, sizeof(uint32_t));
371 vreader_free(reader
);
372 reader
= NULL
; /* we've freed it, don't use it by accident
376 /* TODO: actually flush */
377 send_msg(VSC_FlushComplete
, mhHeader
.reader_id
, NULL
, 0);
380 error_msg
= (VSCMsgError
*) pbSendBuffer
;
381 if (error_msg
->code
== VSC_SUCCESS
) {
382 qemu_mutex_lock(&pending_reader_lock
);
383 if (pending_reader
) {
384 vreader_set_id(pending_reader
, mhHeader
.reader_id
);
385 vreader_free(pending_reader
);
386 pending_reader
= NULL
;
387 qemu_cond_signal(&pending_reader_condition
);
389 qemu_mutex_unlock(&pending_reader_lock
);
392 printf("warning: qemu refused to add reader\n");
393 if (error_msg
->code
== VSC_CANNOT_ADD_MORE_READERS
) {
394 /* clear pending reader, qemu can't handle any more */
395 qemu_mutex_lock(&pending_reader_lock
);
396 if (pending_reader
) {
397 pending_reader
= NULL
;
398 /* make sure the event loop doesn't hang */
399 qemu_cond_signal(&pending_reader_condition
);
401 qemu_mutex_unlock(&pending_reader_lock
);
405 if (on_host_init(&mhHeader
, (VSCMsgInit
*)pbSendBuffer
) < 0) {
414 state
= STATE_HEADER
;
422 do_socket(GIOChannel
*source
,
423 GIOCondition condition
,
426 /* not sure if two watches work well with a single win32 sources */
427 if (condition
& G_IO_OUT
) {
428 if (!do_socket_send(source
, condition
, data
)) {
433 if (condition
& G_IO_IN
) {
434 if (!do_socket_read(source
, condition
, data
)) {
443 update_socket_watch(gboolean out
)
445 if (socket_tag
!= 0) {
446 g_source_remove(socket_tag
);
449 socket_tag
= g_io_add_watch(channel_socket
,
450 G_IO_IN
| (out
? G_IO_OUT
: 0), do_socket
, NULL
);
454 do_command(GIOChannel
*source
,
455 GIOCondition condition
,
459 VCardEmulError error
;
460 static unsigned int default_reader_id
;
461 unsigned int reader_id
;
462 VReader
*reader
= NULL
;
465 g_assert(condition
& G_IO_IN
);
467 reader_id
= default_reader_id
;
468 g_io_channel_read_line(source
, &string
, NULL
, NULL
, &err
);
470 g_error("Error while reading command: %s", err
->message
);
473 if (string
!= NULL
) {
474 if (strncmp(string
, "exit", 4) == 0) {
475 /* remove all the readers */
476 VReaderList
*list
= vreader_get_reader_list();
477 VReaderListEntry
*reader_entry
;
478 printf("Active Readers:\n");
479 for (reader_entry
= vreader_list_get_first(list
); reader_entry
;
480 reader_entry
= vreader_list_get_next(reader_entry
)) {
481 VReader
*reader
= vreader_list_get_reader(reader_entry
);
482 vreader_id_t reader_id
;
483 reader_id
= vreader_get_id(reader
);
484 if (reader_id
== -1) {
487 /* be nice and signal card removal first (qemu probably should
489 if (vreader_card_is_present(reader
) == VREADER_OK
) {
490 send_msg(VSC_CardRemove
, reader_id
, NULL
, 0);
492 send_msg(VSC_ReaderRemove
, reader_id
, NULL
, 0);
495 } else if (strncmp(string
, "insert", 6) == 0) {
496 if (string
[6] == ' ') {
497 reader_id
= get_id_from_string(&string
[7], reader_id
);
499 reader
= vreader_get_reader_by_id(reader_id
);
500 if (reader
!= NULL
) {
501 error
= vcard_emul_force_card_insert(reader
);
502 printf("insert %s, returned %d\n",
503 reader
? vreader_get_name(reader
)
504 : "invalid reader", error
);
506 printf("no reader by id %u found\n", reader_id
);
508 } else if (strncmp(string
, "remove", 6) == 0) {
509 if (string
[6] == ' ') {
510 reader_id
= get_id_from_string(&string
[7], reader_id
);
512 reader
= vreader_get_reader_by_id(reader_id
);
513 if (reader
!= NULL
) {
514 error
= vcard_emul_force_card_remove(reader
);
515 printf("remove %s, returned %d\n",
516 reader
? vreader_get_name(reader
)
517 : "invalid reader", error
);
519 printf("no reader by id %u found\n", reader_id
);
521 } else if (strncmp(string
, "select", 6) == 0) {
522 if (string
[6] == ' ') {
523 reader_id
= get_id_from_string(&string
[7],
524 VSCARD_UNDEFINED_READER_ID
);
526 if (reader_id
!= VSCARD_UNDEFINED_READER_ID
) {
527 reader
= vreader_get_reader_by_id(reader_id
);
530 printf("Selecting reader %u, %s\n", reader_id
,
531 vreader_get_name(reader
));
532 default_reader_id
= reader_id
;
534 printf("Reader with id %u not found\n", reader_id
);
536 } else if (strncmp(string
, "debug", 5) == 0) {
537 if (string
[5] == ' ') {
538 verbose
= get_id_from_string(&string
[6], 0);
540 printf("debug level = %d\n", verbose
);
541 } else if (strncmp(string
, "list", 4) == 0) {
542 VReaderList
*list
= vreader_get_reader_list();
543 VReaderListEntry
*reader_entry
;
544 printf("Active Readers:\n");
545 for (reader_entry
= vreader_list_get_first(list
); reader_entry
;
546 reader_entry
= vreader_list_get_next(reader_entry
)) {
547 VReader
*reader
= vreader_list_get_reader(reader_entry
);
548 vreader_id_t reader_id
;
549 reader_id
= vreader_get_id(reader
);
550 if (reader_id
== -1) {
553 printf("%3u %s %s\n", reader_id
,
554 vreader_card_is_present(reader
) == VREADER_OK
?
555 "CARD_PRESENT" : " ",
556 vreader_get_name(reader
));
558 printf("Inactive Readers:\n");
559 for (reader_entry
= vreader_list_get_first(list
); reader_entry
;
560 reader_entry
= vreader_list_get_next(reader_entry
)) {
561 VReader
*reader
= vreader_list_get_reader(reader_entry
);
562 vreader_id_t reader_id
;
563 reader_id
= vreader_get_id(reader
);
564 if (reader_id
!= -1) {
568 printf("INA %s %s\n",
569 vreader_card_is_present(reader
) == VREADER_OK
?
570 "CARD_PRESENT" : " ",
571 vreader_get_name(reader
));
573 } else if (*string
!= 0) {
574 printf("valid commands:\n");
575 printf("insert [reader_id]\n");
576 printf("remove [reader_id]\n");
577 printf("select reader_id\n");
579 printf("debug [level]\n");
583 vreader_free(reader
);
591 /* just for ease of parsing command line arguments. */
592 #define MAX_CERTS 100
599 struct addrinfo hints
;
600 struct addrinfo
*server
;
603 sock
= qemu_socket(AF_INET
, SOCK_STREAM
, 0);
606 fprintf(stderr
, "Error opening socket!\n");
610 memset(&hints
, 0, sizeof(struct addrinfo
));
611 hints
.ai_family
= AF_UNSPEC
;
612 hints
.ai_socktype
= SOCK_STREAM
;
614 hints
.ai_protocol
= 0; /* Any protocol */
616 ret
= getaddrinfo(host
, port
, &hints
, &server
);
620 fprintf(stderr
, "getaddrinfo failed\n");
624 if (connect(sock
, server
->ai_addr
, server
->ai_addrlen
) < 0) {
626 fprintf(stderr
, "Could not connect\n");
630 printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader
));
641 GIOChannel
*channel_stdin
;
644 VSCMsgHeader mhHeader
;
646 VCardEmulOptions
*command_line_options
= NULL
;
648 char *cert_names
[MAX_CERTS
];
649 char *emul_args
= NULL
;
653 if (socket_init() != 0)
656 while ((c
= getopt(argc
, argv
, "c:e:pd:")) != -1) {
659 if (cert_count
>= MAX_CERTS
) {
660 printf("too many certificates (max = %d)\n", MAX_CERTS
);
663 cert_names
[cert_count
++] = optarg
;
673 verbose
= get_id_from_string(optarg
, 1);
678 if (argc
- optind
!= 2) {
683 if (cert_count
> 0) {
686 /* if we've given some -c options, we clearly we want do so some
687 * software emulation. add that emulation now. this is NSS Emulator
689 if (emul_args
== NULL
) {
690 emul_args
= (char *)"db=\"/etc/pki/nssdb\"";
692 #define SOFT_STRING ",soft=(,Virtual Reader,CAC,,"
693 /* 2 == close paren & null */
694 len
= strlen(emul_args
) + strlen(SOFT_STRING
) + 2;
695 for (i
= 0; i
< cert_count
; i
++) {
696 len
+= strlen(cert_names
[i
])+1; /* 1 == comma */
698 new_args
= g_malloc(len
);
699 strcpy(new_args
, emul_args
);
700 strcat(new_args
, SOFT_STRING
);
701 for (i
= 0; i
< cert_count
; i
++) {
702 strcat(new_args
, cert_names
[i
]);
703 strcat(new_args
, ",");
705 strcat(new_args
, ")");
706 emul_args
= new_args
;
709 command_line_options
= vcard_emul_options(emul_args
);
712 qemu_host
= g_strdup(argv
[argc
- 2]);
713 qemu_port
= g_strdup(argv
[argc
- 1]);
714 sock
= connect_to_qemu(qemu_host
, qemu_port
);
716 fprintf(stderr
, "error opening socket, exiting.\n");
720 socket_to_send
= g_byte_array_new();
721 qemu_mutex_init(&socket_to_send_lock
);
722 qemu_mutex_init(&pending_reader_lock
);
723 qemu_cond_init(&pending_reader_condition
);
725 vcard_emul_init(command_line_options
);
727 loop
= g_main_loop_new(NULL
, true);
733 channel_stdin
= g_io_channel_win32_new_fd(STDIN_FILENO
);
735 channel_stdin
= g_io_channel_unix_new(STDIN_FILENO
);
737 g_io_add_watch(channel_stdin
, G_IO_IN
, do_command
, NULL
);
739 channel_socket
= g_io_channel_win32_new_socket(sock
);
741 channel_socket
= g_io_channel_unix_new(sock
);
743 g_io_channel_set_encoding(channel_socket
, NULL
, NULL
);
744 /* we buffer ourself for thread safety reasons */
745 g_io_channel_set_buffered(channel_socket
, FALSE
);
747 /* Send init message, Host responds (and then we send reader attachments) */
749 .version
= htonl(VSCARD_VERSION
),
750 .magic
= VSCARD_MAGIC
,
753 send_msg(VSC_Init
, mhHeader
.reader_id
, &init
, sizeof(init
));
755 g_main_loop_run(loop
);
756 g_main_loop_unref(loop
);
758 g_io_channel_unref(channel_stdin
);
759 g_io_channel_unref(channel_socket
);
760 g_byte_array_unref(socket_to_send
);