On Mon, 2011-02-07 at 11:32 -0600, Douglas E. Engert wrote:
>
> On 2/4/2011 2:20 AM, Martin Paljak wrote:
>
> > I think Douglas is incrementally working on the existing codebase. Why the
> > cardmod
> > driver was squeezed into reader-pcsc.c the way it is in the first place is
> beyond
> > me, as Francois noted, I "was not very hot about it" [1].
> >
>
> Yes, I am trying to work with the current code base. The missing piece is
> passing
> in the two handles from the cardmod.c to the reader-pcsc.c cardmod code.
> The use of the use_reader and sc_ctx_use_reader can do this.
Have a look at the attached patch.
1. It uses the init() function of reader-drivers to pass in additional
arguments.
2. It adds two fields to sc_context_param_t to let the caller of
sc_context_create() provide its own custom driver. How that is to be
used is shown in the diff of src/cardmod/cardmod.c
Additionally a stripped down reader-pcsc (renamed to reader-cardmod) is
attached. It works well with a modified version of opensc-pkcs11.so and
should work in the same way for cardmod. Integration into the build
system is still required and possibly some debugging.
Regards
Andre
Index: src/libopensc/reader-pcsc.c
===================================================================
--- src/libopensc/reader-pcsc.c (revision 5188)
+++ src/libopensc/reader-pcsc.c (working copy)
@@ -612,7 +612,7 @@
0, 0, NULL
};
-static int pcsc_init(sc_context_t *ctx)
+static int pcsc_init(void *init_data, sc_context_t *ctx)
{
struct pcsc_global_private_data *gpriv;
scconf_block *conf_block = NULL;
@@ -1580,7 +1580,7 @@
0, 0, NULL
};
-static int cardmod_init(sc_context_t *ctx)
+static int cardmod_init(void *init_data, sc_context_t *ctx)
{
struct pcsc_global_private_data *gpriv;
scconf_block *conf_block = NULL;
Index: src/libopensc/ctx.c
===================================================================
--- src/libopensc/ctx.c (revision 5188)
+++ src/libopensc/ctx.c (working copy)
@@ -105,6 +105,7 @@
/* The default driver should be last, as it handles all the
* unrecognized cards. */
{ "default", (void *(*)(void)) sc_get_default_driver },
+ { "iso7816", (void *(*)(void)) sc_get_iso7816_driver },
{ NULL, NULL }
};
@@ -648,21 +649,20 @@
return SC_ERROR_OUT_OF_MEMORY;
}
+ if (parm->reader_drv != NULL) {
+ ctx->reader_driver = parm->reader_drv;
+ } else {
#ifdef ENABLE_PCSC
ctx->reader_driver = sc_get_pcsc_driver();
- #ifdef ENABLE_CARDMOD
- if(strcmp(ctx->app_name, "cardmod") == 0) {
- ctx->reader_driver = sc_get_cardmod_driver();
- }
- #endif
#elif ENABLE_CTAPI
ctx->reader_driver = sc_get_ctapi_driver();
#elif ENABLE_OPENCT
ctx->reader_driver = sc_get_openct_driver();
#endif
+ }
load_reader_driver_options(ctx);
- ctx->reader_driver->ops->init(ctx);
+ ctx->reader_driver->ops->init(parm->reader_drv_init_data, ctx);
load_card_drivers(ctx, &opts);
load_card_atrs(ctx);
Index: src/libopensc/reader-ctapi.c
===================================================================
--- src/libopensc/reader-ctapi.c (revision 5188)
+++ src/libopensc/reader-ctapi.c (working copy)
@@ -499,7 +499,7 @@
return -1;
}
-static int ctapi_init(sc_context_t *ctx)
+static int ctapi_init(void *init_data, sc_context_t *ctx)
{
int i;
struct ctapi_global_private_data *gpriv;
Index: src/libopensc/reader-openct.c
===================================================================
--- src/libopensc/reader-openct.c (revision 5188)
+++ src/libopensc/reader-openct.c (working copy)
@@ -64,7 +64,7 @@
* is loaded
*/
static int
-openct_reader_init(sc_context_t *ctx)
+openct_reader_init(void *init_data, sc_context_t *ctx)
{
unsigned int i,max_virtual;
scconf_block *conf_block;
Index: src/libopensc/opensc.h
===================================================================
--- src/libopensc/opensc.h (revision 5188)
+++ src/libopensc/opensc.h (working copy)
@@ -250,7 +250,7 @@
#define SC_PROTO_RAW 0x00001000
#define SC_PROTO_ANY 0xFFFFFFFF
-struct sc_reader_driver {
+typedef struct sc_reader_driver {
const char *name;
const char *short_name;
struct sc_reader_operations *ops;
@@ -258,7 +258,7 @@
size_t max_send_size; /* Max Lc supported by the reader layer */
size_t max_recv_size; /* Mac Le supported by the reader layer */
void *dll;
-};
+} sc_reader_driver_t;
/* reader flags */
#define SC_READER_CARD_PRESENT 0x00000001
@@ -359,7 +359,7 @@
struct sc_reader_operations {
/* Called during sc_establish_context(), when the driver
* is loaded */
- int (*init)(struct sc_context *ctx);
+ int (*init)(void *init_data, struct sc_context *ctx);
/* Called when the driver is being unloaded. finish() has to
* release any resources. */
int (*finish)(struct sc_context *ctx);
@@ -692,6 +692,10 @@
unsigned long flags;
/** mutex functions to use (optional) */
sc_thread_context_t *thread_ctx;
+ /** custom reader driver or NULL for default driver **/
+ sc_reader_driver_t *reader_drv;
+ /** initial data **/
+ void *reader_drv_init_data;
} sc_context_param_t;
/**
* Creates a new sc_context_t object.
Index: src/cardmod/cardmod.c
===================================================================
--- src/cardmod/cardmod.c (revision 5188)
+++ src/cardmod/cardmod.c (working copy)
@@ -1412,6 +1412,8 @@
memset(&ctx_param, 0, sizeof(ctx_param));
ctx_param.ver = 1;
ctx_param.app_name = "cardmod";
+ ctx_param.reader_drv = get_reader_driver();
+ ctx_param.reader_drv_init_data = /* pointer to struct {SCARDCONTEXT hSCardCtx, SCARDHANDLE hSCard} */
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenSC Project\\Opensc", 0, NULL, \
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS)
/*
* reader-pcsc.c: Reader driver for PC/SC interface
*
* Copyright (C) 2002 Juha Yrjölä <[email protected]>
* Copyright (C) 2009,2010 Martin Paljak <[email protected]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../libopensc/internal.h"
#include "../libopensc/internal-winscard.h"
#include "reader-cardmod.h"
/* Logging */
#define PCSC_TRACE(reader, desc, rv) do { sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "%s:" desc ": 0x%08lx\n", reader->name, rv); } while (0)
#define PCSC_LOG(ctx, desc, rv) do { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, desc ": 0x%08lx\n", rv); } while (0)
struct pcsc_private_data {
SCARDCONTEXT hSCardCtx;
SCARDHANDLE hSCard;
DWORD dwProtocol;
};
static unsigned int pcsc_proto_to_opensc(DWORD proto)
{
switch (proto) {
case SCARD_PROTOCOL_T0:
return SC_PROTO_T0;
case SCARD_PROTOCOL_T1:
return SC_PROTO_T1;
case SCARD_PROTOCOL_RAW:
return SC_PROTO_RAW;
default:
return 0;
}
}
static int pcsc_internal_transmit(sc_reader_t *reader,
const u8 *sendbuf, size_t sendsize,
u8 *recvbuf, size_t *recvsize,
unsigned long control)
{
struct pcsc_private_data *priv = (struct pcsc_private_data *) reader->ctx->reader_drv_data;
SCARD_IO_REQUEST sSendPci, sRecvPci;
DWORD dwSendLength, dwRecvLength;
LONG rv;
SCARDHANDLE card;
SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL);
card = priv->hSCard;
sSendPci.dwProtocol = priv->dwProtocol;
sSendPci.cbPciLength = sizeof(sSendPci);
sRecvPci.dwProtocol = priv->dwProtocol;
sRecvPci.cbPciLength = sizeof(sRecvPci);
dwSendLength = sendsize;
dwRecvLength = *recvsize;
if (!control) {
rv = SCardTransmit(card, &sSendPci, sendbuf, dwSendLength,
&sRecvPci, recvbuf, &dwRecvLength);
} else {
rv = SCardControl(card, (DWORD) control, sendbuf, dwSendLength,
recvbuf, dwRecvLength, &dwRecvLength);
}
if (rv != SCARD_S_SUCCESS) {
PCSC_TRACE(reader, "SCardTransmit/Control failed", rv);
switch (rv) {
case SCARD_W_REMOVED_CARD:
return SC_ERROR_CARD_REMOVED;
default:
return SC_ERROR_TRANSMIT_FAILED;
}
}
if (!control && dwRecvLength < 2)
return SC_ERROR_UNKNOWN_DATA_RECEIVED;
*recvsize = dwRecvLength;
return SC_SUCCESS;
}
static int pcsc_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
{
size_t ssize, rsize, rbuflen = 0;
u8 *sbuf = NULL, *rbuf = NULL;
int r;
struct pcsc_private_data *priv = (struct pcsc_private_data *) reader->ctx->reader_drv_data;
/* we always use a at least 258 byte size big return buffer
* to mimic the behaviour of the old implementation (some readers
* seems to require a larger than necessary return buffer).
* The buffer for the returned data needs to be at least 2 bytes
* larger than the expected data length to store SW1 and SW2. */
rsize = rbuflen = apdu->resplen <= 256 ? 258 : apdu->resplen + 2;
rbuf = malloc(rbuflen);
if (rbuf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
goto out;
}
/* encode and log the APDU */
r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, pcsc_proto_to_opensc(priv->dwProtocol));
if (r != SC_SUCCESS)
goto out;
if (reader->name)
sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "reader '%s'", reader->name);
sc_apdu_log(reader->ctx, SC_LOG_DEBUG_NORMAL, sbuf, ssize, 1);
r = pcsc_internal_transmit(reader, sbuf, ssize,
rbuf, &rsize, apdu->control);
if (r < 0) {
/* unable to transmit ... most likely a reader problem */
sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "unable to transmit");
goto out;
}
sc_apdu_log(reader->ctx, SC_LOG_DEBUG_NORMAL, rbuf, rsize, 0);
/* set response */
r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize);
out:
if (sbuf != NULL) {
sc_mem_clear(sbuf, ssize);
free(sbuf);
}
if (rbuf != NULL) {
sc_mem_clear(rbuf, rbuflen);
free(rbuf);
}
return r;
}
static
int pcsc_init(void *init_data, sc_context_t *ctx)
{
struct pcsc_private_data *priv;
sc_reader_t *reader;
DWORD atr_len = SC_MAX_ATR_SIZE;
DWORD name_len;
DWORD dwState;
size_t i;
int r;
if (init_data == NULL || ctx == NULL) {
return SC_ERROR_INVALID_ARGUMENTS;
}
if (ctx->reader_drv_data != NULL) {
return SC_ERROR_INVALID_DATA; /* Already initialised */
}
ctx->reader_drv_data = calloc(1, sizeof(struct pcsc_private_data));
if (ctx->reader_drv_data == NULL) {
return SC_ERROR_OUT_OF_MEMORY;
}
priv = ctx->reader_drv_data;
priv->hSCardCtx = ((pcsc_ctx_t *) init_data)->hSCardCtx;
priv->hSCard = ((pcsc_ctx_t *) init_data)->hSCard;
reader = calloc(1, sizeof(sc_reader_t));
if (reader == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
goto error;
}
name_len = 127;
reader->name = malloc(sizeof(char) * (name_len + 1));
if (reader->name == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
goto error;
}
r = SCardStatus(priv->hSCard, reader->name, &name_len,
&dwState, &priv->dwProtocol, reader->atr.value, &atr_len);
if (r != SCARD_S_SUCCESS) {
printf("%s\n", pcsc_stringify_error(r));
r = SC_ERROR_READER;
goto error;
}
reader->name[name_len] = 0;
reader->atr.len = atr_len;
printf("Current Reader Name : %s\n", reader->name);
printf("Current Reader State : 0x%lx\n", dwState);
printf("Current Reader Protocol : T%ld\n", priv->dwProtocol - 1);
printf("Current Reader ATR Size : %u\n", reader->atr.len);
printf("Current Reader ATR Value : ");
for (i = 0; i < reader->atr.len; i++) {
printf("%02X ", reader->atr.value[i]);
}
printf("\n");
reader->flags = SC_READER_CARD_PRESENT;
reader->driver = ctx->reader_driver;
reader->ops = reader->driver->ops;
r = _sc_add_reader(ctx, reader);
if (r != SC_SUCCESS) {
goto error;
}
return SC_SUCCESS;
error:
if (reader != NULL) {
if (reader->name != NULL)
free(reader->name);
free(reader);
}
free(ctx->reader_drv_data);
ctx->reader_drv_data = NULL;
return r;
}
static
int pcsc_finish(sc_context_t *ctx)
{
if (ctx->reader_drv_data != NULL) {
free(ctx->reader_drv_data);
ctx->reader_drv_data = NULL;
}
return SC_SUCCESS;
}
static
int pcsc_detect_card_presence(sc_reader_t *reader)
{
return SC_READER_CARD_PRESENT;
}
static
int pcsc_connect(sc_reader_t *reader)
{
return SC_SUCCESS;
}
static
int pcsc_disconnect(sc_reader_t * reader)
{
return SC_SUCCESS;
}
struct sc_reader_driver * get_reader_driver(void)
{
struct sc_reader_driver *pcsc_drv;
pcsc_drv = calloc(1, sizeof(struct sc_reader_driver));
if (pcsc_drv == NULL) {
return NULL;
}
pcsc_drv->ops = calloc(1, sizeof(struct sc_reader_operations));
if (pcsc_drv->ops == NULL) {
free(pcsc_drv);
return NULL;
}
pcsc_drv->name = "cardmod";
pcsc_drv->short_name = "cardmod";
pcsc_drv->ops->init = pcsc_init;
pcsc_drv->ops->finish = pcsc_finish;
pcsc_drv->ops->detect_card_presence = pcsc_detect_card_presence;
pcsc_drv->ops->connect = pcsc_connect;
pcsc_drv->ops->disconnect = pcsc_disconnect;
pcsc_drv->ops->transmit = pcsc_transmit;
return pcsc_drv;
}
typedef struct pcsc_ctx {
SCARDCONTEXT hSCardCtx;
SCARDHANDLE hSCard;
} pcsc_ctx_t;
struct sc_reader_driver * get_reader_driver(void);
_______________________________________________
opensc-devel mailing list
[email protected]
http://www.opensc-project.org/mailman/listinfo/opensc-devel