libopensc:
- Remove slot abstraction from internal API and all reader drivers. CT-API (from where it all comes from) readers with multiple slots (if still found) can be presented as separate readers, OpenCT should remove the slot abstraction, PC/SC never knew about it. None of the tools knew how to use slots. - Add sc_cancel (translates to SCardCancel) - Re-implement sc_wait_for_event; support a blocking call. - Replace the "int reader" API with "* sc_reader_t" style; add "Get reader by name" functionality. - Remove "action" parameter from sc_disconnect_card() (was not used) git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3931 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
0c7d6587be
commit
d006b1845e
|
@ -389,7 +389,7 @@ static int do_single_transmit(sc_card_t *card, sc_apdu_t *apdu)
|
||||||
/* send APDU to the reader driver */
|
/* send APDU to the reader driver */
|
||||||
if (card->reader->ops->transmit == NULL)
|
if (card->reader->ops->transmit == NULL)
|
||||||
return SC_ERROR_NOT_SUPPORTED;
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
r = card->reader->ops->transmit(card->reader, card->slot, apdu);
|
r = card->reader->ops->transmit(card->reader, apdu);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
sc_debug(ctx, "unable to transmit APDU");
|
sc_debug(ctx, "unable to transmit APDU");
|
||||||
return r;
|
return r;
|
||||||
|
@ -414,7 +414,7 @@ static int do_single_transmit(sc_card_t *card, sc_apdu_t *apdu)
|
||||||
if (card->wait_resend_apdu != 0)
|
if (card->wait_resend_apdu != 0)
|
||||||
msleep(card->wait_resend_apdu);
|
msleep(card->wait_resend_apdu);
|
||||||
/* re-transmit the APDU with new Le length */
|
/* re-transmit the APDU with new Le length */
|
||||||
r = card->reader->ops->transmit(card->reader, card->slot, apdu);
|
r = card->reader->ops->transmit(card->reader, apdu);
|
||||||
if (r != SC_SUCCESS) {
|
if (r != SC_SUCCESS) {
|
||||||
sc_debug(ctx, "unable to transmit APDU");
|
sc_debug(ctx, "unable to transmit APDU");
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -282,10 +282,6 @@ static char *pp_msg_pin_mismatch[] = {
|
||||||
"Die von Ihnen eingegebenen PINs unterscheiden sich.\n\nErneut versuchen oder abbrechen?"
|
"Die von Ihnen eingegebenen PINs unterscheiden sich.\n\nErneut versuchen oder abbrechen?"
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pcsc_slot_data {
|
|
||||||
SCARDHANDLE pcsc_card;
|
|
||||||
}; /* comes from reader-pcsc.c */
|
|
||||||
#define GET_SLOT_DATA(r) ((struct pcsc_slot_data *) (r)->drv_data)
|
|
||||||
#define PCSC_ERROR(ctx, desc, rv) sc_debug(ctx, desc ": %lx\n", rv);
|
#define PCSC_ERROR(ctx, desc, rv) sc_debug(ctx, desc ": %lx\n", rv);
|
||||||
|
|
||||||
#endif /* BELPIC_PIN_PAD */
|
#endif /* BELPIC_PIN_PAD */
|
||||||
|
@ -1041,7 +1037,7 @@ static int belpic_init(sc_card_t *card)
|
||||||
#ifdef BELPIC_PIN_PAD
|
#ifdef BELPIC_PIN_PAD
|
||||||
r = belpic_detect_pin_pad(card, priv);
|
r = belpic_detect_pin_pad(card, priv);
|
||||||
if (r == 1)
|
if (r == 1)
|
||||||
card->slot->capabilities |= SC_SLOT_CAP_PIN_PAD;
|
card->reader->capabilities |= SC_READER_CAP_PIN_PAD;
|
||||||
else if (r < 0)
|
else if (r < 0)
|
||||||
return r; /* error loading/initing pin pad lib */
|
return r; /* error loading/initing pin pad lib */
|
||||||
|
|
||||||
|
@ -1303,10 +1299,10 @@ static int belpic_pin_cmd_usage(sc_card_t *card, struct sc_pin_cmd_data *data,
|
||||||
|
|
||||||
struct belpic_priv_data *priv = DRVDATA(card);
|
struct belpic_priv_data *priv = DRVDATA(card);
|
||||||
int lang = belpic_calculate_lang(card);
|
int lang = belpic_calculate_lang(card);
|
||||||
if (card->slot->capabilities & SC_SLOT_CAP_PIN_PAD && priv->scr_init != NULL) {
|
if (card->reader->capabilities & SC_READER_CAP_PIN_PAD && priv->scr_init != NULL) {
|
||||||
LONG r;
|
LONG r;
|
||||||
SCR_Card scr_card = {
|
SCR_Card scr_card = {
|
||||||
GET_SLOT_DATA(card->slot)->pcsc_card,
|
priv->pcsc_card,
|
||||||
lang_codes[lang],
|
lang_codes[lang],
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
,
|
,
|
||||||
|
@ -1385,7 +1381,7 @@ static int belpic_askpin_verify(sc_card_t *card, int pin_usage)
|
||||||
|
|
||||||
#ifdef BELPIC_PIN_PAD
|
#ifdef BELPIC_PIN_PAD
|
||||||
/* In case of a pinpad reader */
|
/* In case of a pinpad reader */
|
||||||
if (card->slot->capabilities & SC_SLOT_CAP_PIN_PAD && priv->scr_init != NULL) {
|
if (card->reader->capabilities & SC_READER_CAP_PIN_PAD && priv->scr_init != NULL) {
|
||||||
data.pin1.data = NULL;
|
data.pin1.data = NULL;
|
||||||
data.pin1.len = 0;
|
data.pin1.len = 0;
|
||||||
|
|
||||||
|
|
|
@ -625,9 +625,7 @@ static int gemsafe_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data,
|
||||||
if (card->reader
|
if (card->reader
|
||||||
&& card->reader->ops
|
&& card->reader->ops
|
||||||
&& card->reader->ops->perform_verify) {
|
&& card->reader->ops->perform_verify) {
|
||||||
r = card->reader->ops->perform_verify(card->reader,
|
r = card->reader->ops->perform_verify(card->reader, data);
|
||||||
card->slot,
|
|
||||||
data);
|
|
||||||
/* sw1/sw2 filled in by reader driver */
|
/* sw1/sw2 filled in by reader driver */
|
||||||
} else {
|
} else {
|
||||||
sc_debug(card->ctx,
|
sc_debug(card->ctx,
|
||||||
|
|
|
@ -114,7 +114,7 @@ gpk_match_card(sc_card_t *card)
|
||||||
|
|
||||||
i = _sc_match_atr(card, gpk_atrs, &card->type);
|
i = _sc_match_atr(card, gpk_atrs, &card->type);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
const u8 *hist_bytes = card->slot->atr_info.hist_bytes;
|
const u8 *hist_bytes = card->reader->atr_info.hist_bytes;
|
||||||
|
|
||||||
/* Gemplus GPK docs say we can use just the
|
/* Gemplus GPK docs say we can use just the
|
||||||
* FMN and PRN fields of the historical bytes
|
* FMN and PRN fields of the historical bytes
|
||||||
|
@ -123,7 +123,7 @@ gpk_match_card(sc_card_t *card)
|
||||||
* We'll use the first 2 bytes as well
|
* We'll use the first 2 bytes as well
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((card->slot->atr_info.hist_bytes_len >= 7)
|
if ((card->reader->atr_info.hist_bytes_len >= 7)
|
||||||
&& (hist_bytes[0] == 0x80)
|
&& (hist_bytes[0] == 0x80)
|
||||||
&& (hist_bytes[1] == 0x65)
|
&& (hist_bytes[1] == 0x65)
|
||||||
&& (hist_bytes[2] == 0xa2)) { /* FMN */
|
&& (hist_bytes[2] == 0xa2)) { /* FMN */
|
||||||
|
|
|
@ -72,8 +72,8 @@ static struct sc_card_driver setcos_drv = {
|
||||||
|
|
||||||
static int match_hist_bytes(sc_card_t *card, const char *str, size_t len)
|
static int match_hist_bytes(sc_card_t *card, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
const char *src = (const char *) card->slot->atr_info.hist_bytes;
|
const char *src = (const char *) card->reader->atr_info.hist_bytes;
|
||||||
size_t srclen = card->slot->atr_info.hist_bytes_len;
|
size_t srclen = card->reader->atr_info.hist_bytes_len;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
|
|
|
@ -792,8 +792,6 @@ static int westcos_pin_cmd(sc_card_t * card, struct sc_pin_cmd_data *data,
|
||||||
&& card->reader->ops->perform_verify) {
|
&& card->reader->ops->perform_verify) {
|
||||||
r = card->reader->ops->perform_verify(card->
|
r = card->reader->ops->perform_verify(card->
|
||||||
reader,
|
reader,
|
||||||
card->
|
|
||||||
slot,
|
|
||||||
data);
|
data);
|
||||||
} else {
|
} else {
|
||||||
r = SC_ERROR_NOT_SUPPORTED;
|
r = SC_ERROR_NOT_SUPPORTED;
|
||||||
|
|
|
@ -96,11 +96,10 @@ static void sc_card_free(sc_card_t *card)
|
||||||
free(card);
|
free(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card_out)
|
int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out)
|
||||||
{
|
{
|
||||||
sc_card_t *card;
|
sc_card_t *card;
|
||||||
sc_context_t *ctx;
|
sc_context_t *ctx;
|
||||||
sc_slot_info_t *slot = _sc_get_slot_info(reader, slot_id);
|
|
||||||
struct sc_card_driver *driver;
|
struct sc_card_driver *driver;
|
||||||
int i, r = 0, idx, connected = 0;
|
int i, r = 0, idx, connected = 0;
|
||||||
|
|
||||||
|
@ -110,29 +109,26 @@ int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card_out)
|
||||||
SC_FUNC_CALLED(ctx, 1);
|
SC_FUNC_CALLED(ctx, 1);
|
||||||
if (reader->ops->connect == NULL)
|
if (reader->ops->connect == NULL)
|
||||||
SC_FUNC_RETURN(ctx, 0, SC_ERROR_NOT_SUPPORTED);
|
SC_FUNC_RETURN(ctx, 0, SC_ERROR_NOT_SUPPORTED);
|
||||||
if (slot == NULL)
|
|
||||||
SC_FUNC_RETURN(ctx, 0, SC_ERROR_SLOT_NOT_FOUND);
|
|
||||||
|
|
||||||
card = sc_card_new(ctx);
|
card = sc_card_new(ctx);
|
||||||
if (card == NULL)
|
if (card == NULL)
|
||||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
|
SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
|
||||||
r = reader->ops->connect(reader, slot);
|
r = reader->ops->connect(reader);
|
||||||
if (r)
|
if (r)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
connected = 1;
|
connected = 1;
|
||||||
card->reader = reader;
|
card->reader = reader;
|
||||||
card->slot = slot;
|
|
||||||
card->ctx = ctx;
|
card->ctx = ctx;
|
||||||
|
|
||||||
/* These can be overridden by the card driver */
|
/* These can be overridden by the card driver */
|
||||||
card->max_send_size = reader->driver->max_send_size;
|
card->max_send_size = reader->driver->max_send_size;
|
||||||
card->max_recv_size = reader->driver->max_recv_size;
|
card->max_recv_size = reader->driver->max_recv_size;
|
||||||
|
|
||||||
memcpy(card->atr, slot->atr, slot->atr_len);
|
memcpy(card->atr, reader->atr, reader->atr_len);
|
||||||
card->atr_len = slot->atr_len;
|
card->atr_len = reader->atr_len;
|
||||||
|
|
||||||
_sc_parse_atr(reader->ctx, slot);
|
_sc_parse_atr(reader);
|
||||||
|
|
||||||
/* See if the ATR matches any ATR specified in the config file */
|
/* See if the ATR matches any ATR specified in the config file */
|
||||||
if ((driver = ctx->forced_driver) == NULL) {
|
if ((driver = ctx->forced_driver) == NULL) {
|
||||||
|
@ -222,13 +218,13 @@ int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card_out)
|
||||||
SC_FUNC_RETURN(ctx, 1, 0);
|
SC_FUNC_RETURN(ctx, 1, 0);
|
||||||
err:
|
err:
|
||||||
if (connected)
|
if (connected)
|
||||||
reader->ops->disconnect(reader, slot);
|
reader->ops->disconnect(reader);
|
||||||
if (card != NULL)
|
if (card != NULL)
|
||||||
sc_card_free(card);
|
sc_card_free(card);
|
||||||
SC_FUNC_RETURN(ctx, 1, r);
|
SC_FUNC_RETURN(ctx, 1, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sc_disconnect_card(sc_card_t *card, int action)
|
int sc_disconnect_card(sc_card_t *card)
|
||||||
{
|
{
|
||||||
sc_context_t *ctx;
|
sc_context_t *ctx;
|
||||||
assert(sc_card_valid(card));
|
assert(sc_card_valid(card));
|
||||||
|
@ -242,7 +238,7 @@ int sc_disconnect_card(sc_card_t *card, int action)
|
||||||
sc_strerror(r));
|
sc_strerror(r));
|
||||||
}
|
}
|
||||||
if (card->reader->ops->disconnect) {
|
if (card->reader->ops->disconnect) {
|
||||||
int r = card->reader->ops->disconnect(card->reader, card->slot);
|
int r = card->reader->ops->disconnect(card->reader);
|
||||||
if (r)
|
if (r)
|
||||||
sc_debug(card->ctx, "disconnect() failed: %s\n",
|
sc_debug(card->ctx, "disconnect() failed: %s\n",
|
||||||
sc_strerror(r));
|
sc_strerror(r));
|
||||||
|
@ -264,7 +260,7 @@ int sc_reset(sc_card_t *card)
|
||||||
if (r != SC_SUCCESS)
|
if (r != SC_SUCCESS)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = card->reader->ops->reset(card->reader, card->slot);
|
r = card->reader->ops->reset(card->reader);
|
||||||
/* invalidate cache */
|
/* invalidate cache */
|
||||||
memset(&card->cache, 0, sizeof(card->cache));
|
memset(&card->cache, 0, sizeof(card->cache));
|
||||||
card->cache_valid = 0;
|
card->cache_valid = 0;
|
||||||
|
@ -291,12 +287,12 @@ int sc_lock(sc_card_t *card)
|
||||||
return r;
|
return r;
|
||||||
if (card->lock_count == 0) {
|
if (card->lock_count == 0) {
|
||||||
if (card->reader->ops->lock != NULL) {
|
if (card->reader->ops->lock != NULL) {
|
||||||
r = card->reader->ops->lock(card->reader, card->slot);
|
r = card->reader->ops->lock(card->reader);
|
||||||
if (r == SC_ERROR_CARD_RESET || r == SC_ERROR_READER_REATTACHED) {
|
if (r == SC_ERROR_CARD_RESET || r == SC_ERROR_READER_REATTACHED) {
|
||||||
/* invalidate cache */
|
/* invalidate cache */
|
||||||
memset(&card->cache, 0, sizeof(card->cache));
|
memset(&card->cache, 0, sizeof(card->cache));
|
||||||
card->cache_valid = 0;
|
card->cache_valid = 0;
|
||||||
r = card->reader->ops->lock(card->reader, card->slot);
|
r = card->reader->ops->lock(card->reader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
|
@ -330,7 +326,7 @@ int sc_unlock(sc_card_t *card)
|
||||||
card->cache_valid = 0;
|
card->cache_valid = 0;
|
||||||
/* release reader lock */
|
/* release reader lock */
|
||||||
if (card->reader->ops->unlock != NULL)
|
if (card->reader->ops->unlock != NULL)
|
||||||
r = card->reader->ops->unlock(card->reader, card->slot);
|
r = card->reader->ops->unlock(card->reader);
|
||||||
}
|
}
|
||||||
r2 = sc_mutex_unlock(card->ctx, card->mutex);
|
r2 = sc_mutex_unlock(card->ctx, card->mutex);
|
||||||
if (r2 != SC_SUCCESS) {
|
if (r2 != SC_SUCCESS) {
|
||||||
|
|
|
@ -77,7 +77,7 @@ ctbcs_build_output_apdu(sc_apdu_t *apdu, const char *message)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data, sc_slot_info_t *slot)
|
ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data)
|
||||||
{
|
{
|
||||||
const char *prompt;
|
const char *prompt;
|
||||||
size_t buflen, count = 0, j = 0, len;
|
size_t buflen, count = 0, j = 0, len;
|
||||||
|
@ -87,7 +87,7 @@ ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *d
|
||||||
ctbcs_init_apdu(apdu,
|
ctbcs_init_apdu(apdu,
|
||||||
SC_APDU_CASE_3_SHORT,
|
SC_APDU_CASE_3_SHORT,
|
||||||
CTBCS_INS_PERFORM_VERIFICATION,
|
CTBCS_INS_PERFORM_VERIFICATION,
|
||||||
CTBCS_P1_INTERFACE1 + (slot ? slot->id : 0),
|
CTBCS_P1_INTERFACE1,
|
||||||
0);
|
0);
|
||||||
|
|
||||||
buflen = sizeof(buf);
|
buflen = sizeof(buf);
|
||||||
|
@ -145,15 +145,14 @@ ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *d
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data, sc_slot_info_t *slot)
|
ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data)
|
||||||
{
|
{
|
||||||
/* to be implemented */
|
/* to be implemented */
|
||||||
return SC_ERROR_NOT_SUPPORTED;
|
return SC_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ctbcs_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot,
|
ctbcs_pin_cmd(sc_reader_t *reader, struct sc_pin_cmd_data *data)
|
||||||
struct sc_pin_cmd_data *data)
|
|
||||||
{
|
{
|
||||||
sc_card_t dummy_card, *card;
|
sc_card_t dummy_card, *card;
|
||||||
sc_apdu_t apdu;
|
sc_apdu_t apdu;
|
||||||
|
@ -162,11 +161,11 @@ ctbcs_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot,
|
||||||
|
|
||||||
switch (data->cmd) {
|
switch (data->cmd) {
|
||||||
case SC_PIN_CMD_VERIFY:
|
case SC_PIN_CMD_VERIFY:
|
||||||
r = ctbcs_build_perform_verification_apdu(&apdu, data, slot);
|
r = ctbcs_build_perform_verification_apdu(&apdu, data);
|
||||||
break;
|
break;
|
||||||
case SC_PIN_CMD_CHANGE:
|
case SC_PIN_CMD_CHANGE:
|
||||||
case SC_PIN_CMD_UNBLOCK:
|
case SC_PIN_CMD_UNBLOCK:
|
||||||
r = ctbcs_build_modify_verification_apdu(&apdu, data, slot);
|
r = ctbcs_build_modify_verification_apdu(&apdu, data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sc_debug(reader->ctx, "Unknown PIN command %d", data->cmd);
|
sc_debug(reader->ctx, "Unknown PIN command %d", data->cmd);
|
||||||
|
@ -176,7 +175,6 @@ ctbcs_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot,
|
||||||
memset(&ops, 0, sizeof(ops));
|
memset(&ops, 0, sizeof(ops));
|
||||||
memset(&dummy_card, 0, sizeof(dummy_card));
|
memset(&dummy_card, 0, sizeof(dummy_card));
|
||||||
dummy_card.reader = reader;
|
dummy_card.reader = reader;
|
||||||
dummy_card.slot = slot;
|
|
||||||
dummy_card.ctx = reader->ctx;
|
dummy_card.ctx = reader->ctx;
|
||||||
r = sc_mutex_create(reader->ctx, &dummy_card.mutex);
|
r = sc_mutex_create(reader->ctx, &dummy_card.mutex);
|
||||||
if (r != SC_SUCCESS)
|
if (r != SC_SUCCESS)
|
||||||
|
|
|
@ -186,6 +186,6 @@
|
||||||
/*
|
/*
|
||||||
* Functions for building CTBCS commands
|
* Functions for building CTBCS commands
|
||||||
*/
|
*/
|
||||||
int ctbcs_pin_cmd(struct sc_reader *, sc_slot_info_t *, struct sc_pin_cmd_data *);
|
int ctbcs_pin_cmd(struct sc_reader *, struct sc_pin_cmd_data *);
|
||||||
|
|
||||||
#endif /* _CTBCS_ */
|
#endif /* _CTBCS_ */
|
||||||
|
|
|
@ -36,10 +36,7 @@ int _sc_add_reader(sc_context_t *ctx, sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
assert(reader != NULL);
|
assert(reader != NULL);
|
||||||
reader->ctx = ctx;
|
reader->ctx = ctx;
|
||||||
if (ctx->reader_count == SC_MAX_READERS)
|
list_append(&ctx->readers, reader);
|
||||||
return SC_ERROR_TOO_MANY_OBJECTS;
|
|
||||||
ctx->reader[ctx->reader_count] = reader;
|
|
||||||
ctx->reader_count++;
|
|
||||||
|
|
||||||
return SC_SUCCESS;
|
return SC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +115,17 @@ struct _sc_ctx_options {
|
||||||
char *forced_card_driver;
|
char *forced_card_driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Simclist helper to locate readers by name */
|
||||||
|
static int reader_list_seeker(const void *el, const void *key) {
|
||||||
|
const struct sc_reader *reader = (struct sc_reader *)el;
|
||||||
|
if ((el == NULL) || (key == NULL))
|
||||||
|
return 0;
|
||||||
|
if (strcmp(reader->name, (char*)key) == 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void del_drvs(struct _sc_ctx_options *opts, int type)
|
static void del_drvs(struct _sc_ctx_options *opts, int type)
|
||||||
{
|
{
|
||||||
struct _sc_driver_entry *lst;
|
struct _sc_driver_entry *lst;
|
||||||
|
@ -658,14 +666,22 @@ int sc_ctx_detect_readers(sc_context_t *ctx)
|
||||||
|
|
||||||
sc_reader_t *sc_ctx_get_reader(sc_context_t *ctx, unsigned int i)
|
sc_reader_t *sc_ctx_get_reader(sc_context_t *ctx, unsigned int i)
|
||||||
{
|
{
|
||||||
if (i >= (unsigned int)ctx->reader_count || i >= SC_MAX_READERS)
|
return list_get_at(&ctx->readers, i);
|
||||||
return NULL;
|
}
|
||||||
return ctx->reader[i];
|
|
||||||
|
sc_reader_t *sc_ctx_get_reader_by_id(sc_context_t *ctx, unsigned int id)
|
||||||
|
{
|
||||||
|
return list_get_at(&ctx->readers, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_reader_t *sc_ctx_get_reader_by_name(sc_context_t *ctx, const char * name)
|
||||||
|
{
|
||||||
|
return list_seek(&ctx->readers, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int sc_ctx_get_reader_count(sc_context_t *ctx)
|
unsigned int sc_ctx_get_reader_count(sc_context_t *ctx)
|
||||||
{
|
{
|
||||||
return (unsigned int)ctx->reader_count;
|
return list_size(&ctx->readers);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sc_establish_context(sc_context_t **ctx_out, const char *app_name)
|
int sc_establish_context(sc_context_t **ctx_out, const char *app_name)
|
||||||
|
@ -703,6 +719,8 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm)
|
||||||
return SC_ERROR_OUT_OF_MEMORY;
|
return SC_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list_init(&ctx->readers);
|
||||||
|
list_attributes_seeker(&ctx->readers, reader_list_seeker);
|
||||||
/* set thread context and create mutex object (if specified) */
|
/* set thread context and create mutex object (if specified) */
|
||||||
if (parm != NULL && parm->thread_ctx != NULL)
|
if (parm != NULL && parm->thread_ctx != NULL)
|
||||||
ctx->thread_ctx = parm->thread_ctx;
|
ctx->thread_ctx = parm->thread_ctx;
|
||||||
|
@ -738,20 +756,51 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm)
|
||||||
return SC_SUCCESS;
|
return SC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Following two are only implemented with internal PC/SC and don't consume a reader object */
|
||||||
|
int sc_cancel(sc_context_t *ctx)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const struct sc_reader_driver *driver;
|
||||||
|
SC_FUNC_CALLED(ctx, 2);
|
||||||
|
for (i = 0; ctx->reader_drivers[i] != NULL; i++) {
|
||||||
|
sc_debug(ctx, "trying %s", ctx->reader_drivers[i]->short_name);
|
||||||
|
driver = ctx->reader_drivers[i];
|
||||||
|
if (driver->ops->cancel != NULL)
|
||||||
|
return driver->ops->cancel(ctx, ctx->reader_drv_data[i]);
|
||||||
|
}
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, int timeout)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const struct sc_reader_driver *driver;
|
||||||
|
SC_FUNC_CALLED(ctx, 2);
|
||||||
|
for (i = 0; ctx->reader_drivers[i] != NULL; i++) {
|
||||||
|
sc_debug(ctx, "trying %s", ctx->reader_drivers[i]->short_name);
|
||||||
|
driver = ctx->reader_drivers[i];
|
||||||
|
if (driver->ops->wait_for_event != NULL)
|
||||||
|
return driver->ops->wait_for_event(ctx, ctx->reader_drv_data[i], event_mask, event_reader, event, timeout);
|
||||||
|
}
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int sc_release_context(sc_context_t *ctx)
|
int sc_release_context(sc_context_t *ctx)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
SC_FUNC_CALLED(ctx, 1);
|
SC_FUNC_CALLED(ctx, 1);
|
||||||
for (i = 0; i < ctx->reader_count; i++) {
|
for (i=0; i<list_size(&ctx->readers); i++) {
|
||||||
sc_reader_t *rdr = ctx->reader[i];
|
sc_reader_t *rdr = (sc_reader_t *) list_get_at(&ctx->readers, i);
|
||||||
|
if (rdr->ops->release != NULL)
|
||||||
if (rdr->ops->release != NULL)
|
rdr->ops->release(rdr);
|
||||||
rdr->ops->release(rdr);
|
free(rdr->name);
|
||||||
free(rdr->name);
|
free(rdr);
|
||||||
free(rdr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; ctx->reader_drivers[i] != NULL; i++) {
|
for (i = 0; ctx->reader_drivers[i] != NULL; i++) {
|
||||||
const struct sc_reader_driver *drv = ctx->reader_drivers[i];
|
const struct sc_reader_driver *drv = ctx->reader_drivers[i];
|
||||||
|
|
||||||
|
@ -783,6 +832,7 @@ int sc_release_context(sc_context_t *ctx)
|
||||||
fclose(ctx->debug_file);
|
fclose(ctx->debug_file);
|
||||||
if (ctx->app_name != NULL)
|
if (ctx->app_name != NULL)
|
||||||
free(ctx->app_name);
|
free(ctx->app_name);
|
||||||
|
list_destroy(&ctx->readers);
|
||||||
sc_mem_clear(ctx, sizeof(*ctx));
|
sc_mem_clear(ctx, sizeof(*ctx));
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return SC_SUCCESS;
|
return SC_SUCCESS;
|
||||||
|
|
|
@ -32,6 +32,7 @@ typedef unsigned __int8 uint8_t;
|
||||||
#define SCARD_STATE_UNAWARE 0x0000 /**< App wants status */
|
#define SCARD_STATE_UNAWARE 0x0000 /**< App wants status */
|
||||||
#define SCARD_STATE_IGNORE 0x0001 /**< Ignore this reader */
|
#define SCARD_STATE_IGNORE 0x0001 /**< Ignore this reader */
|
||||||
#define SCARD_STATE_CHANGED 0x0002 /**< State has changed */
|
#define SCARD_STATE_CHANGED 0x0002 /**< State has changed */
|
||||||
|
#define SCARD_STATE_UNKNOWN 0x0004 /**< Reader unknown */
|
||||||
#define SCARD_STATE_EMPTY 0x0010 /**< Card removed */
|
#define SCARD_STATE_EMPTY 0x0010 /**< Card removed */
|
||||||
#define SCARD_STATE_PRESENT 0x0020 /**< Card inserted */
|
#define SCARD_STATE_PRESENT 0x0020 /**< Card inserted */
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "opensc.h"
|
#include "opensc.h"
|
||||||
|
#include "simclist.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "cards.h"
|
#include "cards.h"
|
||||||
|
@ -68,8 +69,7 @@ struct sc_atr_table {
|
||||||
|
|
||||||
/* Internal use only */
|
/* Internal use only */
|
||||||
int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader);
|
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);
|
int _sc_parse_atr(struct sc_reader *reader);
|
||||||
struct sc_slot_info *_sc_get_slot_info(struct sc_reader *reader, int slot_id);
|
|
||||||
|
|
||||||
/* Add an ATR to the card driver's struct sc_atr_table */
|
/* Add an ATR to the card driver's struct sc_atr_table */
|
||||||
int _sc_add_atr(struct sc_context *ctx, struct sc_card_driver *driver, struct sc_atr_table *src);
|
int _sc_add_atr(struct sc_context *ctx, struct sc_card_driver *driver, struct sc_atr_table *src);
|
||||||
|
|
|
@ -950,9 +950,7 @@ static int iso7816_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
|
||||||
if (card->reader
|
if (card->reader
|
||||||
&& card->reader->ops
|
&& card->reader->ops
|
||||||
&& card->reader->ops->perform_verify) {
|
&& card->reader->ops->perform_verify) {
|
||||||
r = card->reader->ops->perform_verify(card->reader,
|
r = card->reader->ops->perform_verify(card->reader, data);
|
||||||
card->slot,
|
|
||||||
data);
|
|
||||||
/* sw1/sw2 filled in by reader driver */
|
/* sw1/sw2 filled in by reader driver */
|
||||||
} else {
|
} else {
|
||||||
sc_debug(card->ctx,
|
sc_debug(card->ctx,
|
||||||
|
|
|
@ -24,6 +24,7 @@ sc_base64_decode
|
||||||
sc_base64_encode
|
sc_base64_encode
|
||||||
sc_bin_to_hex
|
sc_bin_to_hex
|
||||||
sc_build_pin
|
sc_build_pin
|
||||||
|
sc_cancel
|
||||||
sc_card_ctl
|
sc_card_ctl
|
||||||
sc_card_valid
|
sc_card_valid
|
||||||
sc_change_reference_data
|
sc_change_reference_data
|
||||||
|
@ -39,6 +40,8 @@ sc_copy_asn1_entry
|
||||||
sc_create_file
|
sc_create_file
|
||||||
sc_ctx_detect_readers
|
sc_ctx_detect_readers
|
||||||
sc_ctx_get_reader
|
sc_ctx_get_reader
|
||||||
|
sc_ctx_get_reader_by_id
|
||||||
|
sc_ctx_get_reader_by_name
|
||||||
sc_ctx_get_reader_count
|
sc_ctx_get_reader_count
|
||||||
sc_decipher
|
sc_decipher
|
||||||
sc_delete_file
|
sc_delete_file
|
||||||
|
|
|
@ -94,8 +94,8 @@ void sc_do_log_va(sc_context_t *ctx, int type, const char *file, int line, const
|
||||||
#else
|
#else
|
||||||
gettimeofday (&tv, NULL);
|
gettimeofday (&tv, NULL);
|
||||||
tm = localtime (&tv.tv_sec);
|
tm = localtime (&tv.tv_sec);
|
||||||
strftime (time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", tm);
|
strftime (time_string, sizeof(time_string), "%H:%M:%S", tm);
|
||||||
r = snprintf(p, left, "%s.%03ld ", time_string, tv.tv_usec / 1000);
|
r = snprintf(p, left, "0x%lx %s.%03ld ", (unsigned long)pthread_self(), time_string, tv.tv_usec / 1000);
|
||||||
#endif
|
#endif
|
||||||
p += r;
|
p += r;
|
||||||
left -= r;
|
left -= r;
|
||||||
|
|
|
@ -123,7 +123,6 @@ extern "C" {
|
||||||
#define SC_MAX_READERS 16
|
#define SC_MAX_READERS 16
|
||||||
#define SC_MAX_CARD_DRIVERS 32
|
#define SC_MAX_CARD_DRIVERS 32
|
||||||
#define SC_MAX_CARD_DRIVER_SNAME_SIZE 16
|
#define SC_MAX_CARD_DRIVER_SNAME_SIZE 16
|
||||||
#define SC_MAX_SLOTS 4
|
|
||||||
#define SC_MAX_CARD_APPS 8
|
#define SC_MAX_CARD_APPS 8
|
||||||
#define SC_MAX_APDU_BUFFER_SIZE 258
|
#define SC_MAX_APDU_BUFFER_SIZE 258
|
||||||
#define SC_MAX_EXT_APDU_BUFFER_SIZE 65538
|
#define SC_MAX_EXT_APDU_BUFFER_SIZE 65538
|
||||||
|
@ -206,6 +205,7 @@ extern "C" {
|
||||||
/* Event masks for sc_wait_for_event() */
|
/* Event masks for sc_wait_for_event() */
|
||||||
#define SC_EVENT_CARD_INSERTED 0x0001
|
#define SC_EVENT_CARD_INSERTED 0x0001
|
||||||
#define SC_EVENT_CARD_REMOVED 0x0002
|
#define SC_EVENT_CARD_REMOVED 0x0002
|
||||||
|
#define SC_EVENT_READER_ATTACHED 0x0004
|
||||||
|
|
||||||
typedef struct sc_security_env {
|
typedef struct sc_security_env {
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -279,15 +279,20 @@ struct sc_reader_driver {
|
||||||
void *dll;
|
void *dll;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* slot flags */
|
/* reader flags */
|
||||||
#define SC_SLOT_CARD_PRESENT 0x00000001
|
#define SC_READER_CARD_PRESENT 0x00000001
|
||||||
#define SC_SLOT_CARD_CHANGED 0x00000002
|
#define SC_READER_CARD_CHANGED 0x00000002
|
||||||
/* slot capabilities */
|
/* reader capabilities */
|
||||||
#define SC_SLOT_CAP_DISPLAY 0x00000001
|
#define SC_READER_CAP_DISPLAY 0x00000001
|
||||||
#define SC_SLOT_CAP_PIN_PAD 0x00000002
|
#define SC_READER_CAP_PIN_PAD 0x00000002
|
||||||
|
|
||||||
typedef struct sc_slot_info {
|
typedef struct sc_reader {
|
||||||
int id;
|
struct sc_context *ctx;
|
||||||
|
const struct sc_reader_driver *driver;
|
||||||
|
const struct sc_reader_operations *ops;
|
||||||
|
void *drv_data;
|
||||||
|
char *name;
|
||||||
|
|
||||||
unsigned long flags, capabilities;
|
unsigned long flags, capabilities;
|
||||||
unsigned int supported_protocols, active_protocol;
|
unsigned int supported_protocols, active_protocol;
|
||||||
u8 atr[SC_MAX_ATR_SIZE];
|
u8 atr[SC_MAX_ATR_SIZE];
|
||||||
|
@ -299,24 +304,6 @@ typedef struct sc_slot_info {
|
||||||
int Fi, f, Di, N;
|
int Fi, f, Di, N;
|
||||||
u8 FI, DI;
|
u8 FI, DI;
|
||||||
} atr_info;
|
} atr_info;
|
||||||
|
|
||||||
void *drv_data;
|
|
||||||
} sc_slot_info_t;
|
|
||||||
|
|
||||||
struct sc_event_listener {
|
|
||||||
unsigned int event_mask;
|
|
||||||
void (*func)(void *, const struct sc_slot_info *, unsigned int event);
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct sc_reader {
|
|
||||||
struct sc_context *ctx;
|
|
||||||
const struct sc_reader_driver *driver;
|
|
||||||
const struct sc_reader_operations *ops;
|
|
||||||
void *drv_data;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
struct sc_slot_info slot[SC_MAX_SLOTS];
|
|
||||||
int slot_count;
|
|
||||||
} sc_reader_t;
|
} sc_reader_t;
|
||||||
|
|
||||||
/* This will be the new interface for handling PIN commands.
|
/* This will be the new interface for handling PIN commands.
|
||||||
|
@ -370,12 +357,6 @@ typedef struct sc_serial_number {
|
||||||
size_t len;
|
size_t len;
|
||||||
} sc_serial_number_t;
|
} sc_serial_number_t;
|
||||||
|
|
||||||
/* these flags are deprecated and shouldn't be used anymore */
|
|
||||||
#define SC_DISCONNECT 0
|
|
||||||
#define SC_DISCONNECT_AND_RESET 1
|
|
||||||
#define SC_DISCONNECT_AND_UNPOWER 2
|
|
||||||
#define SC_DISCONNECT_AND_EJECT 3
|
|
||||||
|
|
||||||
struct sc_reader_operations {
|
struct sc_reader_operations {
|
||||||
/* Called during sc_establish_context(), when the driver
|
/* Called during sc_establish_context(), when the driver
|
||||||
* is loaded */
|
* is loaded */
|
||||||
|
@ -386,36 +367,27 @@ struct sc_reader_operations {
|
||||||
/* Called when library wish to detect new readers
|
/* Called when library wish to detect new readers
|
||||||
* should add only new readers. */
|
* should add only new readers. */
|
||||||
int (*detect_readers)(struct sc_context *ctx, void *priv_data);
|
int (*detect_readers)(struct sc_context *ctx, void *priv_data);
|
||||||
|
int (*cancel)(struct sc_context *ctx, void *priv_data);
|
||||||
/* Called when releasing a reader. release() has to
|
/* Called when releasing a reader. release() has to
|
||||||
* deallocate the private data. Other fields will be
|
* deallocate the private data. Other fields will be
|
||||||
* freed by OpenSC. */
|
* freed by OpenSC. */
|
||||||
int (*release)(struct sc_reader *reader);
|
int (*release)(struct sc_reader *reader);
|
||||||
|
|
||||||
int (*detect_card_presence)(struct sc_reader *reader,
|
int (*detect_card_presence)(struct sc_reader *reader);
|
||||||
struct sc_slot_info *slot);
|
int (*connect)(struct sc_reader *reader);
|
||||||
int (*connect)(struct sc_reader *reader, struct sc_slot_info *slot);
|
int (*disconnect)(struct sc_reader *reader);
|
||||||
int (*disconnect)(struct sc_reader *reader, struct sc_slot_info *slot);
|
int (*transmit)(struct sc_reader *reader, sc_apdu_t *apdu);
|
||||||
int (*transmit)(struct sc_reader *reader, struct sc_slot_info *slot,
|
int (*lock)(struct sc_reader *reader);
|
||||||
sc_apdu_t *apdu);
|
int (*unlock)(struct sc_reader *reader);
|
||||||
int (*lock)(struct sc_reader *reader, struct sc_slot_info *slot);
|
int (*set_protocol)(struct sc_reader *reader, unsigned int proto);
|
||||||
int (*unlock)(struct sc_reader *reader, struct sc_slot_info *slot);
|
|
||||||
int (*set_protocol)(struct sc_reader *reader, struct sc_slot_info *slot,
|
|
||||||
unsigned int proto);
|
|
||||||
/* Pin pad functions */
|
/* Pin pad functions */
|
||||||
int (*display_message)(struct sc_reader *, struct sc_slot_info *,
|
int (*display_message)(struct sc_reader *, const char *);
|
||||||
const char *);
|
int (*perform_verify)(struct sc_reader *, struct sc_pin_cmd_data *);
|
||||||
int (*perform_verify)(struct sc_reader *, struct sc_slot_info *,
|
|
||||||
struct sc_pin_cmd_data *);
|
|
||||||
|
|
||||||
/* Wait for an event */
|
/* Wait for an event */
|
||||||
int (*wait_for_event)(struct sc_reader **readers,
|
int (*wait_for_event)(struct sc_context *ctx, void *priv_data, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, int timeout);
|
||||||
struct sc_slot_info **slots,
|
/* Reset a reader */
|
||||||
size_t nslots,
|
int (*reset)(struct sc_reader *);
|
||||||
unsigned int event_mask,
|
|
||||||
int *reader_index,
|
|
||||||
unsigned int *event,
|
|
||||||
int timeout);
|
|
||||||
int (*reset)(struct sc_reader *, struct sc_slot_info *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -472,7 +444,6 @@ struct sc_reader_operations {
|
||||||
typedef struct sc_card {
|
typedef struct sc_card {
|
||||||
struct sc_context *ctx;
|
struct sc_context *ctx;
|
||||||
struct sc_reader *reader;
|
struct sc_reader *reader;
|
||||||
struct sc_slot_info *slot;
|
|
||||||
|
|
||||||
int type; /* Card type, for card driver internal use */
|
int type; /* Card type, for card driver internal use */
|
||||||
unsigned long caps, flags;
|
unsigned long caps, flags;
|
||||||
|
@ -663,13 +634,12 @@ typedef struct sc_context {
|
||||||
FILE *debug_file;
|
FILE *debug_file;
|
||||||
char *preferred_language;
|
char *preferred_language;
|
||||||
|
|
||||||
|
list_t readers;
|
||||||
|
|
||||||
const struct sc_reader_driver *reader_drivers[SC_MAX_READER_DRIVERS];
|
const struct sc_reader_driver *reader_drivers[SC_MAX_READER_DRIVERS];
|
||||||
void *reader_drv_data[SC_MAX_READER_DRIVERS];
|
void *reader_drv_data[SC_MAX_READER_DRIVERS];
|
||||||
|
|
||||||
struct sc_reader *reader[SC_MAX_READERS];
|
struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS];
|
||||||
int reader_count;
|
|
||||||
|
|
||||||
struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS];
|
|
||||||
struct sc_card_driver *forced_driver;
|
struct sc_card_driver *forced_driver;
|
||||||
|
|
||||||
sc_thread_context_t *thread_ctx;
|
sc_thread_context_t *thread_ctx;
|
||||||
|
@ -755,6 +725,16 @@ int sc_ctx_detect_readers(sc_context_t *ctx);
|
||||||
*/
|
*/
|
||||||
sc_reader_t *sc_ctx_get_reader(sc_context_t *ctx, unsigned int i);
|
sc_reader_t *sc_ctx_get_reader(sc_context_t *ctx, unsigned int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the specified sc_reader_t object
|
||||||
|
* @param ctx OpenSC context
|
||||||
|
* @param name name of the reader to look for
|
||||||
|
* @return the requested sc_reader object or NULL if the reader is
|
||||||
|
* not available
|
||||||
|
*/
|
||||||
|
sc_reader_t *sc_ctx_get_reader_by_name(sc_context_t *ctx, const char *name);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number a available sc_reader objects
|
* Returns the number a available sc_reader objects
|
||||||
* @param ctx OpenSC context
|
* @param ctx OpenSC context
|
||||||
|
@ -772,18 +752,16 @@ int sc_set_card_driver(sc_context_t *ctx, const char *short_name);
|
||||||
* Connects to a card in a reader and auto-detects the card driver.
|
* Connects to a card in a reader and auto-detects the card driver.
|
||||||
* The ATR (Answer to Reset) string of the card is also retrieved.
|
* The ATR (Answer to Reset) string of the card is also retrieved.
|
||||||
* @param reader Reader structure
|
* @param reader Reader structure
|
||||||
* @param slot_id Slot ID to connect to
|
|
||||||
* @param card The allocated card object will go here */
|
* @param card The allocated card object will go here */
|
||||||
int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card);
|
int sc_connect_card(sc_reader_t *reader, sc_card_t **card);
|
||||||
/**
|
/**
|
||||||
* Disconnects from a card, and frees the card structure. Any locks
|
* Disconnects from a card, and frees the card structure. Any locks
|
||||||
* made by the application must be released before calling this function.
|
* made by the application must be released before calling this function.
|
||||||
* NOTE: The card is not reset nor powered down after the operation.
|
* NOTE: The card is not reset nor powered down after the operation.
|
||||||
* @param card The card to disconnect
|
* @param card The card to disconnect
|
||||||
* @param flag currently not used (should be set to 0)
|
|
||||||
* @return SC_SUCCESS on success and an error code otherwise
|
* @return SC_SUCCESS on success and an error code otherwise
|
||||||
*/
|
*/
|
||||||
int sc_disconnect_card(sc_card_t *card, int flag);
|
int sc_disconnect_card(sc_card_t *card);
|
||||||
/**
|
/**
|
||||||
* Returns 1 if the magic value of the card object is correct. Mostly
|
* Returns 1 if the magic value of the card object is correct. Mostly
|
||||||
* used internally by the library.
|
* used internally by the library.
|
||||||
|
@ -794,27 +772,26 @@ int sc_card_valid(const sc_card_t *card);
|
||||||
/**
|
/**
|
||||||
* Checks if a card is present in a reader
|
* Checks if a card is present in a reader
|
||||||
* @param reader Reader structure
|
* @param reader Reader structure
|
||||||
* @param slot_id Slot ID
|
|
||||||
* @retval If an error occured, the return value is a (negative)
|
* @retval If an error occured, the return value is a (negative)
|
||||||
* OpenSC error code. If no card is present, 0 is returned.
|
* OpenSC error code. If no card is present, 0 is returned.
|
||||||
* Otherwise, a positive value is returned, which is a
|
* Otherwise, a positive value is returned, which is a
|
||||||
* combination of flags. The flag SC_SLOT_CARD_PRESENT is
|
* combination of flags. The flag SC_READER_CARD_PRESENT is
|
||||||
* always set. In addition, if the card was exchanged,
|
* always set. In addition, if the card was exchanged,
|
||||||
* the SC_SLOT_CARD_CHANGED flag is set.
|
* the SC_READER_CARD_CHANGED flag is set.
|
||||||
*/
|
*/
|
||||||
int sc_detect_card_presence(sc_reader_t *reader, int slot_id);
|
int sc_detect_card_presence(sc_reader_t *reader);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for an event on readers. Note: only the event is detected,
|
* Waits for an event on readers. Note: only the event is detected,
|
||||||
* there is no update of any card or other info.
|
* there is no update of any card or other info.
|
||||||
* @param readers array of pointer to a Reader structure
|
* NOTE: Only PC/SC backend implements this.
|
||||||
* @param reader_count amount of readers in the array
|
* @param ctx pointer to a Context structure
|
||||||
* @param slot_id Slot ID
|
|
||||||
* @param event_mask The types of events to wait for; this should
|
* @param event_mask The types of events to wait for; this should
|
||||||
* be ORed from one of the following
|
* be ORed from one of the following
|
||||||
* SC_EVENT_CARD_REMOVED
|
* SC_EVENT_CARD_REMOVED
|
||||||
* SC_EVENT_CARD_INSERTED
|
* SC_EVENT_CARD_INSERTED
|
||||||
* @param reader (OUT) the reader on which the event was detected
|
* SC_EVENT_READER_ATTACHED
|
||||||
|
* @param event_reader (OUT) the reader on which the event was detected, or NULL if new reader
|
||||||
* @param event (OUT) the events that occurred. This is also ORed
|
* @param event (OUT) the events that occurred. This is also ORed
|
||||||
* from the SC_EVENT_CARD_* constants listed above.
|
* from the SC_EVENT_CARD_* constants listed above.
|
||||||
* @param timeout Amount of millisecs to wait; -1 means forever
|
* @param timeout Amount of millisecs to wait; -1 means forever
|
||||||
|
@ -822,9 +799,8 @@ int sc_detect_card_presence(sc_reader_t *reader, int slot_id);
|
||||||
* @retval = 0 if a an event happened
|
* @retval = 0 if a an event happened
|
||||||
* @retval = 1 if the timeout occured
|
* @retval = 1 if the timeout occured
|
||||||
*/
|
*/
|
||||||
int sc_wait_for_event(sc_reader_t **readers, int *slots, size_t nslots,
|
int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask,
|
||||||
unsigned int event_mask,
|
sc_reader_t **event_reader, unsigned int *event, int timeout);
|
||||||
int *reader, unsigned int *event, int timeout);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the card.
|
* Resets the card.
|
||||||
|
@ -834,6 +810,14 @@ int sc_wait_for_event(sc_reader_t **readers, int *slots, size_t nslots,
|
||||||
*/
|
*/
|
||||||
int sc_reset(sc_card_t *card);
|
int sc_reset(sc_card_t *card);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel all pending PC/SC calls
|
||||||
|
* NOTE: only PC/SC backend implements this function.
|
||||||
|
* @param ctx pointer to application context
|
||||||
|
* @retval SC_SUCCESS on success
|
||||||
|
*/
|
||||||
|
int sc_cancel(sc_context_t *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries acquire the reader lock.
|
* Tries acquire the reader lock.
|
||||||
* @param card The card to lock
|
* @param card The card to lock
|
||||||
|
|
|
@ -184,7 +184,7 @@ static int _validate_pin(struct sc_pkcs15_card *p15card,
|
||||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
/* if we use pinpad, no more checks are needed */
|
/* if we use pinpad, no more checks are needed */
|
||||||
if (p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD)
|
if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD)
|
||||||
return SC_SUCCESS;
|
return SC_SUCCESS;
|
||||||
|
|
||||||
/* If pin is given, make sure it is within limits */
|
/* If pin is given, make sure it is within limits */
|
||||||
|
@ -252,7 +252,7 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
|
||||||
data.pin1.encoding = 0;
|
data.pin1.encoding = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) {
|
if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
|
||||||
data.flags |= SC_PIN_CMD_USE_PINPAD;
|
data.flags |= SC_PIN_CMD_USE_PINPAD;
|
||||||
if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
|
if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
|
||||||
data.pin1.prompt = "Please enter SO PIN";
|
data.pin1.prompt = "Please enter SO PIN";
|
||||||
|
@ -329,7 +329,7 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
|
||||||
}
|
}
|
||||||
|
|
||||||
if((!oldpin || !newpin)
|
if((!oldpin || !newpin)
|
||||||
&& p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) {
|
&& p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
|
||||||
data.flags |= SC_PIN_CMD_USE_PINPAD;
|
data.flags |= SC_PIN_CMD_USE_PINPAD;
|
||||||
if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||||
data.pin1.prompt = "Please enter SO PIN";
|
data.pin1.prompt = "Please enter SO PIN";
|
||||||
|
@ -439,7 +439,7 @@ int sc_pkcs15_unblock_pin(struct sc_pkcs15_card *p15card,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) {
|
if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
|
||||||
data.flags |= SC_PIN_CMD_USE_PINPAD;
|
data.flags |= SC_PIN_CMD_USE_PINPAD;
|
||||||
if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
|
||||||
data.pin1.prompt = "Please enter PUK";
|
data.pin1.prompt = "Please enter PUK";
|
||||||
|
@ -524,7 +524,7 @@ int sc_pkcs15_pincache_revalidate(struct sc_pkcs15_card *p15card, const sc_pkcs1
|
||||||
if (obj->user_consent)
|
if (obj->user_consent)
|
||||||
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
||||||
|
|
||||||
if (p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD)
|
if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD)
|
||||||
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
||||||
|
|
||||||
r = sc_pkcs15_find_pin_by_auth_id(p15card, &obj->auth_id, &pin_obj);
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &obj->auth_id, &pin_obj);
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include <ltdl.h>
|
#include <ltdl.h>
|
||||||
|
|
||||||
#define GET_PRIV_DATA(r) ((struct ctapi_private_data *) (r)->drv_data)
|
#define GET_PRIV_DATA(r) ((struct ctapi_private_data *) (r)->drv_data)
|
||||||
#define GET_SLOT_DATA(r) ((struct ctapi_slot_data *) (r)->drv_data)
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
typedef char pascal CT_INIT_TYPE(unsigned short ctn, unsigned short Pn);
|
typedef char pascal CT_INIT_TYPE(unsigned short ctn, unsigned short Pn);
|
||||||
|
@ -72,14 +71,11 @@ struct ctapi_private_data {
|
||||||
struct ctapi_functions funcs;
|
struct ctapi_functions funcs;
|
||||||
unsigned short ctn;
|
unsigned short ctn;
|
||||||
int ctapi_functional_units;
|
int ctapi_functional_units;
|
||||||
|
int slot;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ctapi_slot_data {
|
/* Reset reader */
|
||||||
void *filler;
|
static int ctapi_reset(sc_reader_t *reader)
|
||||||
};
|
|
||||||
|
|
||||||
/* Reset slot or reader */
|
|
||||||
static int ctapi_reset(sc_reader_t *reader, sc_slot_info_t *slot)
|
|
||||||
{
|
{
|
||||||
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
|
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
|
||||||
char rv;
|
char rv;
|
||||||
|
@ -88,7 +84,7 @@ static int ctapi_reset(sc_reader_t *reader, sc_slot_info_t *slot)
|
||||||
|
|
||||||
cmd[0] = CTBCS_CLA;
|
cmd[0] = CTBCS_CLA;
|
||||||
cmd[1] = CTBCS_INS_RESET;
|
cmd[1] = CTBCS_INS_RESET;
|
||||||
cmd[2] = slot ? CTBCS_P1_INTERFACE1 + slot->id : CTBCS_P1_CT_KERNEL;
|
cmd[2] = priv->slot ? CTBCS_P1_INTERFACE1 + priv->slot : CTBCS_P1_CT_KERNEL;
|
||||||
cmd[3] = 0x00; /* No response. We might also use 0x01 (return ATR) or 0x02 (return historical bytes) here */
|
cmd[3] = 0x00; /* No response. We might also use 0x01 (return ATR) or 0x02 (return historical bytes) here */
|
||||||
cmd[4] = 0x00;
|
cmd[4] = 0x00;
|
||||||
dad = 1;
|
dad = 1;
|
||||||
|
@ -107,138 +103,8 @@ static int ctapi_reset(sc_reader_t *reader, sc_slot_info_t *slot)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_default_fu(sc_reader_t *reader)
|
|
||||||
{
|
|
||||||
if (!reader) return;
|
|
||||||
|
|
||||||
reader->slot_count = 1;
|
static int refresh_attributes(sc_reader_t *reader)
|
||||||
reader->slot[0].id = 0;
|
|
||||||
reader->slot[0].capabilities = 0;
|
|
||||||
reader->slot[0].atr_len = 0;
|
|
||||||
reader->slot[0].drv_data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detect functional units of the reader according to CT-BCS spec version 1.0
|
|
||||||
(14.04.2004, http://www.teletrust.de/down/mct1-0_t4.zip) */
|
|
||||||
static void detect_functional_units(sc_reader_t *reader)
|
|
||||||
{
|
|
||||||
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
|
|
||||||
char rv;
|
|
||||||
u8 cmd[5], rbuf[256], sad, dad;
|
|
||||||
unsigned short lr;
|
|
||||||
int NumUnits;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
priv->ctapi_functional_units = 0;
|
|
||||||
|
|
||||||
cmd[0] = CTBCS_CLA;
|
|
||||||
cmd[1] = CTBCS_INS_STATUS;
|
|
||||||
cmd[2] = CTBCS_P1_CT_KERNEL;
|
|
||||||
cmd[3] = CTBCS_P2_STATUS_TFU;
|
|
||||||
cmd[4] = 0x00;
|
|
||||||
dad = 1;
|
|
||||||
sad = 2;
|
|
||||||
lr = 256;
|
|
||||||
|
|
||||||
rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf);
|
|
||||||
if (rv || (lr < 4) || (rbuf[lr-2] != 0x90)) {
|
|
||||||
sc_debug(reader->ctx, "Error getting status of terminal: %d, using defaults\n", rv);
|
|
||||||
set_default_fu(reader);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rbuf[0] != CTBCS_P2_STATUS_TFU) {
|
|
||||||
/* Number of slots might also detected by using CTBCS_P2_STATUS_ICC.
|
|
||||||
If you think that's important please do it... ;) */
|
|
||||||
set_default_fu(reader);
|
|
||||||
sc_debug(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_TFU: 0x%x\n", rbuf[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NumUnits = rbuf[1];
|
|
||||||
if (NumUnits + 4 > lr) {
|
|
||||||
set_default_fu(reader);
|
|
||||||
sc_debug(reader->ctx, "Invalid data returnd: %d functional units, size %d\n", NumUnits, rv);
|
|
||||||
set_default_fu(reader);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
reader->slot_count = 0;
|
|
||||||
for(i = 0; i < NumUnits; i++) {
|
|
||||||
switch(rbuf[i+2])
|
|
||||||
{
|
|
||||||
case CTBCS_P1_INTERFACE1:
|
|
||||||
case CTBCS_P1_INTERFACE2:
|
|
||||||
case CTBCS_P1_INTERFACE3:
|
|
||||||
case CTBCS_P1_INTERFACE4:
|
|
||||||
case CTBCS_P1_INTERFACE5:
|
|
||||||
case CTBCS_P1_INTERFACE6:
|
|
||||||
case CTBCS_P1_INTERFACE7:
|
|
||||||
case CTBCS_P1_INTERFACE8:
|
|
||||||
case CTBCS_P1_INTERFACE9:
|
|
||||||
case CTBCS_P1_INTERFACE10:
|
|
||||||
case CTBCS_P1_INTERFACE11:
|
|
||||||
case CTBCS_P1_INTERFACE12:
|
|
||||||
case CTBCS_P1_INTERFACE13:
|
|
||||||
case CTBCS_P1_INTERFACE14:
|
|
||||||
/* Maybe a weak point here if multiple interfaces are present and not returned
|
|
||||||
in the "canonical" order. This is not forbidden by the specs, but why should
|
|
||||||
anyone want to do that? */
|
|
||||||
if (reader->slot_count >= SC_MAX_SLOTS) {
|
|
||||||
sc_debug(reader->ctx, "Ignoring slot id 0x%x, can only handle %d slots\n", rbuf[i+2], SC_MAX_SLOTS);
|
|
||||||
} else {
|
|
||||||
reader->slot[reader->slot_count].id = reader->slot_count;
|
|
||||||
reader->slot[reader->slot_count].capabilities = 0; /* Just to start with */
|
|
||||||
reader->slot[reader->slot_count].atr_len = 0;
|
|
||||||
reader->slot[reader->slot_count].drv_data = NULL;
|
|
||||||
reader->slot_count++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CTBCS_P1_DISPLAY:
|
|
||||||
priv->ctapi_functional_units |= CTAPI_FU_DISPLAY;
|
|
||||||
sc_debug(reader->ctx, "Display detected\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CTBCS_P1_KEYPAD:
|
|
||||||
priv->ctapi_functional_units |= CTAPI_FU_KEYBOARD;
|
|
||||||
sc_debug(reader->ctx, "Keypad detected\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CTBCS_P1_PRINTER:
|
|
||||||
priv->ctapi_functional_units |= CTAPI_FU_PRINTER;
|
|
||||||
sc_debug(reader->ctx, "Printer detected\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CTBCS_P1_FINGERPRINT:
|
|
||||||
case CTBCS_P1_VOICEPRINT:
|
|
||||||
case CTBCS_P1_DSV:
|
|
||||||
case CTBCS_P1_FACE_RECOGNITION:
|
|
||||||
case CTBCS_P1_IRISSCAN:
|
|
||||||
priv->ctapi_functional_units |= CTAPI_FU_BIOMETRIC;
|
|
||||||
sc_debug(reader->ctx, "Biometric sensor detected\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sc_debug(reader->ctx, "Unknown functional unit 0x%x\n", rbuf[i+2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (reader->slot_count == 0) {
|
|
||||||
sc_debug(reader->ctx, "No slots returned, assuming one default slot\n");
|
|
||||||
set_default_fu(reader);
|
|
||||||
}
|
|
||||||
/* CT-BCS does not define Keyboard/Display for each slot, so I assume
|
|
||||||
those additional units can be used for each slot */
|
|
||||||
if (priv->ctapi_functional_units) {
|
|
||||||
for(i = 0; i < reader->slot_count; i++) {
|
|
||||||
if (priv->ctapi_functional_units & CTAPI_FU_KEYBOARD)
|
|
||||||
reader->slot[i].capabilities |= SC_SLOT_CAP_PIN_PAD;
|
|
||||||
if (priv->ctapi_functional_units & CTAPI_FU_DISPLAY)
|
|
||||||
reader->slot[i].capabilities |= SC_SLOT_CAP_DISPLAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int refresh_slot_attributes(sc_reader_t *reader,
|
|
||||||
sc_slot_info_t *slot)
|
|
||||||
{
|
{
|
||||||
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
|
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
|
||||||
char rv;
|
char rv;
|
||||||
|
@ -254,7 +120,7 @@ static int refresh_slot_attributes(sc_reader_t *reader,
|
||||||
sad = 2;
|
sad = 2;
|
||||||
lr = 256;
|
lr = 256;
|
||||||
|
|
||||||
slot->flags = 0;
|
reader->flags = 0;
|
||||||
|
|
||||||
rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf);
|
rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf);
|
||||||
if (rv || (lr < 3) || (rbuf[lr-2] != 0x90)) {
|
if (rv || (lr < 3) || (rbuf[lr-2] != 0x90)) {
|
||||||
|
@ -262,31 +128,23 @@ static int refresh_slot_attributes(sc_reader_t *reader,
|
||||||
return SC_ERROR_TRANSMIT_FAILED;
|
return SC_ERROR_TRANSMIT_FAILED;
|
||||||
}
|
}
|
||||||
if (lr < 4) {
|
if (lr < 4) {
|
||||||
/* Looks like older readers do not return data tag and length field, so assume one slot only */
|
|
||||||
if (slot->id > 0) {
|
|
||||||
sc_debug(reader->ctx, "Status for slot id %d not returned, have only 1\n", slot->id);
|
|
||||||
return SC_ERROR_SLOT_NOT_FOUND;
|
|
||||||
}
|
|
||||||
if (rbuf[0] & CTBCS_DATA_STATUS_CARD)
|
if (rbuf[0] & CTBCS_DATA_STATUS_CARD)
|
||||||
slot->flags = SC_SLOT_CARD_PRESENT;
|
reader->flags = SC_READER_CARD_PRESENT;
|
||||||
} else {
|
} else {
|
||||||
if (rbuf[0] != CTBCS_P2_STATUS_ICC) {
|
if (rbuf[0] != CTBCS_P2_STATUS_ICC) {
|
||||||
/* Should we be more tolerant here? I do not think so... */
|
/* Should we be more tolerant here? I do not think so... */
|
||||||
sc_debug(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_ICC: 0x%x\n", rbuf[0]);
|
sc_debug(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_ICC: 0x%x\n", rbuf[0]);
|
||||||
return SC_ERROR_TRANSMIT_FAILED;
|
return SC_ERROR_TRANSMIT_FAILED;
|
||||||
}
|
|
||||||
if (rbuf[1] <= slot->id) {
|
|
||||||
sc_debug(reader->ctx, "Status for slot id %d not returned, only %d\n", slot->id, rbuf[1]);
|
|
||||||
return SC_ERROR_SLOT_NOT_FOUND;
|
|
||||||
}
|
}
|
||||||
if (rbuf[2+slot->id] & CTBCS_DATA_STATUS_CARD)
|
/* Fixme - should not be reached */
|
||||||
slot->flags = SC_SLOT_CARD_PRESENT;
|
sc_debug(reader->ctx, "Returned status for %d slots\n", rbuf[1]);
|
||||||
|
reader->flags = SC_READER_CARD_PRESENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctapi_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
|
static int ctapi_internal_transmit(sc_reader_t *reader,
|
||||||
const u8 *sendbuf, size_t sendsize,
|
const u8 *sendbuf, size_t sendsize,
|
||||||
u8 *recvbuf, size_t *recvsize,
|
u8 *recvbuf, size_t *recvsize,
|
||||||
unsigned long control)
|
unsigned long control)
|
||||||
|
@ -298,10 +156,9 @@ static int ctapi_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
|
||||||
|
|
||||||
if (control)
|
if (control)
|
||||||
dad = 1;
|
dad = 1;
|
||||||
else if (!slot || slot->id == 0)
|
|
||||||
dad = 0;
|
|
||||||
else
|
else
|
||||||
dad = slot->id + 1; /* Adressing of multiple slots, according to CT API 1.0 */
|
dad = 0;
|
||||||
|
|
||||||
sad = 2;
|
sad = 2;
|
||||||
lr = *recvsize;
|
lr = *recvsize;
|
||||||
|
|
||||||
|
@ -315,8 +172,7 @@ static int ctapi_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctapi_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
|
static int ctapi_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
|
||||||
sc_apdu_t *apdu)
|
|
||||||
{
|
{
|
||||||
size_t ssize, rsize, rbuflen = 0;
|
size_t ssize, rsize, rbuflen = 0;
|
||||||
u8 *sbuf = NULL, *rbuf = NULL;
|
u8 *sbuf = NULL, *rbuf = NULL;
|
||||||
|
@ -334,7 +190,7 @@ static int ctapi_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
|
||||||
goto out;
|
goto out;
|
||||||
if (reader->ctx->debug >= 6)
|
if (reader->ctx->debug >= 6)
|
||||||
sc_apdu_log(reader->ctx, sbuf, ssize, 1);
|
sc_apdu_log(reader->ctx, sbuf, ssize, 1);
|
||||||
r = ctapi_internal_transmit(reader, slot, sbuf, ssize,
|
r = ctapi_internal_transmit(reader, sbuf, ssize,
|
||||||
rbuf, &rsize, apdu->control);
|
rbuf, &rsize, apdu->control);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
/* unable to transmit ... most likely a reader problem */
|
/* unable to transmit ... most likely a reader problem */
|
||||||
|
@ -358,17 +214,17 @@ out:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctapi_detect_card_presence(sc_reader_t *reader, sc_slot_info_t *slot)
|
static int ctapi_detect_card_presence(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = refresh_slot_attributes(reader, slot);
|
r = refresh_attributes(reader);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
return slot->flags;
|
return reader->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctapi_connect(sc_reader_t *reader, sc_slot_info_t *slot)
|
static int ctapi_connect(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
|
struct ctapi_private_data *priv = GET_PRIV_DATA(reader);
|
||||||
char rv;
|
char rv;
|
||||||
|
@ -378,7 +234,7 @@ static int ctapi_connect(sc_reader_t *reader, sc_slot_info_t *slot)
|
||||||
|
|
||||||
cmd[0] = CTBCS_CLA;
|
cmd[0] = CTBCS_CLA;
|
||||||
cmd[1] = CTBCS_INS_REQUEST;
|
cmd[1] = CTBCS_INS_REQUEST;
|
||||||
cmd[2] = CTBCS_P1_INTERFACE1+slot->id;
|
cmd[2] = CTBCS_P1_INTERFACE1;
|
||||||
cmd[3] = CTBCS_P2_REQUEST_GET_ATR;
|
cmd[3] = CTBCS_P2_REQUEST_GET_ATR;
|
||||||
cmd[4] = 0x00;
|
cmd[4] = 0x00;
|
||||||
dad = 1;
|
dad = 1;
|
||||||
|
@ -395,18 +251,18 @@ static int ctapi_connect(sc_reader_t *reader, sc_slot_info_t *slot)
|
||||||
lr -= 2;
|
lr -= 2;
|
||||||
if (lr > SC_MAX_ATR_SIZE)
|
if (lr > SC_MAX_ATR_SIZE)
|
||||||
lr = SC_MAX_ATR_SIZE;
|
lr = SC_MAX_ATR_SIZE;
|
||||||
memcpy(slot->atr, rbuf, lr);
|
memcpy(reader->atr, rbuf, lr);
|
||||||
slot->atr_len = lr;
|
reader->atr_len = lr;
|
||||||
r = _sc_parse_atr(reader->ctx, slot);
|
r = _sc_parse_atr(reader);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (slot->atr_info.Fi > 0) {
|
if (reader->atr_info.Fi > 0) {
|
||||||
/* Perform PPS negotiation */
|
/* Perform PPS negotiation */
|
||||||
cmd[1] = CTBCS_INS_RESET;
|
cmd[1] = CTBCS_INS_RESET;
|
||||||
cmd[4] = 0x03;
|
cmd[4] = 0x03;
|
||||||
cmd[5] = 0xFF;
|
cmd[5] = 0xFF;
|
||||||
cmd[6] = 0x10;
|
cmd[6] = 0x10;
|
||||||
cmd[7] = (slot->atr_info.FI << 4) | slot->atr_info.DI;
|
cmd[7] = (reader->atr_info.FI << 4) | reader->atr_info.DI;
|
||||||
cmd[8] = 0x00;
|
cmd[8] = 0x00;
|
||||||
dad = 1;
|
dad = 1;
|
||||||
sad = 2;
|
sad = 2;
|
||||||
|
@ -422,17 +278,17 @@ static int ctapi_connect(sc_reader_t *reader, sc_slot_info_t *slot)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctapi_disconnect(sc_reader_t *reader, sc_slot_info_t *slot)
|
static int ctapi_disconnect(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctapi_lock(sc_reader_t *reader, sc_slot_info_t *slot)
|
static int ctapi_lock(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctapi_unlock(sc_reader_t *reader, sc_slot_info_t *slot)
|
static int ctapi_unlock(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -480,7 +336,12 @@ static int ctapi_load_module(sc_context_t *ctx,
|
||||||
struct ctapi_module *mod;
|
struct ctapi_module *mod;
|
||||||
const scconf_list *list;
|
const scconf_list *list;
|
||||||
void *dlh;
|
void *dlh;
|
||||||
int r, i;
|
int r, i, NumUnits;
|
||||||
|
char rv;
|
||||||
|
u8 cmd[5], rbuf[256], sad, dad;
|
||||||
|
unsigned short lr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
list = scconf_find_list(conf, "ports");
|
list = scconf_find_list(conf, "ports");
|
||||||
if (list == NULL) {
|
if (list == NULL) {
|
||||||
|
@ -522,8 +383,99 @@ static int ctapi_load_module(sc_context_t *ctx,
|
||||||
sc_debug(ctx, "CT_init() failed with %d\n", rv);
|
sc_debug(ctx, "CT_init() failed with %d\n", rv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Detect functional units of the reader according to CT-BCS spec version 1.0
|
||||||
|
(14.04.2004, http://www.teletrust.de/down/mct1-0_t4.zip) */
|
||||||
|
cmd[0] = CTBCS_CLA;
|
||||||
|
cmd[1] = CTBCS_INS_STATUS;
|
||||||
|
cmd[2] = CTBCS_P1_CT_KERNEL;
|
||||||
|
cmd[3] = CTBCS_P2_STATUS_TFU;
|
||||||
|
cmd[4] = 0x00;
|
||||||
|
dad = 1;
|
||||||
|
sad = 2;
|
||||||
|
lr = 256;
|
||||||
|
|
||||||
|
rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf);
|
||||||
|
if (rv || (lr < 4) || (rbuf[lr-2] != 0x90)) {
|
||||||
|
sc_debug(reader->ctx, "Error getting status of terminal: %d, using defaults\n", rv);
|
||||||
|
}
|
||||||
|
if (rbuf[0] != CTBCS_P2_STATUS_TFU) {
|
||||||
|
/* Number of slots might also detected by using CTBCS_P2_STATUS_ICC.
|
||||||
|
If you think that's important please do it... ;) */
|
||||||
|
sc_debug(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_TFU: 0x%x\n", rbuf[0]);
|
||||||
|
}
|
||||||
|
NumUnits = rbuf[1];
|
||||||
|
if (NumUnits + 4 > lr) {
|
||||||
|
sc_debug(reader->ctx, "Invalid data returnd: %d functional units, size %d\n", NumUnits, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < NumUnits; i++) {
|
||||||
|
switch(rbuf[i+2]) {
|
||||||
|
case CTBCS_P1_INTERFACE1:
|
||||||
|
case CTBCS_P1_INTERFACE2:
|
||||||
|
case CTBCS_P1_INTERFACE3:
|
||||||
|
case CTBCS_P1_INTERFACE4:
|
||||||
|
case CTBCS_P1_INTERFACE5:
|
||||||
|
case CTBCS_P1_INTERFACE6:
|
||||||
|
case CTBCS_P1_INTERFACE7:
|
||||||
|
case CTBCS_P1_INTERFACE8:
|
||||||
|
case CTBCS_P1_INTERFACE9:
|
||||||
|
case CTBCS_P1_INTERFACE10:
|
||||||
|
case CTBCS_P1_INTERFACE11:
|
||||||
|
case CTBCS_P1_INTERFACE12:
|
||||||
|
case CTBCS_P1_INTERFACE13:
|
||||||
|
case CTBCS_P1_INTERFACE14:
|
||||||
|
/* Maybe a weak point here if multiple interfaces are present and not returned
|
||||||
|
in the "canonical" order. This is not forbidden by the specs, but why should
|
||||||
|
anyone want to do that? */
|
||||||
|
sc_debug(reader->ctx, "Found slot id 0x%x\n", rbuf[i+2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CTBCS_P1_DISPLAY:
|
||||||
|
priv->ctapi_functional_units |= CTAPI_FU_DISPLAY;
|
||||||
|
sc_debug(reader->ctx, "Display detected\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CTBCS_P1_KEYPAD:
|
||||||
|
priv->ctapi_functional_units |= CTAPI_FU_KEYBOARD;
|
||||||
|
sc_debug(reader->ctx, "Keypad detected\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CTBCS_P1_PRINTER:
|
||||||
|
priv->ctapi_functional_units |= CTAPI_FU_PRINTER;
|
||||||
|
sc_debug(reader->ctx, "Printer detected\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CTBCS_P1_FINGERPRINT:
|
||||||
|
case CTBCS_P1_VOICEPRINT:
|
||||||
|
case CTBCS_P1_DSV:
|
||||||
|
case CTBCS_P1_FACE_RECOGNITION:
|
||||||
|
case CTBCS_P1_IRISSCAN:
|
||||||
|
priv->ctapi_functional_units |= CTAPI_FU_BIOMETRIC;
|
||||||
|
sc_debug(reader->ctx, "Biometric sensor detected\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
sc_debug(reader->ctx, "Unknown functional unit 0x%x\n", rbuf[i+2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* CT-BCS does not define Keyboard/Display for each slot, so I assume
|
||||||
|
those additional units can be used for each slot */
|
||||||
|
if (priv->ctapi_functional_units) {
|
||||||
|
if (priv->ctapi_functional_units & CTAPI_FU_KEYBOARD)
|
||||||
|
reader->capabilities |= SC_READER_CAP_PIN_PAD;
|
||||||
|
if (priv->ctapi_functional_units & CTAPI_FU_DISPLAY)
|
||||||
|
reader->capabilities |= SC_READER_CAP_DISPLAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
reader = (sc_reader_t *) calloc(1, sizeof(sc_reader_t));
|
reader = (sc_reader_t *) calloc(1, sizeof(sc_reader_t));
|
||||||
priv = (struct ctapi_private_data *) malloc(sizeof(struct ctapi_private_data));
|
priv = (struct ctapi_private_data *) calloc(1, sizeof(struct ctapi_private_data));
|
||||||
|
if (!priv) return SC_ERROR_OUT_OF_MEMORY;
|
||||||
reader->drv_data = priv;
|
reader->drv_data = priv;
|
||||||
reader->ops = &ctapi_ops;
|
reader->ops = &ctapi_ops;
|
||||||
reader->driver = &ctapi_drv;
|
reader->driver = &ctapi_drv;
|
||||||
|
@ -543,10 +495,7 @@ static int ctapi_load_module(sc_context_t *ctx,
|
||||||
detect_functional_units(reader);
|
detect_functional_units(reader);
|
||||||
|
|
||||||
ctapi_reset(reader, NULL);
|
ctapi_reset(reader, NULL);
|
||||||
for(i = 0; i < reader->slot_count; i++) {
|
refresh_attributes(reader);
|
||||||
refresh_slot_attributes(reader, &(reader->slot[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
mod->ctn_count++;
|
mod->ctn_count++;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -26,22 +26,14 @@ static int openct_reader_init(sc_context_t *ctx, void **priv_data);
|
||||||
static int openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info);
|
static int openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info);
|
||||||
static int openct_reader_finish(sc_context_t *ctx, void *priv_data);
|
static int openct_reader_finish(sc_context_t *ctx, void *priv_data);
|
||||||
static int openct_reader_release(sc_reader_t *reader);
|
static int openct_reader_release(sc_reader_t *reader);
|
||||||
static int openct_reader_detect_card_presence(sc_reader_t *reader,
|
static int openct_reader_detect_card_presence(sc_reader_t *reader);
|
||||||
sc_slot_info_t *slot);
|
static int openct_reader_connect(sc_reader_t *reader);
|
||||||
static int openct_reader_connect(sc_reader_t *reader,
|
static int openct_reader_disconnect(sc_reader_t *reader);
|
||||||
sc_slot_info_t *slot);
|
static int openct_reader_transmit(sc_reader_t *reader, sc_apdu_t *apdu);
|
||||||
static int openct_reader_disconnect(sc_reader_t *reader,
|
static int openct_reader_perform_verify(sc_reader_t *reader, struct sc_pin_cmd_data *info);
|
||||||
sc_slot_info_t *slot);
|
static int openct_reader_lock(sc_reader_t *reader);
|
||||||
static int openct_reader_transmit(sc_reader_t *reader,
|
static int openct_reader_unlock(sc_reader_t *reader);
|
||||||
sc_slot_info_t *slot, sc_apdu_t *apdu);
|
static int openct_error(sc_reader_t *, int);
|
||||||
static int openct_reader_perform_verify(sc_reader_t *reader,
|
|
||||||
sc_slot_info_t *slot,
|
|
||||||
struct sc_pin_cmd_data *info);
|
|
||||||
static int openct_reader_lock(sc_reader_t *reader,
|
|
||||||
sc_slot_info_t *slot);
|
|
||||||
static int openct_reader_unlock(sc_reader_t *reader,
|
|
||||||
sc_slot_info_t *slot);
|
|
||||||
static int openct_error(sc_reader_t *, int);
|
|
||||||
|
|
||||||
static struct sc_reader_operations openct_ops;
|
static struct sc_reader_operations openct_ops;
|
||||||
|
|
||||||
|
@ -57,11 +49,9 @@ struct driver_data {
|
||||||
ct_handle * h;
|
ct_handle * h;
|
||||||
unsigned int num;
|
unsigned int num;
|
||||||
ct_info_t info;
|
ct_info_t info;
|
||||||
};
|
|
||||||
|
|
||||||
struct slot_data {
|
|
||||||
ct_lock_handle excl_lock;
|
ct_lock_handle excl_lock;
|
||||||
ct_lock_handle shared_lock;
|
ct_lock_handle shared_lock;
|
||||||
|
unsigned int slot;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -78,7 +68,6 @@ openct_reader_init(sc_context_t *ctx, void **priv_data)
|
||||||
|
|
||||||
SC_FUNC_CALLED(ctx, 1);
|
SC_FUNC_CALLED(ctx, 1);
|
||||||
|
|
||||||
|
|
||||||
max_virtual = 2;
|
max_virtual = 2;
|
||||||
conf_block = sc_get_conf_block(ctx, "reader_driver", "openct", 1);
|
conf_block = sc_get_conf_block(ctx, "reader_driver", "openct", 1);
|
||||||
if (conf_block) {
|
if (conf_block) {
|
||||||
|
@ -87,7 +76,7 @@ openct_reader_init(sc_context_t *ctx, void **priv_data)
|
||||||
|
|
||||||
for (i = 0; i < OPENCT_MAX_READERS; i++) {
|
for (i = 0; i < OPENCT_MAX_READERS; i++) {
|
||||||
ct_info_t info;
|
ct_info_t info;
|
||||||
|
/* XXX: As long as OpenCT has slots, multislot readers should create several instances here. */
|
||||||
if (ct_reader_info(i, &info) >= 0) {
|
if (ct_reader_info(i, &info) >= 0) {
|
||||||
openct_add_reader(ctx, i, &info);
|
openct_add_reader(ctx, i, &info);
|
||||||
} else if (i < max_virtual) {
|
} else if (i < max_virtual) {
|
||||||
|
@ -124,7 +113,6 @@ openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info)
|
||||||
reader->ops = &openct_ops;
|
reader->ops = &openct_ops;
|
||||||
reader->drv_data = data;
|
reader->drv_data = data;
|
||||||
reader->name = strdup(data->info.ct_name);
|
reader->name = strdup(data->info.ct_name);
|
||||||
reader->slot_count = data->info.ct_slots;
|
|
||||||
|
|
||||||
if ((rc = _sc_add_reader(ctx, reader)) < 0) {
|
if ((rc = _sc_add_reader(ctx, reader)) < 0) {
|
||||||
free(data);
|
free(data);
|
||||||
|
@ -133,15 +121,10 @@ openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < SC_MAX_SLOTS; i++) {
|
if (data->info.ct_display)
|
||||||
reader->slot[i].drv_data = calloc(1, sizeof(struct slot_data));
|
reader->capabilities |= SC_READER_CAP_DISPLAY;
|
||||||
reader->slot[i].id = i;
|
if (data->info.ct_keypad)
|
||||||
if (data->info.ct_display)
|
reader->capabilities |= SC_READER_CAP_PIN_PAD;
|
||||||
reader->slot[i].capabilities |= SC_SLOT_CAP_DISPLAY;
|
|
||||||
if (data->info.ct_keypad)
|
|
||||||
reader->slot[i].capabilities |= SC_SLOT_CAP_PIN_PAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,11 +156,6 @@ static int openct_reader_release(sc_reader_t *reader)
|
||||||
reader->drv_data = NULL;
|
reader->drv_data = NULL;
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < SC_MAX_SLOTS; i++) {
|
|
||||||
if(reader->slot[i].drv_data)
|
|
||||||
free(reader->slot[i].drv_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SC_NO_ERROR;
|
return SC_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -185,32 +163,30 @@ static int openct_reader_release(sc_reader_t *reader)
|
||||||
/*
|
/*
|
||||||
* Check whether a card was added/removed
|
* Check whether a card was added/removed
|
||||||
*/
|
*/
|
||||||
static int openct_reader_detect_card_presence(sc_reader_t *reader,
|
static int openct_reader_detect_card_presence(sc_reader_t *reader)
|
||||||
sc_slot_info_t *slot)
|
|
||||||
{
|
{
|
||||||
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
||||||
int rc, status;
|
int rc, status;
|
||||||
|
|
||||||
SC_FUNC_CALLED(reader->ctx, 1);
|
SC_FUNC_CALLED(reader->ctx, 1);
|
||||||
|
|
||||||
slot->flags = 0;
|
reader->flags = 0;
|
||||||
if (!data->h && !(data->h = ct_reader_connect(data->num)))
|
if (!data->h && !(data->h = ct_reader_connect(data->num)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((rc = ct_card_status(data->h, slot->id, &status)) < 0)
|
if ((rc = ct_card_status(data->h, data->slot, &status)) < 0)
|
||||||
return SC_ERROR_TRANSMIT_FAILED;
|
return SC_ERROR_TRANSMIT_FAILED;
|
||||||
|
|
||||||
if (status & IFD_CARD_PRESENT) {
|
if (status & IFD_CARD_PRESENT) {
|
||||||
slot->flags = SC_SLOT_CARD_PRESENT;
|
reader->flags = SC_READER_CARD_PRESENT;
|
||||||
if (status & IFD_CARD_STATUS_CHANGED)
|
if (status & IFD_CARD_STATUS_CHANGED)
|
||||||
slot->flags = SC_SLOT_CARD_PRESENT;
|
reader->flags = SC_READER_CARD_PRESENT;
|
||||||
}
|
}
|
||||||
return slot->flags;
|
return reader->flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
openct_reader_connect(sc_reader_t *reader,
|
openct_reader_connect(sc_reader_t *reader)
|
||||||
sc_slot_info_t *slot)
|
|
||||||
{
|
{
|
||||||
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -225,8 +201,8 @@ openct_reader_connect(sc_reader_t *reader,
|
||||||
return SC_ERROR_CARD_NOT_PRESENT;
|
return SC_ERROR_CARD_NOT_PRESENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ct_card_request(data->h, slot->id, 0, NULL,
|
rc = ct_card_request(data->h, reder->id, 0, NULL,
|
||||||
slot->atr, sizeof(slot->atr));
|
reader->atr, sizeof(reader->atr));
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
sc_debug(reader->ctx,
|
sc_debug(reader->ctx,
|
||||||
"openct_reader_connect read failed: %s\n",
|
"openct_reader_connect read failed: %s\n",
|
||||||
|
@ -239,13 +215,12 @@ openct_reader_connect(sc_reader_t *reader,
|
||||||
return SC_ERROR_READER;
|
return SC_ERROR_READER;
|
||||||
}
|
}
|
||||||
|
|
||||||
slot->atr_len = rc;
|
reader->atr_len = rc;
|
||||||
return SC_NO_ERROR;
|
return SC_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
openct_reader_reconnect(sc_reader_t *reader,
|
openct_reader_reconnect(sc_reader_t *reader)
|
||||||
sc_slot_info_t *slot)
|
|
||||||
{
|
{
|
||||||
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -253,12 +228,12 @@ openct_reader_reconnect(sc_reader_t *reader,
|
||||||
if (data->h != NULL)
|
if (data->h != NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((rc = openct_reader_connect(reader, slot)) < 0)
|
if ((rc = openct_reader_connect(reader)) < 0)
|
||||||
return SC_ERROR_READER_DETACHED;
|
return SC_ERROR_READER_DETACHED;
|
||||||
return SC_ERROR_READER_REATTACHED;
|
return SC_ERROR_READER_REATTACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openct_reader_disconnect(sc_reader_t *reader, sc_slot_info_t *slot)
|
static int openct_reader_disconnect(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
||||||
|
|
||||||
|
@ -271,7 +246,6 @@ static int openct_reader_disconnect(sc_reader_t *reader, sc_slot_info_t *slot)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
openct_reader_internal_transmit(sc_reader_t *reader,
|
openct_reader_internal_transmit(sc_reader_t *reader,
|
||||||
sc_slot_info_t *slot,
|
|
||||||
const u8 *sendbuf, size_t sendsize,
|
const u8 *sendbuf, size_t sendsize,
|
||||||
u8 *recvbuf, size_t *recvsize, unsigned long control)
|
u8 *recvbuf, size_t *recvsize, unsigned long control)
|
||||||
{
|
{
|
||||||
|
@ -279,10 +253,10 @@ openct_reader_internal_transmit(sc_reader_t *reader,
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Hotplug check */
|
/* Hotplug check */
|
||||||
if ((rc = openct_reader_reconnect(reader, slot)) < 0)
|
if ((rc = openct_reader_reconnect(reader)) < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc = ct_card_transact(data->h, slot->id,
|
rc = ct_card_transact(data->h, data->slot,
|
||||||
sendbuf, sendsize,
|
sendbuf, sendsize,
|
||||||
recvbuf, *recvsize);
|
recvbuf, *recvsize);
|
||||||
|
|
||||||
|
@ -298,8 +272,7 @@ openct_reader_internal_transmit(sc_reader_t *reader,
|
||||||
return openct_error(reader, rc);
|
return openct_error(reader, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openct_reader_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
|
static int openct_reader_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
|
||||||
sc_apdu_t *apdu)
|
|
||||||
{
|
{
|
||||||
size_t ssize, rsize, rbuflen = 0;
|
size_t ssize, rsize, rbuflen = 0;
|
||||||
u8 *sbuf = NULL, *rbuf = NULL;
|
u8 *sbuf = NULL, *rbuf = NULL;
|
||||||
|
@ -317,7 +290,7 @@ static int openct_reader_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
|
||||||
goto out;
|
goto out;
|
||||||
if (reader->ctx->debug >= 6)
|
if (reader->ctx->debug >= 6)
|
||||||
sc_apdu_log(reader->ctx, sbuf, ssize, 1);
|
sc_apdu_log(reader->ctx, sbuf, ssize, 1);
|
||||||
r = openct_reader_internal_transmit(reader, slot, sbuf, ssize,
|
r = openct_reader_internal_transmit(reader, sbuf, ssize,
|
||||||
rbuf, &rsize, apdu->control);
|
rbuf, &rsize, apdu->control);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
/* unable to transmit ... most likely a reader problem */
|
/* unable to transmit ... most likely a reader problem */
|
||||||
|
@ -341,8 +314,7 @@ out:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openct_reader_perform_verify(sc_reader_t *reader,
|
static int openct_reader_perform_verify(sc_reader_t *reader, struct sc_pin_cmd_data *info)
|
||||||
sc_slot_info_t *slot, struct sc_pin_cmd_data *info)
|
|
||||||
{
|
{
|
||||||
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
||||||
unsigned int pin_length = 0, pin_encoding;
|
unsigned int pin_length = 0, pin_encoding;
|
||||||
|
@ -351,7 +323,7 @@ static int openct_reader_perform_verify(sc_reader_t *reader,
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Hotplug check */
|
/* Hotplug check */
|
||||||
if ((rc = openct_reader_reconnect(reader, slot)) < 0)
|
if ((rc = openct_reader_reconnect(reader)) < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (info->apdu == NULL) {
|
if (info->apdu == NULL) {
|
||||||
|
@ -384,7 +356,7 @@ static int openct_reader_perform_verify(sc_reader_t *reader,
|
||||||
else
|
else
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
rc = ct_card_verify(data->h, slot->id,
|
rc = ct_card_verify(data->h, data->slot,
|
||||||
0, /* no timeout?! */
|
0, /* no timeout?! */
|
||||||
info->pin1.prompt,
|
info->pin1.prompt,
|
||||||
pin_encoding,
|
pin_encoding,
|
||||||
|
@ -401,37 +373,35 @@ static int openct_reader_perform_verify(sc_reader_t *reader,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openct_reader_lock(sc_reader_t *reader, sc_slot_info_t *slot)
|
static int openct_reader_lock(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
||||||
struct slot_data *slot_data = (struct slot_data *) slot->drv_data;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
SC_FUNC_CALLED(reader->ctx, 1);
|
SC_FUNC_CALLED(reader->ctx, 1);
|
||||||
|
|
||||||
/* Hotplug check */
|
/* Hotplug check */
|
||||||
if ((rc = openct_reader_reconnect(reader, slot)) < 0)
|
if ((rc = openct_reader_reconnect(reader)) < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc = ct_card_lock(data->h, slot->id,
|
rc = ct_card_lock(data->h, data->slot,
|
||||||
IFD_LOCK_EXCLUSIVE,
|
IFD_LOCK_EXCLUSIVE,
|
||||||
&slot_data->excl_lock);
|
&data->excl_lock);
|
||||||
|
|
||||||
if (rc == IFD_ERROR_NOT_CONNECTED) {
|
if (rc == IFD_ERROR_NOT_CONNECTED) {
|
||||||
ct_reader_disconnect(data->h);
|
ct_reader_disconnect(data->h);
|
||||||
data->h = NULL;
|
data->h = NULL;
|
||||||
|
|
||||||
/* Try to reconnect as reader may be plugged-in again */
|
/* Try to reconnect as reader may be plugged-in again */
|
||||||
return openct_reader_reconnect(reader, slot);
|
return openct_reader_reconnect(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
return openct_error(reader, rc);
|
return openct_error(reader, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openct_reader_unlock(sc_reader_t *reader, sc_slot_info_t *slot)
|
static int openct_reader_unlock(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
struct driver_data *data = (struct driver_data *) reader->drv_data;
|
||||||
struct slot_data *slot_data = (struct slot_data *) slot->drv_data;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
SC_FUNC_CALLED(reader->ctx, 1);
|
SC_FUNC_CALLED(reader->ctx, 1);
|
||||||
|
@ -440,7 +410,7 @@ static int openct_reader_unlock(sc_reader_t *reader, sc_slot_info_t *slot)
|
||||||
if (data->h == NULL)
|
if (data->h == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rc = ct_card_unlock(data->h, slot->id, slot_data->excl_lock);
|
rc = ct_card_unlock(data->h, data->slot, data->excl_lock);
|
||||||
|
|
||||||
/* We couldn't care less */
|
/* We couldn't care less */
|
||||||
if (rc == IFD_ERROR_NOT_CONNECTED)
|
if (rc == IFD_ERROR_NOT_CONNECTED)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -181,60 +181,17 @@ int sc_compare_oid(const struct sc_object_id *oid1, const struct sc_object_id *o
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_slot_info_t * _sc_get_slot_info(sc_reader_t *reader, int slot_id)
|
int sc_detect_card_presence(sc_reader_t *reader)
|
||||||
{
|
|
||||||
assert(reader != NULL);
|
|
||||||
if (slot_id < 0 || slot_id > reader->slot_count)
|
|
||||||
return NULL;
|
|
||||||
return &reader->slot[slot_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
int sc_detect_card_presence(sc_reader_t *reader, int slot_id)
|
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
sc_slot_info_t *slot = _sc_get_slot_info(reader, slot_id);
|
|
||||||
|
|
||||||
if (slot == NULL)
|
|
||||||
SC_FUNC_RETURN(reader->ctx, 0, SC_ERROR_SLOT_NOT_FOUND);
|
|
||||||
SC_FUNC_CALLED(reader->ctx, 1);
|
SC_FUNC_CALLED(reader->ctx, 1);
|
||||||
if (reader->ops->detect_card_presence == NULL)
|
if (reader->ops->detect_card_presence == NULL)
|
||||||
SC_FUNC_RETURN(reader->ctx, 0, SC_ERROR_NOT_SUPPORTED);
|
SC_FUNC_RETURN(reader->ctx, 0, SC_ERROR_NOT_SUPPORTED);
|
||||||
|
|
||||||
r = reader->ops->detect_card_presence(reader, slot);
|
r = reader->ops->detect_card_presence(reader);
|
||||||
SC_FUNC_RETURN(reader->ctx, 1, r);
|
SC_FUNC_RETURN(reader->ctx, 1, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sc_wait_for_event(sc_reader_t *readers[], int slot_id[], size_t nslots,
|
|
||||||
unsigned int event_mask,
|
|
||||||
int *reader, unsigned int *event, int timeout)
|
|
||||||
{
|
|
||||||
sc_slot_info_t *slotp[SC_MAX_SLOTS * SC_MAX_READERS];
|
|
||||||
sc_context_t *ctx;
|
|
||||||
unsigned int j;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (nslots == 0 || nslots > SC_MAX_SLOTS * SC_MAX_READERS)
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
ctx = readers[0]->ctx;
|
|
||||||
|
|
||||||
SC_FUNC_CALLED(ctx, 1);
|
|
||||||
for (j = 0; j < nslots; j++) {
|
|
||||||
slotp[j] = _sc_get_slot_info(readers[j], slot_id[j]);
|
|
||||||
|
|
||||||
if (slotp[j] == NULL)
|
|
||||||
SC_FUNC_RETURN(ctx, 0, SC_ERROR_SLOT_NOT_FOUND);
|
|
||||||
/* XXX check to make sure all readers share the same operations
|
|
||||||
* struct */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readers[0]->ops->wait_for_event == NULL)
|
|
||||||
SC_FUNC_RETURN(ctx, 0, SC_ERROR_NOT_SUPPORTED);
|
|
||||||
|
|
||||||
r = readers[0]->ops->wait_for_event(readers, slotp, nslots,
|
|
||||||
event_mask, reader, event, timeout);
|
|
||||||
SC_FUNC_RETURN(ctx, 1, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
int sc_path_set(sc_path_t *path, int type, const u8 *id, size_t id_len,
|
int sc_path_set(sc_path_t *path, int type, const u8 *id, size_t id_len,
|
||||||
int idx, int count)
|
int idx, int count)
|
||||||
{
|
{
|
||||||
|
@ -642,10 +599,10 @@ int sc_file_valid(const sc_file_t *file) {
|
||||||
return file->magic == SC_FILE_MAGIC;
|
return file->magic == SC_FILE_MAGIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _sc_parse_atr(sc_context_t *ctx, sc_slot_info_t *slot)
|
int _sc_parse_atr(sc_reader_t *reader)
|
||||||
{
|
{
|
||||||
u8 *p = slot->atr;
|
u8 *p = reader->atr;
|
||||||
int atr_len = (int) slot->atr_len;
|
int atr_len = (int) reader->atr_len;
|
||||||
int n_hist, x;
|
int n_hist, x;
|
||||||
int tx[4];
|
int tx[4];
|
||||||
int i, FI, DI;
|
int i, FI, DI;
|
||||||
|
@ -659,16 +616,16 @@ int _sc_parse_atr(sc_context_t *ctx, sc_slot_info_t *slot)
|
||||||
-1, 1, 2, 4, 8, 16, 32, -1,
|
-1, 1, 2, 4, 8, 16, 32, -1,
|
||||||
12, 20, -1, -1, -1, -1, -1, -1 };
|
12, 20, -1, -1, -1, -1, -1, -1 };
|
||||||
|
|
||||||
slot->atr_info.hist_bytes_len = 0;
|
reader->atr_info.hist_bytes_len = 0;
|
||||||
slot->atr_info.hist_bytes = NULL;
|
reader->atr_info.hist_bytes = NULL;
|
||||||
|
|
||||||
if (atr_len == 0) {
|
if (atr_len == 0) {
|
||||||
sc_debug(ctx, "empty ATR - card not present?\n");
|
sc_debug(reader->ctx, "empty ATR - card not present?\n");
|
||||||
return SC_ERROR_INTERNAL;
|
return SC_ERROR_INTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p[0] != 0x3B && p[0] != 0x3F) {
|
if (p[0] != 0x3B && p[0] != 0x3F) {
|
||||||
sc_debug(ctx, "invalid sync byte in ATR: 0x%02X\n", p[0]);
|
sc_debug(reader->ctx, "invalid sync byte in ATR: 0x%02X\n", p[0]);
|
||||||
return SC_ERROR_INTERNAL;
|
return SC_ERROR_INTERNAL;
|
||||||
}
|
}
|
||||||
n_hist = p[1] & 0x0F;
|
n_hist = p[1] & 0x0F;
|
||||||
|
@ -684,20 +641,20 @@ int _sc_parse_atr(sc_context_t *ctx, sc_slot_info_t *slot)
|
||||||
tx[i] = -1;
|
tx[i] = -1;
|
||||||
}
|
}
|
||||||
if (tx[0] >= 0) {
|
if (tx[0] >= 0) {
|
||||||
slot->atr_info.FI = FI = tx[0] >> 4;
|
reader->atr_info.FI = FI = tx[0] >> 4;
|
||||||
slot->atr_info.DI = DI = tx[0] & 0x0F;
|
reader->atr_info.DI = DI = tx[0] & 0x0F;
|
||||||
slot->atr_info.Fi = Fi_table[FI];
|
reader->atr_info.Fi = Fi_table[FI];
|
||||||
slot->atr_info.f = f_table[FI];
|
reader->atr_info.f = f_table[FI];
|
||||||
slot->atr_info.Di = Di_table[DI];
|
reader->atr_info.Di = Di_table[DI];
|
||||||
} else {
|
} else {
|
||||||
slot->atr_info.Fi = -1;
|
reader->atr_info.Fi = -1;
|
||||||
slot->atr_info.f = -1;
|
reader->atr_info.f = -1;
|
||||||
slot->atr_info.Di = -1;
|
reader->atr_info.Di = -1;
|
||||||
}
|
}
|
||||||
if (tx[2] >= 0)
|
if (tx[2] >= 0)
|
||||||
slot->atr_info.N = tx[3];
|
reader->atr_info.N = tx[3];
|
||||||
else
|
else
|
||||||
slot->atr_info.N = -1;
|
reader->atr_info.N = -1;
|
||||||
while (tx[3] > 0 && tx[3] & 0xF0 && atr_len > 0) {
|
while (tx[3] > 0 && tx[3] & 0xF0 && atr_len > 0) {
|
||||||
x = tx[3] >> 4;
|
x = tx[3] >> 4;
|
||||||
for (i = 0; i < 4 && atr_len > 0; i++) {
|
for (i = 0; i < 4 && atr_len > 0; i++) {
|
||||||
|
@ -713,8 +670,8 @@ int _sc_parse_atr(sc_context_t *ctx, sc_slot_info_t *slot)
|
||||||
return 0;
|
return 0;
|
||||||
if (n_hist > atr_len)
|
if (n_hist > atr_len)
|
||||||
n_hist = atr_len;
|
n_hist = atr_len;
|
||||||
slot->atr_info.hist_bytes_len = n_hist;
|
reader->atr_info.hist_bytes_len = n_hist;
|
||||||
slot->atr_info.hist_bytes = p;
|
reader->atr_info.hist_bytes = p;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "simclist.h"
|
||||||
typedef unsigned char u8;
|
typedef unsigned char u8;
|
||||||
|
|
||||||
#define SC_MAX_OBJECT_ID_OCTETS 16
|
#define SC_MAX_OBJECT_ID_OCTETS 16
|
||||||
|
|
Loading…
Reference in New Issue