From ca2a5e11fd4a5bf235eb9971bf4b0ca1cecccb65 Mon Sep 17 00:00:00 2001 From: nils Date: Sun, 5 Feb 2006 19:00:01 +0000 Subject: [PATCH] - 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 --- src/libopensc/apdu.c | 174 ++++++++++++---------------------- src/libopensc/ctx.c | 31 ------ src/libopensc/internal.h | 27 ++++++ src/libopensc/opensc.h | 9 +- src/libopensc/reader-ctapi.c | 45 ++++++++- src/libopensc/reader-openct.c | 50 +++++++++- src/libopensc/reader-pcsc.c | 51 +++++++++- 7 files changed, 228 insertions(+), 159 deletions(-) diff --git a/src/libopensc/apdu.c b/src/libopensc/apdu.c index 03b68d7e..6924a15f 100644 --- a/src/libopensc/apdu.c +++ b/src/libopensc/apdu.c @@ -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; diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index 0dd61598..b1b7a2be 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -32,13 +32,6 @@ #include #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); diff --git a/src/libopensc/internal.h b/src/libopensc/internal.h index 8bbebadd..ef8512e4 100644 --- a/src/libopensc/internal.h +++ b/src/libopensc/internal.h @@ -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 diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index acccc53d..90598dc3 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -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, diff --git a/src/libopensc/reader-ctapi.c b/src/libopensc/reader-ctapi.c index fd0cc386..c208ceb4 100644 --- a/src/libopensc/reader-ctapi.c +++ b/src/libopensc/reader-ctapi.c @@ -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, diff --git a/src/libopensc/reader-openct.c b/src/libopensc/reader-openct.c index 26f596aa..17325769 100644 --- a/src/libopensc/reader-openct.c +++ b/src/libopensc/reader-openct.c @@ -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, diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index a78e800a..8fe8e402 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -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)