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 = \
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 \

View File

@ -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 \

View File

@ -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:

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)
{
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;

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);
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);

View File

@ -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);

View File

@ -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;