diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index a3bea3c6..0f92feea 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -22,8 +22,8 @@ AM_OBJCFLAGS = $(AM_CFLAGS) libopensc_la_SOURCES_BASE = \ sc.c ctx.c log.c errors.c \ - asn1.c base64.c sec.c card.c iso7816.c dir.c ef-atr.c padding.c apdu.c \ - simpletlv.c \ + asn1.c base64.c sec.c card.c iso7816.c dir.c ef-atr.c \ + ef-gdo.c padding.c apdu.c simpletlv.c \ \ pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \ pkcs15-prkey.c pkcs15-pubkey.c pkcs15-skey.c \ diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak index 5808f38e..bfee45f8 100644 --- a/src/libopensc/Makefile.mak +++ b/src/libopensc/Makefile.mak @@ -4,7 +4,7 @@ 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 ef-atr.obj \ - padding.obj apdu.obj simpletlv.obj \ + ef-gdo.obj padding.obj apdu.obj simpletlv.obj \ \ pkcs15.obj pkcs15-cert.obj pkcs15-data.obj pkcs15-pin.obj \ pkcs15-prkey.obj pkcs15-pubkey.obj pkcs15-skey.obj \ diff --git a/src/libopensc/card-starcos.c b/src/libopensc/card-starcos.c index b2d93bbc..ac22a926 100644 --- a/src/libopensc/card-starcos.c +++ b/src/libopensc/card-starcos.c @@ -1631,13 +1631,13 @@ static int starcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) { int r; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - const u8 *p; - unsigned int ef_gdo_tag, cla; - size_t ef_gdo_tag_len; + const unsigned char *iccsn; + size_t iccsn_len; sc_apdu_t apdu; if (!serial) return SC_ERROR_INVALID_ARGUMENTS; + /* see if we have cached serial number */ if (card->serialnr.len) { memcpy(serial, &card->serialnr, sizeof(*serial)); @@ -1646,25 +1646,12 @@ static int starcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) switch (card->type) { case SC_CARD_TYPE_STARCOS_V3_4: - r = sc_select_file(card, sc_get_mf_path(), NULL); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT MF failed"); - /* get serial number via EF.GDO */ - sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0, 0x82, 0x00); - apdu.resp = rbuf; - apdu.resplen = sizeof(rbuf); - apdu.le = 256; - apdu.lc = 0; - apdu.datalen = 0; - r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); - p = apdu.resp; - r = sc_asn1_read_tag(&p, apdu.resplen, &cla, &ef_gdo_tag, &ef_gdo_tag_len); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to parse EF.GDO"); - if ((ef_gdo_tag|cla) != 0x5A) - return SC_ERROR_INTERNAL; + r = sc_parse_ef_gdo(card, &iccsn, &iccsn_len, NULL, 0); + if (r < 0) + return r; /* cache serial number */ - memcpy(card->serialnr.value, p, MIN(ef_gdo_tag_len, SC_MAX_SERIALNR)); - card->serialnr.len = MIN(ef_gdo_tag_len, SC_MAX_SERIALNR); + memcpy(card->serialnr.value, iccsn, MIN(iccsn_len, SC_MAX_SERIALNR)); + card->serialnr.len = MIN(iccsn_len, SC_MAX_SERIALNR); break; default: diff --git a/src/libopensc/card-tcos.c b/src/libopensc/card-tcos.c index c8048784..12b71290 100644 --- a/src/libopensc/card-tcos.c +++ b/src/libopensc/card-tcos.c @@ -705,33 +705,28 @@ static int tcos_setperm(sc_card_t *card, int enable_nullpin) static int tcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) { - int r; - u8 buf[64]; - size_t len; - sc_path_t tpath; - sc_file_t *tfile = NULL; + int r; + const unsigned char *iccsn; + size_t iccsn_len; - if (!serial) return SC_ERROR_INVALID_ARGUMENTS; + if (!serial) + return SC_ERROR_INVALID_ARGUMENTS; /* see if we have cached serial number */ if (card->serialnr.len) { memcpy(serial, &card->serialnr, sizeof(*serial)); return SC_SUCCESS; } - sc_format_path("3F002F02", &tpath); - r = sc_select_file(card, &tpath, &tfile); - if (r < 0) return r; - len = tfile->size; - sc_file_free(tfile); - if (len > sizeof(buf) || len < 12) return SC_ERROR_INTERNAL; + r = sc_parse_ef_gdo(card, &iccsn, &iccsn_len, NULL, 0); + if (r < 0) + return r; - r = sc_read_binary(card, 0, buf, len, 0); - if (r < 0) return r; - if (buf[0] != 0x5a || buf[1] > len - 2) return SC_ERROR_INTERNAL; + /* cache serial number */ + memcpy(card->serialnr.value, iccsn, MIN(iccsn_len, SC_MAX_SERIALNR)); + card->serialnr.len = MIN(iccsn_len, SC_MAX_SERIALNR); - card->serialnr.len = buf[1]; - memcpy(card->serialnr.value, buf+2, buf[1]); + /* copy and return serial number */ memcpy(serial, &card->serialnr, sizeof(*serial)); return SC_SUCCESS; diff --git a/src/libopensc/ef-gdo.c b/src/libopensc/ef-gdo.c new file mode 100644 index 00000000..4d7a86ba --- /dev/null +++ b/src/libopensc/ef-gdo.c @@ -0,0 +1,132 @@ +/* + * ef-atr.c: Stuff for handling EF(GDO) + * + * Copyright (C) 2017 Frank Morgner + * + * 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 "config.h" +#endif + +#include "internal.h" +#include "asn1.h" + +static int +sc_parse_ef_gdo_content(const unsigned char *gdo, size_t gdo_len, + const unsigned char **iccsn, size_t *iccsn_len, + const unsigned char **chn, size_t *chn_len) +{ + int r = SC_SUCCESS; + const unsigned char *p = gdo; + size_t left = gdo_len; + + if (iccsn) + *iccsn = NULL; + if (iccsn_len) + *iccsn_len = 0; + if (chn) + *chn = NULL; + if (chn_len) + *chn_len = 0; + + while (left >= 2) { + unsigned int cla, tag; + size_t tag_len; + + r = sc_asn1_read_tag(&p, left, &cla, &tag, &tag_len); + if (r != SC_SUCCESS) { + if (r == SC_ERROR_ASN1_END_OF_CONTENTS) { + /* not enough data */ + r = SC_SUCCESS; + } + break; + } + if (tag == SC_ASN1_TAG_EOC) { + /* done parsing */ + break; + } + + if (cla == SC_ASN1_TAG_APPLICATION) { + switch (tag) { + case 0x1A: + if (iccsn) + *iccsn = p; + if (iccsn_len) + *iccsn_len = tag_len; + break; + case 0x1F20: + if (chn) + *chn = p; + if (chn_len) + *chn_len = tag_len; + break; + } + } + + p += tag_len; + left -= (p - gdo); + } + + return r; +} + + + +int +sc_parse_ef_gdo(struct sc_card *card, + const unsigned char **iccsn, size_t *iccsn_len, + const unsigned char **chn, size_t *chn_len) +{ + struct sc_context *ctx; + struct sc_path path; + struct sc_file *file; + unsigned char *gdo = NULL; + size_t gdo_len = 0; + int r; + + if (!card) + return SC_ERROR_INVALID_ARGUMENTS; + + ctx = card->ctx; + + LOG_FUNC_CALLED(ctx); + + sc_format_path("3F002F02", &path); + r = sc_select_file(card, &path, &file); + LOG_TEST_GOTO_ERR(ctx, r, "Cannot select EF(GDO) file"); + + if (file->size) { + gdo_len = file->size; + } else { + gdo_len = 64; + } + gdo = malloc(gdo_len); + if (!gdo) { + r = SC_ERROR_OUT_OF_MEMORY; + goto err; + } + + r = sc_read_binary(card, 0, gdo, gdo_len, 0); + LOG_TEST_GOTO_ERR(ctx, r, "Cannot read EF(GDO) file"); + + r = sc_parse_ef_gdo_content(gdo, r, iccsn, iccsn_len, chn, chn_len); + +err: + sc_file_free(file); + free(gdo); + + LOG_FUNC_RETURN(ctx, r); +} diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 209e4aba..5c2ec3cf 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -1317,6 +1317,9 @@ struct sc_app_info *sc_find_app(struct sc_card *card, struct sc_aid *aid); void sc_free_apps(struct sc_card *card); int sc_parse_ef_atr(struct sc_card *card); void sc_free_ef_atr(struct sc_card *card); +int sc_parse_ef_gdo(struct sc_card *card, + const unsigned char **iccsn, size_t *iccsn_len, + const unsigned char **chn, size_t *chn_len); int sc_update_dir(struct sc_card *card, sc_app_info_t *app); void sc_print_cache(struct sc_card *card); diff --git a/src/libopensc/pkcs15-infocamere.c b/src/libopensc/pkcs15-infocamere.c index 14c18879..63ffee13 100644 --- a/src/libopensc/pkcs15-infocamere.c +++ b/src/libopensc/pkcs15-infocamere.c @@ -166,10 +166,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) sc_card_t *card = p15card->card; sc_path_t path; - sc_file_t *file; sc_pkcs15_id_t id, auth_id; - unsigned char buffer[256]; - unsigned char ef_gdo[256]; char serial[256]; unsigned char certlen[2]; int authority, change_sign = 0; @@ -235,64 +232,31 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) SC_PKCS15_PIN_FLAG_INITIALIZED | SC_PKCS15_PIN_FLAG_NEEDS_PADDING; - int r, len_iccsn, len_chn; + int r; - sc_format_path("3F002F02", &path); + const unsigned char *iccsn, *chn; + size_t iccsn_len, chn_len; - r = sc_select_file(card, &path, &file); + r = sc_parse_ef_gdo(card, &iccsn, &iccsn_len, &chn, &chn_len); + if (r < 0) + return r; - if (r != SC_SUCCESS || file->size > 255) { - /* Not EF.GDO */ - sc_file_free(file); + if (!iccsn_len || chn_len < 2 || chn_len > 8) { return SC_ERROR_WRONG_CARD; } - sc_read_binary(card, 0, ef_gdo, file->size, 0); - - if (ef_gdo[0] != 0x5A || file->size < 3) { - /* Not EF.GDO */ - sc_file_free(file); - return SC_ERROR_WRONG_CARD; - } - - len_iccsn = ef_gdo[1]; - - memcpy(buffer, ef_gdo + 2, len_iccsn); - - sc_bin_to_hex(buffer, len_iccsn, serial, sizeof(serial), 0); - - if (file->size < (size_t) (len_iccsn + 5)) { - /* Not CHN */ - sc_file_free(file); - return SC_ERROR_WRONG_CARD; - } - sc_file_free(file); + sc_bin_to_hex(iccsn, iccsn_len, serial, sizeof(serial), 0); if (! - (ef_gdo[len_iccsn + 2] == 0x5F - && ef_gdo[len_iccsn + 3] == 0x20)) { - /* Not CHN */ - return SC_ERROR_WRONG_CARD; - } - - len_chn = ef_gdo[len_iccsn + 4]; - - if (len_chn < 2 || len_chn > 8) { - /* Length CHN incorrect */ - return SC_ERROR_WRONG_CARD; - } - - if (! - (ef_gdo[len_iccsn + 5] == 0x12 - && (ef_gdo[len_iccsn + 6] == 0x02 - || ef_gdo[len_iccsn + 6] == 0x03))) { + (chn[0] == 0x12 + && (chn[1] == 0x02 || chn[1] == 0x03))) { /* Not Infocamere Card */ return SC_ERROR_WRONG_CARD; } set_string(&p15card->tokeninfo->serial_number, serial); - if (ef_gdo[len_iccsn + 6] == 0x02) + if (chn[1] == 0x02) set_string(&p15card->tokeninfo->label, "Infocamere 1202 Card"); else { set_string(&p15card->tokeninfo->label, "Infocamere 1203 Card"); @@ -305,7 +269,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) /* Get the authentication certificate length */ - sc_format_path(infocamere_auth_certpath[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_auth_certpath[chn[1]-2], &path); r = sc_select_file(card, &path, NULL); @@ -336,11 +300,11 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) if (!change_sign) { /* add authentication PIN */ - sc_format_path(infocamere_auth_path[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_auth_path[chn[1]-2], &path); sc_pkcs15_format_id("01", &id); sc_pkcs15emu_add_pin(p15card, &id, - authPIN, &path, infocamere_idpin_auth_obj[ef_gdo[len_iccsn+6]-2], + authPIN, &path, infocamere_idpin_auth_obj[chn[1]-2], SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, 3, 0, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); @@ -354,7 +318,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) authPRKEY, SC_PKCS15_TYPE_PRKEY_RSA, 1024, authprkey_usage, - &path, infocamere_idprkey_auth_obj[ef_gdo[len_iccsn+6]-2], + &path, infocamere_idprkey_auth_obj[chn[1]-2], &auth_id, SC_PKCS15_CO_FLAG_PRIVATE); } @@ -362,7 +326,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) /* Get the non-repudiation certificate length */ - sc_format_path(infocamere_cert_path[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_cert_path[chn[1]-2], &path); if (sc_select_file(card, &path, NULL) < 0) { return SC_ERROR_INTERNAL; @@ -392,7 +356,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) authority = 1; - sc_format_path(infocamere_cacert_path[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_cacert_path[chn[1]-2], &path); r = sc_select_file(card, &path, NULL); @@ -425,11 +389,11 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) /* add non repudiation PIN */ - sc_format_path(infocamere_nrepud_path[ef_gdo[len_iccsn+6]-2], &path); + sc_format_path(infocamere_nrepud_path[chn[1]-2], &path); sc_pkcs15_format_id("02", &id); sc_pkcs15emu_add_pin(p15card, &id, - nonrepPIN, &path, infocamere_idpin_nrepud_obj[ef_gdo[len_iccsn+6]-2], + nonrepPIN, &path, infocamere_idpin_nrepud_obj[chn[1]-2], SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, 3, 0, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); @@ -442,7 +406,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card) sc_pkcs15emu_add_prkey(p15card, &id, nonrepPRKEY, SC_PKCS15_TYPE_PRKEY_RSA, 1024, prkey_usage, - &path, infocamere_idprkey_nrepud_obj[ef_gdo[len_iccsn+6]-2], + &path, infocamere_idprkey_nrepud_obj[chn[1]-2], &auth_id, SC_PKCS15_CO_FLAG_PRIVATE); diff --git a/src/libopensc/pkcs15-tccardos.c b/src/libopensc/pkcs15-tccardos.c index b1779b5e..d8986a9d 100644 --- a/src/libopensc/pkcs15-tccardos.c +++ b/src/libopensc/pkcs15-tccardos.c @@ -304,9 +304,9 @@ static int sc_pkcs15_tccardos_init_func(sc_pkcs15_card_t *p15card) int r; struct sc_path path; struct sc_file *file = NULL; - u8 gdo[MAX_INFO1_SIZE]; char hex_buf[256]; - size_t gdo_len = MAX_INFO1_SIZE; + const unsigned char *iccsn; + size_t iccsn_len; struct sc_card *card = p15card->card; /* check if we have the correct card OS */ @@ -329,10 +329,10 @@ static int sc_pkcs15_tccardos_init_func(sc_pkcs15_card_t *p15card) if (p15card->tokeninfo->manufacturer_id == NULL) return SC_ERROR_OUT_OF_MEMORY; /* set the serial number */ - r = read_file(p15card->card, "3F002F02", gdo, &gdo_len); - if (r != SC_SUCCESS) + r = sc_parse_ef_gdo(card, &iccsn, &iccsn_len, NULL, 0); + if (r != SC_SUCCESS || iccsn_len < 5+8) return SC_ERROR_INTERNAL; - sc_bin_to_hex(gdo + 7, 8, hex_buf, sizeof(hex_buf), 0); + sc_bin_to_hex(iccsn + 5, 8, hex_buf, sizeof(hex_buf), 0); p15card->tokeninfo->serial_number = strdup(hex_buf); if (p15card->tokeninfo->serial_number == NULL) return SC_ERROR_OUT_OF_MEMORY;