From 24128057ff86e4696658423b73f472a71325686a Mon Sep 17 00:00:00 2001 From: Frank Morgner Date: Tue, 24 Jul 2012 22:36:22 +0200 Subject: [PATCH] added abstraction layer to smart card connector PC/SC can now be replaced by some arbitrary backend that communicates to a smart card. --- pcsc-relay/src/Makefile.am | 4 +- pcsc-relay/src/pcsc-relay.c | 85 +++++++++-------- pcsc-relay/src/pcsc-relay.h | 11 +++ pcsc-relay/src/pcsc.c | 184 ++++++++++++++++++++++++++++++++++++ pcsc-relay/src/pcscutil.c | 126 ------------------------ pcsc-relay/src/pcscutil.h | 64 ------------- 6 files changed, 244 insertions(+), 230 deletions(-) create mode 100644 pcsc-relay/src/pcsc.c delete mode 100644 pcsc-relay/src/pcscutil.c delete mode 100644 pcsc-relay/src/pcscutil.h diff --git a/pcsc-relay/src/Makefile.am b/pcsc-relay/src/Makefile.am index a47845c..1adfc93 100644 --- a/pcsc-relay/src/Makefile.am +++ b/pcsc-relay/src/Makefile.am @@ -28,11 +28,11 @@ pcsc-relay.1: bin_PROGRAMS = pcsc-relay bin_SCRIPTS = picc.py -pcsc_relay_SOURCES = pcsc-relay.c pcscutil.c opicc.c lnfc.c $(BUILT_SOURCES) +pcsc_relay_SOURCES = pcsc-relay.c pcsc.c opicc.c lnfc.c $(BUILT_SOURCES) pcsc_relay_LDADD = $(PCSC_LIBS) $(LIBNFC_LIBS) pcsc_relay_CFLAGS = $(PCSC_CFLAGS) $(LIBNFC_CFLAGS) -noinst_HEADERS = pcscutil.h pcsc-relay.h +noinst_HEADERS = pcsc-relay.h pcsc-relay.c: $(BUILT_SOURCES) diff --git a/pcsc-relay/src/pcsc-relay.c b/pcsc-relay/src/pcsc-relay.c index 1c6940d..d8c4e77 100644 --- a/pcsc-relay/src/pcsc-relay.c +++ b/pcsc-relay/src/pcsc-relay.c @@ -17,22 +17,19 @@ * You should have received a copy of the GNU General Public License along with * pcsc-relay. If not, see . */ -#include -#include +#include #include #include +#include #include #include -#include #include +#include +#include #include -#include -#include -#include #include "cmdline.h" #include "pcsc-relay.h" -#include "pcscutil.h" #ifndef MAX_BUFFER_SIZE #define MAX_BUFFER_SIZE 264 /**< Maximum Tx/Rx Buffer for short APDU */ @@ -41,18 +38,16 @@ static int doinfo = 0; static int dodaemon = 1; int verbose = 0; -static struct rf_driver *driver = &driver_openpicc; -static driver_data_t *driver_data = NULL; - - -static LPSTR readers = NULL; -static SCARDCONTEXT hContext = 0; -static SCARDHANDLE hCard = 0; +static struct rf_driver *rfdriver = &driver_openpicc; +static driver_data_t *rfdriver_data = NULL; +static struct sc_driver *scdriver = &driver_pcsc; +static driver_data_t *scdriver_data = NULL; /* Forward declaration */ static void daemonize(void); static void cleanup_exit(int signo); static void cleanup(void); +static void printb(const char *label, unsigned char *buf, size_t len); #if HAVE_WORKING_FORK @@ -111,9 +106,26 @@ void cleanup_exit(int signo){ } void cleanup(void) { - driver->disconnect(driver_data); - driver_data = NULL; - pcsc_disconnect(hContext, hCard, readers); + rfdriver->disconnect(rfdriver_data); + rfdriver_data = NULL; + scdriver->disconnect(scdriver_data); + scdriver_data = NULL; +} + +void +printb(const char *label, unsigned char *buf, size_t len) +{ + size_t i = 0; + printf("%s", label); + while (i < len) { + printf("%02X", buf[i]); + i++; + if (i%20) + printf(" "); + else if (i != len) + printf("\n"); + } + printf("\n"); } int main (int argc, char **argv) @@ -123,11 +135,10 @@ int main (int argc, char **argv) size_t buflen; int i, oindex; - BYTE outputBuffer[MAX_BUFFER_SIZE]; - DWORD outputLength; + unsigned char outputBuffer[MAX_BUFFER_SIZE]; + size_t outputLength; - LONG r = SCARD_S_SUCCESS; - DWORD ctl, protocol; + /*LONG r = SCARD_S_SUCCESS;*/ struct gengetopt_args_info args_info; @@ -137,15 +148,15 @@ int main (int argc, char **argv) exit(1) ; switch (args_info.emulator_arg) { case emulator_arg_openpicc: - driver = &driver_openpicc; + rfdriver = &driver_openpicc; break; case emulator_arg_libnfc: - driver = &driver_libnfc; + rfdriver = &driver_libnfc; break; default: exit(2); } - + readernum = args_info.reader_arg; #if HAVE_SIGACTION struct sigaction new_sig, old_sig; @@ -162,15 +173,13 @@ int main (int argc, char **argv) #endif - /* Open the device */ - if (!driver->connect(&driver_data)) + /* connect to reader and card */ + if (!scdriver->connect(&scdriver_data)) goto err; - /* connect to reader and card */ - r = pcsc_connect(args_info.reader_arg, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_ANY, - &hContext, &readers, &hCard, &protocol); - if (r != SCARD_S_SUCCESS) + /* Open the device */ + if (!rfdriver->connect(&rfdriver_data)) goto err; @@ -183,7 +192,7 @@ int main (int argc, char **argv) while(1) { /* get C-APDU */ - if (!driver->receive_capdu(driver_data, &buf, &buflen)) + if (!rfdriver->receive_capdu(rfdriver_data, &buf, &buflen)) goto err; if (!buflen || !buf) continue; @@ -194,8 +203,8 @@ int main (int argc, char **argv) /* transmit APDU to card */ outputLength = sizeof outputBuffer; - r = pcsc_transmit(protocol, hCard, buf, buflen, outputBuffer, &outputLength); - if (r != SCARD_S_SUCCESS) + if (!scdriver->transmit(scdriver_data, buf, buflen, outputBuffer, + &outputLength)) goto err; @@ -203,7 +212,7 @@ int main (int argc, char **argv) if (verbose >= 0) printb("R-APDU:\n", outputBuffer, outputLength); - if (!driver->send_rapdu(driver_data, outputBuffer, outputLength)) + if (!rfdriver->send_rapdu(rfdriver_data, outputBuffer, outputLength)) goto err; } @@ -211,10 +220,10 @@ int main (int argc, char **argv) err: cleanup(); - if (r != SCARD_S_SUCCESS) { - RELAY_ERROR("%s\n", stringify_error(r)); - exit(1); - } + /*if (r != SCARD_S_SUCCESS) {*/ + /*RELAY_ERROR("%s\n", stringify_error(r));*/ + /*exit(1);*/ + /*}*/ exit(0); } diff --git a/pcsc-relay/src/pcsc-relay.h b/pcsc-relay/src/pcsc-relay.h index a550734..fc8e39e 100644 --- a/pcsc-relay/src/pcsc-relay.h +++ b/pcsc-relay/src/pcsc-relay.h @@ -45,6 +45,17 @@ extern int verbose; extern struct rf_driver driver_openpicc; extern struct rf_driver driver_libnfc; +struct sc_driver { + int (*connect) (driver_data_t **driver_data); + int (*disconnect) (driver_data_t *driver_data); + int (*transmit) (driver_data_t *driver_data, + const unsigned char *send, size_t send_len, + unsigned char *recv, size_t *recv_len); +}; + +extern struct sc_driver driver_pcsc; +extern unsigned int readernum; + #define LEVEL_INFO 1 #define LEVEL_DEBUG 2 #define DEBUG(...) \ diff --git a/pcsc-relay/src/pcsc.c b/pcsc-relay/src/pcsc.c new file mode 100644 index 0000000..8196193 --- /dev/null +++ b/pcsc-relay/src/pcsc.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2010 Frank Morgner + * + * This file is part of pcsc-relay. + * + * pcsc-relay is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * pcsc-relay is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * pcsc-relay. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pcsc-relay.h" + +#include +#include +#include + +#ifdef HAVE_PCSCLITE_H +#include +#define stringify_error(r) pcsc_stringify_error(r) +#else +#define stringify_error(r) "PC/SC error code %u\n", (unsigned int) r +#define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1) +#endif + +#ifdef HAVE_READER_H +#include +#endif + +#define SHAREMODE SCARD_SHARE_EXCLUSIVE +#define PREFERREDPROTOCOL SCARD_PROTOCOL_ANY + + +struct pcsc_data { + LPSTR readers; + SCARDCONTEXT hContext; + SCARDHANDLE hCard; + DWORD dwActiveProtocol; +}; + + + +unsigned int readernum = -1; + + +static int pcsc_connect(driver_data_t **driver_data) +{ + struct pcsc_data *data; + + LONG r; + DWORD readerslen = SCARD_AUTOALLOCATE; + LPSTR readers = NULL; + char *reader; + size_t l, i; + + if (!driver_data) + return 0; + + + data = realloc(*driver_data, sizeof *data); + if (!data) + return 0; + data->readers = NULL; + data->hContext = 0; + data->hCard = 0; + *driver_data = data; + + + r = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &data->hContext); + if (r != SCARD_S_SUCCESS) { + RELAY_ERROR("Could not connect to PC/SC Service\n"); + goto err; + } + + + r = SCardListReaders(data->hContext, NULL, (LPSTR) &readers, &readerslen); + if (r != SCARD_S_SUCCESS) { + RELAY_ERROR("Could not get readers\n"); + goto err; + } + data->readers = readers; + + for (reader = readers, i = 0; readerslen > 0; + l = strlen(reader)+1, readerslen -= l, reader += l, i++) { + + if (i == readernum) + break; + } + if (readerslen <= 0) { + RELAY_ERROR("Could not find reader number %u\n", readernum); + r = SCARD_E_UNKNOWN_READER; + goto err; + } + + + r = SCardConnect(data->hContext, reader, SHAREMODE, PREFERREDPROTOCOL, + &data->hCard, &data->dwActiveProtocol); + if (r != SCARD_S_SUCCESS) { + RELAY_ERROR("Could not connect to %s\n", reader); + goto err; + } + INFO("Connected to %s\n", reader); + +err: + if (r != SCARD_S_SUCCESS) { + RELAY_ERROR("%s\n", stringify_error(r)); + return 0; + } + + return 1; +} + +static int pcsc_disconnect(driver_data_t *driver_data) +{ + struct pcsc_data *data = driver_data; + + if (data) { + SCardDisconnect(data->hCard, SCARD_LEAVE_CARD); + SCardFreeMemory(data->hContext, data->readers); + SCardReleaseContext(data->hContext); + free(data); + } + + return 1; +} + +static int pcsc_transmit(driver_data_t *driver_data, + const unsigned char *send, size_t send_len, + unsigned char *recv, size_t *recv_len) +{ + struct pcsc_data *data = driver_data; + LPCBYTE pbSendBuffer = send; + DWORD cbSendLength = send_len; + LPBYTE pbRecvBuffer = recv; + DWORD cbRecvLength = *recv_len; + + LONG r; + SCARD_IO_REQUEST ioRecvPci; + + switch (data->dwActiveProtocol) { + case SCARD_PROTOCOL_T0: + r = SCardTransmit(data->hCard, SCARD_PCI_T0, pbSendBuffer, cbSendLength, + &ioRecvPci, pbRecvBuffer, &cbRecvLength); + break; + + case SCARD_PROTOCOL_T1: + r = SCardTransmit(data->hCard, SCARD_PCI_T1, pbSendBuffer, cbSendLength, + &ioRecvPci, pbRecvBuffer, &cbRecvLength); + break; + + default: + RELAY_ERROR("Could not transmit with unknown protocol %u\n", + (unsigned int) data->dwActiveProtocol); + r = SCARD_E_PROTO_MISMATCH; + break; + } + + if (r != SCARD_S_SUCCESS) { + RELAY_ERROR("%s\n", stringify_error(r)); + return 0; + } + + *recv_len = cbRecvLength; + + return 1; +} + + +struct sc_driver driver_pcsc = { + .connect = pcsc_connect, + .disconnect = pcsc_disconnect, + .transmit = pcsc_transmit, +}; diff --git a/pcsc-relay/src/pcscutil.c b/pcsc-relay/src/pcscutil.c deleted file mode 100644 index 8e4dc9d..0000000 --- a/pcsc-relay/src/pcscutil.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2010 Frank Morgner - * - * This file is part of ccid. - * - * ccid is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. - * - * ccid is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * ccid. If not, see . - */ -#include -#include - -#include "pcscutil.h" - -#pragma comment(lib, "winscard.lib") - -LONG -pcsc_connect(unsigned int readernum, DWORD dwShareMode, DWORD dwPreferredProtocols, - LPSCARDCONTEXT phContext, LPSTR *readers, LPSCARDHANDLE phCard, - LPDWORD pdwActiveProtocol) -{ - LONG r; - DWORD ctl, readerslen; - char *reader; - size_t l, i; - - r = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, phContext); - if (r != SCARD_S_SUCCESS) { - fprintf(stderr, "Could not connect to PC/SC Service\n"); - goto err; - } - - - readerslen = SCARD_AUTOALLOCATE; - r = SCardListReaders(*phContext, NULL, (LPTSTR) readers, &readerslen); - if (r != SCARD_S_SUCCESS) { - fprintf(stderr, "Could not get readers\n"); - goto err; - } - - for (reader = *readers, i = 0; readerslen > 0; - l = strlen(reader) + 1, readerslen -= l, reader += l, i++) { - - if (i == readernum) - break; - } - if (readerslen <= 0) { - fprintf(stderr, "Could not find reader number %u\n", readernum); - r = SCARD_E_UNKNOWN_READER; - goto err; - } - - - r = SCardConnect(*phContext, reader, dwShareMode, dwPreferredProtocols, - phCard, pdwActiveProtocol); - if (r != SCARD_S_SUCCESS) { - fprintf(stderr, "Could not connect to %s\n", reader); - goto err; - } - printf("Connected to %s\n", reader); - -err: - return r; -} - -void -pcsc_disconnect(SCARDCONTEXT hContext, SCARDHANDLE hCard, LPSTR readers) -{ - SCardDisconnect(hCard, SCARD_LEAVE_CARD); - SCardFreeMemory(hContext, readers); - SCardReleaseContext(hContext); -} - -LONG -pcsc_transmit(DWORD dwActiveProtocol, SCARDHANDLE hCard, - LPCBYTE pbSendBuffer, DWORD cbSendLength, - LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength) -{ - LONG r; - SCARD_IO_REQUEST ioRecvPci; - - switch (dwActiveProtocol) { - case SCARD_PROTOCOL_T0: - r = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, cbSendLength, - &ioRecvPci, pbRecvBuffer, pcbRecvLength); - break; - - case SCARD_PROTOCOL_T1: - r = SCardTransmit(hCard, SCARD_PCI_T1, pbSendBuffer, cbSendLength, - &ioRecvPci, pbRecvBuffer, pcbRecvLength); - break; - - default: - fprintf(stderr, "Could not transmit with unknown protocol %u\n", - (unsigned int) dwActiveProtocol); - r = SCARD_E_PROTO_MISMATCH; - break; - } - - return r; -} - -void -printb(const char *label, unsigned char *buf, size_t len) -{ - size_t i = 0; - printf("%s", label); - while (i < len) { - printf("%02X", buf[i]); - i++; - if (i%20) - printf(" "); - else if (i != len) - printf("\n"); - } - printf("\n"); -} diff --git a/pcsc-relay/src/pcscutil.h b/pcsc-relay/src/pcscutil.h deleted file mode 100644 index c5d31c4..0000000 --- a/pcsc-relay/src/pcscutil.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2010-2012 Frank Morgner . - * - * This file is part of ccid. - * - * ccid is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. - * - * ccid is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * ccid. If not, see . - */ -#ifndef _PCSCUTIL_H -#define _PCSCUTIL_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#ifdef HAVE_PCSCLITE_H -#include -#define stringify_error(r) pcsc_stringify_error(r) -#else -#define stringify_error(r) "PC/SC error code %u\n", (unsigned int) r -#define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1) -#endif - -#ifdef HAVE_READER_H -#include -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -LONG -pcsc_connect(unsigned int readernum, DWORD dwShareMode, DWORD dwPreferredProtocol, - SCARDCONTEXT *hContext, LPSTR *readers, LPSCARDHANDLE phCard, - LPDWORD pdwActiveProtocol); - -void -pcsc_disconnect(SCARDCONTEXT hContext, SCARDHANDLE hCard, LPSTR readers); - -LONG -pcsc_transmit(DWORD dwActiveProtocol, SCARDHANDLE hCard, - LPCBYTE pbSendBuffer, DWORD cbSendLength, - LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength); - -void -printb(const char *label, unsigned char *buf, size_t len); - -#ifdef __cplusplus -} -#endif -#endif