unified reading of EF.GDO
This commit is contained in:
parent
293d02ea4b
commit
0502a839c6
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -706,32 +706,27 @@ 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;
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue