reader: by default only short APDU supported

default values of reader's max send/receive sizes correspond to only short APDU supported;
these values can be overwritten by reader itself with the proper value of dwMaxAPDUDataSize from TLV properties,
or with the corresponding options in OpenSC configuration.

resolves issue #735
This commit is contained in:
Viktor Tarasov 2016-04-19 13:24:09 +02:00
parent 41f34fdbcf
commit e95b515163
6 changed files with 86 additions and 72 deletions

View File

@ -66,9 +66,9 @@ app default {
# The following section shows definitions for PC/SC readers.
reader_driver pcsc {
# Limit command and response sizes.
# Default: n/a
# max_send_size = 255;
# max_recv_size = 256;
# Default: max_send_size = 255, max_recv_size = 256;
# max_send_size = 0;
# max_recv_size = 0;
#
# Connect to reader in exclusive mode?
# Default: false

View File

@ -356,34 +356,6 @@ load_parameters(sc_context_t *ctx, scconf_block *block, struct _sc_ctx_options *
return err;
}
static void load_reader_driver_options(sc_context_t *ctx)
{
struct sc_reader_driver *driver = ctx->reader_driver;
scconf_block *conf_block = NULL;
sc_reader_t *reader;
int max_send_size;
int max_recv_size;
conf_block = sc_get_conf_block(ctx, "reader_driver", driver->short_name, 1);
if (conf_block != NULL) {
max_send_size = scconf_get_int(conf_block, "max_send_size", -1);
max_recv_size = scconf_get_int(conf_block, "max_recv_size", -1);
if (max_send_size >= 0 || max_recv_size >= 0) {
if (list_iterator_start(&ctx->readers)) {
reader = list_iterator_next(&ctx->readers);
while (reader) {
if (max_send_size >= 0)
reader->max_send_size = max_send_size;
if (max_recv_size >= 0)
reader->max_recv_size = max_recv_size;
reader = list_iterator_next(&ctx->readers);
}
list_iterator_stop(&ctx->readers);
}
}
}
}
/**
* find library module for provided driver in configuration file
@ -824,7 +796,6 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm)
}
del_drvs(&opts);
sc_ctx_detect_readers(ctx);
load_reader_driver_options(ctx);
*ctx_out = ctx;
return SC_SUCCESS;

View File

@ -294,6 +294,10 @@ struct sc_reader_driver {
#define SC_READER_CAP_PACE_DESTROY_CHANNEL 0x00000010
#define SC_READER_CAP_PACE_GENERIC 0x00000020
/* reader send/receive length of short APDU */
#define SC_READER_SHORT_APDU_MAX_SEND_SIZE 255
#define SC_READER_SHORT_APDU_MAX_RECV_SIZE 256
typedef struct sc_reader {
struct sc_context *ctx;
const struct sc_reader_driver *driver;

View File

@ -322,20 +322,18 @@ static struct ctapi_module * add_module(struct ctapi_global_private_data *gpriv,
}
static int ctapi_load_module(sc_context_t *ctx,
struct ctapi_global_private_data *gpriv,
scconf_block *conf)
struct ctapi_global_private_data *gpriv, scconf_block *conf)
{
const char *val;
struct ctapi_functions funcs;
struct ctapi_module *mod;
const scconf_list *list;
scconf_block *conf_block = NULL;
void *dlh;
int r, i, NumUnits;
u8 cmd[5], rbuf[256], sad, dad;
unsigned short lr;
list = scconf_find_list(conf, "ports");
if (list == NULL) {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "No ports configured.\n");
@ -391,6 +389,16 @@ static int ctapi_load_module(sc_context_t *ctx,
reader->name = strdup(namebuf);
priv->funcs = funcs;
priv->ctn = mod->ctn_count;
reader->max_send_size = SC_READER_SHORT_APDU_MAX_SEND_SIZE;
reader->max_recv_size = SC_READER_SHORT_APDU_MAX_RECV_SIZE;
conf_block = sc_get_conf_block(ctx, "reader_driver", "ctapi", 1);
if (conf_block) {
reader->max_send_size = scconf_get_int(conf_block, "max_send_size", reader->max_send_size);
reader->max_recv_size = scconf_get_int(conf_block, "max_recv_size", reader->max_recv_size);
}
r = _sc_add_reader(ctx, reader);
if (r) {
funcs.CT_close((unsigned short)mod->ctn_count);
@ -506,21 +514,13 @@ static int ctapi_init(sc_context_t *ctx)
return SC_ERROR_OUT_OF_MEMORY;
ctx->reader_drv_data = gpriv;
for (i = 0; ctx->conf_blocks[i] != NULL; i++) {
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i],
"reader_driver", "ctapi");
if (blocks && blocks[0])
conf_block = blocks[0];
conf_block = sc_get_conf_block(ctx, "reader_driver", "ctapi", 1);
if (conf_block) {
blocks = scconf_find_blocks(ctx->conf, conf_block, "module", NULL);
for (i = 0; blocks != NULL && blocks[i] != NULL; i++)
ctapi_load_module(ctx, gpriv, blocks[i]);
free(blocks);
if (conf_block != NULL)
break;
}
if (conf_block == NULL)
return 0;
blocks = scconf_find_blocks(ctx->conf, conf_block, "module", NULL);
for (i = 0; blocks != NULL && blocks[i] != NULL; i++)
ctapi_load_module(ctx, gpriv, blocks[i]);
free(blocks);
return 0;
}

View File

@ -96,6 +96,7 @@ static int
openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info)
{
sc_reader_t *reader;
scconf_block *conf_block;
struct driver_data *data;
int rc;
@ -119,6 +120,12 @@ openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info)
reader->drv_data = data;
reader->name = strdup(data->info.ct_name);
conf_block = sc_get_conf_block(ctx, "reader_driver", "openct", 1);
if (conf_block) {
reader->max_send_size = scconf_get_int(conf_block, "max_send_size", reader->max_send_size);
reader->max_recv_size = scconf_get_int(conf_block, "max_recv_size", reader->max_recv_size);
}
if ((rc = _sc_add_reader(ctx, reader)) < 0) {
free(data);
free(reader->name);

View File

@ -704,8 +704,10 @@ static int pcsc_init(sc_context_t *ctx)
gpriv->provider_library =
scconf_get_str(conf_block, "provider_library", gpriv->provider_library);
}
sc_log(ctx, "PC/SC options: connect_exclusive=%d disconnect_action=%d transaction_end_action=%d reconnect_action=%d enable_pinpad=%d enable_pace=%d",
gpriv->connect_exclusive, gpriv->disconnect_action, gpriv->transaction_end_action, gpriv->reconnect_action, gpriv->enable_pinpad, gpriv->enable_pace);
sc_log(ctx, "PC/SC options: connect_exclusive=%d disconnect_action=%d transaction_end_action=%d"
" reconnect_action=%d enable_pinpad=%d enable_pace=%d",
gpriv->connect_exclusive, gpriv->disconnect_action, gpriv->transaction_end_action,
gpriv->reconnect_action, gpriv->enable_pinpad, gpriv->enable_pace);
gpriv->dlhandle = sc_dlopen(gpriv->provider_library);
if (gpriv->dlhandle == NULL) {
@ -870,31 +872,32 @@ part10_find_property_by_tag(unsigned char buffer[], int length,
*/
static size_t part10_detect_max_data(sc_reader_t *reader, SCARDHANDLE card_handle)
{
u8 rbuf[256];
DWORD rcount = sizeof rbuf;
struct pcsc_private_data *priv;
/* 0 means no limitations */
size_t max_data = 0;
u8 rbuf[256];
DWORD rcount = sizeof rbuf;
struct pcsc_private_data *priv = NULL;
/* 0 means extended APDU not supported */
size_t max_data = 0;
int r;
if (!reader)
goto err;
priv = GET_PRIV_DATA(reader);
if (!priv)
goto err;
if (!reader)
goto err;
priv = GET_PRIV_DATA(reader);
if (!priv)
goto err;
if (priv->get_tlv_properties && priv->gpriv) {
if (priv->get_tlv_properties && priv->gpriv) {
if (SCARD_S_SUCCESS != priv->gpriv->SCardControl(card_handle,
priv->get_tlv_properties, NULL, 0, rbuf, sizeof(rbuf),
&rcount)) {
sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL,
"PC/SC v2 part 10: Get TLV properties failed!");
priv->get_tlv_properties, NULL, 0, rbuf, sizeof(rbuf), &rcount)) {
sc_log(reader->ctx, "PC/SC v2 part 10: Get TLV properties failed!");
goto err;
}
r = part10_find_property_by_tag(rbuf, rcount,
PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize);
if (r >= 0)
sc_log(reader->ctx, "get dwMaxAPDUDataSize property returned %i", r);
/* 256 < X <= 0x10000: short and extended APDU of up to X bytes of data */
if (r > 0x100 && r <= 0x10000)
max_data = r;
}
@ -1058,11 +1061,13 @@ static void detect_reader_features(sc_reader_t *reader, SCARDHANDLE card_handle)
}
if (priv->get_tlv_properties) {
/* Set reader max_send_size and max_recv_size based on
/* Try to set reader max_send_size and max_recv_size based on
* detected max_data */
reader->max_send_size = part10_detect_max_data(reader,
card_handle);
reader->max_recv_size = reader->max_send_size;
int max_data = part10_detect_max_data(reader, card_handle);
if (max_data > 0) {
reader->max_send_size = max_data;
reader->max_recv_size = max_data;
}
/* debug the product and vendor ID of the reader */
part10_get_vendor_product(reader, card_handle, NULL, NULL);
@ -1171,6 +1176,7 @@ static int pcsc_detect_readers(sc_context_t *ctx)
for (reader_name = reader_buf; *reader_name != '\x0'; reader_name += strlen(reader_name) + 1) {
sc_reader_t *reader = NULL, *old_reader;
struct pcsc_private_data *priv = NULL;
scconf_block *conf_block = NULL;
int found = 0;
for (i=0;i < sc_ctx_get_reader_count(ctx) && !found;i++) {
@ -1196,7 +1202,7 @@ static int pcsc_detect_readers(sc_context_t *ctx)
ret = SC_ERROR_OUT_OF_MEMORY;
goto err1;
}
if ((priv = calloc(1, sizeof(struct pcsc_private_data))) == NULL) {
if ((priv = calloc(1, sizeof(struct pcsc_private_data))) == NULL) {
ret = SC_ERROR_OUT_OF_MEMORY;
goto err1;
}
@ -1208,6 +1214,7 @@ static int pcsc_detect_readers(sc_context_t *ctx)
ret = SC_ERROR_OUT_OF_MEMORY;
goto err1;
}
priv->gpriv = gpriv;
if (_sc_add_reader(ctx, reader)) {
ret = SC_SUCCESS; /* silent ignore */
@ -1238,10 +1245,25 @@ static int pcsc_detect_readers(sc_context_t *ctx)
PCSC_TRACE(reader, "SCardConnect(SHARED)", rv);
}
/* max send/receive sizes: with default values only short APDU supported */
reader->max_send_size = SC_READER_SHORT_APDU_MAX_SEND_SIZE;
reader->max_recv_size = SC_READER_SHORT_APDU_MAX_RECV_SIZE;
/* max send/receive sizes: check if reader explicitely declares support of extended APDU */
if (rv == SCARD_S_SUCCESS) {
detect_reader_features(reader, card_handle);
gpriv->SCardDisconnect(card_handle, SCARD_LEAVE_CARD);
}
/* max send/receive sizes: if exist in configuration these options overwrite
* the values by default and values declared by reader */
conf_block = sc_get_conf_block(ctx, "reader_driver", "pcsc", 1);
if (conf_block) {
reader->max_send_size = scconf_get_int(conf_block, "max_send_size", reader->max_send_size);
reader->max_recv_size = scconf_get_int(conf_block, "max_recv_size", reader->max_recv_size);
}
sc_log(ctx, "reader's max-send-size: %i, max-recv-size: %i", reader->max_send_size, reader->max_recv_size);
}
continue;
@ -2257,6 +2279,7 @@ int cardmod_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcs
SCARDHANDLE card_handle;
u8 feature_buf[256], rbuf[SC_MAX_APDU_BUFFER_SIZE];
PCSC_TLV_STRUCTURE *pcsc_tlv;
scconf_block *conf_block = NULL;
struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) ctx->reader_drv_data;
LONG rv;
char reader_name[128];
@ -2318,6 +2341,15 @@ int cardmod_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcs
}
priv->gpriv = gpriv;
reader->max_send_size = SC_READER_SHORT_APDU_MAX_SEND_SIZE;
reader->max_recv_size = SC_READER_SHORT_APDU_MAX_RECV_SIZE;
conf_block = sc_get_conf_block(ctx, "reader_driver", "cardmod", 1);
if (conf_block) {
reader->max_send_size = scconf_get_int(conf_block, "max_send_size", reader->max_send_size);
reader->max_recv_size = scconf_get_int(conf_block, "max_recv_size", reader->max_recv_size);
}
/* attempt to detect protocol in use T0/T1/RAW */
rv = priv->gpriv->SCardStatus(card_handle, NULL, &readers_len,
&state, &prot, atr, &atr_len);