- Added support for CT-API

- Improved config file loading
- Implemented ATR parsing


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@396 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2002-03-26 11:38:40 +00:00
parent b2d2bc77ae
commit 59d4e9b7be
10 changed files with 702 additions and 83 deletions

View File

@ -38,7 +38,21 @@ app default {
#
# reader_drivers = pcsc, ctapi;
# What reader drivers to load at start-up
reader_driver ctapi {
module /usr/local/towitoko/lib/libtowitoko.so {
# CT-API ports:
# 0..3 COM1..4
# 4 Printer
# 5 Modem
# 6..7 LPT1..2
ports = 0;
}
# module /usr/local/lib/ctapi/ctapi2.so {
# ports = 1, 6;
# }
}
# What card drivers to load at start-up
#
# A special value of 'internal' will load all
# statically linked drivers. If an unknown (ie. not

View File

@ -21,7 +21,7 @@ libopensc_la_SOURCES = sc.c ctx.c asn1.c base64.c sec.c log.c \
card.c iso7816.c dir.c \
pkcs15.c pkcs15-cert.c pkcs15-pin.c \
pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \
pkcs15-cache.c $(PCSC_SRC) \
pkcs15-cache.c $(PCSC_SRC) reader-ctapi.c \
card-setcos.c card-miocos.c card-flex.c card-gpk.c \
card-tcos.c card-emv.c card-default.c
libopensc_la_LDFLAGS = -version-info 0:6:0

151
src/libopensc/ctbcs.h Normal file
View File

@ -0,0 +1,151 @@
/*
CT-BCS commands, responses and parameters for terminals
without keypad and display.
This file is part of the Unix driver for Towitoko smartcard readers
Copyright (C) 1998 1999 2000 Carlos Prados <cprados@yahoo.com>
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 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
*/
#ifndef _CTBCS_
#define _CTBCS_
/*
* Command and response size
*/
#define CTBCS_MIN_COMMAND_SIZE 2
#define CTBCS_MIN_RESPONSE_SIZE 2
/*
* Class byte of all CTBCS commands
*/
#define CTBCS_CLA 0x20
/*
* Mandatory CT-BCS commands
*/
#define CTBCS_INS_RESET 0x11 /* Reset CT */
#define CTBCS_INS_REQUEST 0x12 /* Request ICC */
#define CTBCS_INS_STATUS 0x13 /* Get reader status */
#define CTBCS_INS_EJECT 0x15 /* Eject ICC */
/*
* P1 parameter: functional units
*/
#define CTBCS_P1_CT_KERNEL 0x00
#define CTBCS_P1_INTERFACE1 0x01
#define CTBCS_P1_INTERFACE2 0x02
#define CTBCS_P1_INTERFACE3 0x03
#define CTBCS_P1_INTERFACE4 0x04
#define CTBCS_P1_INTERFACE5 0x05
#define CTBCS_P1_INTERFACE6 0x06
#define CTBCS_P1_INTERFACE7 0x07
#define CTBCS_P1_INTERFACE8 0x08
#define CTBCS_P1_INTERFACE9 0x09
#define CTBCS_P1_INTERFACE10 0x0A
#define CTBCS_P1_INTERFACE11 0x0B
#define CTBCS_P1_INTERFACE12 0x0C
#define CTBCS_P1_INTERFACE13 0x0D
#define CTBCS_P1_INTERFACE14 0x0E
#define CTBCS_P1_DISPLAY 0x40
#define CTBCS_P1_KEYPAD 0x50
/*
* P2 parameter for Reset CT: data to be returned
*/
#define CTBCS_P2_RESET_NO_RESP 0x00 /* Return no data */
#define CTBCS_P2_RESET_GET_ATR 0x01 /* Return complete ATR */
#define CTBCS_P2_RESET_GET_HIST 0x02 /* Return historical bytes */
/*
* P2 parameter for Request ICC: data to be returned
*/
#define CTBCS_P2_REQUEST_NO_RESP 0x00 /* Return no data */
#define CTBCS_P2_REQUEST_GET_ATR 0x01 /* Return complete ATR */
#define CTBCS_P2_REQUEST_GET_HIST 0x02 /* Return historical bytes */
/*
* P2 parameter for Get status: TAG of data object to return
*/
#define CTBCS_P2_STATUS_MANUFACTURER 0x46 /* Return manufacturer DO */
#define CTBCS_P2_STATUS_ICC 0x80 /* Return ICC DO */
/*
* General return codes
*/
#define CTBCS_SW1_OK 0x90 /* Command successful */
#define CTBCS_SW2_OK 0x00
#define CTBCS_SW1_WRONG_LENGTH 0x67 /* Wrong length */
#define CTBCS_SW2_WRONG_LENGTH 0x00
#define CTBCS_SW1_COMMAND_NOT_ALLOWED 0x69 /* Command not allowed */
#define CTBCS_SW2_COMMAND_NOT_ALLOWED 0x00
#define CTBCS_SW1_WRONG_PARAM 0x6A /* Wrong parameters P1, P2 */
#define CTBCS_SW2_WRONG_PARAM 0x00
#define CTBCS_SW1_WRONG_INS 0x6D /* Wrong Instruction */
#define CTBCS_SW2_WRONG_INS 0x00
#define CTBCS_SW1_WRONG_CLA 0x6E /* Class not supported */
#define CTBCS_SW2_WRONG_CLA 0x00
#define CTBCS_SW1_ICC_ERROR 0x6F /* ICC removed, defective or */
#define CTBCS_SW2_ICC_ERROR 0x00 /* no longer reacts */
/*
* Return codes for Reset CT
*/
#define CTBCS_SW1_RESET_CT_OK 0x90 /* Reset CT successful */
#define CTBCS_SW2_RESET_CT_OK 0x00
#define CTBCS_SW1_RESET_SYNC_OK 0x90 /* Synchoronous ICC, */
#define CTBCS_SW2_RESET_SYNC_OK 0x00 /* reset successful */
#define CTBCS_SW1_RESET_ASYNC_OK 0x90 /* Asynchoronous ICC, */
#define CTBCS_SW2_RESET_ASYNC_OK 0x01 /* reset successful */
#define CTBCS_SW1_RESET_ERROR 0x64 /* Reset not successful */
#define CTBCS_SW2_RESET_ERROR 0x00
/*
* Return codes for Request ICC
*/
#define CTBCS_SW1_REQUEST_SYNC_OK 0x90 /* Synchoronous ICC, */
#define CTBCS_SW2_REQUEST_SYNC_OK 0x00 /* reset successful */
#define CTBCS_SW1_REQUEST_ASYNC_OK 0x90 /* Asynchoronous ICC, */
#define CTBCS_SW2_REQUEST_ASYNC_OK 0x01 /* reset successful */
#define CTBCS_SW1_REQUEST_NO_CARD 0x62 /* No card present */
#define CTBCS_SW2_REQUEST_NO_CARD 0x00
#define CTBCS_SW1_REQUEST_CARD_PRESENT 0x62 /* Card already present */
#define CTBCS_SW2_REQUEST_CARD_PRESENT 0x01
#define CTBCS_SW1_REQUEST_ERROR 0x64 /* Reset not successful */
#define CTBCS_SW2_REQUEST_ERROR 0x00
#define CTBCS_SW1_REQUEST_TIMER_ERROR 0x69 /* Timer not supported */
#define CTBCS_SW2_REQUEST_TIMER_ERROR 0x00
/*
* Return codes for Eject ICC
*/
#define CTBCS_SW1_EJECT_OK 0x90 /* Command succesful, */
#define CTBCS_SW2_EJECT_OK 0x00
#define CTBCS_SW1_EJECT_REMOVED 0x90 /* Command succesful, */
#define CTBCS_SW2_EJECT_REMOVED 0x01 /* Card removed */
#define CTBCS_SW1_EJECT_NOT_REMOVED 0x62 /* Card not removed */
#define CTBCS_SW2_EJECT_NOT_REMOVED 0x00
/*
* Data returned on Get Status command
*/
#define CTBCS_DATA_STATUS_NOCARD 0x00 /* No card present */
#define CTBCS_DATA_STATUS_CARD 0x01 /* Card present */
#define CTBCS_DATA_STATUS_CARD_CONNECT 0x05 /* Card present */
#endif /* _CTBCS_ */

View File

@ -65,6 +65,7 @@ static const struct _sc_driver_entry internal_reader_drivers[] = {
#ifdef HAVE_LIBPCSCLITE
{ "pcsc", sc_get_pcsc_driver },
#endif
{ "ctapi", sc_get_ctapi_driver },
{ NULL }
};
@ -144,75 +145,61 @@ static void add_internal_drvs(struct _sc_ctx_options *opts, int type)
}
}
static int load_parameters(struct sc_context *ctx, const char *app,
static int load_parameters(struct sc_context *ctx, scconf_block *block,
struct _sc_ctx_options *opts)
{
scconf_block **blocks = NULL;
int i, err = 0;
blocks = scconf_find_blocks(ctx->conf, NULL, "app", NULL);
for (i = 0; blocks[i]; i++) {
const scconf_block *block = blocks[i];
const scconf_list *list;
const char *s_internal = "internal", *val;
if (strcmp(block->name->data, app))
continue;
val = scconf_get_str(block, "debug", NULL);
if (val)
sscanf(val, "%d", &ctx->debug);
val = scconf_get_str(block, "debug_file", NULL);
if (val) {
if (ctx->debug_file && ctx->debug_file != stdout)
fclose(ctx->debug_file);
if (strcmp(val, "stdout") == 0)
ctx->debug_file = fopen(val, "a");
else
ctx->debug_file = stdout;
}
val = scconf_get_str(block, "error_file", NULL);
if (val) {
if (ctx->error_file && ctx->error_file != stderr)
fclose(ctx->error_file);
if (strcmp(val, "stderr") != 0)
ctx->error_file = fopen(val, "a");
else
ctx->error_file = stderr;
}
list = scconf_find_list(block, "reader_drivers");
if (list == NULL) {
if (opts->rcount == 0) /* Add the internal drivers */
add_internal_drvs(opts, 0);
} else
del_drvs(opts, 0);
while (list != NULL) {
if (strcmp(list->data, s_internal) == 0)
add_internal_drvs(opts, 1);
else
add_drv(opts, 0, list->data);
list = list->next;
}
if (err)
break;
list = scconf_find_list(block, "card_drivers");
if (list == NULL) {
if (opts->ccount == 0) /* Add the internal drivers */
add_internal_drvs(opts, 1);
} else
del_drvs(opts, 1);
while (list != NULL) {
if (strcmp(list->data, s_internal) == 0)
add_internal_drvs(opts, 1);
else
add_drv(opts, 1, list->data);
list = list->next;
}
if (err)
break;
int err = 0;
const scconf_list *list;
const char *val;
const char *s_internal = "internal";
ctx->debug = scconf_get_int(block, "debug", ctx->debug);
val = scconf_get_str(block, "debug_file", NULL);
if (val) {
if (ctx->debug_file && ctx->debug_file != stdout)
fclose(ctx->debug_file);
if (strcmp(val, "stdout") == 0)
ctx->debug_file = fopen(val, "a");
else
ctx->debug_file = stdout;
}
free(blocks);
val = scconf_get_str(block, "error_file", NULL);
if (val) {
if (ctx->error_file && ctx->error_file != stderr)
fclose(ctx->error_file);
if (strcmp(val, "stderr") != 0)
ctx->error_file = fopen(val, "a");
else
ctx->error_file = stderr;
}
list = scconf_find_list(block, "reader_drivers");
if (list == NULL) {
if (opts->rcount == 0) /* Add the internal drivers */
add_internal_drvs(opts, 0);
} else
del_drvs(opts, 0);
while (list != NULL) {
if (strcmp(list->data, s_internal) == 0)
add_internal_drvs(opts, 1);
else
add_drv(opts, 0, list->data);
list = list->next;
}
list = scconf_find_list(block, "card_drivers");
if (list == NULL) {
if (opts->ccount == 0) /* Add the internal drivers */
add_internal_drvs(opts, 1);
} else
del_drvs(opts, 1);
while (list != NULL) {
if (strcmp(list->data, s_internal) == 0)
add_internal_drvs(opts, 1);
else
add_drv(opts, 1, list->data);
list = list->next;
}
return err;
}
@ -281,12 +268,39 @@ static int load_card_drivers(struct sc_context *ctx,
return 0;
}
void process_config_file(struct sc_context *ctx, struct _sc_ctx_options *opts)
{
int i, r, count = 0;
scconf_block **blocks;
ctx->conf = scconf_init(OPENSC_CONF_PATH);
if (ctx->conf == NULL)
return;
r = scconf_parse(ctx->conf);
if (r < 1) {
scconf_deinit(ctx->conf);
ctx->conf = NULL;
return;
}
blocks = scconf_find_blocks(ctx->conf, NULL, "app", ctx->app_name);
if (blocks[0])
ctx->conf_blocks[count++] = blocks[0];
free(blocks);
if (strcmp(ctx->app_name, "default") != 0) {
blocks = scconf_find_blocks(ctx->conf, NULL, "app", "default");
if (blocks[0])
ctx->conf_blocks[count++] = blocks[0];
free(blocks);
}
for (i = 0; i < count; i++)
load_parameters(ctx, ctx->conf_blocks[i], opts);
}
int sc_establish_context(struct sc_context **ctx_out, const char *app_name)
{
const char *default_app = "default";
struct sc_context *ctx;
struct _sc_ctx_options opts;
int r;
assert(ctx_out != NULL);
ctx = malloc(sizeof(struct sc_context));
@ -296,19 +310,7 @@ int sc_establish_context(struct sc_context **ctx_out, const char *app_name)
memset(&opts, 0, sizeof(opts));
set_defaults(ctx, &opts);
ctx->app_name = app_name ? strdup(app_name) : strdup(default_app);
ctx->conf = scconf_init(OPENSC_CONF_PATH);
if (ctx->conf) {
r = scconf_parse(ctx->conf);
if (r < 1) {
scconf_deinit(ctx->conf);
ctx->conf = NULL;
} else {
load_parameters(ctx, default_app, &opts);
if (strcmp(default_app, ctx->app_name)) {
load_parameters(ctx, ctx->app_name, &opts);
}
}
}
process_config_file(ctx, &opts);
#ifdef HAVE_PTHREAD
pthread_mutex_init(&ctx->mutex, NULL);
#endif

View File

@ -43,6 +43,7 @@ int sc_check_sw(struct sc_card *card, int sw1, int sw2);
size_t _sc_count_bit_string_size(const void * buf, size_t bufsize);
int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader);
int _sc_parse_atr(struct sc_context *ctx, struct sc_slot_info *slot);
struct sc_slot_info * _sc_get_slot_info(struct sc_reader *reader, int slot_id);
/* Returns an index number if a match was found, -1 otherwise. table has to

View File

@ -323,7 +323,14 @@ struct sc_slot_info {
unsigned int supported_protocols, active_protocol;
u8 atr[SC_MAX_ATR_SIZE];
size_t atr_len;
struct _atr_info {
u8 *hist_bytes;
size_t hist_bytes_len;
int Fi, f, Di, N;
u8 FI, DI;
} atr_info;
void *drv_data;
};
typedef struct sc_slot_info sc_slot_info_t;
@ -533,6 +540,7 @@ struct sc_card_driver {
struct sc_context {
scconf_context *conf;
scconf_block *conf_blocks[3];
char *app_name;
int debug;
@ -759,6 +767,7 @@ const char *sc_strerror(int sc_errno);
extern const char *sc_version;
extern const struct sc_reader_driver *sc_get_pcsc_driver(void);
extern const struct sc_reader_driver *sc_get_ctapi_driver(void);
extern const struct sc_card_driver *sc_get_iso7816_driver(void);
extern const struct sc_card_driver *sc_get_emv_driver(void);

View File

@ -0,0 +1,371 @@
/*
* reader-ctapi.c: Reader driver for CT-API
*
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
*
* 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 "sc-internal.h"
#include "sc-log.h"
#include "ctbcs.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#define GET_SLOT_PTR(s, i) (&(s)->slot[(i)])
#define GET_PRIV_DATA(r) ((struct ctapi_private_data *) (r)->drv_data)
#define GET_SLOT_DATA(r) ((struct ctapi_slot_data *) (r)->drv_data)
struct ctapi_module {
char *name;
void *dlhandle;
int ctn_count;
};
struct ctapi_global_private_data {
int module_count;
struct ctapi_module *modules;
};
struct ctapi_functions {
char (* CT_init)(unsigned short ctn, unsigned short Pn);
char (* CT_close)(unsigned short ctn);
char (* CT_data)(unsigned short ctn, unsigned char *dad,
unsigned char *sad, unsigned short lc,
unsigned char *cmd, unsigned short *lr,
unsigned char *rsp);
};
/* Reader specific private data */
struct ctapi_private_data {
struct ctapi_functions funcs;
unsigned short ctn;
};
struct ctapi_slot_data {
};
static int refresh_slot_attributes(struct sc_reader *reader,
struct sc_slot_info *slot)
{
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
char rv;
u8 cmd[5], rbuf[256], sad, dad;
unsigned short lr;
cmd[0] = CTBCS_CLA;
cmd[1] = CTBCS_INS_STATUS;
cmd[2] = CTBCS_P1_CT_KERNEL;
cmd[3] = CTBCS_P2_STATUS_ICC;
cmd[4] = 0x00;
dad = 1;
sad = 2;
lr = 256;
slot->flags = 0;
rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf);
if (rv || rbuf[lr-2] != 0x90) {
error(reader->ctx, "Error getting status of terminal: %d\n", rv);
return SC_ERROR_TRANSMIT_FAILED;
}
if (rbuf[0] == CTBCS_DATA_STATUS_CARD_CONNECT)
slot->flags = SC_SLOT_CARD_PRESENT;
return 0;
}
static int ctapi_transmit(struct sc_reader *reader, struct sc_slot_info *slot,
const u8 *sendbuf, size_t sendsize,
u8 *recvbuf, size_t *recvsize)
{
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
u8 dad, sad;
unsigned short lr;
char rv;
dad = 0;
sad = 2;
lr = *recvsize;
rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, sendsize, (u8 *) sendbuf, &lr, recvbuf);
if (rv != 0) {
error(reader->ctx, "Error transmitting APDU: %d\n", rv);
return SC_ERROR_TRANSMIT_FAILED;
}
*recvsize = lr;
return 0;
}
static int ctapi_detect_card_presence(struct sc_reader *reader, struct sc_slot_info *slot)
{
int r;
r = refresh_slot_attributes(reader, slot);
if (r)
return r;
if (slot->flags & SC_SLOT_CARD_PRESENT)
return 1;
return 0;
}
static int ctapi_connect(struct sc_reader *reader, struct sc_slot_info *slot)
{
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
char rv;
u8 cmd[9], rbuf[256], sad, dad;
unsigned short lr;
int r;
cmd[0] = CTBCS_CLA;
cmd[1] = CTBCS_INS_REQUEST;
cmd[2] = CTBCS_P1_INTERFACE1;
cmd[3] = CTBCS_P2_REQUEST_GET_ATR;
cmd[4] = 0x00;
dad = 1;
sad = 2;
lr = 256;
rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf);
if (rv || rbuf[lr-2] != 0x90) {
error(reader->ctx, "Error activating card: %d\n", rv);
return SC_ERROR_TRANSMIT_FAILED;
}
if (lr < 2)
SC_FUNC_RETURN(reader->ctx, 0, SC_ERROR_INTERNAL);
lr -= 2;
if (lr > SC_MAX_ATR_SIZE)
lr = SC_MAX_ATR_SIZE;
memcpy(slot->atr, rbuf, lr);
slot->atr_len = lr;
r = _sc_parse_atr(reader->ctx, slot);
#if 0
if (slot->atr_info.Fi > 0) {
/* Perform PPS negotiation */
cmd[1] = CTBCS_INS_RESET;
cmd[4] = 0x03;
cmd[5] = 0xFF;
cmd[6] = 0x10;
cmd[7] = (slot->atr_info.FI << 4) | slot->atr_info.DI;
cmd[8] = 0x00;
dad = 1;
sad = 2;
lr = 256;
rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 9, cmd, &lr, rbuf);
if (rv) {
error(reader->ctx, "Error negotiating PPS: %d\n", rv);
return SC_ERROR_TRANSMIT_FAILED;
}
}
#endif
return 0;
}
static int ctapi_disconnect(struct sc_reader *reader, struct sc_slot_info *slot,
int action)
{
return 0;
}
static int ctapi_lock(struct sc_reader *reader, struct sc_slot_info *slot)
{
return 0;
}
static int ctapi_unlock(struct sc_reader *reader, struct sc_slot_info *slot)
{
return 0;
}
static int ctapi_release(struct sc_reader *reader)
{
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
free(priv);
return 0;
}
static struct sc_reader_operations ctapi_ops;
static const struct sc_reader_driver ctapi_drv = {
"CT-API module",
"ctapi",
&ctapi_ops
};
static struct ctapi_module * add_module(struct ctapi_global_private_data *gpriv,
const char *name, void *dlhandle)
{
int i;
i = gpriv->module_count;
gpriv->modules = realloc(gpriv->modules, sizeof(struct ctapi_module) * (i+1));
gpriv->modules[i].name = strdup(name);
gpriv->modules[i].dlhandle = dlhandle;
gpriv->modules[i].ctn_count = 0;
gpriv->module_count++;
return &gpriv->modules[i];
}
static int ctapi_load_module(struct sc_context *ctx,
struct ctapi_global_private_data *gpriv,
scconf_block *conf)
{
const char *val;
struct ctapi_functions funcs;
void *dlh, *func;
struct ctapi_module *mod;
const scconf_list *list;
int r;
list = scconf_find_list(conf, "ports");
if (list == NULL) {
error(ctx, "No ports configured.\n");
return -1;
}
val = conf->name->data;
dlh = dlopen(val, RTLD_LAZY);
if (dlh == NULL) {
error(ctx, "Unable to open shared library '%s'\n", val);
return -1;
}
func = dlsym(dlh, "CT_init");
if (func == NULL)
goto symerr;
funcs.CT_init = func;
func = dlsym(dlh, "CT_close");
if (func == NULL)
goto symerr;
funcs.CT_close = func;
func = dlsym(dlh, "CT_data");
if (func == NULL)
goto symerr;
funcs.CT_data = func;
mod = add_module(gpriv, val, dlh);
for (; list != NULL; list = list->next) {
int port;
char namebuf[128];
char rv;
struct sc_reader *reader;
struct ctapi_private_data *priv;
struct sc_slot_info *slot;
if (sscanf(list->data, "%d", &port) != 1) {
error(ctx, "Port '%s' is not a number.\n", list->data);
continue;
}
rv = funcs.CT_init(mod->ctn_count, port);
if (rv) {
error(ctx, "CT_init() failed with %d\n", rv);
continue;
}
reader = malloc(sizeof(struct sc_reader));
priv = malloc(sizeof(struct ctapi_private_data));
memset(reader, 0, sizeof(*reader));
reader->drv_data = priv;
reader->ops = &ctapi_ops;
reader->driver = &ctapi_drv;
reader->slot_count = 1;
snprintf(namebuf, sizeof(namebuf), "CT-API %s, port %d", mod->name, port);
reader->name = strdup(namebuf);
priv->funcs = funcs;
priv->ctn = mod->ctn_count;
r = _sc_add_reader(ctx, reader);
if (r) {
funcs.CT_close(mod->ctn_count);
free(priv);
free(reader->name);
free(reader);
break;
}
slot = &reader->slot[0];
slot->id = 0;
slot->capabilities = 0;
slot->atr_len = 0;
slot->drv_data = NULL;
refresh_slot_attributes(reader, slot);
mod->ctn_count++;
}
return 0;
symerr:
error(ctx, "Unable to resolve CT-API symbols.\n");
dlclose(dlh);
return -1;
}
static int ctapi_init(struct sc_context *ctx, void **reader_data)
{
int i;
struct ctapi_global_private_data *gpriv;
scconf_block **blocks = NULL, *conf_block = NULL;
gpriv = malloc(sizeof(struct ctapi_global_private_data));
if (gpriv == NULL)
return SC_ERROR_OUT_OF_MEMORY;
memset(gpriv, 0, sizeof(*gpriv));
*reader_data = gpriv;
for (i = 0; ctx->conf_blocks[i] != NULL; i++) {
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i],
"reader_driver", "ctapi");
conf_block = blocks[0];
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;
}
static int ctapi_finish(void *prv_data)
{
struct ctapi_global_private_data *priv = (struct ctapi_global_private_data *) prv_data;
if (priv) {
free(priv);
}
return 0;
}
const struct sc_reader_driver * sc_get_ctapi_driver()
{
ctapi_ops.init = ctapi_init;
ctapi_ops.finish = ctapi_finish;
ctapi_ops.transmit = ctapi_transmit;
ctapi_ops.detect_card_presence = ctapi_detect_card_presence;
ctapi_ops.lock = ctapi_lock;
ctapi_ops.unlock = ctapi_unlock;
ctapi_ops.release = ctapi_release;
ctapi_ops.connect = ctapi_connect;
ctapi_ops.disconnect = ctapi_disconnect;
return &ctapi_drv;
}

View File

@ -337,6 +337,7 @@ static int pcsc_init(struct sc_context *ctx, void **reader_data)
if (r) {
free(priv->reader_name);
free(priv);
free(reader->name);
free(reader);
break;
}

View File

@ -43,6 +43,7 @@ int sc_check_sw(struct sc_card *card, int sw1, int sw2);
size_t _sc_count_bit_string_size(const void * buf, size_t bufsize);
int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader);
int _sc_parse_atr(struct sc_context *ctx, struct sc_slot_info *slot);
struct sc_slot_info * _sc_get_slot_info(struct sc_reader *reader, int slot_id);
/* Returns an index number if a match was found, -1 otherwise. table has to

View File

@ -376,3 +376,72 @@ inline int sc_file_valid(const struct sc_file *file) {
#endif
return file->magic == SC_FILE_MAGIC;
}
int _sc_parse_atr(struct sc_context *ctx, struct sc_slot_info *slot)
{
u8 *p = slot->atr;
int atr_len = (int) slot->atr_len;
int n_hist, x;
int tx[4];
int i, FI, DI;
const int Fi_table[] = {
372, 372, 558, 744, 1116, 1488, 1860, -1,
-1, 512, 768, 1024, 1536, 2048, -1, -1 };
const int f_table[] = {
40, 50, 60, 80, 120, 160, 200, -1,
-1, 50, 75, 100, 150, 200, -1, -1 };
const int Di_table[] = {
-1, 1, 2, 4, 8, 16, 32, -1,
12, 20, -1, -1, -1, -1, -1, -1 };
if (p[0] != 0x3B && p[0] != 0x3F) {
error(ctx, "invalid sync byte in ATR: 0x%02X\n", p[0]);
return SC_ERROR_INTERNAL;
}
n_hist = p[1] & 0x0F;
x = p[1] >> 4;
p += 2;
atr_len -= 2;
for (i = 0; i < 4 && atr_len > 0; i++) {
if (x & (1 << i)) {
tx[i] = *p;
p++;
atr_len--;
} else
tx[i] = -1;
}
if (tx[0] >= 0) {
slot->atr_info.FI = FI = tx[0] >> 4;
slot->atr_info.DI = DI = tx[0] & 0x0F;
slot->atr_info.Fi = Fi_table[FI];
slot->atr_info.f = f_table[FI];
slot->atr_info.Di = Di_table[DI];
} else {
slot->atr_info.Fi = -1;
slot->atr_info.f = -1;
slot->atr_info.Di = -1;
}
if (tx[2] >= 0)
slot->atr_info.N = tx[3];
else
slot->atr_info.N = -1;
while (tx[3] > 0 && tx[3] & 0xF0 && atr_len > 0) {
x = tx[3] >> 4;
for (i = 0; i < 4 && atr_len > 0; i++) {
if (x & (1 << i)) {
tx[i] = *p;
p++;
atr_len--;
} else
tx[i] = -1;
}
}
if (atr_len <= 0)
return 0;
if (n_hist > atr_len)
n_hist = atr_len;
slot->atr_info.hist_bytes_len = n_hist;
slot->atr_info.hist_bytes = p;
return 0;
}