This adds option -p to talk to a real HW smartcard through PCSC and compare the anser of HW with libcacard. Original commit from Marc-Andre Lureau rebased to current version: https://github.com/qemu/qemu/commit/812d2f042d39afdcfce958aba37c04f5b5c34ab5 This also fixes the changeset to build without PCSC support and adds colors for better oriantation in the differences. Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx> Reviewed-by: Robert Relyea <rrelyea@xxxxxxxxxx> --- Makefile.am | 4 +- src/vscclient.c | 161 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 156 insertions(+), 9 deletions(-) diff --git a/Makefile.am b/Makefile.am index 1b46bdb..eaae2c5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -55,8 +55,8 @@ pkgconfig_DATA = libcacard.pc bin_PROGRAMS = vscclient vscclient_SOURCES = src/vscclient.c -vscclient_LDADD = libcacard.la $(GTHREAD_LIBS) -vscclient_CFLAGS = $(AM_CPPFLAGS) $(GTHREAD_CFLAGS) +vscclient_LDADD = libcacard.la $(GTHREAD_LIBS) $(PCSC_LIBS) +vscclient_CFLAGS = $(AM_CPPFLAGS) $(GTHREAD_CFLAGS) $(PCSC_CFLAGS) if OS_WIN32 vscclient_CFLAGS += -D__USE_MINGW_ANSI_STDIO=1 diff --git a/src/vscclient.c b/src/vscclient.c index fa60162..89cb294 100644 --- a/src/vscclient.c +++ b/src/vscclient.c @@ -25,6 +25,15 @@ #include <getopt.h> #endif +#if defined(ENABLE_PCSC) +# ifdef __APPLE__ +# include <PCSC/winscard.h> +# include <PCSC/wintypes.h> +# else +# include <winscard.h> +# endif +#endif + #include "glib-compat.h" #include "vscard_common.h" @@ -34,6 +43,7 @@ #include "vevent.h" static int verbose; +static int with_pcsc; static void print_byte_array( @@ -49,11 +59,95 @@ print_byte_array( static void print_usage(void) { - printf("vscclient [-c <certname> .. -e <emul_args> -d <level>] " - "<host> <port>\n"); + printf("vscclient OPTIONS <host> <port>\n"); + printf(" -e <emul_args> - Emulator arguments, see below\n"); + printf(" -c <certname> - Software emulation certificates\n"); + printf(" -d <level> - Debug level\n"); + printf(" -p - Use real smartcard to compare with emulator\n"); vcard_emul_usage(); } +#if defined(ENABLE_PCSC) +static SCARD_IO_REQUEST scard_pci; +static SCARDHANDLE scard; +static SCARDCONTEXT scard_ctxt; + +static gboolean pcsc_transmit(BYTE *cmd, LONG cmdlen, BYTE *recv, int *recvlen) +{ + LONG rv; + + rv = SCardTransmit(scard, &scard_pci, cmd, cmdlen, + NULL, recv, (DWORD*)recvlen); + g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE); + + return 0; +} + +static gboolean pcsc_init(void) +{ + LONG rv; + DWORD nreaders, protocol; + LPTSTR readers; + + rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scard_ctxt); + g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE); + +#ifdef SCARD_AUTOALLOCATE + nreaders = SCARD_AUTOALLOCATE; + + rv = SCardListReaders(scard_ctxt, NULL, (LPTSTR)&readers, &nreaders); + g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE); +#else + rv = SCardListReaders(scard_ctxt, NULL, NULL, &nreaders); + g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE); + + readers = g_new0(char, nreaders); + rv = SCardListReaders(scard_ctxt, NULL, readers, &nreaders); + g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE); +#endif + printf("reader name: %s\n", readers); + + rv = SCardConnect(scard_ctxt, readers, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &scard, &protocol); + g_return_val_if_fail(rv == SCARD_S_SUCCESS, FALSE); + + switch(protocol) { + case SCARD_PROTOCOL_T0: + scard_pci = *SCARD_PCI_T0; + break; + + case SCARD_PROTOCOL_T1: + scard_pci = *SCARD_PCI_T1; + break; + default: + g_return_val_if_reached(FALSE); + } + +#ifdef SCARD_AUTOALLOCATE + rv = SCardFreeMemory(scard_ctxt, readers); + g_warn_if_fail(rv == SCARD_S_SUCCESS); +#else + g_free(readers); +#endif + + return TRUE; +} + +static void pcsc_deinit(void) +{ + LONG rv; + + rv = SCardDisconnect(scard, SCARD_LEAVE_CARD); + g_warn_if_fail(rv == SCARD_S_SUCCESS); + scard = 0; + + rv = SCardReleaseContext(scard_ctxt); + g_warn_if_fail(rv == SCARD_S_SUCCESS); + scard_ctxt = 0; +} +#endif + + static GIOChannel *channel_socket; static GByteArray *socket_to_send; static CompatGMutex socket_to_send_lock; @@ -346,12 +440,19 @@ do_socket_read(GIOChannel *source, } if (state == STATE_MESSAGE) { + char *reply = NULL; +#if defined(ENABLE_PCSC) + int reply_size; +#endif + switch (mhHeader.type) { case VSC_APDU: if (verbose) { - printf(" recv APDU: "); + static int n = 0; + printf("\n\n >>> %d recv APDU: \n", n++); print_byte_array(pbSendBuffer, mhHeader.length); } + /* Transmit received APDU */ dwSendLength = mhHeader.length; dwRecvLength = sizeof(pbRecvBuffer); @@ -359,18 +460,44 @@ do_socket_read(GIOChannel *source, reader_status = vreader_xfr_bytes(reader, pbSendBuffer, dwSendLength, pbRecvBuffer, &dwRecvLength); + if (verbose) { + printf("libcacard response: "); + print_byte_array(pbRecvBuffer, dwRecvLength); + } + +#if defined(ENABLE_PCSC) + if (with_pcsc) { + reply_size = dwRecvLength; + reply = g_memdup(pbRecvBuffer, reply_size); + + dwSendLength = mhHeader.length; + dwRecvLength = sizeof(pbRecvBuffer); + + if (!pcsc_transmit(pbSendBuffer, dwSendLength, + pbRecvBuffer, &dwRecvLength)) + reader_status = VREADER_OK; + else + reader_status = VREADER_NO_CARD; + } +#endif + if (reader_status == VREADER_OK) { mhHeader.length = dwRecvLength; - if (verbose) { - printf(" send response: "); +#if defined(ENABLE_PCSC) + if (with_pcsc && verbose) { + int diff = (unsigned int) reply_size != mhHeader.length || + memcmp(pbRecvBuffer, reply, reply_size); + printf("HW response:%s ", diff ? "\x1B[31m!!!\x1B[0m" : ""); print_byte_array(pbRecvBuffer, mhHeader.length); } +#endif send_msg(VSC_APDU, mhHeader.reader_id, pbRecvBuffer, dwRecvLength); } else { rv = reader_status; /* warning: not meaningful */ send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t)); } + g_free(reply); vreader_free(reader); reader = NULL; /* we've freed it, don't use it by accident again */ @@ -678,14 +805,14 @@ main( } #endif - while ((c = getopt(argc, argv, "c:e:d:")) != -1) { + while ((c = getopt(argc, argv, "c:e:d:p")) != -1) { if (c == '?') { break; } - assert(optarg != NULL); switch (c) { case 'c': + assert(optarg != NULL); if (cert_count >= MAX_CERTS) { printf("too many certificates (max = %d)\n", MAX_CERTS); exit(5); @@ -693,11 +820,16 @@ main( cert_names[cert_count++] = optarg; break; case 'e': + assert(optarg != NULL); emul_args = optarg; break; case 'd': + assert(optarg != NULL); verbose = get_id_from_string(optarg, 1); break; + case 'p': + with_pcsc = 1; + break; default: g_warn_if_reached(); } @@ -767,6 +899,16 @@ main( /* we buffer ourself for thread safety reasons */ g_io_channel_set_buffered(channel_socket, FALSE); + if (with_pcsc) { +#if defined(ENABLE_PCSC) + if (!pcsc_init()) + return 1; +#else + printf("No PCSC support\n"); + return 1; +#endif + } + /* Send init message, Host responds (and then we send reader attachments) */ init = (VSCMsgInit) { .version = htonl(VSCARD_VERSION), @@ -783,5 +925,10 @@ main( g_byte_array_free(socket_to_send, TRUE); closesocket(sock); + +#if defined(ENABLE_PCSC) + pcsc_deinit(); +#endif + return 0; } -- 2.17.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel