From d4ee5d391f8f813637eb6bbe9dcd67f542859865 Mon Sep 17 00:00:00 2001 From: frankmorgner Date: Tue, 9 Nov 2010 20:07:26 +0000 Subject: [PATCH] refactored picc_to_pcsc to support other drivers to send data via rfid. renamed to pcsc-relay. git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@348 96b47cad-a561-4643-ad3b-153ac7d7599c --- picc_to_pcsc/configure.ac | 22 +- picc_to_pcsc/src/Makefile.am | 10 +- picc_to_pcsc/src/opicc.c | 220 ++++++++++++++++++ .../src/{picc_to_pcsc.c => pcsc-relay.c} | 135 +---------- picc_to_pcsc/src/pcsc-relay.h | 49 ++++ 5 files changed, 299 insertions(+), 137 deletions(-) create mode 100644 picc_to_pcsc/src/opicc.c rename picc_to_pcsc/src/{picc_to_pcsc.c => pcsc-relay.c} (56%) create mode 100644 picc_to_pcsc/src/pcsc-relay.h diff --git a/picc_to_pcsc/configure.ac b/picc_to_pcsc/configure.ac index eb38e86..5c6d558 100644 --- a/picc_to_pcsc/configure.ac +++ b/picc_to_pcsc/configure.ac @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) -AC_INIT([picc_to_pcsc], [0.1], [http://sourceforge.net/projects/vsmartcard/support]) -AC_CONFIG_SRCDIR([src/picc_to_pcsc.c]) +AC_INIT([pcsc-relay], [0.2], [http://sourceforge.net/projects/vsmartcard/support]) +AC_CONFIG_SRCDIR([src/pcsc-relay.c]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE @@ -17,17 +17,27 @@ PKG_PROG_PKG_CONFIG PKG_CHECK_EXISTS([libpcsclite], [PKG_CHECK_MODULES([PCSC], [libpcsclite])], [AC_MSG_WARN([libpcsclite not found by pkg-config])]) +# Checks for libraries. +PKG_CHECK_EXISTS([libnfc >= 1.3.9], + [PKG_CHECK_MODULES([LIBNFC], [libnfc >= 1.3.9])], + [AC_MSG_WARN([libnfc >= 1.3.9 not found by pkg-config])]) + saved_CPPFLAGS="$CPPFLAGS" saved_LIBS="$LIBS" -CPPFLAGS="$CPPFLAGS $PCSC_CFLAGS" -LIBS="$LDFLAGS $PCSC_LIBS" +CPPFLAGS="$CPPFLAGS $PCSC_CFLAGS $LIBNFC_CFLAGS" +LIBS="$LDFLAGS $PCSC_LIBS $LIBNFC_LIBS" AC_CHECK_HEADERS(winscard.h, [], [ AC_MSG_ERROR([winscard.h not found, install PC/SC Lite or similar or use ./configure PCSC_CFLAGS=...]) ]) AC_CHECK_HEADERS(reader.h, [AC_DEFINE(HAVE_READER_H, 1, [use reader.h from PC/SC Lite])], []) AC_CHECK_HEADERS(pcsclite.h, [AC_DEFINE(HAVE_PCSCLITE_H, 1, [use pcsclite.h from PC/SC Lite])], []) AC_MSG_CHECKING([for SCardEstablishContext]) AC_TRY_LINK_FUNC(SCardEstablishContext, [ AC_MSG_RESULT([yes]) ], [ AC_MSG_ERROR([libpcsclite not found, use ./configure PCSC_LIBS=...]) ]) +AC_CHECK_HEADERS(nfc/nfc.h,, + [ AC_MSG_ERROR([nfc/nfc.h not found, install libnfc >= 1.3.9 or use ./configure LIBNFC_CFLAGS=...]) ]) +AC_MSG_CHECKING([for nfc_initiator_select_passive_target]) +AC_TRY_LINK_FUNC(nfc_initiator_select_passive_target, [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_ERROR([libnfc >= 1.3.9 not found, use ./configure LIBNFC_LIBS=...]) ]) CPPFLAGS="$saved_CPPFLAGS" LIBS="$saved_LIBS" @@ -51,7 +61,7 @@ AC_FUNC_MALLOC cat << EOF -picc_to_pcsc has been configured with following options: +pcsc-relay has been configured with following options: Version: ${PACKAGE_VERSION} User binaries: $(eval eval eval echo "${bindir}") @@ -67,6 +77,8 @@ Linker flags: ${LDFLAGS} Libraries: ${LIBS} PCSC_CFLAGS: ${PCSC_CFLAGS} PCSC_LIBS: ${PCSC_LIBS} +LIBNFC_CFLAGS: ${LIBNFC_CFLAGS} +LIBNFC_LIBS: ${LIBNFC_LIBS} EOF diff --git a/picc_to_pcsc/src/Makefile.am b/picc_to_pcsc/src/Makefile.am index 513c119..0e1b7d7 100644 --- a/picc_to_pcsc/src/Makefile.am +++ b/picc_to_pcsc/src/Makefile.am @@ -1,10 +1,10 @@ EXTRA_DIST = picc.py -bin_PROGRAMS = picc_to_pcsc +bin_PROGRAMS = pcsc-relay bin_SCRIPTS = picc.py -picc_to_pcsc_SOURCES = picc_to_pcsc.c pcscutil.c -picc_to_pcsc_LDADD = $(PCSC_LIBS) -picc_to_pcsc_CFLAGS = $(PCSC_CFLAGS) +pcsc_relay_SOURCES = pcsc-relay.c pcscutil.c opicc.c +pcsc_relay_LDADD = $(PCSC_LIBS) +pcsc_relay_CFLAGS = $(PCSC_CFLAGS) -noinst_HEADERS = pcscutil.h +noinst_HEADERS = pcscutil.h pcsc-relay.h diff --git a/picc_to_pcsc/src/opicc.c b/picc_to_pcsc/src/opicc.c new file mode 100644 index 0000000..d13bb10 --- /dev/null +++ b/picc_to_pcsc/src/opicc.c @@ -0,0 +1,220 @@ +/* + * 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 "config.h" +#include "pcsc-relay.h" + +struct picc_data { + char *read; + size_t readlen; + FILE *fd; +}; +static size_t picc_encode_rapdu(const unsigned char *inbuf, size_t inlen, char **outbuf); +static size_t picc_decode_apdu(const char *inbuf, size_t inlen, unsigned char **outbuf); + + +size_t picc_encode_rapdu(const unsigned char *inbuf, size_t inlen, char **outbuf) +{ + char *p; + const unsigned char *next; + size_t length; + + if (!inbuf || inlen > 0xffff || !outbuf) + goto err; + + length = 5+inlen*3+1; + p = realloc(*outbuf, length); + if (!p) { + if (debug || verbose) + fprintf(stderr, "Error allocating memory for encoded R-APDU\n"); + goto err; + } + *outbuf = p; + + sprintf(*outbuf, "%04X:", inlen); + + next = inbuf; + /* let p point behind ':' */ + p += 5; + while (inbuf+inlen > next) { + sprintf(p," %02X",*next); + next++; + p += 3; + } + + return length; + +err: + return 0; +} + +size_t picc_decode_apdu(const char *inbuf, size_t inlen, unsigned char **outbuf) +{ + size_t pos, length; + unsigned char buf[0xffff]; + char *end, *p; + unsigned long int b; + + if (!outbuf || inbuf == NULL || inlen == 0 || inbuf[0] == '\0') { + /* Ignore invalid parameters, empty and 'RESET' lines */ + goto noapdu; + } + + length = strtoul(inbuf, &end, 16); + + /* check for ':' right behind the length */ + if (inbuf+inlen < end+1 || end[0] != ':') + goto noapdu; + end++; + + p = realloc(*outbuf, length); + if (!p) { + if (debug || verbose) + fprintf(stderr, "Error allocating memory for decoded C-APDU\n"); + goto noapdu; + } + *outbuf = p; + + pos = 0; + while(inbuf+inlen > end && length > pos) { + b = strtoul(end, &end, 16); + if (b > 0xff) { + if (debug || verbose) + fprintf(stderr, "%s:%u Error decoding C-APDU\n", __FILE__, __LINE__); + goto noapdu; + } + + (*outbuf)[pos++] = b; + } + + return length; + +noapdu: + return 0; +} + + +static int picc_connect(void **driver_data) +{ + struct picc_data *p; + + if (!driver_data) + return 0; + + p = realloc(*driver_data, sizeof *p); + if (!p) + return 0; + *driver_data = p; + + p->fd = fopen(PICCDEV, "a+"); /*O_NOCTTY ?*/ + if (!p->fd) { + if (debug || verbose) + fprintf(stderr,"Error opening %s\n", PICCDEV); + return 0; + } + if (debug || verbose) + printf("Connected to %s\n", PICCDEV); + + return 1; +} + +static int picc_disconnect(void *driver_data) +{ + struct picc_data *data = driver_data; + if (data && data->fd) + fclose(data->fd); + + return 1; +} + +static int picc_receive_capdu(void *driver_data, + unsigned char **capdu, size_t *len) +{ + ssize_t linelen; + struct picc_data *data = driver_data; + + if (!data || !capdu || !len) + return 0; + + + /* read C-APDU */ + linelen = getline(&data->read, &data->readlen, data->fd); + if (linelen < 0) { + if (linelen < 0) { + if (debug || verbose) + fprintf(stderr,"Error reading from %s\n", PICCDEV); + return 0; + } + } + if (linelen == 0) { + *len = 0; + return 1; + } + fflush(data->fd); + + if (debug) + printf("%s\n", data->read); + + + /* decode C-APDU */ + *len = picc_decode_apdu(data->read, linelen, capdu); + + return 1; +} + +static int picc_send_rapdu(void *driver_data, + const unsigned char *rapdu, size_t len) +{ + char *buf = NULL; + size_t buflen; + struct picc_data *data = driver_data; + + if (!data || !rapdu) + return 0; + + + /* encode R-APDU */ + buflen = picc_encode_rapdu(rapdu, len, &buf); + + + /* write R-APDU */ + if (debug) + printf("INF: Writing R-APDU\n\n%s\n\n", buf); + + if (fprintf(data->fd,"%s\r\n", (char *) buf) < 0 + || fflush(data->fd) != 0) { + free(buf); + return 0; + } + + free(buf); + + return 1; +} + + +struct rf_driver driver_openpicc = { + .data = NULL, + .connect = picc_connect, + .disconnect = picc_disconnect, + .receive_capdu = picc_receive_capdu, + .send_rapdu = picc_send_rapdu, +}; diff --git a/picc_to_pcsc/src/picc_to_pcsc.c b/picc_to_pcsc/src/pcsc-relay.c similarity index 56% rename from picc_to_pcsc/src/picc_to_pcsc.c rename to picc_to_pcsc/src/pcsc-relay.c index 480c398..18bb401 100644 --- a/picc_to_pcsc/src/picc_to_pcsc.c +++ b/picc_to_pcsc/src/pcsc-relay.c @@ -30,21 +30,21 @@ #include #include "config.h" +#include "pcsc-relay.h" #include "pcscutil.h" -static FILE *picc_fd = NULL; /*filehandle used for PICCDEV*/ +struct rf_driver *driver = &driver_openpicc; + static LPSTR readers = NULL; static SCARDCONTEXT hContext = 0; static SCARDHANDLE hCard = 0; -static int verbose = 0, debug = 0; +int verbose = 0, debug = 0; /* Forward declaration */ static void daemonize(); static void cleanup_exit(int signo); static void cleanup(void); -static size_t picc_decode_apdu(char *inbuf, size_t inlen, unsigned char **outbuf); -static size_t picc_encode_rapdu(unsigned char *inbuf, size_t inlen, char **outbuf); void daemonize() { pid_t pid, sid; @@ -86,91 +86,10 @@ void cleanup_exit(int signo){ } void cleanup(void) { - if (picc_fd) - fclose(picc_fd); + driver->disconnect(driver->data); pcsc_disconnect(hContext, hCard, readers); } -size_t picc_decode_apdu(char *inbuf, size_t inlen, unsigned char **outbuf) -{ - size_t pos, length; - unsigned char buf[0xffff]; - char *end, *p; - unsigned long int b; - - if (!outbuf || inbuf == NULL || inlen == 0 || inbuf[0] == '\0') { - /* Ignore invalid parameters, empty and 'RESET' lines */ - goto noapdu; - } - - length = strtoul(inbuf, &end, 16); - - /* check for ':' right behind the length */ - if (inbuf+inlen < end+1 || end[0] != ':') - goto noapdu; - end++; - - p = realloc(*outbuf, length); - if (!p) { - if (debug || verbose) - fprintf(stderr, "Error allocating memory for decoded C-APDU\n"); - goto noapdu; - } - *outbuf = p; - - pos = 0; - while(inbuf+inlen > end && length > pos) { - b = strtoul(end, &end, 16); - if (b > 0xff) { - if (debug || verbose) - fprintf(stderr, "%s:%u Error decoding C-APDU\n", __FILE__, __LINE__); - goto noapdu; - } - - (*outbuf)[pos++] = b; - } - - return length; - -noapdu: - return 0; -} - -size_t picc_encode_rapdu(unsigned char *inbuf, size_t inlen, char **outbuf) -{ - char *p; - unsigned char *next; - size_t length; - - if (!inbuf || inlen > 0xffff || !outbuf) - goto err; - - length = 5+inlen*3+1; - p = realloc(*outbuf, length); - if (!p) { - if (debug || verbose) - fprintf(stderr, "Error allocating memory for encoded R-APDU\n"); - goto err; - } - *outbuf = p; - - sprintf(*outbuf, "%04X:", inlen); - - next = inbuf; - /* let p point behind ':' */ - p += 5; - while (inbuf+inlen > next) { - sprintf(p," %02X",*next); - next++; - p += 3; - } - - return length; - -err: - return 0; -} - int main (int argc, char **argv) { /*printf("%s:%d\n", __FILE__, __LINE__);*/ @@ -185,7 +104,6 @@ int main (int argc, char **argv) char *read = NULL; size_t readlen = 0; - ssize_t linelen; unsigned int readernum = 0; @@ -223,15 +141,7 @@ parse_err: /* Open the device */ - picc_fd = fopen(PICCDEV, "a+"); /*O_NOCTTY ?*/ - if (!picc_fd) { - if (debug || verbose) - fprintf(stderr,"Error opening %s\n", PICCDEV); - goto err; - } - if (debug || verbose) - printf("Connected to %s\n", PICCDEV); - + driver->connect(&driver->data); /* connect to reader and card */ r = pcsc_connect(readernum, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_ANY, @@ -241,27 +151,7 @@ parse_err: while(1) { - /* read C-APDU */ - linelen = getline(&read, &readlen, picc_fd); - if (linelen < 0) { - if (linelen < 0) { - if (debug || verbose) - fprintf(stderr,"Error reading from %s\n", PICCDEV); - goto err; - } - } - if (linelen == 0) - continue; - fflush(picc_fd); - - if (debug) - printf("%s\n", read); - - - /* decode C-APDU */ - buflen = picc_decode_apdu(read, linelen, (unsigned char **) &buf); - if (!buflen) - continue; + driver->receive_capdu(driver->data, (unsigned char **) &buf, &buflen); if (!verbose) printb("C-APDU: ===================================================\n", buf, buflen); @@ -277,16 +167,7 @@ parse_err: printb("R-APDU:\n", outputBuffer, outputLength); - /* encode R-APDU */ - buflen = picc_encode_rapdu(outputBuffer, outputLength, (char **) &buf); - - - /* write R-APDU */ - if (debug) - printf("INF: Writing R-APDU\n\n%s\n\n", (char *) buf); - - fprintf(picc_fd,"%s\r\n", (char *) buf); - fflush(picc_fd); + driver->send_rapdu(driver->data, outputBuffer, outputLength); } err: diff --git a/picc_to_pcsc/src/pcsc-relay.h b/picc_to_pcsc/src/pcsc-relay.h new file mode 100644 index 0000000..8ffc7a4 --- /dev/null +++ b/picc_to_pcsc/src/pcsc-relay.h @@ -0,0 +1,49 @@ +/* + * 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 . + */ +/** + * @file + */ +#ifndef _PCSC_RELAY_H +#define _PCSC_RELAY_H + + +#ifdef __cplusplus +extern "C" { +#endif + +struct rf_driver { + void *data; + int (*connect) (void **driver_data); + int (*disconnect) (void *driver_data); + int (*receive_capdu) (void *driver_data, + unsigned char **capdu, size_t *len); + int (*send_rapdu) (void *driver_data, + const unsigned char *rapdu, size_t len); +}; + +extern int verbose, debug; + +extern struct rf_driver driver_openpicc; +extern struct rf_driver driver_libnfc; + + +#ifdef __cplusplus +} +#endif +#endif