[Spice-devel] [PATCH libcacard 4/7] vscclient: learn to diff with real card for debug
Jakub Jelen
jjelen at redhat.com
Tue Jul 31 09:35:48 UTC 2018
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 at redhat.com>
Reviewed-by: Robert Relyea <rrelyea at redhat.com>
---
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
More information about the Spice-devel
mailing list