- made apdu_masquerade functionality available to all readers, not just pcsc

- added new parameters max_send_size and max_recv_size, roughly corresponding
  to the old max_le (SC_APDU_CHOP_SIZE) parameter. You can now set this
  chop limit per driver class (pcsc, openct, ctapi), which sets
  driver->max_{send,recv}_size. This value is copied to
  card->max_{send,recv}_size in sc_connect_card, and can be overridden
  by the card driver.


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1683 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
okir 2003-12-18 16:35:28 +00:00
parent af37c4e026
commit 5dda541b7e
10 changed files with 176 additions and 118 deletions

View File

@ -239,6 +239,10 @@ gpk_init(struct sc_card *card)
/* State that we have an RNG */
card->caps |= SC_CARD_CAP_RNG;
/* Make sure max send/receive size is 4 byte aligned. */
card->max_send_size &= ~3;
card->max_recv_size &= ~3;
return 0;
}

View File

@ -85,7 +85,10 @@ static int miocos_init(struct sc_card *card)
/* read_binary and friends shouldn't do more than 244 bytes
* per operation */
card->max_le = 244;
if (card->max_send_size > 244)
card->max_send_size = 244;
if (card->max_recv_size > 244)
card->max_recv_size = 244;
return 0;
}

View File

@ -253,7 +253,10 @@ static int starcos_init(struct sc_card *card)
return SC_ERROR_INTERNAL;
/* we need read_binary&friends with max 128 bytes per read */
card->max_le = 0x80;
if (card->max_send_size > 128)
card->max_send_size = 128;
if (card->max_recv_size > 128)
card->max_recv_size = 128;
return 0;
}

View File

@ -90,6 +90,39 @@ static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
return 0;
}
/*
* Handle APDU masquerading
*/
static int
sc_masquerade_apdu(sc_card_t *card, sc_apdu_t *apdu)
{
sc_context_t *ctx = card->reader->ctx;
int masq = card->reader->driver->apdu_masquerade;
int is_t0;
is_t0 = (card->slot->active_protocol == SC_PROTO_T0);
if (apdu->cse == SC_APDU_CASE_4_SHORT
&& is_t0 && (masq & SC_APDU_MASQUERADE_4AS3)) {
if (ctx->debug >= 5)
sc_debug(ctx, "Masquerading case 4 APDU as case 3");
apdu->cse = SC_APDU_CASE_3_SHORT;
return 1;
}
if (apdu->cse == SC_APDU_CASE_1
&& ((is_t0 && (masq & SC_APDU_MASQUERADE_1AS2))
|| ((masq & SC_APDU_MASQUERADE_1AS2_ALWAYS)))) {
if (ctx->debug >= 5)
sc_debug(ctx, "Masquerading case 1 APDU as case 2");
apdu->cse = SC_APDU_CASE_2_SHORT;
apdu->le = 0;
return 1;
}
return 0;
}
static int sc_transceive(struct sc_card *card, struct sc_apdu *apdu)
{
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
@ -99,9 +132,21 @@ static int sc_transceive(struct sc_card *card, struct sc_apdu *apdu)
size_t data_bytes = apdu->lc;
int r;
#if 0
if (card->ctx->debug >= 6)
sc_debug(card->ctx, "masq=%x, max_send=%u, max_recv=%u",
card->reader->driver->apdu_masquerade,
card->max_recv_size,
card->max_send_size);
#endif
if (card->reader->ops->transmit == NULL)
return SC_ERROR_NOT_SUPPORTED;
assert(card->reader->ops->transmit != NULL);
/* APDU masquerading */
if (card->reader->driver->apdu_masquerade)
sc_masquerade_apdu(card, apdu);
if (data_bytes == 0)
data_bytes = 256;
*data++ = apdu->cla;
@ -267,7 +312,6 @@ static struct sc_card * sc_card_new()
free(card);
return NULL;
}
card->max_le = SC_APDU_CHOP_SIZE;
card->app_count = -1;
card->magic = SC_CARD_MAGIC;
card->mutex = sc_mutex_new();
@ -317,6 +361,10 @@ int sc_connect_card(struct sc_reader *reader, int slot_id,
card->slot = slot;
card->ctx = ctx;
/* These can be overridden by the card driver */
card->max_send_size = reader->driver->max_send_size;
card->max_recv_size = reader->driver->max_recv_size;
memcpy(card->atr, slot->atr, slot->atr_len);
card->atr_len = slot->atr_len;
@ -507,6 +555,7 @@ int sc_delete_file(struct sc_card *card, const struct sc_path *path)
int sc_read_binary(struct sc_card *card, unsigned int idx,
unsigned char *buf, size_t count, unsigned long flags)
{
size_t max_le = card->max_recv_size;
int r;
assert(card != NULL && card->ops != NULL && buf != NULL);
@ -516,14 +565,14 @@ int sc_read_binary(struct sc_card *card, unsigned int idx,
return 0;
if (card->ops->read_binary == NULL)
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED);
if (count > card->max_le) {
if (count > max_le) {
int bytes_read = 0;
unsigned char *p = buf;
r = sc_lock(card);
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
while (count > 0) {
int n = count > card->max_le ? card->max_le : count;
int n = count > max_le ? max_le : count;
r = sc_read_binary(card, idx, p, n, flags);
if (r < 0) {
sc_unlock(card);
@ -548,6 +597,7 @@ int sc_read_binary(struct sc_card *card, unsigned int idx,
int sc_write_binary(struct sc_card *card, unsigned int idx,
const u8 *buf, size_t count, unsigned long flags)
{
size_t max_lc = card->max_send_size;
int r;
assert(card != NULL && card->ops != NULL && buf != NULL);
@ -557,14 +607,14 @@ int sc_write_binary(struct sc_card *card, unsigned int idx,
return 0;
if (card->ops->write_binary == NULL)
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED);
if (count > card->max_le) {
if (count > max_lc) {
int bytes_written = 0;
const u8 *p = buf;
r = sc_lock(card);
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
while (count > 0) {
int n = count > card->max_le ? card->max_le : count;
int n = count > max_lc? max_lc : count;
r = sc_write_binary(card, idx, p, n, flags);
if (r < 0) {
sc_unlock(card);
@ -589,6 +639,7 @@ int sc_write_binary(struct sc_card *card, unsigned int idx,
int sc_update_binary(struct sc_card *card, unsigned int idx,
const u8 *buf, size_t count, unsigned long flags)
{
size_t max_lc = card->max_send_size;
int r;
assert(card != NULL && card->ops != NULL && buf != NULL);
@ -598,14 +649,14 @@ int sc_update_binary(struct sc_card *card, unsigned int idx,
return 0;
if (card->ops->update_binary == NULL)
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED);
if (count > card->max_le) {
if (count > max_lc) {
int bytes_written = 0;
const u8 *p = buf;
r = sc_lock(card);
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
while (count > 0) {
int n = count > card->max_le ? card->max_le : count;
int n = count > max_lc? max_lc : count;
r = sc_update_binary(card, idx, p, n, flags);
if (r < 0) {
sc_unlock(card);

View File

@ -27,6 +27,13 @@
#include <sys/stat.h>
#include <limits.h>
/* Default value for apdu_masquerade option */
#ifndef _WIN32
# define DEF_APDU_MASQ SC_APDU_MASQUERADE_NONE
#else
# define DEF_APDU_MASQ SC_APDU_MASQUERADE_4AS3
#endif
int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader)
{
assert(reader != NULL);
@ -41,29 +48,29 @@ int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader)
struct _sc_driver_entry {
char *name;
void *func;
struct sc_reader_driver *(*func)(void);
char *libpath;
struct sc_atr_table *atrs;
unsigned int natrs;
};
static const struct _sc_driver_entry internal_card_drivers[] = {
{ "emv", (void *) sc_get_emv_driver, NULL },
{ "etoken", (void *) sc_get_etoken_driver, NULL },
{ "flex", (void *) sc_get_cryptoflex_driver, NULL },
{ "cyberflex", (void *) sc_get_cyberflex_driver, NULL },
{ "emv", sc_get_emv_driver, NULL },
{ "etoken", sc_get_etoken_driver, NULL },
{ "flex", sc_get_cryptoflex_driver, NULL },
{ "cyberflex", sc_get_cyberflex_driver, NULL },
#ifdef HAVE_OPENSSL
{ "gpk", (void *) sc_get_gpk_driver, NULL },
{ "gpk", sc_get_gpk_driver, NULL },
#endif
{ "miocos", (void *) sc_get_miocos_driver, NULL },
{ "mcrd", (void *) sc_get_mcrd_driver, NULL },
{ "setcos", (void *) sc_get_setcos_driver, NULL },
{ "starcos", (void *) sc_get_starcos_driver, NULL },
{ "tcos", (void *) sc_get_tcos_driver, NULL },
{ "opengpg", (void *) sc_get_openpgp_driver, NULL },
{ "miocos", sc_get_miocos_driver, NULL },
{ "mcrd", sc_get_mcrd_driver, NULL },
{ "setcos", sc_get_setcos_driver, NULL },
{ "starcos", sc_get_starcos_driver, NULL },
{ "tcos", sc_get_tcos_driver, NULL },
{ "opengpg", sc_get_openpgp_driver, NULL },
/* The default driver should be last, as it handles all the
* unrecognized cards. */
{ "default", (void *) sc_get_default_driver, NULL },
{ "default", sc_get_default_driver, NULL },
{ NULL, NULL, NULL }
};
@ -224,6 +231,63 @@ static int load_parameters(struct sc_context *ctx, scconf_block *block,
return err;
}
static void load_reader_driver_options(sc_context_t *ctx,
struct sc_reader_driver *driver)
{
const char *name = driver->short_name;
scconf_block *conf_block = NULL;
int i;
for (i = 0; ctx->conf_blocks[i] != NULL; i++) {
scconf_block **blocks;
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i],
"reader_driver", name);
conf_block = blocks[0];
free(blocks);
if (conf_block != NULL)
break;
}
driver->apdu_masquerade = DEF_APDU_MASQ;
driver->max_send_size = SC_APDU_CHOP_SIZE;
driver->max_recv_size = SC_APDU_CHOP_SIZE;
if (conf_block != NULL) {
const scconf_list *list;
if (scconf_get_bool(conf_block, "apdu_fix", 0))
driver->apdu_masquerade |= SC_APDU_MASQUERADE_4AS3;
list = scconf_find_list(conf_block, "apdu_masquerade");
if (list)
driver->apdu_masquerade = 0;
for (; list; list = list->next) {
if (!strcmp(list->data, "case4as3")) {
driver->apdu_masquerade |= SC_APDU_MASQUERADE_4AS3;
} else if (!strcmp(list->data, "case1as2")) {
driver->apdu_masquerade |= SC_APDU_MASQUERADE_1AS2;
} else if (!strcmp(list->data, "case1as2_always")) {
driver->apdu_masquerade |= SC_APDU_MASQUERADE_1AS2_ALWAYS;
} else if (!strcmp(list->data, "none")) {
driver->apdu_masquerade = 0;
} else {
/* no match. Should something be logged? */
sc_error(ctx,
"Unexpected keyword \"%s\" in "
"apdu_masquerade; ignored\n",
list->data);
}
}
driver->max_send_size = scconf_get_int(conf_block,
"max_send_size",
SC_APDU_CHOP_SIZE);
driver->max_recv_size = scconf_get_int(conf_block,
"max_recv_size",
SC_APDU_CHOP_SIZE);
}
}
static int load_reader_drivers(struct sc_context *ctx,
struct _sc_ctx_options *opts)
{
@ -234,13 +298,14 @@ static int load_reader_drivers(struct sc_context *ctx,
for (drv_count = 0; ctx->reader_drivers[drv_count] != NULL; drv_count++);
for (i = 0; i < opts->rcount; i++) {
const struct sc_reader_driver * (* func)(void) = NULL;
struct sc_reader_driver *driver;
struct sc_reader_driver * (*func)(void) = NULL;
int j;
ent = &opts->rdrv[i];
for (j = 0; internal_reader_drivers[j].name != NULL; j++)
if (strcmp(ent->name, internal_reader_drivers[j].name) == 0) {
func = (const struct sc_reader_driver * (*)(void)) internal_reader_drivers[j].func;
func = (struct sc_reader_driver * (*)(void)) internal_reader_drivers[j].func;
break;
}
if (func == NULL) {
@ -250,8 +315,11 @@ static int load_reader_drivers(struct sc_context *ctx,
ent->name);
continue;
}
ctx->reader_drivers[drv_count] = func();
ctx->reader_drivers[drv_count]->ops->init(ctx, &ctx->reader_drv_data[i]);
driver = func();
load_reader_driver_options(ctx, driver);
driver->ops->init(ctx, &ctx->reader_drv_data[i]);
ctx->reader_drivers[drv_count] = driver;
drv_count++;
}
return 0;

View File

@ -110,6 +110,7 @@ static int iso7816_read_binary(struct sc_card *card,
u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE];
int r;
assert(count <= card->max_recv_size);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0,
(idx >> 8) & 0x7F, idx & 0xFF);
apdu.le = count;
@ -237,7 +238,7 @@ static int iso7816_write_binary(struct sc_card *card,
struct sc_apdu apdu;
int r;
assert(count <= card->max_le);
assert(count <= card->max_send_size);
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD0,
(idx >> 8) & 0x7F, idx & 0xFF);
apdu.lc = count;
@ -258,7 +259,7 @@ static int iso7816_update_binary(struct sc_card *card,
struct sc_apdu apdu;
int r;
assert(count <= card->max_le);
assert(count <= card->max_send_size);
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6,
(idx >> 8) & 0x7F, idx & 0xFF);
apdu.lc = count;

View File

@ -257,7 +257,14 @@ struct sc_reader_driver {
const char *name;
const char *short_name;
struct sc_reader_operations *ops;
size_t max_send_size, max_recv_size;
int apdu_masquerade;
};
#define SC_APDU_MASQUERADE_NONE 0x00
#define SC_APDU_MASQUERADE_4AS3 0x01
#define SC_APDU_MASQUERADE_1AS2 0x02
#define SC_APDU_MASQUERADE_1AS2_ALWAYS 0x04
/* slot flags */
#define SC_SLOT_CARD_PRESENT 0x00000001
@ -432,7 +439,8 @@ struct sc_card {
int cla;
u8 atr[SC_MAX_ATR_SIZE];
size_t atr_len;
size_t max_le;
size_t max_send_size;
size_t max_recv_size;
struct sc_app_info *app[SC_MAX_CARD_APPS];
int app_count;
@ -842,9 +850,9 @@ struct sc_card_error {
extern const char *sc_get_version(void);
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_reader_driver *sc_get_openct_driver(void);
extern struct sc_reader_driver *sc_get_pcsc_driver(void);
extern struct sc_reader_driver *sc_get_ctapi_driver(void);
extern struct sc_reader_driver *sc_get_openct_driver(void);
extern struct sc_card_driver *sc_get_default_driver(void);
extern struct sc_card_driver *sc_get_emv_driver(void);

View File

@ -204,7 +204,7 @@ static int ctapi_release(struct sc_reader *reader)
static struct sc_reader_operations ctapi_ops;
static const struct sc_reader_driver ctapi_drv = {
static struct sc_reader_driver ctapi_drv = {
"CT-API module",
"ctapi",
&ctapi_ops
@ -362,7 +362,7 @@ static int ctapi_finish(struct sc_context *ctx, void *prv_data)
return 0;
}
const struct sc_reader_driver * sc_get_ctapi_driver(void)
struct sc_reader_driver * sc_get_ctapi_driver(void)
{
ctapi_ops.init = ctapi_init;
ctapi_ops.finish = ctapi_finish;

View File

@ -427,7 +427,7 @@ openct_error(struct sc_reader *reader, int code)
return SC_ERROR_READER;
}
const struct sc_reader_driver *sc_get_openct_driver(void)
struct sc_reader_driver *sc_get_openct_driver(void)
{
openct_ops.init = openct_reader_init;
openct_ops.finish = openct_reader_finish;

View File

@ -56,26 +56,12 @@
#endif
#define MASQUERADE_NONE 0x00
#define MASQUERADE_4AS3 0x01
#define MASQUERADE_1AS2 0x02
#define MASQUERADE_1AS2_ALWAYS 0x04
#define DO_MASQ(priv, mask) ((prv)->gpriv->apdu_masquerade & (mask))
/* Default value for apdu_fix option */
#ifndef _WIN32
# define DEF_APDU_MASQ MASQUERADE_NONE
#else
# define DEF_APDU_MASQ MASQUERADE_4AS3
#endif
#define GET_SLOT_PTR(s, i) (&(s)->slot[(i)])
#define GET_PRIV_DATA(r) ((struct pcsc_private_data *) (r)->drv_data)
#define GET_SLOT_DATA(r) ((struct pcsc_slot_data *) (r)->drv_data)
struct pcsc_global_private_data {
SCARDCONTEXT pcsc_ctx;
int apdu_masquerade; /* bitmask to indicate whether to
'fix' some T=0 APDUs */
};
struct pcsc_private_data {
@ -144,10 +130,7 @@ static int pcsc_transmit(struct sc_reader *reader, struct sc_slot_info *slot,
DWORD dwSendLength, dwRecvLength;
LONG rv;
SCARDHANDLE card;
u8 masqueraded_apdu[5];
struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot);
struct pcsc_private_data *prv = GET_PRIV_DATA(reader);
int protocol = slot->active_protocol;
assert(pslot != NULL);
card = pslot->pcsc_card;
@ -157,40 +140,6 @@ static int pcsc_transmit(struct sc_reader *reader, struct sc_slot_info *slot,
sRecvPci.dwProtocol = opensc_proto_to_pcsc(slot->active_protocol);
sRecvPci.cbPciLength = sizeof(sRecvPci);
if (sendsize >= 6
&& DO_MASQ(prv, MASQUERADE_4AS3) && protocol == SC_PROTO_T0) {
/* Check if the APDU in question is of Case 4 */
const u8 *p = sendbuf;
int lc;
p += 4;
lc = *p;
if (lc == 0)
lc = 256;
if (sendsize == lc + 6) {
/* Le is present, cut it out */
if (reader->ctx->debug >= 5) {
sc_debug(reader->ctx,
"Removing Le byte from Case 4 APDU\n");
}
sendsize--;
}
}
/* Masquerading case 1 APDUs */
if (sendsize == 4
&& (DO_MASQ(prv, MASQUERADE_1AS2_ALWAYS)
|| (DO_MASQ(priv, MASQUERADE_1AS2) && protocol == SC_PROTO_T0))) {
if (reader->ctx->debug >= 5) {
sc_debug(reader->ctx,
"Adding Lc byte to Case 1 APDU\n");
}
memcpy(masqueraded_apdu, sendbuf, 4);
masqueraded_apdu[4] = 0;
sendbuf = masqueraded_apdu;
sendsize = 5;
}
dwSendLength = sendsize;
dwRecvLength = *recvsize;
@ -506,7 +455,7 @@ static int pcsc_release(struct sc_reader *reader)
static struct sc_reader_operations pcsc_ops;
static const struct sc_reader_driver pcsc_drv = {
static struct sc_reader_driver pcsc_drv = {
"PC/SC reader",
"pcsc",
&pcsc_ops
@ -541,7 +490,6 @@ static int pcsc_init(struct sc_context *ctx, void **reader_data)
return SC_ERROR_OUT_OF_MEMORY;
}
gpriv->pcsc_ctx = pcsc_ctx;
gpriv->apdu_masquerade = DEF_APDU_MASQ;
*reader_data = gpriv;
reader_buf = (char *) malloc(sizeof(char) * reader_buf_size);
@ -598,34 +546,6 @@ static int pcsc_init(struct sc_context *ctx, void **reader_data)
break;
}
if (conf_block != NULL) {
const scconf_list *list;
if (scconf_get_bool(conf_block, "apdu_fix", 0))
gpriv->apdu_masquerade |= MASQUERADE_4AS3;
list = scconf_find_list(conf_block, "apdu_masquerade");
if (list)
gpriv->apdu_masquerade = 0;
for (; list; list = list->next) {
if (!strcmp(list->data, "case4as3")) {
gpriv->apdu_masquerade |= MASQUERADE_4AS3;
} else if (!strcmp(list->data, "case1as2")) {
gpriv->apdu_masquerade |= MASQUERADE_1AS2;
} else if (!strcmp(list->data, "case1as2_always")) {
gpriv->apdu_masquerade |= MASQUERADE_1AS2_ALWAYS;
} else if (!strcmp(list->data, "none")) {
gpriv->apdu_masquerade = 0;
} else {
/* no match. Should something be logged? */
sc_error(ctx,
"Unexpected keyword \"%s\" in "
"apdu_masquerade; ignored\n",
list->data);
}
}
}
return 0;
}
@ -641,7 +561,7 @@ static int pcsc_finish(struct sc_context *ctx, void *prv_data)
return 0;
}
const struct sc_reader_driver * sc_get_pcsc_driver(void)
struct sc_reader_driver * sc_get_pcsc_driver(void)
{
pcsc_ops.init = pcsc_init;
pcsc_ops.finish = pcsc_finish;