diff --git a/etc/opensc.conf.in b/etc/opensc.conf.in index 749bb521..1c2e8c5a 100644 --- a/etc/opensc.conf.in +++ b/etc/opensc.conf.in @@ -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 diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index 03c92c75..8b2acf8a 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -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; diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 728e8e4e..c97154d2 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -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; diff --git a/src/libopensc/reader-ctapi.c b/src/libopensc/reader-ctapi.c index 9fa1f98e..456edd36 100644 --- a/src/libopensc/reader-ctapi.c +++ b/src/libopensc/reader-ctapi.c @@ -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; } diff --git a/src/libopensc/reader-openct.c b/src/libopensc/reader-openct.c index b0e4f663..45d76b0a 100644 --- a/src/libopensc/reader-openct.c +++ b/src/libopensc/reader-openct.c @@ -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); diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 4afc9b65..587f2b3c 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -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);