- move APDU encoding to the reader layer

- remove APDU masquerading code, it shouldn't be necessary
  anymore


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@2831 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
nils 2006-02-05 19:00:01 +00:00
parent 85aaa4466d
commit ca2a5e11fd
7 changed files with 228 additions and 159 deletions

View File

@ -34,7 +34,7 @@
* @param proto the desired protocol
* @return length of the encoded APDU
*/
static size_t sc_get_apdu_length(const sc_apdu_t *apdu, unsigned int proto)
static size_t sc_apdu_get_length(const sc_apdu_t *apdu, unsigned int proto)
{
size_t ret = 4;
@ -80,7 +80,7 @@ static int sc_apdu2bytes(sc_context_t *ctx, const sc_apdu_t *apdu,
{
u8 *p = out;
size_t len = sc_get_apdu_length(apdu, proto);
size_t len = sc_apdu_get_length(apdu, proto);
if (out == NULL || outlen < len)
return SC_ERROR_INVALID_ARGUMENTS;
@ -168,139 +168,89 @@ static int sc_apdu2bytes(sc_context_t *ctx, const sc_apdu_t *apdu,
return SC_SUCCESS;
}
static void sc_apdu_log_in(sc_context_t *ctx, const u8 *data, size_t len, int s)
static void sc_apdu_log(sc_context_t *ctx, const u8 *data, size_t len,
int is_sensitive, int is_outgoing)
{
size_t buflen = len * 5 + 128;
char * buf = malloc(buflen);
size_t blen = len * 5 + 128;
char *buf = malloc(blen);
if (buf == NULL)
return;
if (s == 0 || ctx->debug >= 6)
sc_hex_dump(ctx, data, len, buf, buflen);
else
snprintf(buf, buflen, "%02x %02x %02x %02x [sensitive data]\n",
if (is_sensitive == 0 || ctx->debug >= 6)
sc_hex_dump(ctx, data, len, buf, blen);
else {
if (is_outgoing != 0)
/* is case of a outgoing APDU log the command header */
snprintf(buf, blen, "%02x %02x %02x %02x "
"[senstive data]\n",
data[0], data[1], data[2], data[3]);
else
snprintf(buf, blen, "[sensitive data]\n");
}
sc_debug(ctx,
"\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> %4d bytes send\n"
sc_debug(ctx, "\n%s APDU data [%5u bytes] =====================================\n"
"%s"
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n",
(int)len, buf);
"======================================================================\n",
is_outgoing != 0 ? "Outgoing" : "Incoming", len,
buf);
free(buf);
}
static void sc_apdu_log_out(sc_context_t *ctx, const u8 *data, size_t len, int s)
int sc_apdu_get_octets(sc_context_t *ctx, const sc_apdu_t *apdu, u8 **buf,
size_t *len, unsigned int proto, int do_log)
{
size_t buflen = len * 5 + 128;
char * buf = malloc(buflen);
if (buf == NULL)
return;
size_t nlen;
u8 *nbuf;
if (s == 0 || ctx->debug >= 6)
sc_hex_dump(ctx, data, len, buf, buflen);
else
snprintf(buf, buflen, "[sensitive data]\n");
if (apdu == NULL || buf == NULL || len == NULL)
return SC_ERROR_INVALID_ARGUMENTS;
sc_debug(ctx,
"\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< %4d bytes received\n"
"%s"
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
(int)len, buf);
free(buf);
}
/** Encodes the APDU in a octet buffer and sends it to the token
* using the sc_reader_operations::transmit function.
* @param card sc_card_t object of the token to which the APDU
* should be sent
* @param apdu sc_apdu_t object to transmit
* @return SC_SUCCESS on success and an error code otherwise
*/
static int sc_apdu_encode_send(sc_card_t *card, sc_apdu_t *apdu,
unsigned int proto)
{
size_t sendsize, recvsize, rbuflen = 0;
u8 *sbuf = NULL, *rbuf = NULL;
int r;
sc_context_t *ctx = card->ctx;
if (card->reader->ops->transmit == NULL)
return SC_ERROR_NOT_SUPPORTED;
/* we always use a at least 258 byte size big return buffer
* to mimic the behaviour of the old implementation (some readers
* seems to require a larger than necessary return buffer).
* The buffer for the returned data needs to be at least 2 bytes
* larger than the expected data length to store SW1 and SW2. */
recvsize = rbuflen = apdu->resplen <= 256 ? 258 : apdu->resplen + 2;
rbuf = malloc(rbuflen);
/* get the estimated length of encoded APDU */
sendsize = sc_get_apdu_length(apdu, proto);
if (sendsize == 0) {
r = SC_ERROR_INTERNAL;
goto out;
}
sbuf = malloc(sendsize);
if (sbuf == NULL || rbuf == NULL) {
r = SC_ERROR_MEMORY_FAILURE;
goto out;
}
nlen = sc_apdu_get_length(apdu, proto);
if (nlen == 0)
return SC_ERROR_INTERNAL;
nbuf = malloc(nlen);
if (nbuf == NULL)
return SC_ERROR_MEMORY_FAILURE;
/* encode the APDU in the buffer */
r = sc_apdu2bytes(ctx, apdu, proto, sbuf, sendsize);
if (r != SC_SUCCESS)
goto out;
if (sc_apdu2bytes(ctx, apdu, proto, nbuf, nlen) != SC_SUCCESS)
return SC_ERROR_INTERNAL;
*buf = nbuf;
*len = nlen;
/* log outgoing APDU */
#ifndef OPENSC_DONT_LOG_SENSITIVE
if (ctx->debug >= 5)
sc_apdu_log_in(ctx, sbuf, sendsize, (int)apdu->sensitive);
#endif
/* now let the reader driver transmit the APDU to the token */
r = card->reader->ops->transmit(card->reader, card->slot, sbuf,
sendsize, rbuf, &recvsize,
apdu->control);
if (r < 0) {
/* unable to transmit ... most likely a reader problem */
sc_error(ctx, "unable to transmit");
goto out;
}
/* log incoming data */
#ifndef OPENSC_DONT_LOG_SENSITIVE
if (ctx->debug >= 5)
sc_apdu_log_out(ctx, rbuf, recvsize, (int)apdu->sensitive);
if (do_log != 0 && ctx->debug >= 5)
sc_apdu_log(ctx, nbuf, nlen, apdu->sensitive, 1);
#endif
if (recvsize < 2) {
return SC_SUCCESS;
}
int sc_apdu_set_resp(sc_context_t *ctx, sc_apdu_t *apdu, const u8 *buf,
size_t len, int do_log)
{
#ifndef OPENSC_DONT_LOG_SENSITIVE
if (do_log != 0 && ctx->debug >= 5)
sc_apdu_log(ctx, buf, len, apdu->sensitive, 0);
#endif
if (len < 2) {
/* no SW1 SW2 ... something went terrible wrong */
sc_error(ctx, "SW1 SW2 missing");
r = SC_ERROR_INTERNAL;
goto out;
sc_error(ctx, "invalid response: SW1 SW2 missing");
return SC_ERROR_INTERNAL;
}
/* the last two bytes contain the status bytes SW1 and SW2 */
apdu->sw1 = (unsigned int)rbuf[recvsize - 2];
apdu->sw2 = (unsigned int)rbuf[recvsize - 1];
recvsize -= 2;
/* set the SW1 and SW2 status bytes (the last two bytes of
* the response */
apdu->sw1 = (unsigned int)buf[len - 2];
apdu->sw2 = (unsigned int)buf[len - 1];
len -= 2;
/* set output length and copy the returned data if necessary */
if (recvsize <= apdu->resplen)
apdu->resplen = recvsize;
if (len <= apdu->resplen)
apdu->resplen = len;
if (apdu->resplen != 0)
memcpy(apdu->resp, rbuf, apdu->resplen);
memcpy(apdu->resp, buf, apdu->resplen);
r = SC_SUCCESS;
out:
if (sbuf != NULL) {
sc_mem_clear(sbuf, sendsize);
free(sbuf);
}
if (rbuf != NULL) {
sc_mem_clear(rbuf, rbuflen);
free(rbuf);
}
return r;
return SC_SUCCESS;
}
/*********************************************************************/
@ -456,7 +406,9 @@ static int do_single_transmit(sc_card_t *card, sc_apdu_t *apdu)
*/
/* send APDU to the reader driver */
r = sc_apdu_encode_send(card, apdu, card->slot->active_protocol);
if (card->reader->ops->transmit == NULL)
return SC_ERROR_NOT_SUPPORTED;
r = card->reader->ops->transmit(card->reader, card->slot, apdu);
if (r != 0) {
sc_error(ctx, "unable to transmit APDU");
return r;

View File

@ -32,13 +32,6 @@
#include <winreg.h>
#endif
/* 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(sc_context_t *ctx, sc_reader_t *reader)
{
assert(reader != NULL);
@ -260,33 +253,9 @@ static void load_reader_driver_options(sc_context_t *ctx,
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;
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);

View File

@ -157,6 +157,33 @@ void sc_mutex_destroy(const sc_context_t *ctx, void *mutex);
*/
unsigned long sc_thread_id(const sc_context_t *ctx);
/********************************************************************/
/* internal APDU handling functions */
/********************************************************************/
/**
* Returns the encoded APDU in newly created buffer.
* @param ctx sc_context_t object
* @param apdu sc_apdu_t object with the APDU to encode
* @param buf pointer to the newly allocated buffer
* @param len length of the encoded APDU
* @param proto protocol to be used
* @param do_log log data to send
* @return SC_SUCCESS on success and an error code otherwise
*/
int sc_apdu_get_octets(sc_context_t *ctx, const sc_apdu_t *apdu, u8 **buf,
size_t *len, unsigned int proto, int do_log);
/**
* Sets the status bytes and return data in the APDU
* @param ctx sc_context_t object
* @param apdu the apdu to which the data should be written
* @param buf returned data
* @param len length of the returned data
* @param do_log log returned data
* @return SC_SUCCESS on success and an error code otherwise
*/
int sc_apdu_set_resp(sc_context_t *ctx, sc_apdu_t *apdu, const u8 *buf,
size_t len, int do_log);
#ifdef __cplusplus
}
#endif

View File

@ -265,13 +265,8 @@ struct sc_reader_driver {
struct sc_reader_operations *ops;
size_t max_send_size, max_recv_size;
int apdu_masquerade;
void *dll;
};
#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
@ -386,9 +381,7 @@ struct sc_reader_operations {
int (*disconnect)(struct sc_reader *reader, struct sc_slot_info *slot,
int action);
int (*transmit)(struct sc_reader *reader, struct sc_slot_info *slot,
const u8 *sendbuf, size_t sendsize,
u8 *recvbuf, size_t *recvsize,
unsigned long control);
sc_apdu_t *apdu);
int (*lock)(struct sc_reader *reader, struct sc_slot_info *slot);
int (*unlock)(struct sc_reader *reader, struct sc_slot_info *slot);
int (*set_protocol)(struct sc_reader *reader, struct sc_slot_info *slot,

View File

@ -286,7 +286,7 @@ static int refresh_slot_attributes(sc_reader_t *reader,
return 0;
}
static int ctapi_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
static int ctapi_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
const u8 *sendbuf, size_t sendsize,
u8 *recvbuf, size_t *recvsize,
unsigned long control)
@ -315,6 +315,47 @@ static int ctapi_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
return 0;
}
static int ctapi_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
sc_apdu_t *apdu)
{
size_t ssize, rsize, rbuflen = 0;
u8 *sbuf = NULL, *rbuf = NULL;
int r;
rsize = rbuflen = apdu->resplen + 2;
rbuf = malloc(rbuflen);
if (rbuf == NULL) {
r = SC_ERROR_MEMORY_FAILURE;
goto out;
}
/* encode and log the APDU */
r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW, 1);
if (r != SC_SUCCESS)
goto out;
r = ctapi_internal_transmit(reader, slot, sbuf, ssize,
rbuf, &rsize, apdu->control);
if (r < 0) {
/* unable to transmit ... most likely a reader problem */
sc_error(reader->ctx, "unable to transmit");
goto out;
}
/* log and set response */
r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize, 1);
if (r != SC_SUCCESS)
return r;
out:
if (sbuf != NULL) {
sc_mem_clear(sbuf, ssize);
free(sbuf);
}
if (rbuf != NULL) {
sc_mem_clear(rbuf, rbuflen);
free(rbuf);
}
return r;
}
static int ctapi_detect_card_presence(sc_reader_t *reader, sc_slot_info_t *slot)
{
int r;
@ -411,7 +452,7 @@ static struct sc_reader_driver ctapi_drv = {
"CT-API module",
"ctapi",
&ctapi_ops,
0, 0, 0, NULL
0, 0, NULL
};
static struct ctapi_module * add_module(struct ctapi_global_private_data *gpriv,

View File

@ -43,9 +43,7 @@ static int openct_reader_connect(sc_reader_t *reader,
static int openct_reader_disconnect(sc_reader_t *reader,
sc_slot_info_t *slot, int action);
static int openct_reader_transmit(sc_reader_t *reader,
sc_slot_info_t *slot,
const u8 *sendbuf, size_t sendsize,
u8 *recvbuf, size_t *recvsize, unsigned long control);
sc_slot_info_t *slot, sc_apdu_t *apdu);
static int openct_reader_perform_verify(sc_reader_t *reader,
sc_slot_info_t *slot,
struct sc_pin_cmd_data *info);
@ -61,7 +59,7 @@ static struct sc_reader_driver openct_reader_driver = {
"OpenCT reader",
"openct",
&openct_ops,
0, 0, 0, NULL
0, 0, NULL
};
/* private data structures */
@ -287,7 +285,7 @@ openct_reader_disconnect(sc_reader_t *reader,
}
int
openct_reader_transmit(sc_reader_t *reader,
openct_reader_internal_transmit(sc_reader_t *reader,
sc_slot_info_t *slot,
const u8 *sendbuf, size_t sendsize,
u8 *recvbuf, size_t *recvsize, unsigned long control)
@ -315,6 +313,48 @@ openct_reader_transmit(sc_reader_t *reader,
return openct_error(reader, rc);
}
static int openct_reader_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
sc_apdu_t *apdu)
{
size_t ssize, rsize, rbuflen = 0;
u8 *sbuf = NULL, *rbuf = NULL;
int r;
rsize = rbuflen = apdu->resplen + 2;
rbuf = malloc(rbuflen);
if (rbuf == NULL) {
r = SC_ERROR_MEMORY_FAILURE;
goto out;
}
/* encode and log the APDU */
r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, SC_PROTO_RAW, 1);
if (r != SC_SUCCESS)
goto out;
r = openct_reader_internal_transmit(reader, slot, sbuf, ssize,
rbuf, &rsize, apdu->control);
if (r < 0) {
/* unable to transmit ... most likely a reader problem */
sc_error(reader->ctx, "unable to transmit");
goto out;
}
/* log and set response */
r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize, 1);
if (r != SC_SUCCESS)
return r;
out:
if (sbuf != NULL) {
sc_mem_clear(sbuf, ssize);
free(sbuf);
}
if (rbuf != NULL) {
sc_mem_clear(rbuf, rbuflen);
free(rbuf);
}
return r;
}
int
openct_reader_perform_verify(sc_reader_t *reader,
sc_slot_info_t *slot,

View File

@ -141,7 +141,7 @@ static DWORD opensc_proto_to_pcsc(unsigned int proto)
}
}
static int pcsc_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
static int pcsc_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
const u8 *sendbuf, size_t sendsize,
u8 *recvbuf, size_t *recvsize,
unsigned long control)
@ -202,6 +202,53 @@ static int pcsc_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
return 0;
}
static int pcsc_transmit(sc_reader_t *reader, sc_slot_info_t *slot,
sc_apdu_t *apdu)
{
size_t ssize, rsize, rbuflen = 0;
u8 *sbuf = NULL, *rbuf = NULL;
int r;
/* we always use a at least 258 byte size big return buffer
* to mimic the behaviour of the old implementation (some readers
* seems to require a larger than necessary return buffer).
* The buffer for the returned data needs to be at least 2 bytes
* larger than the expected data length to store SW1 and SW2. */
rsize = rbuflen = apdu->resplen <= 256 ? 258 : apdu->resplen + 2;
rbuf = malloc(rbuflen);
if (rbuf == NULL) {
r = SC_ERROR_MEMORY_FAILURE;
goto out;
}
/* encode and log the APDU */
r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, slot->active_protocol, 1);
if (r != SC_SUCCESS)
goto out;
r = pcsc_internal_transmit(reader, slot, sbuf, ssize,
rbuf, &rsize, apdu->control);
if (r < 0) {
/* unable to transmit ... most likely a reader problem */
sc_error(reader->ctx, "unable to transmit");
goto out;
}
/* log and set response */
r = sc_apdu_set_resp(reader->ctx, apdu, rbuf, rsize, 1);
if (r != SC_SUCCESS)
return r;
out:
if (sbuf != NULL) {
sc_mem_clear(sbuf, ssize);
free(sbuf);
}
if (rbuf != NULL) {
sc_mem_clear(rbuf, rbuflen);
free(rbuf);
}
return r;
}
static int refresh_slot_attributes(sc_reader_t *reader, sc_slot_info_t *slot)
{
struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
@ -586,7 +633,7 @@ static struct sc_reader_driver pcsc_drv = {
"PC/SC reader",
"pcsc",
&pcsc_ops,
0, 0, 0, NULL
0, 0, NULL
};
static int pcsc_init(sc_context_t *ctx, void **reader_data)