unified reading of EF.GDO

This commit is contained in:
Frank Morgner 2017-09-13 12:21:59 +02:00
parent 293d02ea4b
commit 0502a839c6
8 changed files with 183 additions and 102 deletions

View File

@ -22,8 +22,8 @@ AM_OBJCFLAGS = $(AM_CFLAGS)
libopensc_la_SOURCES_BASE = \ libopensc_la_SOURCES_BASE = \
sc.c ctx.c log.c errors.c \ 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 \ asn1.c base64.c sec.c card.c iso7816.c dir.c ef-atr.c \
simpletlv.c \ ef-gdo.c padding.c apdu.c simpletlv.c \
\ \
pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \ pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \
pkcs15-prkey.c pkcs15-pubkey.c pkcs15-skey.c \ pkcs15-prkey.c pkcs15-pubkey.c pkcs15-skey.c \

View File

@ -4,7 +4,7 @@ TARGET = opensc.dll opensc_a.lib
OBJECTS = \ OBJECTS = \
sc.obj ctx.obj log.obj errors.obj \ sc.obj ctx.obj log.obj errors.obj \
asn1.obj base64.obj sec.obj card.obj iso7816.obj dir.obj ef-atr.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.obj pkcs15-cert.obj pkcs15-data.obj pkcs15-pin.obj \
pkcs15-prkey.obj pkcs15-pubkey.obj pkcs15-skey.obj \ pkcs15-prkey.obj pkcs15-pubkey.obj pkcs15-skey.obj \

View File

@ -1631,13 +1631,13 @@ static int starcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
{ {
int r; int r;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
const u8 *p; const unsigned char *iccsn;
unsigned int ef_gdo_tag, cla; size_t iccsn_len;
size_t ef_gdo_tag_len;
sc_apdu_t apdu; sc_apdu_t apdu;
if (!serial) if (!serial)
return SC_ERROR_INVALID_ARGUMENTS; return SC_ERROR_INVALID_ARGUMENTS;
/* see if we have cached serial number */ /* see if we have cached serial number */
if (card->serialnr.len) { if (card->serialnr.len) {
memcpy(serial, &card->serialnr, sizeof(*serial)); 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) { switch (card->type) {
case SC_CARD_TYPE_STARCOS_V3_4: case SC_CARD_TYPE_STARCOS_V3_4:
r = sc_select_file(card, sc_get_mf_path(), NULL); r = sc_parse_ef_gdo(card, &iccsn, &iccsn_len, NULL, 0);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT MF failed"); if (r < 0)
/* get serial number via EF.GDO */ return r;
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;
/* cache serial number */ /* cache serial number */
memcpy(card->serialnr.value, p, MIN(ef_gdo_tag_len, SC_MAX_SERIALNR)); memcpy(card->serialnr.value, iccsn, MIN(iccsn_len, SC_MAX_SERIALNR));
card->serialnr.len = MIN(ef_gdo_tag_len, SC_MAX_SERIALNR); card->serialnr.len = MIN(iccsn_len, SC_MAX_SERIALNR);
break; break;
default: default:

View File

@ -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) static int tcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
{ {
int r; int r;
u8 buf[64]; const unsigned char *iccsn;
size_t len; size_t iccsn_len;
sc_path_t tpath;
sc_file_t *tfile = NULL;
if (!serial) return SC_ERROR_INVALID_ARGUMENTS; if (!serial)
return SC_ERROR_INVALID_ARGUMENTS;
/* see if we have cached serial number */ /* see if we have cached serial number */
if (card->serialnr.len) { if (card->serialnr.len) {
memcpy(serial, &card->serialnr, sizeof(*serial)); memcpy(serial, &card->serialnr, sizeof(*serial));
return SC_SUCCESS; return SC_SUCCESS;
} }
sc_format_path("3F002F02", &tpath);
r = sc_select_file(card, &tpath, &tfile);
if (r < 0) return r;
len = tfile->size; r = sc_parse_ef_gdo(card, &iccsn, &iccsn_len, NULL, 0);
sc_file_free(tfile); if (r < 0)
if (len > sizeof(buf) || len < 12) return SC_ERROR_INTERNAL; return r;
r = sc_read_binary(card, 0, buf, len, 0); /* cache serial number */
if (r < 0) return r; memcpy(card->serialnr.value, iccsn, MIN(iccsn_len, SC_MAX_SERIALNR));
if (buf[0] != 0x5a || buf[1] > len - 2) return SC_ERROR_INTERNAL; card->serialnr.len = MIN(iccsn_len, SC_MAX_SERIALNR);
card->serialnr.len = buf[1]; /* copy and return serial number */
memcpy(card->serialnr.value, buf+2, buf[1]);
memcpy(serial, &card->serialnr, sizeof(*serial)); memcpy(serial, &card->serialnr, sizeof(*serial));
return SC_SUCCESS; return SC_SUCCESS;

132
src/libopensc/ef-gdo.c Normal file
View File

@ -0,0 +1,132 @@
/*
* ef-atr.c: Stuff for handling EF(GDO)
*
* Copyright (C) 2017 Frank Morgner <frankmorgner@gmail.com>
*
* 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);
}

View File

@ -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); void sc_free_apps(struct sc_card *card);
int sc_parse_ef_atr(struct sc_card *card); int sc_parse_ef_atr(struct sc_card *card);
void sc_free_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); int sc_update_dir(struct sc_card *card, sc_app_info_t *app);
void sc_print_cache(struct sc_card *card); void sc_print_cache(struct sc_card *card);

View File

@ -166,10 +166,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card)
sc_card_t *card = p15card->card; sc_card_t *card = p15card->card;
sc_path_t path; sc_path_t path;
sc_file_t *file;
sc_pkcs15_id_t id, auth_id; sc_pkcs15_id_t id, auth_id;
unsigned char buffer[256];
unsigned char ef_gdo[256];
char serial[256]; char serial[256];
unsigned char certlen[2]; unsigned char certlen[2];
int authority, change_sign = 0; 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_INITIALIZED |
SC_PKCS15_PIN_FLAG_NEEDS_PADDING; 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) { if (!iccsn_len || chn_len < 2 || chn_len > 8) {
/* Not EF.GDO */
sc_file_free(file);
return SC_ERROR_WRONG_CARD; return SC_ERROR_WRONG_CARD;
} }
sc_read_binary(card, 0, ef_gdo, file->size, 0); sc_bin_to_hex(iccsn, iccsn_len, serial, sizeof(serial), 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);
if (! if (!
(ef_gdo[len_iccsn + 2] == 0x5F (chn[0] == 0x12
&& ef_gdo[len_iccsn + 3] == 0x20)) { && (chn[1] == 0x02 || chn[1] == 0x03))) {
/* 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))) {
/* Not Infocamere Card */ /* Not Infocamere Card */
return SC_ERROR_WRONG_CARD; return SC_ERROR_WRONG_CARD;
} }
set_string(&p15card->tokeninfo->serial_number, serial); 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"); set_string(&p15card->tokeninfo->label, "Infocamere 1202 Card");
else { else {
set_string(&p15card->tokeninfo->label, "Infocamere 1203 Card"); 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 */ /* 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); r = sc_select_file(card, &path, NULL);
@ -336,11 +300,11 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card)
if (!change_sign) { if (!change_sign) {
/* add authentication PIN */ /* 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_pkcs15_format_id("01", &id);
sc_pkcs15emu_add_pin(p15card, &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, SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
5, 8, flags, 3, 0, 5, 8, flags, 3, 0,
SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); 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, authPRKEY,
SC_PKCS15_TYPE_PRKEY_RSA, SC_PKCS15_TYPE_PRKEY_RSA,
1024, authprkey_usage, 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); &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 */ /* 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) { if (sc_select_file(card, &path, NULL) < 0) {
return SC_ERROR_INTERNAL; return SC_ERROR_INTERNAL;
@ -392,7 +356,7 @@ static int infocamere_1200_init(sc_pkcs15_card_t * p15card)
authority = 1; 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); 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 */ /* 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_pkcs15_format_id("02", &id);
sc_pkcs15emu_add_pin(p15card, &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_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, 3, 0,
SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE); 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_pkcs15emu_add_prkey(p15card, &id, nonrepPRKEY,
SC_PKCS15_TYPE_PRKEY_RSA, SC_PKCS15_TYPE_PRKEY_RSA,
1024, prkey_usage, 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); &auth_id, SC_PKCS15_CO_FLAG_PRIVATE);

View File

@ -304,9 +304,9 @@ static int sc_pkcs15_tccardos_init_func(sc_pkcs15_card_t *p15card)
int r; int r;
struct sc_path path; struct sc_path path;
struct sc_file *file = NULL; struct sc_file *file = NULL;
u8 gdo[MAX_INFO1_SIZE];
char hex_buf[256]; 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; struct sc_card *card = p15card->card;
/* check if we have the correct card OS */ /* 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) if (p15card->tokeninfo->manufacturer_id == NULL)
return SC_ERROR_OUT_OF_MEMORY; return SC_ERROR_OUT_OF_MEMORY;
/* set the serial number */ /* set the serial number */
r = read_file(p15card->card, "3F002F02", gdo, &gdo_len); r = sc_parse_ef_gdo(card, &iccsn, &iccsn_len, NULL, 0);
if (r != SC_SUCCESS) if (r != SC_SUCCESS || iccsn_len < 5+8)
return SC_ERROR_INTERNAL; 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); p15card->tokeninfo->serial_number = strdup(hex_buf);
if (p15card->tokeninfo->serial_number == NULL) if (p15card->tokeninfo->serial_number == NULL)
return SC_ERROR_OUT_OF_MEMORY; return SC_ERROR_OUT_OF_MEMORY;