- 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:
parent
b2d2bc77ae
commit
59d4e9b7be
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue