diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index b5271cb2..b6f09984 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -19,7 +19,7 @@ INCLUDES = -I$(top_srcdir)/src libopensc_la_SOURCES = \ sc.c ctx.c log.c errors.c \ - asn1.c base64.c sec.c card.c iso7816.c dir.c padding.c apdu.c \ + asn1.c base64.c sec.c card.c iso7816.c dir.c ef-atr.c padding.c apdu.c \ \ pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \ pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \ diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index 14b6fdb7..90a00722 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -3,7 +3,7 @@ TOPDIR = ..\.. TARGET = opensc.dll opensc_a.lib OBJECTS = \ sc.obj ctx.obj log.obj errors.obj \ - asn1.obj base64.obj sec.obj card.obj iso7816.obj dir.obj padding.obj apdu.obj \ + asn1.obj base64.obj sec.obj card.obj iso7816.obj dir.obj ef-atr.obj padding.obj apdu.obj \ \ pkcs15.obj pkcs15-cert.obj pkcs15-data.obj pkcs15-pin.obj \ pkcs15-prkey.obj pkcs15-pubkey.obj pkcs15-sec.obj \ diff --git a/src/libopensc/card.c b/src/libopensc/card.c index 39db5c54..fd39aa1b 100644 --- a/src/libopensc/card.c +++ b/src/libopensc/card.c @@ -87,6 +87,7 @@ static sc_card_t * sc_card_new(sc_context_t *ctx) static void sc_card_free(sc_card_t *card) { sc_free_apps(card); + sc_free_ef_atr(card); if (card->ef_dir != NULL) sc_file_free(card->ef_dir); free(card->ops); diff --git a/src/libopensc/ef-atr.c b/src/libopensc/ef-atr.c new file mode 100644 index 00000000..e638b7bf --- /dev/null +++ b/src/libopensc/ef-atr.c @@ -0,0 +1,152 @@ +/* + * ef-atr.c: Stuff for handling EF(ATR) + * + * Copyright (C) 2001, 2002 Juha Yrjölä + * Copyright (C) 2010 Viktor Tarasov + * OpenTrust + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "internal.h" +#include "asn1.h" +#include "iso7816.h" + +static int +sc_parse_ef_atr_content(struct sc_card *card, unsigned char *buf, size_t buflen) +{ + struct sc_context *ctx = card->ctx; + const unsigned char *tag = NULL; + size_t taglen; + struct sc_ef_atr ef_atr; + + LOG_FUNC_CALLED(ctx); + tag = sc_asn1_find_tag(ctx, buf, buflen, ISO7816_TAG_II_CARD_SERVICE, &taglen); + if (tag && taglen >= 1) { + ef_atr.card_service = *tag; + sc_log(ctx, "From EF.ATR: card service 0x%X", ef_atr.card_service); + } + + tag = sc_asn1_find_tag(ctx, buf, buflen, ISO7816_TAG_II_PRE_ISSUING, &taglen); + if (tag && taglen >= 4) { + ef_atr.ic_manufacturer = *(tag + 0); + ef_atr.ic_type = *(tag + 1); + ef_atr.os_version = *(tag + 2); + ef_atr.iasecc_version = *(tag + 3); + sc_log(ctx, "From EF.ATR: IC manufacturer/type %X/%X, OS/IasEcc versions %X/%X", + ef_atr.ic_manufacturer, ef_atr.ic_type, + ef_atr.os_version, ef_atr.iasecc_version); + } + + tag = sc_asn1_find_tag(ctx, buf, buflen, ISO7816_TAG_II_CARD_CAPABILITIES, &taglen); + if (tag && taglen >= 3) { + ef_atr.df_selection = *(tag + 0); + ef_atr.unit_size = *(tag + 1); + ef_atr.card_capabilities = *(tag + 2); + sc_log(ctx, "From EF.ATR: DF selection %X, unit_size %X, card caps %X", + ef_atr.df_selection, ef_atr.unit_size, ef_atr.card_capabilities); + } + + tag = sc_asn1_find_tag(ctx, buf, buflen, ISO7816_TAG_II_AID, &taglen); + if (tag) { + if (taglen > sizeof(ef_atr.aid.value)) + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Invalid MF AID size"); + memcpy(ef_atr.aid.value, tag, taglen); + ef_atr.aid.len = taglen; + sc_log(ctx, "From EF.ATR: AID(%i) %s", ef_atr.aid.len, + sc_dump_hex(ef_atr.aid.value, ef_atr.aid.len)); + } + + tag = sc_asn1_find_tag(ctx, buf, buflen, ISO7816_TAG_II_IO_BUFFER_SIZES, &taglen); + if (tag && taglen >= 0x10) { + ef_atr.max_size_send = *(tag + 2) * 0x100 + *(tag + 3); + ef_atr.max_size_send_sc = *(tag + 6) * 0x100 + *(tag + 7); + ef_atr.max_size_recv = *(tag + 10) * 0x100 + *(tag + 11); + ef_atr.max_size_recv_sc = *(tag + 14) * 0x100 + *(tag + 15); + + /* FIXME: tell me why '-5' */ + card->max_send_size = ef_atr.max_size_send - 5; + card->max_recv_size = ef_atr.max_size_recv; + sc_log(ctx, "From EF.ATR: mas send/recv size %X/%X", card->max_send_size, card->max_recv_size); + } + + tag = sc_asn1_find_tag(ctx, buf, buflen, ISO7816_TAG_II_ALLOCATION_SCHEME, &taglen); + if (tag && taglen < sizeof(ef_atr.allocation_oid)) { + sc_log(ctx, "From EF.ATR: OID %s", sc_dump_hex(tag, sizeof(taglen))); + memcpy(ef_atr.allocation_oid.value, tag, taglen); + } + + tag = sc_asn1_find_tag(ctx, buf, buflen, ISO7816_TAG_II_STATUS, &taglen); + if (tag && taglen == 2) { + ef_atr.status = *(tag + 0) * 0x100 + *(tag + 1); + sc_log(ctx, "From EF.ATR: status word 0x%X", ef_atr.status); + } + + if (!card->ef_atr) + card->ef_atr = calloc(1, sizeof(struct sc_ef_atr)); + + if (!card->ef_atr) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + + memcpy(card->ef_atr, &ef_atr, sizeof(struct sc_ef_atr)); + + LOG_FUNC_RETURN(ctx, SC_SUCCESS); +} + + +int sc_parse_ef_atr(struct sc_card *card) +{ + struct sc_context *ctx = card->ctx; + struct sc_path path; + struct sc_file *file; + int rv; + unsigned char *buf = NULL; + + LOG_FUNC_CALLED(ctx); + + sc_format_path("3F002F01", &path); + rv = sc_select_file(card, &path, &file); + if (rv == SC_ERROR_FILE_NOT_FOUND) + LOG_FUNC_RETURN(ctx, SC_SUCCESS); + LOG_TEST_RET(ctx, rv, "Cannot select EF(ATR) file"); + + buf = malloc(file->size); + if (!buf) + LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Memory allocation error"); + rv = sc_read_binary(card, 0, buf, file->size, 0); + LOG_TEST_RET(ctx, rv, "Cannot read EF(ATR) file"); + + rv = sc_parse_ef_atr_content(card, buf, file->size); + LOG_TEST_RET(ctx, rv, "EF(ATR) parse error"); + + free(buf); + sc_file_free(file); + + LOG_FUNC_RETURN(ctx, SC_SUCCESS); +} + +void sc_free_ef_atr(sc_card_t *card) +{ + if (card->ef_atr) + free(card->ef_atr); + card->ef_atr = NULL; +} diff --git a/src/libopensc/iso7816.h b/src/libopensc/iso7816.h index 43d1a2f5..d8730258 100644 --- a/src/libopensc/iso7816.h +++ b/src/libopensc/iso7816.h @@ -15,6 +15,16 @@ extern "C" { #define ISO7816_TAG_FCP_ID 0x83 #define ISO7816_TAG_FCP_ACLS 0x86 +/* Interindustry data tags */ +#define ISO7816_TAG_II_CARD_SERVICE 0x43 +#define ISO7816_TAG_II_INITIAL_ACCESS_DATA 0x44 +#define ISO7816_TAG_II_CARD_ISSUER_DATA 0x45 +#define ISO7816_TAG_II_PRE_ISSUING 0x46 +#define ISO7816_TAG_II_CARD_CAPABILITIES 0x47 +#define ISO7816_TAG_II_AID 0x4F +#define ISO7816_TAG_II_IO_BUFFER_SIZES 0xE0 +#define ISO7816_TAG_II_ALLOCATION_SCHEME 0x78 +#define ISO7816_TAG_II_STATUS 0x82 #define ISO7816_FILE_TYPE_TRANSPARENT_EF 0x01 #define ISO7816_FILE_TYPE_DF 0x38 diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index 5d4f96ab..b79112ec 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -80,6 +80,7 @@ sc_disconnect_card sc_do_log _sc_debug sc_enum_apps +sc_parse_ef_atr sc_establish_context sc_file_add_acl_entry sc_file_clear_acl_entries @@ -98,6 +99,7 @@ sc_format_asn1_entry sc_format_oid sc_format_path sc_free_apps +sc_free_ef_atr sc_get_cache_dir sc_get_challenge sc_get_conf_block diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 954cf555..19ec82b4 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -217,6 +217,29 @@ typedef struct sc_app_info { int rec_nr; /* -1, if EF(DIR) is transparent */ } sc_app_info_t; +struct sc_ef_atr { + unsigned char card_service; + unsigned char ic_manufacturer; + unsigned char ic_type; + unsigned char os_version; + unsigned char iasecc_version; + + unsigned char df_selection; + size_t unit_size; + unsigned char card_capabilities; + + struct sc_aid aid; + + size_t max_size_send; + size_t max_size_send_sc; + size_t max_size_recv; + size_t max_size_recv_sc; + + struct sc_object_id allocation_oid; + + unsigned status; +}; + struct sc_card_cache { struct sc_path current_path; @@ -431,6 +454,8 @@ typedef struct sc_card { int app_count; struct sc_file *ef_dir; + struct sc_ef_atr *ef_atr; + struct sc_algorithm_info *algorithms; int algorithm_count; @@ -1120,6 +1145,8 @@ int sc_make_cache_dir(sc_context_t *ctx); int sc_enum_apps(sc_card_t *card); void sc_free_apps(sc_card_t *card); +int sc_parse_ef_atr(sc_card_t *card); +void sc_free_ef_atr(sc_card_t *card); int sc_update_dir(sc_card_t *card, sc_app_info_t *app); struct sc_algorithm_info * sc_card_find_rsa_alg(sc_card_t *card,