Skip to content

Commit

Permalink
Initial support for SetCOSXpresso (GemXpresso R4 with EID 2.x applet)
Browse files Browse the repository at this point in the history
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3070 c6295689-39f2-0310-b995-f0e70906c6a9
  • Loading branch information
jps committed Dec 8, 2006
1 parent 31f4fad commit 462cd0d
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 55 deletions.
165 changes: 110 additions & 55 deletions src/libopensc/card-setcos.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ static struct sc_atr_table setcos_atrs[] = {
{ NULL, NULL, NULL, 0, 0, NULL }
};

#define SETCOS_IS_EID_APPLET(card) ((card)->type == SC_CARD_TYPE_SETCOS_EID_V2_0 || (card)->type == SC_CARD_TYPE_SETCOS_EID_V2_1)

/* Setcos 4.4 Life Cycle Status Integer */
#define SETEC_LCSI_CREATE 0x01
#define SETEC_LCSI_INIT 0x03
Expand Down Expand Up @@ -94,6 +96,8 @@ static int match_hist_bytes(sc_card_t *card, const char *str, size_t len)

static int setcos_match_card(sc_card_t *card)
{
sc_apdu_t apdu;
u8 buf[6];
int i;

i = _sc_match_atr(card, setcos_atrs, &card->type);
Expand All @@ -107,6 +111,26 @@ static int setcos_match_card(sc_card_t *card)
card->type = SC_CARD_TYPE_SETCOS_GENERIC;
return 1;
}
/* Check if it's a EID2.x applet by reading the version info */
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0xDF, 0x30);
apdu.cla = 0x00;
apdu.resp = buf;
apdu.resplen = 5;
apdu.le = 5;
i = sc_transmit_apdu(card, &apdu);
if (i == 0 && apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && apdu.resplen == 5) {
if (memcmp(buf, "v2.0", 4) == 0)
card->type = SC_CARD_TYPE_SETCOS_EID_V2_0;
else if (memcmp(buf, "v2.1", 4) == 0)
card->type = SC_CARD_TYPE_SETCOS_EID_V2_1;
else {
buf[sizeof(buf) - 1] = '\0';
sc_error(card->ctx, "SetCOS EID applet %s is not supported", (char *) buf);
return 0;
}
return 1;
}

return 0;
}
card->flags = setcos_atrs[i].flags;
Expand Down Expand Up @@ -151,6 +175,8 @@ static int setcos_init(sc_card_t *card)
card->caps |= SC_CARD_CAP_RNG;
break;
case SC_CARD_TYPE_SETCOS_44:
case SC_CARD_TYPE_SETCOS_EID_V2_0:
case SC_CARD_TYPE_SETCOS_EID_V2_1:
card->cla = 0x00;
card->caps |= SC_CARD_CAP_USE_FCI_AC;
card->caps |= SC_CARD_CAP_RNG;
Expand Down Expand Up @@ -179,6 +205,8 @@ static int setcos_init(sc_card_t *card)
break;
case SC_CARD_TYPE_SETCOS_44:
case SC_CARD_TYPE_SETCOS_NIDEL:
case SC_CARD_TYPE_SETCOS_EID_V2_0:
case SC_CARD_TYPE_SETCOS_EID_V2_1:
{
unsigned long flags;

Expand All @@ -202,20 +230,27 @@ static int setcos_construct_fci_44(sc_card_t *card, const sc_file_t *file, u8 *o
u8 *p = out;
u8 buf[64];
const u8 *pin_key_info;
int len;

/* Command */
*p++ = 0x6F;
p++;

/* Length */
buf[0] = (file->size >> 8) & 0xFF;
buf[1] = file->size & 0xFF;
sc_asn1_put_tag(0x81, buf, 2, p, 16, &p);
/* Size (set to 0 for keys/PINs on a Java card) */
if (SETCOS_IS_EID_APPLET(card) &&
(file->type == SC_FILE_TYPE_INTERNAL_EF ||
(file->type == SC_FILE_TYPE_WORKING_EF && file->ef_structure == 0x22)))
buf[0] = buf[1] = 0x00;
else {
buf[0] = (file->size >> 8) & 0xFF;
buf[1] = file->size & 0xFF;
}
sc_asn1_put_tag(0x81, buf, 2, p, *outlen - (p - out), &p);

/* Type */
if (file->type_attr_len) {
memcpy(buf, file->type_attr, file->type_attr_len);
sc_asn1_put_tag(0x82, buf, file->type_attr_len, p, 16, &p);
sc_asn1_put_tag(0x82, buf, file->type_attr_len, p, *outlen - (p - out), &p);
} else {
u8 bLen = 1;

Expand All @@ -226,13 +261,17 @@ static int setcos_construct_fci_44(sc_card_t *card, const sc_file_t *file, u8 *o
break;
case SC_FILE_TYPE_WORKING_EF:
if (file->ef_structure == 0x22) { /* pin-file */
/* ISF key-file, Setcos V4.4 specific */
bLen = 5;
buf[0] = 0x0A; /* EF linear fixed EF for ISF keys */
buf[1] = 0x41; /* fixed */
buf[2] = file->record_length >> 8; /* 2 byte record length */
buf[3] = file->record_length & 0xFF;
buf[4] = file->size / file->record_length; /* record count */
if (SETCOS_IS_EID_APPLET(card))
bLen = 1;
else {
/* Setcos V4.4 */
bLen = 5;
buf[1] = 0x41; /* fixed */
buf[2] = file->record_length >> 8; /* 2 byte record length */
buf[3] = file->record_length & 0xFF;
buf[4] = file->size / file->record_length; /* record count */
}
} else {
buf[0] |= file->ef_structure & 7; /* set file-type, only for EF, not for DF objects */
}
Expand All @@ -243,49 +282,57 @@ static int setcos_construct_fci_44(sc_card_t *card, const sc_file_t *file, u8 *o
default:
return SC_ERROR_NOT_SUPPORTED;
}
sc_asn1_put_tag(0x82, buf, bLen, p, 16, &p);
sc_asn1_put_tag(0x82, buf, bLen, p, *outlen - (p - out), &p);
}

/* File-id */
/* File ID */
buf[0] = (file->id >> 8) & 0xFF;
buf[1] = file->id & 0xFF;
sc_asn1_put_tag(0x83, buf, 2, p, 16, &p);

/* file state */
if (file->prop_attr_len) {
memcpy(buf, file->prop_attr, file->prop_attr_len);
sc_asn1_put_tag(0x8A, buf, file->prop_attr_len, p, 18, &p);
}

/* Access control */
memcpy(buf, file->sec_attr, file->sec_attr_len);
sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, 18, &p);
sc_asn1_put_tag(0x83, buf, 2, p, *outlen - (p - out), &p);

switch (file->type) {
case SC_FILE_TYPE_DF:
/* DF name */
if (file->type == SC_FILE_TYPE_DF) {
if (file->name[0] != 0)
sc_asn1_put_tag(0x84, (u8 *) file->name, file->namelen, p, 18, &p);
else { /* Name required -> take the FID */
sc_asn1_put_tag(0x84, (u8 *) file->name, file->namelen, p, *outlen - (p - out), &p);
else { /* Name required -> take the FID if not specified */
buf[0] = (file->id >> 8) & 0xFF;
buf[1] = file->id & 0xFF;
sc_asn1_put_tag(0x84, buf, 2, p, 16, &p);
sc_asn1_put_tag(0x84, buf, 2, p, *outlen - (p - out), &p);
}
}

/* Pin/key info: define 4 pins, no keys */
if(file->path.len == 2)
pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84\xC2\x00"; /* root-MF: use local pin-file */
else
pin_key_info = (const u8 *)"\xC1\x04\x01\x02\x03\x04\xC2\x00"; /* sub-DF: use parent pin-file in root-MF */
sc_asn1_put_tag(0xA5, pin_key_info, 8, p, 18, &p);
break;
/* Security Attributes */
memcpy(buf, file->sec_attr, file->sec_attr_len);
sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, *outlen - (p - out), &p);

case SC_FILE_TYPE_INTERNAL_EF: /* RSA keyfiles */
/* Get pin-number */
/* Define AC for RSA-files */
break;
/* Life cycle status */
if (file->prop_attr_len) {
memcpy(buf, file->prop_attr, file->prop_attr_len);
sc_asn1_put_tag(0x8A, buf, file->prop_attr_len, p, *outlen - (p - out), &p);
}

/* Length */
/* PIN definitions */
if (file->type == SC_FILE_TYPE_DF) {
if (card->type == SC_CARD_TYPE_SETCOS_EID_V2_1) {
pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84";
len = 6;
}
else if (card->type == SC_CARD_TYPE_SETCOS_EID_V2_0) {
pin_key_info = (const u8*)"\xC1\x04\x81\x82"; /* Max 2 PINs supported */
len = 4;
}
else {
/* Pin/key info: define 4 pins, no keys */
if(file->path.len == 2)
pin_key_info = (const u8*)"\xC1\x04\x81\x82\x83\x84\xC2\x00"; /* root-MF: use local pin-file */
else
pin_key_info = (const u8 *)"\xC1\x04\x01\x02\x03\x04\xC2\x00"; /* sub-DF: use parent pin-file in root-MF */
len = 8;
}
sc_asn1_put_tag(0xA5, pin_key_info, len, p, *outlen - (p - out), &p);
}

/* Length */
out[1] = p - out - 2;

*outlen = p - out;
Expand All @@ -295,7 +342,8 @@ static int setcos_construct_fci_44(sc_card_t *card, const sc_file_t *file, u8 *o
static int setcos_construct_fci(sc_card_t *card, const sc_file_t *file, u8 *out, size_t *outlen)
{
if (card->type == SC_CARD_TYPE_SETCOS_44 ||
card->type == SC_CARD_TYPE_SETCOS_NIDEL)
card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
SETCOS_IS_EID_APPLET(card))
return setcos_construct_fci_44(card, file, out, outlen);
else
return iso_ops->construct_fci(card, file, out, outlen);
Expand Down Expand Up @@ -365,11 +413,10 @@ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)
const u8 bFileStatus = file->status == SC_FILE_STATUS_CREATION ?
SETEC_LCSI_CREATE : SETEC_LCSI_ACTIVATED;
u8 bCommands_always = 0;
int pins[] = {-1, -1, -1, -1, -1, -1, -1};
int pins[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
u8 bCommands_pin[sizeof(pins)/sizeof(pins[0])]; /* both 7 entries big */
u8 bCommands_key = 0;
u8 bNumber = 0;
u8 bPinNumber = 0;
u8 bKeyNumber = 0;
unsigned int bMethod = 0;

Expand Down Expand Up @@ -426,11 +473,10 @@ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)
bCommands_always |= 1;
break;
case SC_AC_CHV: /* pin */
if (bNumber == 0 || bNumber > 7) {
if ((bNumber & 0x7F) == 0 || (bNumber & 0x7F) > 7) {
sc_error(card->ctx, "SetCOS 4.4 PIN refs can only be 1..7\n");
return SC_ERROR_INVALID_ARGUMENTS;
}
bPinNumber = bNumber;
bCommands_pin[setcos_pin_index_44(pins, sizeof(pins), (int) bNumber)] |= 1 << i;
break;
case SC_AC_TERM: /* key */
Expand All @@ -449,7 +495,10 @@ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)
for (i = 0; i < (int)sizeof(bCommands_pin) && pins[i] != -1; i++) {
bBuf[len++] = 2;
bBuf[len++] = bCommands_pin[i];
bBuf[len++] = pins[i] & 0x07; /* pin ref */
if (SETCOS_IS_EID_APPLET(card))
bBuf[len++] = pins[i]; /* pin ref */
else
bBuf[len++] = pins[i] & 0x07; /* pin ref */
}
/* Add ommands that require the key */
if (bCommands_key) {
Expand All @@ -459,7 +508,6 @@ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)
}
/* RSA signing/decryption requires AC adaptive coding, can't be put
in AC simple coding. Only implemented for pins, not for a key. */
bPinNumber = 0;
bKeyNumber = 0;
if ( (file->type == SC_FILE_TYPE_INTERNAL_EF) &&
(acl_to_byte_44(file->acl[SC_AC_OP_CRYPTO], &bNumber) == SC_AC_CHV) ) {
Expand All @@ -477,7 +525,7 @@ static int setcos_create_file_44(sc_card_t *card, sc_file_t *file)

static int setcos_create_file(sc_card_t *card, sc_file_t *file)
{
if (card->type == SC_CARD_TYPE_SETCOS_44)
if (card->type == SC_CARD_TYPE_SETCOS_44 || SETCOS_IS_EID_APPLET(card))
return setcos_create_file_44(card, file);

if (file->prop_attr_len == 0)
Expand Down Expand Up @@ -526,7 +574,8 @@ static int setcos_set_security_env2(sc_card_t *card,
assert(card != NULL && env != NULL);

if (card->type == SC_CARD_TYPE_SETCOS_44 ||
card->type == SC_CARD_TYPE_SETCOS_NIDEL) {
card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
SETCOS_IS_EID_APPLET(card)) {
if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) {
sc_error(card->ctx, "asymmetric keyref not supported.\n");
return SC_ERROR_NOT_SUPPORTED;
Expand All @@ -548,7 +597,8 @@ static int setcos_set_security_env2(sc_card_t *card,
/* Should be 0x41 */
apdu.p1 = ((card->type == SC_CARD_TYPE_SETCOS_FINEID_V2) ||
(card->type == SC_CARD_TYPE_SETCOS_44) ||
(card->type == SC_CARD_TYPE_SETCOS_NIDEL)) ? 0x41 : 0x81;
(card->type == SC_CARD_TYPE_SETCOS_NIDEL) ||
SETCOS_IS_EID_APPLET(card)) ? 0x41 : 0x81;
apdu.p2 = 0xB6;
break;
default:
Expand Down Expand Up @@ -630,6 +680,8 @@ static int setcos_set_security_env(sc_card_t *card,
case SC_CARD_TYPE_SETCOS_FINEID_V2:
case SC_CARD_TYPE_SETCOS_NIDEL:
case SC_CARD_TYPE_SETCOS_44:
case SC_CARD_TYPE_SETCOS_EID_V2_0:
case SC_CARD_TYPE_SETCOS_EID_V2_1:
break;
default:
sc_error(card->ctx, "Card does not support RSA.\n");
Expand Down Expand Up @@ -857,7 +909,8 @@ static int setcos_select_file(sc_card_t *card,
return r;
if (file != NULL) {
if (card->type == SC_CARD_TYPE_SETCOS_44 ||
card->type == SC_CARD_TYPE_SETCOS_NIDEL)
card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
SETCOS_IS_EID_APPLET(card))
parse_sec_attr_44(*file, (*file)->sec_attr, (*file)->sec_attr_len);
else
parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
Expand All @@ -872,7 +925,8 @@ static int setcos_list_files(sc_card_t *card, u8 * buf, size_t buflen)

sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0);
if (card->type == SC_CARD_TYPE_SETCOS_44 ||
card->type == SC_CARD_TYPE_SETCOS_NIDEL)
card->type == SC_CARD_TYPE_SETCOS_NIDEL ||
SETCOS_IS_EID_APPLET(card))
apdu.cla = 0x80;
apdu.resp = buf;
apdu.resplen = buflen;
Expand All @@ -893,7 +947,8 @@ static int setcos_process_fci(sc_card_t *card, sc_file_t *file,

/* SetCOS 4.4: RSA key file is an internal EF but it's
* file descriptor doesn't seem to follow ISO7816. */
if (r >= 0 && card->type == SC_CARD_TYPE_SETCOS_44) {
if (r >= 0 && (card->type == SC_CARD_TYPE_SETCOS_44 ||
SETCOS_IS_EID_APPLET(card))) {
const u8 *tag;
size_t taglen = 1;
tag = (u8 *) sc_asn1_find_tag(card->ctx, buf, buflen, 0x82, &taglen);
Expand Down Expand Up @@ -1038,7 +1093,7 @@ static int setcos_activate_file(sc_card_t *card)

static int setcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
{
if (card->type != SC_CARD_TYPE_SETCOS_44)
if (card->type != SC_CARD_TYPE_SETCOS_44 && !SETCOS_IS_EID_APPLET(card))
return SC_ERROR_NOT_SUPPORTED;

switch(cmd) {
Expand Down
2 changes: 2 additions & 0 deletions src/libopensc/cards.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ enum {
SC_CARD_TYPE_SETCOS_FINEID_V2,
SC_CARD_TYPE_SETCOS_NIDEL,
SC_CARD_TYPE_SETCOS_44 = 6100,
SC_CARD_TYPE_SETCOS_EID_V2_0,
SC_CARD_TYPE_SETCOS_EID_V2_1,

/* starcos driver */
SC_CARD_TYPE_STARCOS_BASE = 7000,
Expand Down

0 comments on commit 462cd0d

Please sign in to comment.