Skip to content

Commit

Permalink
- added partial support for TCOS 2.0 cards
Browse files Browse the repository at this point in the history
- default card driver now tries to do a GET RESPONSE
  instead of SELECT FILE to detect the correct
  CLA byte
- moved security attribute parsing from iso7816.c to card-setec.c
- added some more sanity checking to sc_check_apdu
- added 'debug' command line option to opensc-explorer


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@210 c6295689-39f2-0310-b995-f0e70906c6a9
  • Loading branch information
jey committed Feb 11, 2002
1 parent 6db645e commit 709727d
Show file tree
Hide file tree
Showing 10 changed files with 329 additions and 75 deletions.
2 changes: 1 addition & 1 deletion src/libopensc/Makefile.am
Expand Up @@ -11,7 +11,7 @@ libopensc_la_SOURCES = asn1.c base64.c sec.c log.c sc.c card.c iso7816.c \
pkcs15.c pkcs15-cert.c pkcs15-pin.c \
pkcs15-prkey.c pkcs15-sec.c pkcs15-cache.c \
card-setec.c card-flex.c card-gpk.c \
card-emv.c card-default.c
card-tcos.c card-emv.c card-default.c
libopensc_la_LDFLAGS = -version-info 0:5:0

if HAVE_SSL
Expand Down
17 changes: 6 additions & 11 deletions src/libopensc/card-default.c
Expand Up @@ -43,7 +43,6 @@ static int autodetect_class(struct sc_card *card)
{
int classes[] = { 0x00, 0xC0, 0xB0, 0xA0 };
int class_count = sizeof(classes)/sizeof(int);
u8 buf[2];
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
struct sc_apdu apdu;
int i, r;
Expand All @@ -54,26 +53,22 @@ static int autodetect_class(struct sc_card *card)
if (card->ctx->debug >= 2)
debug(card->ctx, "trying with 0x%02X\n", classes[i]);
apdu.cla = classes[i];
apdu.cse = SC_APDU_CASE_3_SHORT;
memcpy(buf, "\x3F\x00", 2);
apdu.data = buf;
apdu.datalen = 2;
apdu.lc = 2;
apdu.resplen = sizeof(rbuf);
apdu.resp = rbuf;
apdu.ins = 0xA4;
apdu.cse = SC_APDU_CASE_1;
apdu.ins = 0xC0;
apdu.p1 = apdu.p2 = 0;
apdu.datalen = 0;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x6E)
continue;
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
break;
if (apdu.sw1 == 0x61)
break;
if (apdu.sw1 == 0x6E)
continue;
if (card->ctx->debug >= 2)
debug(card->ctx, "got strange SWs: 0x%02X 0x%02X\n",
apdu.sw1, apdu.sw2);
break;
}
if (i == class_count)
return -1;
Expand Down
42 changes: 42 additions & 0 deletions src/libopensc/card-setcos.c
Expand Up @@ -111,6 +111,47 @@ static int setec_set_security_env(struct sc_card *card,
return iso_ops->set_security_env(card, env, se_num);
}

static unsigned int byte_to_acl(u8 byte)
{
switch (byte >> 4) {
case 0:
return SC_AC_NONE;
case 1:
return SC_AC_CHV1;
case 2:
return SC_AC_CHV2;
case 4:
return SC_AC_TERM;
case 15:
return SC_AC_NEVER;
}
return SC_AC_UNKNOWN;
}

static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
{
int i;

if (len < 6)
return;
for (i = 0; i < 6; i++)
file->acl[i] = byte_to_acl(buf[i]);
}

static int setec_select_file(struct sc_card *card,
const struct sc_path *in_path,
struct sc_file *file)
{
int r;

r = iso_ops->select_file(card, in_path, file);
if (r)
return r;
if (file != NULL)
parse_sec_attr(file, file->sec_attr, file->sec_attr_len);
return 0;
}

static const struct sc_card_driver * sc_get_driver(void)
{
const struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
Expand All @@ -123,6 +164,7 @@ static const struct sc_card_driver * sc_get_driver(void)
iso_ops = iso_drv->ops;
setec_ops.create_file = setec_create_file;
setec_ops.set_security_env = setec_set_security_env;
setec_ops.select_file = setec_select_file;

return &setec_drv;
}
Expand Down
182 changes: 182 additions & 0 deletions src/libopensc/card-tcos.c
@@ -0,0 +1,182 @@
/*
* card-setec.c: Support for TCOS 2.0 cards
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
*
* 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
*/

#include "sc-internal.h"
#include "sc-log.h"

static const char *tcos_atrs[] = {
"3B:BA:96:00:81:31:86:5D:00:64:05:60:02:03:31:80:90:00:66",
NULL
};

static struct sc_card_operations tcos_ops;
static const struct sc_card_driver tcos_drv = {
NULL,
"TCOS 2.0 cards",
"tcos",
&tcos_ops
};

static int tcos_finish(struct sc_card *card)
{
return 0;
}

static int tcos_match_card(struct sc_card *card)
{
int i, match = -1;

for (i = 0; tcos_atrs[i] != NULL; i++) {
u8 defatr[SC_MAX_ATR_SIZE];
size_t len = sizeof(defatr);
const char *atrp = tcos_atrs[i];

if (sc_hex_to_bin(atrp, defatr, &len))
continue;
if (len != card->atr_len)
continue;
if (memcmp(card->atr, defatr, len) != 0)
continue;
match = i;
break;
}
if (match == -1)
return 0;

return 1;
}

static int tcos_init(struct sc_card *card)
{
card->ops_data = NULL;
card->cla = 0x00;

return 0;
}

static const struct sc_card_operations *iso_ops = NULL;

static int tcos_create_file(struct sc_card *card, struct sc_file *file)
{
struct sc_file tmp;

tmp = *file;
memcpy(tmp.prop_attr, "\x03\x00\x00", 3);
tmp.prop_attr_len = 3;
return iso_ops->create_file(card, &tmp);
}

static int tcos_set_security_env(struct sc_card *card,
const struct sc_security_env *env,
int se_num)
{
if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
struct sc_security_env tmp;

tmp = *env;
tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
if (tmp.algorithm != SC_ALGORITHM_RSA) {
error(card->ctx, "Only RSA algorithm supported.\n");
return SC_ERROR_NOT_SUPPORTED;
}
tmp.algorithm_ref = 0x00;
if (tmp.algorithm_flags & SC_ALGORITHM_RSA_PKCS1_PAD)
tmp.algorithm_ref = 0x02;
if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
tmp.algorithm_ref |= 0x10;
return iso_ops->set_security_env(card, &tmp, se_num);

}
return iso_ops->set_security_env(card, env, se_num);
}

static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
{
return;
}

static int tcos_select_file(struct sc_card *card,
const struct sc_path *in_path,
struct sc_file *file)
{
int r;

r = iso_ops->select_file(card, in_path, file);
if (r)
return r;
if (file != NULL)
parse_sec_attr(file, file->sec_attr, file->sec_attr_len);
return 0;
}

static int tcos_list_files(struct sc_card *card, u8 *buf, size_t buflen)
{
struct sc_apdu apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 p1s[2] = { 0x01, 0x02 };
int r, i, count = 0;

for (i = 0; i < 2; i++) {
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, p1s[i], 0);
apdu.cla = 0x80;
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = 256;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
if (r == SC_ERROR_FILE_NOT_FOUND)
continue;
SC_TEST_RET(card->ctx, r, "Card returned error");
if (apdu.resplen > buflen)
return SC_ERROR_BUFFER_TOO_SMALL;
memcpy(buf, apdu.resp, apdu.resplen);
buf += apdu.resplen;
buflen -= apdu.resplen;
count += apdu.resplen;
}
return count;
}

static const struct sc_card_driver * sc_get_driver(void)
{
const struct sc_card_driver *iso_drv = sc_get_iso7816_driver();

tcos_ops = *iso_drv->ops;
tcos_ops.match_card = tcos_match_card;
tcos_ops.init = tcos_init;
tcos_ops.finish = tcos_finish;
if (iso_ops == NULL)
iso_ops = iso_drv->ops;
tcos_ops.create_file = tcos_create_file;
tcos_ops.set_security_env = tcos_set_security_env;
tcos_ops.select_file = tcos_select_file;
tcos_ops.list_files = tcos_list_files;

return &tcos_drv;
}

#if 1
const struct sc_card_driver * sc_get_tcos_driver(void)
{
return sc_get_driver();
}
#endif
21 changes: 20 additions & 1 deletion src/libopensc/card.c
Expand Up @@ -89,6 +89,14 @@ static int _sc_pcscret_to_error(long rv)

static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
{
if (apdu->le > 256) {
error(ctx, "Value of Le too big (maximum 256 bytes)\n");
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
}
if (apdu->lc > 256) {
error(ctx, "Value of Lc too big (maximum 256 bytes)\n");
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
}
switch (apdu->cse) {
case SC_APDU_CASE_1:
if (apdu->datalen > 0) {
Expand All @@ -101,6 +109,10 @@ static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
error(ctx, "Case 2 APDU with data supplied\n");
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
}
if (apdu->le == 0) {
error(ctx, "Case 2 APDU with no response expected\n");
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
}
if (apdu->resplen < apdu->le) {
error(ctx, "Response buffer size < Le\n");
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
Expand All @@ -117,6 +129,10 @@ static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
error(ctx, "Case 3 APDU with no data supplied\n");
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
}
if (apdu->le == 0) {
error(ctx, "Case 4 APDU with no response expected\n");
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
}
if (apdu->resplen < apdu->le) {
error(ctx, "Le > response buffer size\n");
SC_FUNC_RETURN(ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
Expand Down Expand Up @@ -197,7 +213,10 @@ static int sc_transceive_t0(struct sc_card *card, struct sc_apdu *apdu)
return SC_ERROR_INVALID_ARGUMENTS;
memcpy(data, apdu->data, data_bytes);
data += data_bytes;
*data++ = (u8) apdu->le;
if (apdu->le == 256)
*data++ = 0x00;
else
*data++ = (u8) apdu->le;
break;
}

Expand Down

0 comments on commit 709727d

Please sign in to comment.