support for TCOS3

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3309 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
pk 2007-12-28 18:18:57 +00:00
parent 1667798217
commit 513a3dde0a
4 changed files with 672 additions and 702 deletions

View File

@ -1,8 +1,9 @@
/*
* card-tcos.c: Support for TCOS 2.0 cards
* card-tcos.c: Support for TCOS cards
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* Copyright (C) 2007 Peter Koch <Koch@smartcard-auth.de>
* Copyright (C) 2002 g10 Code GmbH
* 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
@ -28,20 +29,22 @@
#include <stdlib.h>
static struct sc_atr_table tcos_atrs[] = {
/* SLE44 */
{ "3B:BA:13:00:81:31:86:5D:00:64:05:0A:02:01:31:80:90:00:8B", NULL, NULL, SC_CARD_TYPE_TCOS_GENERIC, 0, NULL },
/* SLE66S */
{ "3B:BA:14:00:81:31:86:5D:00:64:05:14:02:02:31:80:90:00:91", NULL, NULL, SC_CARD_TYPE_TCOS_GENERIC, 0, NULL },
/* SLE66CX320P */
{ "3B:BA:96:00:81:31:86:5D:00:64:05:60:02:03:31:80:90:00:66", NULL, NULL, SC_CARD_TYPE_TCOS_GENERIC, 0, NULL },
/* SLE66CX322P */
{ "3B:BA:96:00:81:31:86:5D:00:64:05:7B:02:03:31:80:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_GENERIC, 0, NULL },
/* Infineon SLE44 */
{ "3B:BA:13:00:81:31:86:5D:00:64:05:0A:02:01:31:80:90:00:8B", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
/* Infineon SLE66S */
{ "3B:BA:14:00:81:31:86:5D:00:64:05:14:02:02:31:80:90:00:91", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
/* Infineon SLE66CX320P */
{ "3B:BA:96:00:81:31:86:5D:00:64:05:60:02:03:31:80:90:00:66", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
/* Infoneon SLE66CX322P */
{ "3B:BA:96:00:81:31:86:5D:00:64:05:7B:02:03:31:80:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_V2, 0, NULL },
/* Philips P5CT072 */
{ "3B:BF:96:00:81:31:FE:5D:00:64:04:11:03:01:31:C0:73:F7:01:D0:00:90:00:7D", NULL, NULL, SC_CARD_TYPE_TCOS_V3, 0, NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
static struct sc_card_operations tcos_ops;
static struct sc_card_driver tcos_drv = {
"TCOS 2.0",
"TCOS 3.0",
"tcos",
&tcos_ops,
NULL, 0, NULL
@ -51,15 +54,17 @@ static const struct sc_card_operations *iso_ops = NULL;
typedef struct tcos_data_st {
unsigned int pad_flags;
unsigned int sign_with_def_env;
unsigned int next_sign;
} tcos_data;
static int tcos_finish(sc_card_t *card)
{
free(card->drv_data);
return 0;
}
static int tcos_match_card(sc_card_t *card)
{
int i;
@ -70,13 +75,13 @@ static int tcos_match_card(sc_card_t *card)
return 1;
}
static int tcos_init(sc_card_t *card)
{
unsigned long flags;
tcos_data *data = (tcos_data *) malloc(sizeof(tcos_data));
if (!data)
return SC_ERROR_OUT_OF_MEMORY;
if (!data) return SC_ERROR_OUT_OF_MEMORY;
card->name = "TCOS";
card->drv_data = (void *)data;
@ -90,6 +95,14 @@ static int tcos_init(sc_card_t *card)
_sc_card_add_rsa_alg(card, 768, flags, 0);
_sc_card_add_rsa_alg(card, 1024, flags, 0);
if (card->type == SC_CARD_TYPE_TCOS_V3) {
card->caps |= SC_CARD_CAP_RSA_2048|SC_CARD_CAP_APDU_EXT;
_sc_card_add_rsa_alg(card, 1280, flags, 0);
_sc_card_add_rsa_alg(card, 1536, flags, 0);
_sc_card_add_rsa_alg(card, 1792, flags, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
}
return 0;
}
@ -216,40 +229,36 @@ static int tcos_create_file(sc_card_t *card, sc_file_t *file)
}
static unsigned int map_operations (int commandbyte )
{
unsigned int op = (unsigned int)-1;
unsigned int op = (unsigned int)-1;
switch ( (commandbyte & 0xfe) )
{
case 0xe2: /* append record */ op = SC_AC_OP_UPDATE; break;
case 0x24: /* change password */ op = SC_AC_OP_UPDATE; break;
case 0xe0: /* create */ op = SC_AC_OP_CREATE; break;
case 0xe4: /* delete */ op = SC_AC_OP_DELETE; break;
case 0xe8: /* exclude sfi */ op = SC_AC_OP_WRITE; break;
case 0x82: /* external auth */ op = SC_AC_OP_READ; break;
case 0xe6: /* include sfi */ op = SC_AC_OP_WRITE; break;
case 0x88: /* internal auth */ op = SC_AC_OP_READ; break;
case 0x04: /* invalidate */ op = SC_AC_OP_INVALIDATE; break;
case 0x2a: /* perform sec. op */ op = SC_AC_OP_SELECT; break;
case 0xb0: /* read binary */ op = SC_AC_OP_READ; break;
case 0xb2: /* read record */ op = SC_AC_OP_READ; break;
case 0x44: /* rehabilitate */ op = SC_AC_OP_REHABILITATE; break;
case 0xa4: /* select */ op = SC_AC_OP_SELECT; break;
case 0xee: /* set permanent */ op = SC_AC_OP_CREATE; break;
case 0x2c: /* unblock password */op = SC_AC_OP_WRITE; break;
case 0xd6: /* update binary */ op = SC_AC_OP_WRITE; break;
case 0xdc: /* update record */ op = SC_AC_OP_WRITE; break;
case 0x20: /* verify password */ op = SC_AC_OP_SELECT; break;
case 0x60: /* admin group */ op = SC_AC_OP_CREATE; break;
}
return op;
switch ( (commandbyte & 0xfe) ) {
case 0xe2: /* append record */ op = SC_AC_OP_UPDATE; break;
case 0x24: /* change password */ op = SC_AC_OP_UPDATE; break;
case 0xe0: /* create */ op = SC_AC_OP_CREATE; break;
case 0xe4: /* delete */ op = SC_AC_OP_DELETE; break;
case 0xe8: /* exclude sfi */ op = SC_AC_OP_WRITE; break;
case 0x82: /* external auth */ op = SC_AC_OP_READ; break;
case 0xe6: /* include sfi */ op = SC_AC_OP_WRITE; break;
case 0x88: /* internal auth */ op = SC_AC_OP_READ; break;
case 0x04: /* invalidate */ op = SC_AC_OP_INVALIDATE; break;
case 0x2a: /* perform sec. op */ op = SC_AC_OP_SELECT; break;
case 0xb0: /* read binary */ op = SC_AC_OP_READ; break;
case 0xb2: /* read record */ op = SC_AC_OP_READ; break;
case 0x44: /* rehabilitate */ op = SC_AC_OP_REHABILITATE; break;
case 0xa4: /* select */ op = SC_AC_OP_SELECT; break;
case 0xee: /* set permanent */ op = SC_AC_OP_CREATE; break;
case 0x2c: /* unblock password */op = SC_AC_OP_WRITE; break;
case 0xd6: /* update binary */ op = SC_AC_OP_WRITE; break;
case 0xdc: /* update record */ op = SC_AC_OP_WRITE; break;
case 0x20: /* verify password */ op = SC_AC_OP_SELECT; break;
case 0x60: /* admin group */ op = SC_AC_OP_CREATE; break;
}
return op;
}
/* Hmmm, I don't know what to do. It seems that the ACL design of
OpenSC should be enhanced to allow for the command based security
attributes of TCOS. FIXME: This just allows to create a very basic
@ -319,155 +328,47 @@ static void parse_sec_attr(sc_card_t *card,
}
}
/* Arghh. duplicated from iso7816.c */
static void tcos_process_fci(sc_context_t *ctx, sc_file_t *file,
const u8 *buf, size_t buflen)
{
size_t taglen, len = buflen;
const u8 *tag = NULL, *p = buf;
if (ctx->debug >= 3)
sc_debug(ctx, "processing FCI bytes\n");
tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen);
if (tag != NULL && taglen == 2) {
file->id = (tag[0] << 8) | tag[1];
if (ctx->debug >= 3)
sc_debug(ctx, " file identifier: 0x%02X%02X\n", tag[0],
tag[1]);
}
tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen);
if (tag != NULL && taglen >= 2) {
int bytes = (tag[0] << 8) + tag[1];
if (ctx->debug >= 3)
sc_debug(ctx, " bytes in file: %d\n", bytes);
file->size = bytes;
}
if (tag == NULL) {
tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
if (tag != NULL && taglen >= 2) {
int bytes = (tag[0] << 8) + tag[1];
if (ctx->debug >= 3)
sc_debug(ctx, " bytes in file: %d\n", bytes);
file->size = bytes;
}
}
tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
if (tag != NULL) {
if (taglen > 0) {
unsigned char byte = tag[0];
const char *type;
file->shareable = byte & 0x40 ? 1 : 0;
if (ctx->debug >= 3)
sc_debug(ctx, " shareable: %s\n",
(byte & 0x40) ? "yes" : "no");
file->ef_structure = byte & 0x07;
switch ((byte >> 3) & 7) {
case 0:
type = "working EF";
file->type = SC_FILE_TYPE_WORKING_EF;
break;
case 1:
type = "internal EF";
file->type = SC_FILE_TYPE_INTERNAL_EF;
break;
case 7:
type = "DF";
file->type = SC_FILE_TYPE_DF;
break;
default:
type = "unknown";
break;
}
if (ctx->debug >= 3) {
sc_debug(ctx, " type: %s\n", type);
sc_debug(ctx, " EF structure: %d\n",
byte & 0x07);
}
}
}
tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen);
if (tag != NULL && taglen > 0 && taglen <= 16) {
char name[17];
size_t i;
memcpy(file->name, tag, taglen);
file->namelen = taglen;
for (i = 0; i < taglen; i++) {
if (isalnum(tag[i]) || ispunct(tag[i])
|| isspace(tag[i]))
name[i] = tag[i];
else
name[i] = '?';
}
name[taglen] = 0;
if (ctx->debug >= 3)
sc_debug(ctx, "File name: %s\n", name);
}
tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen);
if (tag != NULL && taglen) {
sc_file_set_prop_attr(file, tag, taglen);
} else
file->prop_attr_len = 0;
tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen);
if (tag != NULL && taglen) {
sc_file_set_prop_attr(file, tag, taglen);
}
tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen);
if (tag != NULL && taglen) {
sc_file_set_sec_attr(file, tag, taglen);
}
file->magic = SC_FILE_MAGIC;
}
/* This is a special version of the standard select_file which is
needed to cope with some starngeness in APDU construction. It is
probably better to have this specfic for TCOS, so that support for
other cards does not break. */
static int hacked_iso7816_select_file(sc_card_t *card,
const sc_path_t *in_path,
sc_file_t **file_out)
static int tcos_select_file(sc_card_t *card,
const sc_path_t *in_path,
sc_file_t **file_out)
{
sc_context_t *ctx;
sc_apdu_t apdu;
u8 buf[SC_MAX_APDU_BUFFER_SIZE];
u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
int r, pathlen;
sc_file_t *file = NULL;
sc_file_t *file=NULL;
u8 buf[SC_MAX_APDU_BUFFER_SIZE], pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
int i, r, pathlen;
assert(card != NULL && in_path != NULL);
ctx = card->ctx;
ctx=card->ctx;
memcpy(path, in_path->value, in_path->len);
pathlen = in_path->len;
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0);
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0x04);
switch (in_path->type) {
case SC_PATH_TYPE_FILE_ID:
apdu.p1 = 0;
if (pathlen != 2)
return SC_ERROR_INVALID_ARGUMENTS;
if (pathlen != 2) return SC_ERROR_INVALID_ARGUMENTS;
case SC_PATH_TYPE_FROM_CURRENT:
apdu.p1 = 9;
break;
case SC_PATH_TYPE_DF_NAME:
apdu.p1 = 4;
break;
case SC_PATH_TYPE_PATH:
apdu.p1 = 8;
if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0) {
if (pathlen == 2) { /* only 3F00 supplied */
apdu.p1 = 0;
break;
}
path += 2;
pathlen -= 2;
}
if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0) path += 2, pathlen -= 2;
if (pathlen == 0) apdu.p1 = 0;
break;
case SC_PATH_TYPE_PARENT:
apdu.p1 = 3;
pathlen = 0;
break;
default:
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
SC_FUNC_RETURN(ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
}
apdu.p2 = 0; /* first record, return FCI */
if( pathlen == 0 ) apdu.cse = SC_APDU_CASE_2_SHORT;
apdu.lc = pathlen;
apdu.data = path;
apdu.datalen = pathlen;
@ -475,90 +376,96 @@ static int hacked_iso7816_select_file(sc_card_t *card,
if (file_out != NULL) {
apdu.resp = buf;
apdu.resplen = sizeof(buf);
apdu.le = 255; /* 256 will be represented as 0 which
conflicts with the apdu sanity check */
apdu.le = 256;
} else {
apdu.resp = buf;
apdu.resplen = sizeof(buf);
apdu.le = 255;
/* does not work apdu.cse = SC_APDU_CASE_3_SHORT;*/
apdu.resplen = 0;
apdu.le = 0;
apdu.p2 = 0x0C;
apdu.cse = (pathlen == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT;
}
if (!apdu.lc) /* never send an empty lc */
apdu.cse = SC_APDU_CASE_2_SHORT;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (file_out == NULL) {
if (apdu.sw1 == 0x61)
SC_FUNC_RETURN(card->ctx, 2, 0);
SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
SC_TEST_RET(ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r)
SC_FUNC_RETURN(card->ctx, 2, r);
if (r || file_out == NULL) SC_FUNC_RETURN(ctx, 2, r);
switch (apdu.resp[0]) {
case 0x6F:
file = sc_file_new();
if (file == NULL)
SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
file->path = *in_path;
if (apdu.resp[1] <= apdu.resplen)
tcos_process_fci(card->ctx, file,
apdu.resp+2, apdu.resp[1]);
*file_out = file;
break;
case 0x00: /* proprietary coding */
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
default:
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
if (apdu.resplen < 1 || apdu.resp[0] != 0x62){
sc_debug(ctx, "received invalid template %02X\n", apdu.resp[0]);
SC_FUNC_RETURN(ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
}
return 0;
}
file = sc_file_new();
if (file == NULL) SC_FUNC_RETURN(ctx, 0, SC_ERROR_OUT_OF_MEMORY);
file->path = *in_path;
for(i=2; i+1<apdu.resplen && i+1+apdu.resp[i+1]<apdu.resplen; i+=2+apdu.resp[i+1]){
int j, len=apdu.resp[i+1];
unsigned char type=apdu.resp[i], *d=apdu.resp+i+2;
static int tcos_select_file(sc_card_t *card,
const sc_path_t *in_path,
sc_file_t **file)
{
int r;
/*r = iso_ops->select_file(card, in_path, file);*/
r = hacked_iso7816_select_file(card, in_path, file);
if (r)
return r;
switch (type) {
case 0x80:
case 0x81:
file->size=0;
for(j=0; j<len; ++j) file->size = (file->size<<8) | d[j];
break;
case 0x82:
file->shareable = (d[0] & 0x40) ? 1 : 0;
file->ef_structure = d[0] & 7;
switch ((d[0]>>3) & 7) {
case 0: file->type = SC_FILE_TYPE_WORKING_EF; break;
case 7: file->type = SC_FILE_TYPE_DF; break;
default:
sc_debug(ctx, "invalid file type %02X in file descriptor\n", d[0]);
SC_FUNC_RETURN(ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
}
break;
case 0x83:
file->id = (d[0]<<8) | d[1];
break;
case 0x84:
memcpy(file->name, d, len);
file->namelen = len;
break;
case 0x86:
sc_file_set_sec_attr(file, d, len);
break;
default:
if (len>0) sc_file_set_prop_attr(file, d, len);
}
}
file->magic = SC_FILE_MAGIC;
*file_out = file;
if (file) {
parse_sec_attr(card, (*file), (*file)->sec_attr,
(*file)->sec_attr_len);
}
parse_sec_attr(card, file, file->sec_attr, file->sec_attr_len);
return 0;
}
static int tcos_list_files(sc_card_t *card, u8 *buf, size_t buflen)
{
sc_context_t *ctx;
sc_apdu_t apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 p1s[2] = { 0x01, 0x02 };
int r, i, count = 0;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], p1;
int r, count = 0;
for (i = 0; i < 2; i++) {
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, p1s[i], 0);
assert(card != NULL);
ctx = card->ctx;
for (p1=1; p1<=2; p1++) {
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, p1, 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");
SC_TEST_RET(ctx, r, "APDU transmit failed");
if (apdu.sw1==0x6A && (apdu.sw2==0x82 || apdu.sw2==0x88)) continue;
r = sc_check_sw(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;
SC_TEST_RET(ctx, r, "List Dir failed");
if (apdu.resplen > buflen) return SC_ERROR_BUFFER_TOO_SMALL;
if(ctx->debug >= 3) sc_debug(ctx, "got %d %s-FileIDs\n", apdu.resplen/2, p1==1 ? "DF" : "EF");
memcpy(buf, apdu.resp, apdu.resplen);
buf += apdu.resplen;
buflen -= apdu.resplen;
@ -568,7 +475,6 @@ static int tcos_list_files(sc_card_t *card, u8 *buf, size_t buflen)
}
static int tcos_delete_file(sc_card_t *card, const sc_path_t *path)
{
int r;
@ -593,210 +499,167 @@ static int tcos_delete_file(sc_card_t *card, const sc_path_t *path)
return sc_check_sw(card, apdu.sw1, apdu.sw2);
}
/* Crypto operations */
/* TCOS has two kind of RSA-keys: signature-keys and encryption-keys
signature-keys: can be used for sign-operations only and can be used
only within the default security environment. hence must be
stored as local key 0, a SetSecEnv-cmd must not be used (if you
do - even with default parameters - it will fail with 6A88)
encryption-keys: can be used for both sign- and decipher-operations,
can be used within any security environment, a SetSecEnv-cmd
must be used (even if you want to use the default security environment
you must a SetSecEnv-cmd with default parameters)
Unfortunately we cannot find out wether the referenced key is a
signature-key or encryption-key when this routine is called. Therefore
we have a problem if the key-reference is 0x80. If the referenced key
was a signature-key a SetSecEnv must not be used, if the key was an
encryption-key it must be used.
Therefore we suppress error-messages in this case, try a SetSecEnv-cmd
with default parameters and watch out for 6A88-responses [pk_opensc@web.de]
*/
static int tcos_set_security_env(sc_card_t *card,
const sc_security_env_t *env,
int se_num)
static int tcos_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num)
{
sc_context_t *ctx;
sc_apdu_t apdu;
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE], *p;
int r, sign_with_def_env=0;
int r, default_key, tcos3;
tcos_data *data;
assert(card != NULL && env != NULL);
ctx = card->ctx;
tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
data=(tcos_data *)card->drv_data;
if (se_num) SC_FUNC_RETURN(ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
if(ctx->debug >= 3) sc_debug(ctx, "Security Environment Ref=%d:%02X\n", env->key_ref_len, *env->key_ref);
if(env->operation == SC_SEC_OPERATION_SIGN &&
(!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || (env->key_ref_len==1 && *env->key_ref==0x80))
){
if (ctx->debug >= 3) sc_debug(ctx, "Sign-Operation with Default Security Environment\n");
sign_with_def_env=1;
if (se_num || (env->operation!=SC_SEC_OPERATION_DECIPHER && env->operation!=SC_SEC_OPERATION_SIGN)){
SC_FUNC_RETURN(ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
}
if(ctx->debug >= 3){
if(!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)) sc_debug(ctx, "No Key-Reference in SecEnvironment\n");
else sc_debug(ctx, "Key-Reference %02X (len=%d)\n", env->key_ref[0], env->key_ref_len);
}
// Key-Reference 0x80 ??
default_key= !(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || (env->key_ref_len==1 && env->key_ref[0]==0x80);
if(ctx->debug>=3){
sc_debug(ctx, "TCOS3:%d PKCS1:%d\n", tcos3, !!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1));
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
switch (env->operation) {
case SC_SEC_OPERATION_DECIPHER:
case SC_SEC_OPERATION_SIGN:
apdu.p1 = 0xC1;
apdu.p2 = 0xB8;
/* save padding flags and default secEnv indictor */
((tcos_data *)card->drv_data)->pad_flags = env->algorithm_flags;
((tcos_data *)card->drv_data)->sign_with_def_env = sign_with_def_env;
break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
data->pad_flags = env->algorithm_flags;
data->next_sign = default_key;
apdu.le = 0;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, tcos3 ? 0x41 : 0xC1, 0xB8);
p = sbuf;
if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
*p++ = 0x80; /* algorithm reference */
*p++ = 0x01;
*p++ = env->algorithm_ref & 0xFF;
}
*p++=0x80; *p++=0x01; *p++=tcos3 ? 0x0A : 0x10;
if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
*p++ = (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC) ? 0x83 : 0x84;
*p++ = env->key_ref_len;
memcpy(p, env->key_ref, env->key_ref_len);
p += env->key_ref_len;
}
r = p - sbuf;
apdu.lc = r;
apdu.datalen = r;
apdu.data = sbuf;
apdu.resplen = 0;
apdu.lc = apdu.datalen = (p - sbuf);
if (apdu.datalen != 0) {
r = sc_transmit_apdu(card, &apdu);
if (r) {
sc_perror(ctx, r, "APDU transmit failed");
return r;
}
if (sign_with_def_env && apdu.sw1==0x6A && apdu.sw2==0x88) return 0;
((tcos_data *)card->drv_data)->sign_with_def_env = sign_with_def_env = 0;
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r) {
sc_perror(ctx, r, "Card returned error");
return r;
}
if ((r=sc_transmit_apdu(card, &apdu))) {
sc_perror(ctx, r, "APDU transmit failed");
return r;
}
return 0;
if (apdu.sw1==0x6A && (apdu.sw2==0x81 || apdu.sw2==0x88)) {
if (ctx->debug >= 3) sc_debug(ctx, "Detected Signature-Only key\n");
if (env->operation==SC_SEC_OPERATION_SIGN && default_key) return SC_SUCCESS;
}
SC_FUNC_RETURN(ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
/* See tcos_set_security_env() for comments. So we always return
success */
static int tcos_restore_security_env(sc_card_t *card, int se_num)
{
return 0;
}
/**
* TCOS compute_signature command. As TCOS can compute signatures
* with the default security environment only, signatures with other
* security environments are computed by encrypting the pkcs1-padded data
*/
static int tcos_compute_signature(sc_card_t *card, const u8 * data, size_t datalen, u8 * out, size_t outlen)
{
int r;
size_t i;
size_t i, dlen=datalen;
sc_apdu_t apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
int tcos3, r;
assert(card != NULL && data != NULL && out != NULL);
tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
if (datalen > 255) SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
if(((tcos_data *)card->drv_data)->sign_with_def_env){
if(((tcos_data *)card->drv_data)->next_sign){
if(datalen>48){
sc_error(card->ctx, "Data to be signed is too long (TCOS supports max. 48 bytes)\n");
SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A);
memcpy(sbuf, data, datalen);
dlen=datalen;
} else {
unsigned int keylen=128; /* FIXME: use correct key-size */
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x84);
for(i = 0; i < sizeof(sbuf); ++i)
sbuf[i]=0xff;
sbuf[0]=0x00; sbuf[1]=0x01; sbuf[keylen-datalen-1]=0x00;
memcpy(sbuf+keylen-datalen, data, datalen);
datalen=keylen;
int keylen= tcos3 ? 256 : 128;
sc_format_apdu(card, &apdu, keylen>255 ? SC_APDU_CASE_4_EXT : SC_APDU_CASE_4_SHORT, 0x2A,0x80,0x86);
for(i=0; i<sizeof(sbuf);++i) sbuf[i]=0xff;
sbuf[0]=0x02; sbuf[1]=0x00; sbuf[2]=0x01; sbuf[keylen-datalen]=0x00;
memcpy(sbuf+keylen-datalen+1, data, datalen);
dlen=keylen+1;
}
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = 256;
apdu.le = tcos3 ? 256 : 128;
apdu.data = sbuf;
apdu.lc = datalen;
apdu.datalen = datalen;
apdu.sensitive = 1;
apdu.lc = apdu.datalen = dlen;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
if (tcos3 && apdu.p1==0x80 && apdu.sw1==0x6A && apdu.sw2==0x87) {
int keylen=128;
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A,0x80,0x86);
for(i=0; i<sizeof(sbuf);++i) sbuf[i]=0xff;
sbuf[0]=0x02; sbuf[1]=0x00; sbuf[2]=0x01; sbuf[keylen-datalen]=0x00;
memcpy(sbuf+keylen-datalen+1, data, datalen);
dlen=keylen+1;
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = 128;
apdu.data = sbuf;
apdu.lc = apdu.datalen = dlen;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
}
if (apdu.sw1==0x90 && apdu.sw2==0x00) {
size_t len = apdu.resplen>outlen ? outlen : apdu.resplen;
memcpy(out, apdu.resp, len);
SC_FUNC_RETURN(card->ctx, 4, len);
}
SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
/**
* TCOS decipher command (same as iso7816_decipher besides setting
* the padding byte).
*/
static int tcos_decipher(sc_card_t *card,
const u8 * crgram, size_t crgram_len,
u8 * out, size_t outlen)
static int tcos_decipher(sc_card_t *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
{
int r;
sc_context_t *ctx;
sc_apdu_t apdu;
tcos_data *xdata;
u8 pad_byte;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
tcos_data *data;
int tcos3, r;
assert(card != NULL && crgram != NULL && out != NULL);
SC_FUNC_CALLED(card->ctx, 2);
if (crgram_len > 255)
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
ctx = card->ctx;
tcos3=(card->type==SC_CARD_TYPE_TCOS_V3);
data=(tcos_data *)card->drv_data;
/* INS: 0x2A PERFORM SECURITY OPERATION
* P1: 0x80 Resp: Plain value
* P2: 0x86 Cmd: Padding indicator byte followed by cryptogram */
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
SC_FUNC_CALLED(ctx, 2);
if(ctx->debug>=3) sc_debug(ctx, "TCOS3:%d PKCS1:%d\n",tcos3,!!(data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1));
sc_format_apdu(card, &apdu, crgram_len>255 ? SC_APDU_CASE_4_EXT : SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = crgram_len;
apdu.sensitive = 1;
xdata = (tcos_data *)card->drv_data;
if (xdata->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
pad_byte = 0x81; /* pkcs1 padding */
else
pad_byte = 0x02; /* no padding */
/* Note: the 'ISO' padding (0x80, 0x00, 0x00 ...) supported
* by TCOS cards is ignored here as OpenSC doesn't support it
* -- Nils
*/
sbuf[0] = pad_byte;
memcpy(sbuf + 1, crgram, crgram_len);
apdu.data = sbuf;
apdu.lc = crgram_len + 1;
apdu.datalen = crgram_len + 1;
apdu.lc = apdu.datalen = crgram_len+1;
sbuf[0] = tcos3 ? 0x00 : ((data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) ? 0x81 : 0x02);
memcpy(sbuf+1, crgram, crgram_len);
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
memcpy(out, apdu.resp, len);
SC_FUNC_RETURN(card->ctx, 2, len);
if (apdu.sw1==0x90 && apdu.sw2==0x00) {
size_t len= (apdu.resplen>outlen) ? outlen : apdu.resplen;
int offset=0;
if(tcos3 && (data->pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) && apdu.resp[0]==0 && apdu.resp[1]==2){
offset=2; while(offset<len && apdu.resp[offset]!=0) ++offset;
offset=(offset<len-1) ? offset+1 : 0;
}
memcpy(out, apdu.resp+offset, len-offset);
SC_FUNC_RETURN(card->ctx, 2, len-offset);
}
SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
@ -822,7 +685,7 @@ static int tcos_setperm(sc_card_t *card, int enable_nullpin)
return sc_check_sw(card, apdu.sw1, apdu.sw2);
}
/* read the card serial number from the EF_gdo system file */
static int tcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
{
int r;
@ -831,35 +694,33 @@ static int tcos_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
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 */
if (card->serialnr.len) {
memcpy(serial, &card->serialnr, sizeof(*serial));
return SC_SUCCESS;
}
/* read EF_gdo */
sc_format_path("3F002F02", &tpath);
r = sc_select_file(card, &tpath, &tfile);
if (r < 0)
return r;
if (r < 0) return r;
len = tfile->size;
sc_file_free(tfile);
if (len > sizeof(buf) || len < 12)
return SC_ERROR_INTERNAL;
if (len > sizeof(buf) || len < 12) return SC_ERROR_INTERNAL;
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;
if (r < 0) return r;
if (buf[0] != 0x5a || buf[1] > len - 2) return SC_ERROR_INTERNAL;
card->serialnr.len = buf[1];
memcpy(card->serialnr.value, buf+2, buf[1]);
memcpy(serial, &card->serialnr, sizeof(*serial));
return SC_SUCCESS;
}
static int tcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
{
switch (cmd) {
@ -872,32 +733,26 @@ static int tcos_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
}
/* Driver binding stuff */
static struct sc_card_driver * sc_get_driver(void)
struct sc_card_driver * sc_get_tcos_driver(void)
{
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
if (iso_ops == NULL) iso_ops = iso_drv->ops;
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;
tcos_ops.delete_file = tcos_delete_file;
tcos_ops.set_security_env = tcos_set_security_env;
tcos_ops.compute_signature = tcos_compute_signature;
tcos_ops.decipher = tcos_decipher;
tcos_ops.restore_security_env = tcos_restore_security_env;
tcos_ops.card_ctl = tcos_card_ctl;
tcos_ops.match_card = tcos_match_card;
tcos_ops.init = tcos_init;
tcos_ops.finish = tcos_finish;
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;
tcos_ops.delete_file = tcos_delete_file;
tcos_ops.set_security_env = tcos_set_security_env;
tcos_ops.compute_signature = tcos_compute_signature;
tcos_ops.decipher = tcos_decipher;
tcos_ops.restore_security_env = tcos_restore_security_env;
tcos_ops.card_ctl = tcos_card_ctl;
return &tcos_drv;
}
struct sc_card_driver * sc_get_tcos_driver(void)
{
return sc_get_driver();
}

View File

@ -92,6 +92,8 @@ enum {
/* tcos driver */
SC_CARD_TYPE_TCOS_BASE = 8000,
SC_CARD_TYPE_TCOS_GENERIC,
SC_CARD_TYPE_TCOS_V2,
SC_CARD_TYPE_TCOS_V3,
/* openpgp driver */
SC_CARD_TYPE_OPENPGP_BASE = 9000,

View File

@ -1,9 +1,7 @@
/*
* PKCS15 emulation layer for TCOS based preformatted cards
*
* Copyright (C) 2006, Peter Koch <pk@opensc-project.org>
* Copyright (C) 2004, Antonino Iacono <ant_iacono@tin.it>
* Copyright (C) 2003, Olaf Kirch <okir@suse.de>
* Copyright (C) 2007, Peter Koch <Koch@smartcard-auth.de>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -29,325 +27,438 @@
#include <stdio.h>
#include "strlcpy.h"
static void set_string(char **strp, const char *value)
{
if (*strp) free(*strp);
*strp = value ? strdup(value) : NULL;
static int insert_cert(
sc_pkcs15_card_t *p15card,
char *path,
unsigned char id,
int writable,
char *label
){
sc_card_t *card=p15card->card;
sc_context_t *ctx=p15card->card->ctx;
struct sc_pkcs15_cert_info cert_info;
struct sc_pkcs15_object cert_obj;
unsigned char cert[20];
int r;
memset(&cert_info, 0, sizeof(cert_info));
cert_info.id.len = 1;
cert_info.id.value[0] = id;
cert_info.authority = 0;
sc_format_path(path, &cert_info.path);
memset(&cert_obj, 0, sizeof(cert_obj));
strlcpy(cert_obj.label, label, sizeof(cert_obj.label));
cert_obj.flags = writable ? SC_PKCS15_CO_FLAG_MODIFIABLE : 0;
if(sc_select_file(card, &cert_info.path, NULL)!=SC_SUCCESS){
if(ctx->debug>=1) sc_debug(ctx,"Select(%s) failed\n", path);
return 1;
}
if(sc_read_binary(card, 0, cert, sizeof(cert), 0)<0){
if(ctx->debug>=1) sc_debug(ctx,"ReadBinary(%s) failed\n", path);
return 2;
}
if(cert[0]!=0x30 || cert[1]!=0x82){
if(ctx->debug>=1) sc_debug(ctx,"Invalid Cert: %02X:%02X:...\n", cert[0], cert[1]);
return 3;
}
// some certificates are prefixed by an OID
if(cert[4]==0x06 && cert[5]<10 && cert[6+cert[5]]==0x30 && cert[7+cert[5]]==0x82){
cert_info.path.index=6+cert[5];
cert_info.path.count=(cert[8+cert[5]]<<8) + cert[9+cert[5]] + 4;
} else {
cert_info.path.index=0;
cert_info.path.count=(cert[2]<<8) + cert[3] + 4;
}
r=sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
if(r!=SC_SUCCESS){
sc_debug(ctx, "sc_pkcs15emu_add_x509_cert(%s) failed\n", path);
return 4;
}
sc_debug(ctx, "%s: OK, Index=%d, Count=%d\n", path, cert_info.path.index, cert_info.path.count);
return 0;
}
extern int sc_pkcs15emu_tcos_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
static int insert_key(
sc_pkcs15_card_t *p15card,
char *path,
unsigned char id,
unsigned char key_reference,
int key_length,
unsigned char auth_id,
char *label
){
sc_card_t *card=p15card->card;
sc_context_t *ctx=p15card->card->ctx;
sc_file_t *f;
struct sc_pkcs15_prkey_info prkey_info;
struct sc_pkcs15_object prkey_obj;
int r, can_sign, can_crypt;
int sc_pkcs15emu_tcos_init_ex(sc_pkcs15_card_t *p15card,
sc_pkcs15emu_opt_t *opts)
{
static const struct {
const char *card, *manufacturer;
} cardlist[]={
{"Netkey E4 Card", "TeleSec GmbH"},
{"SignTrust Card", "Deutsche Post"},
{"DATEV classic", "DATEV"},
{"Smartkey Card TypA", "Kobil GmbH"},
{"Smartkey Card TypB", "Kobil GmbH"},
{"Chipkarte JLU Giessen", "Kobil GmbH"}
};
static struct {
int flags;
const int type, id, writable;
const char *path;
const char *label;
} certlist[]={
{0, 1, 0x45, 0, "DF01C000", "Telesec Signatur Zertifikat"},
{3, 1, 0x45, 1, "DF014331", "Signatur Zertifikat 1"},
{3, 1, 0x45, 1, "DF014332", "Signatur Zertifikat 2"},
{1, 1, 0x46, 0, "DF01C100", "Telesec Authentifizierungs Zertifikat"},
{3, 1, 0x46, 1, "DF014371", "Authentifizierungs Zertifikat 1"},
{3, 1, 0x46, 1, "DF014372", "Authentifizierungs Zertifikat 2"},
{1, 1, 0x47, 0, "DF01C200", "Telesec Verschluesselungs Zertifikat"},
{3, 1, 0x47, 1, "DF0143B1", "Verschluesselungs Zertifikat 1"},
{3, 1, 0x47, 1, "DF0143B2", "Verschluesselungs Zertifikat 2"},
{1, 1, 0x48, 1, "DF06C000", "SigG Zertifikat 1"},
{1, 1, 0x48, 1, "DF064331", "SigG Zertifikat 2"},
{1, 1, 0x48, 1, "DF064332", "SigG Zertifikat 3"},
{1, 1, 0x49, 1, "41014352", "W2K Logon Zertifikat"},
{0, 2, 0x45, 1, "8000DF01C000", "SignTrust Signatur Zertifikat"},
{1, 2, 0x46, 1, "800082008220", "SignTrust Verschluesselungs Zertifikat"},
{1, 2, 0x47, 1, "800083008320", "SignTrust Authentifizierungs Zertifikat"},
{0, 3, 0x45, 0, "3000C500", "DATEV Signatur Zertifikat"},
{1, 3, 0x46, 0, "DF02C200", "DATEV Verschluesselungs Zertifikat"},
{1, 3, 0x47, 0, "DF02C500", "DATEV Authentifizierungs Zertifikat"},
{0, 4, 0x45, 1, "41004352", "Smartkey Zertifikat 1"},
{0, 4, 0x46, 1, "41004353", "Smartkey Zertifikat 2"},
{0, 5, 0x45, 1, "41014352", "Smartkey Zertifikat 1"},
{0, 5, 0x46, 1, "41014353", "Smartkey Zertifikat 2"},
{0, 6, 0x45, 1, "41004352", "UniCard Giessen Zertifikat"},
{0, 0, 0, 0, NULL, NULL}
};
static const struct {
int type, id, auth_id;
const char *path;
unsigned char key_reference;
const char *label;
} keylist[]={
{1, 0x45, 4, "DF015331", 0x80, "Signatur Schluessel"},
{1, 0x46, 3, "DF015371", 0x82, "Authentifizierungs Schluessel"},
{1, 0x47, 3, "DF0153B1", 0x81, "Verschluesselungs Schluessel"},
{1, 0x48, 5, "DF065331", 0x80, "SigG Schluessel"},
{1, 0x49, 1, "41015103", 0x83, "W2K Logon Schluessel"},
{2, 0x45, 1, "8000DF015331", 0x80, "Signatur Schluessel"},
{2, 0x46, 2, "800082008210", 0x80, "Verschluesselungs Schluessel"},
{2, 0x47, 3, "800083008310", 0x80, "Authentifizierungs Schluessel"},
{3, 0x45, 1, "30005371", 0x82, "Signatur Schluessel"},
{3, 0x46, 1, "DF0253B1", 0x81, "Verschluesselungs Schluessel"},
{3, 0x47, 1, "DF025371", 0x82, "Authentifizierung Schluessel"},
{4, 0x45, 1, "41005103", 0x83, "Smartkey Schluessel 1"},
{4, 0x46, 1, "41005104", 0x84, "Smartkey Schluessel 2"},
{5, 0x45, 1, "41015103", 0x83, "Smartkey Schluessel 1"},
{5, 0x46, 1, "41015104", 0x84, "Smartkey Schluessel 2"},
{6, 0x45, 1, "3F004100", 0x83, "UniCard Giessen Schluessel"},
{0, 0, 0, NULL, 0, NULL}
};
static const struct {
int type, id, auth_id, min_length;
unsigned char reference;
const char *path;
const char *label;
int flags;
} pinlist[]={
{1, 1, 2, 6, 0x00, "5000", "globale PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN},
{1, 2, 0, 8, 0x01, "5001", "globale PUK",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN},
{1, 3, 1, 6, 0x80, "DF015080", "Netkey PIN0",
memset(&prkey_info, 0, sizeof(prkey_info));
prkey_info.id.len = 1;
prkey_info.id.value[0] = id;
prkey_info.native = 1;
prkey_info.key_reference = key_reference;
prkey_info.modulus_length = key_length;
sc_format_path(path, &prkey_info.path);
memset(&prkey_obj, 0, sizeof(prkey_obj));
strlcpy(prkey_obj.label, label, sizeof(prkey_obj.label));
prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
prkey_obj.auth_id.len = 1;
prkey_obj.auth_id.value[0] = auth_id;
can_sign=can_crypt=0;
if(card->type==SC_CARD_TYPE_TCOS_V3){
unsigned char buf[256];
int i, rec_no=0;
if(prkey_info.path.len>=2) prkey_info.path.len-=2;
sc_append_file_id(&prkey_info.path, 0x5349);
if(sc_select_file(card, &prkey_info.path, NULL)!=SC_SUCCESS){
if(ctx->debug>=1) sc_debug(ctx,"Select(%s) failed\n", sc_print_path(&prkey_info.path));
return 1;
}
if(ctx->debug>=4) sc_debug(ctx,"Searching for Key-Ref %02X\n", key_reference);
while((r=sc_read_record(card, ++rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR))>0){
int found=0;
if(buf[0]!=0xA0) continue;
for(i=2;i<buf[1]+2;i+=2+buf[i+1]){
if(buf[i]==0x83 && buf[i+1]==1 && buf[i+2]==key_reference) ++found;
}
if(found) break;
}
if(r<=0){
sc_debug(ctx,"No EF_KEYD-Record found\n");
return 1;
}
for(i=0;i<r;i+=2+buf[i+1]){
if(buf[i]==0xB6) can_sign++;
if(buf[i]==0xB8) can_crypt++;
}
} else {
if(sc_select_file(card, &prkey_info.path, &f)!=SC_SUCCESS){
if(ctx->debug>=1) sc_debug(ctx,"Select(%s) failed\n", sc_print_path(&prkey_info.path));
return 1;
}
if (f->prop_attr[1] & 0x04) can_crypt=1;
if (f->prop_attr[1] & 0x08) can_sign=1;
sc_file_free(f);
}
prkey_info.usage= SC_PKCS15_PRKEY_USAGE_SIGN;
if(can_crypt) prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT|SC_PKCS15_PRKEY_USAGE_DECRYPT;
if(can_sign) prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
r=sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
if(r!=SC_SUCCESS){
sc_debug(ctx, "sc_pkcs15emu_add_rsa_prkey(%s) failed\n", path);
return 4;
}
sc_debug(ctx, "%s: OK%s%s\n", path, can_sign ? ", Sign" : "", can_crypt ? ", Crypt" : "");
return 0;
}
static int insert_pin(
sc_pkcs15_card_t *p15card,
char *path,
unsigned char id,
unsigned char auth_id,
unsigned char pin_reference,
int min_length,
char *label,
int pin_flags
){
sc_card_t *card=p15card->card;
sc_context_t *ctx=p15card->card->ctx;
sc_file_t *f;
struct sc_pkcs15_pin_info pin_info;
struct sc_pkcs15_object pin_obj;
int r;
memset(&pin_info, 0, sizeof(pin_info));
pin_info.auth_id.len = 1;
pin_info.auth_id.value[0] = id;
pin_info.reference = pin_reference;
pin_info.flags = pin_flags;
pin_info.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
pin_info.min_length = min_length;
pin_info.stored_length = 16;
pin_info.max_length = 16;
pin_info.pad_char = '\0';
sc_format_path(path, &pin_info.path);
memset(&pin_obj, 0, sizeof(pin_obj));
strlcpy(pin_obj.label, label, sizeof(pin_obj.label));
pin_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
pin_obj.auth_id.len = auth_id ? 0 : 1;
pin_obj.auth_id.value[0] = auth_id;
if(card->type==SC_CARD_TYPE_TCOS_V3){
unsigned char buf[256];
int i, r, rec_no=0;
if(pin_info.path.len>=2) pin_info.path.len-=2;
sc_append_file_id(&pin_info.path, 0x5049);
if(sc_select_file(card, &pin_info.path, NULL)!=SC_SUCCESS){
if(ctx->debug>=1) sc_debug(ctx,"Select(%s) failed\n", sc_print_path(&pin_info.path));
return 1;
}
if(ctx->debug>=4) sc_debug(ctx,"Searching for PIN-Ref %02X\n", pin_reference);
while((r=sc_read_record(card, ++rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR))>0){
int found=0, fbz=-1;
if(buf[0]!=0xA0) continue;
for(i=2;i<buf[1]+2;i+=2+buf[i+1]){
if(buf[i]==0x83 && buf[i+1]==1 && buf[i+2]==pin_reference) ++found;
if(buf[i]==0x90) fbz=buf[i+1+buf[i+1]];
}
if(found) pin_info.tries_left=fbz;
if(found) break;
}
if(r<=0){
sc_debug(ctx,"No EF_PWDD-Record found\n");
return 1;
}
} else {
if(sc_select_file(card, &pin_info.path, &f)!=SC_SUCCESS){
if(ctx->debug>=1) sc_debug(ctx,"Select(%s) failed\n", path);
return 1;
}
pin_info.tries_left=f->prop_attr[3];
sc_file_free(f);
}
r=sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
if(r!=SC_SUCCESS){
sc_debug(ctx, "sc_pkcs15emu_add_pin_obj(%s) failed\n", path);
return 4;
}
sc_debug(ctx, "%s: OK, FBZ=%d\n", path, pin_info.tries_left);
return 0;
}
static char *dirpath(char *dir, char *path){
static char buf[SC_MAX_PATH_STRING_SIZE];
strcpy(buf,dir);
return strcat(buf,path);
}
static int detect_netkey(
sc_pkcs15_card_t *p15card
){
sc_card_t *card=p15card->card;
sc_path_t p;
sc_file_t *f;
int keylen;
char dir[10], *c_auth;
// NKS-Applikation ?
p.len=7; p.type=SC_PATH_TYPE_DF_NAME;
memcpy(p.value, "\xD2\x76\x00\x00\x03\x01\x02", p.len=7);
if (sc_select_file(card,&p,&f)!=SC_SUCCESS) return 1;
sprintf(dir,"%04X", f->id);
sc_file_free(f);
p15card->manufacturer_id = strdup("TeleSec GmbH");
p15card->label = strdup(card->type==SC_CARD_TYPE_TCOS_V3 ? "NetKey V3 Card" : "NetKey Card");
keylen= card->type==SC_CARD_TYPE_TCOS_V3 ? 2048 : 1024;
c_auth= card->type==SC_CARD_TYPE_TCOS_V3 ? "C500" : "C100";
insert_cert(p15card, dirpath(dir,"4331"), 0x45, 1, "Signatur Zertifikat 1");
insert_cert(p15card, dirpath(dir,"4332"), 0x45, 1, "Signatur Zertifikat 2");
insert_cert(p15card, dirpath(dir,"C000"), 0x45, 0, "Telesec Signatur Zertifikat");
insert_cert(p15card, dirpath(dir,"43B1"), 0x46, 1, "Verschluesselungs Zertifikat 1");
insert_cert(p15card, dirpath(dir,"43B2"), 0x46, 1, "Verschluesselungs Zertifikat 2");
insert_cert(p15card, dirpath(dir,"C200"), 0x46, 0, "Telesec Verschluesselungs Zertifikat");
insert_cert(p15card, dirpath(dir,"4371"), 0x47, 1, "Authentifizierungs Zertifikat 1");
insert_cert(p15card, dirpath(dir,"4372"), 0x47, 1, "Authentifizierungs Zertifikat 2");
insert_cert(p15card, dirpath(dir,c_auth), 0x47, 0, "Telesec Authentifizierungs Zertifikat");
insert_cert(p15card, dirpath(dir,"C201"), 0x48, 0, "Telesec 1024bit Zertifikat");
insert_key(p15card, dirpath(dir,"5331"), 0x45, 0x80, keylen, 4, "Signatur Schluessel");
insert_key(p15card, dirpath(dir,"53B1"), 0x46, 0x81, keylen, 3, "Verschluesselungs Schluessel");
insert_key(p15card, dirpath(dir,"5371"), 0x47, 0x82, keylen, 3, "Authentifizierungs Schluessel");
insert_key(p15card, dirpath(dir,"0000"), 0x48, 0x83, 1024, 3, "1024bit Schluessel");
insert_pin(p15card, "5000", 1, 2, 0x00, 6, "PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
);
insert_pin(p15card, "5001", 2, 0, 0x01, 8, "PUK",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN
);
if(card->type==SC_CARD_TYPE_TCOS_V3){
insert_pin(p15card, dirpath(dir,"0000"), 3, 1, 0x83, 6, "NetKey PIN2",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED},
{1, 4, 1, 6, 0x81, "DF015081", "Netkey PIN1",
SC_PKCS15_PIN_FLAG_INITIALIZED
);
} else {
insert_pin(p15card, dirpath(dir,"5080"), 3, 1, 0x80, 6, "NetKey PIN0",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED},
{1, 5, 0, 6, 0x81, "DF065081", "SigG PIN",
SC_PKCS15_PIN_FLAG_INITIALIZED
);
}
insert_pin(p15card, dirpath(dir,"5081"), 4, 1, 0x81, 6, "NetKey PIN1",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED
);
// SigG-Applikation ?
p.len=7; p.type=SC_PATH_TYPE_DF_NAME;
memcpy(p.value, "\xD2\x76\x00\x00\x66\x01", p.len=6);
if (sc_select_file(card,&p,&f)==SC_SUCCESS){
sprintf(dir,"%04X", f->id);
sc_file_free(f);
insert_cert(p15card, dirpath(dir,"C000"), 0x49, 1, "SigG Zertifikat 1");
insert_cert(p15card, dirpath(dir,"4331"), 0x49, 1, "SigG Zertifikat 2");
insert_cert(p15card, dirpath(dir,"4332"), 0x49, 1, "SigG Zertifikat 3");
if(card->type==SC_CARD_TYPE_TCOS_V3){
insert_key(p15card, dirpath(dir,"0000"), 0x49, 0x84, 2048, 5, "SigG Schluessel");
} else {
insert_key(p15card, dirpath(dir,"5331"), 0x49, 0x80, 1024, 5, "SigG Schluessel");
}
insert_pin(p15card, dirpath(dir,"5081"), 6, 0, 0x81, 6, "SigG PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED},
{2, 1, 0, 6, 0x81, "8000DF010000", "Signatur PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED},
{2, 2, 0, 6, 0x81, "800082000040", "Verschluesselungs PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED},
{2, 3, 0, 6, 0x81, "800083000040", "Authentifizierungs PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED},
{3, 1, 0, 6, 0x01, "5001", "globale PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN},
{4, 1, 2, 6, 0x00, "5000", "globale PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN},
{4, 2, 0, 8, 0x01, "5008", "globale PUK",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN},
{5, 1, 2, 6, 0x00, "5000", "globale PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN},
{5, 2, 0, 8, 0x01, "5008", "globale PUK",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN},
{6, 1, 0, 6, 0x00, "4100", "globale PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED},
{0, 0, 0, 0, 0, NULL, NULL, 0}
};
SC_PKCS15_PIN_FLAG_INITIALIZED
);
if(card->type==SC_CARD_TYPE_TCOS_V3){
insert_pin(p15card, dirpath(dir,"0000"), 7, 0, 0x83, 8, "SigG PIN2",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED
);
}
}
return 0;
}
static int detect_signtrust(
sc_pkcs15_card_t *p15card
){
if(insert_cert(p15card,"8000DF01C000", 0x45, 1, "Signatur Zertifikat")) return 1;
p15card->manufacturer_id = strdup("Deutsche Post");
p15card->label = strdup("SignTrust Card");
insert_cert(p15card,"800082008220", 0x46, 1, "Verschluesselungs Zertifikat");
insert_cert(p15card,"800083008320", 0x47, 1, "Authentifizierungs Zertifikat");
insert_key(p15card,"8000DF015331", 0x45, 0x80, 1024, 1, "Signatur Schluessel");
insert_key(p15card,"800082008210", 0x46, 0x80, 1024, 2, "Verschluesselungs Schluessel");
insert_key(p15card,"800083008310", 0x47, 0x80, 1024, 3, "Authentifizierungs Schluessel");
insert_pin(p15card,"8000DF010000", 1, 0, 0x81, 6, "Signatur PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED
);
insert_pin(p15card,"800082000040", 2, 0, 0x81, 6, "Verschluesselungs PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED
);
insert_pin(p15card,"800083000040", 3, 0, 0x81, 6, "Authentifizierungs PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
SC_PKCS15_PIN_FLAG_INITIALIZED
);
return 0;
}
static int detect_datev(
sc_pkcs15_card_t *p15card
){
if(insert_cert(p15card,"3000C500", 0x45, 0, "Signatur Zertifikat")) return 1;
p15card->manufacturer_id = strdup("DATEV");
p15card->label = strdup("DATEV Classic");
insert_cert(p15card,"DF02C200", 0x46, 0, "Verschluesselungs Zertifikat");
insert_cert(p15card,"DF02C500", 0x47, 0, "Authentifizierungs Zertifikat");
insert_key(p15card,"30005371", 0x45, 0x82, 1024, 1, "Signatur Schluessel");
insert_key(p15card,"DF0253B1", 0x46, 0x81, 1024, 1, "Verschluesselungs Schluessel");
insert_key(p15card,"DF025371", 0x47, 0x82, 1024, 1, "Authentifizierungs Schluessel");
insert_pin(p15card,"5001", 1, 0, 0x01, 6, "PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
);
return 0;
}
static int detect_unicard(
sc_pkcs15_card_t *p15card
){
if(!insert_cert(p15card,"41004352", 0x45, 1, "Zertifikat 1")){
p15card->manufacturer_id = strdup("JLU Giessen");
p15card->label = strdup("JLU Giessen Card");
insert_cert(p15card,"41004353", 0x46, 1, "Zertifikat 2");
insert_cert(p15card,"41004354", 0x47, 1, "Zertifikat 3");
insert_key(p15card,"41005103", 0x45, 0x83, 1024, 1, "Schluessel 1");
insert_key(p15card,"41005104", 0x46, 0x84, 1024, 1, "Schluessel 2");
insert_key(p15card,"41005105", 0x47, 0x85, 1024, 1, "Schluessel 3");
} else if(!insert_cert(p15card,"41014352", 0x45, 1, "Zertifikat 1")){
p15card->manufacturer_id = strdup("TU Darmstadt");
p15card->label = strdup("TUD Card");
insert_cert(p15card,"41014353", 0x46, 1, "Zertifikat 2");
insert_cert(p15card,"41014354", 0x47, 1, "Zertifikat 3");
insert_key(p15card,"41015103", 0x45, 0x83, 1024, 1, "Schluessel 1");
insert_key(p15card,"41015104", 0x46, 0x84, 1024, 1, "Schluessel 2");
insert_key(p15card,"41015105", 0x47, 0x85, 1024, 1, "Schluessel 3");
} else return 1;
insert_pin(p15card,"5000", 1, 2, 0x00, 6, "PIN",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
);
insert_pin(p15card,"5008", 2, 0, 0x01, 8, "PUK",
SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN
);
return 0;
}
int sc_pkcs15emu_tcos_init_ex(
sc_pkcs15_card_t *p15card,
sc_pkcs15emu_opt_t *opts
){
sc_card_t *card = p15card->card;
sc_context_t *ctx = p15card->card->ctx;
sc_path_t path;
sc_file_t *file;
sc_serial_number_t serialnr;
char serial[30];
int i, j, found, r, usage, cardtype;
int i, r;
/* check if we have the correct card OS unless SC_PKCS15EMU_FLAGS_NO_CHECK */
i=(opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK);
if (!i && strcmp(card->name, "TCOS")) return SC_ERROR_WRONG_CARD;
// check if we have the correct card OS unless SC_PKCS15EMU_FLAGS_NO_CHECK
i=(opts && (opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK));
if (!i && card->type!=SC_CARD_TYPE_TCOS_V2 && card->type!=SC_CARD_TYPE_TCOS_V3) return SC_ERROR_WRONG_CARD;
/* get the card serial number */
// get the card serial number
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serialnr);
if (r < 0) {
sc_debug(ctx, "unable to get ICCSN\n");
r = SC_ERROR_WRONG_CARD;
goto failed;
return SC_ERROR_WRONG_CARD;
}
sc_bin_to_hex(serialnr.value, serialnr.len , serial, sizeof(serial), 0);
serial[19] = '\0';
set_string(&p15card->serial_number, serial);
p15card->serial_number = strdup(serial);
/* detect cardtype and certificates */
cardtype=0;
for(i=0; certlist[i].id; ++i){
if(cardtype && certlist[i].type!=cardtype) continue;
if(!cardtype && (certlist[i].flags&1)) continue;
if(!cardtype && ctx->debug>=2) sc_debug(ctx, "Testing %s\n",cardlist[certlist[i].type-1].card);
if(ctx->debug>=2) sc_debug(ctx, "Testing Cert %s, %s\n", certlist[i].path, certlist[i].label);
sc_ctx_suppress_errors_on(ctx);
sc_format_path(certlist[i].path, &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, NULL);
sc_ctx_suppress_errors_off(ctx);
if(r<0) continue;
cardtype=certlist[i].type;
certlist[i].flags |= 4;
}
if(ctx->debug >= 1) sc_debug(ctx, "Cardtype=%d, %s\n", cardtype, cardlist[cardtype-1].card);
if(cardtype<1 || cardtype>(int)(sizeof(cardlist)/sizeof(cardlist[0]))){
r = SC_ERROR_WRONG_CARD;
goto failed;
}
set_string(&p15card->label, cardlist[cardtype-1].card);
set_string(&p15card->manufacturer_id, cardlist[cardtype-1].manufacturer);
if(!detect_netkey(p15card)) return SC_SUCCESS;
if(!detect_signtrust(p15card)) return SC_SUCCESS;
if(!detect_datev(p15card)) return SC_SUCCESS;
if(!detect_unicard(p15card)) return SC_SUCCESS;
/* insert certificates */
for(found=1;found;){
for(i=found=0; certlist[i].id && !found; ++i) if(certlist[i].flags&4) found=certlist[i].id;
for(j=0; j<2; ++j) for(i=0; certlist[i].id; ++i){
struct sc_pkcs15_cert_info cert_info;
struct sc_pkcs15_object cert_obj;
unsigned char cert[20];
sc_ctx_suppress_errors_off(ctx);
if(certlist[i].id!=found) continue;
if((certlist[i].flags&2) == 2*j) continue;
if(!(certlist[i].flags&4)) continue;
certlist[i].flags-=4;
sc_format_path(certlist[i].path, &path);
if(sc_select_file(card, &path, NULL)<0) continue;
/* read first 20 bytes of certificate, first two bytes
* must be 0x30 0x82, otherwise this is an empty cert-file
*/
r = sc_read_binary(card, 0, cert, sizeof(cert), 0);
if(r<0 || cert[0]!=0x30 || cert[1]!=0x82) continue;
if(ctx->debug>=1){
sc_debug(ctx,"Cert %02X %s, %s\n",certlist[i].id,certlist[i].path,certlist[i].label);
}
/* Telesec-Certificates are prefixed by an OID,
* for example 06:03:55:04:24. so use appropriate offset
*/
if(cert[4]==0x06 && cert[5]<10 && cert[6+cert[5]]==0x30 && cert[7+cert[5]]==0x82){
path.index=6+cert[5];
path.count=(cert[8+cert[5]]<<8) + cert[9+cert[5]] + 4;
} else {
path.index=0;
path.count=(cert[2]<<8) + cert[3] + 4;
}
memset(&cert_info, 0, sizeof(cert_info));
cert_info.id.len = 1;
cert_info.id.value[0] = certlist[i].id;
cert_info.authority = 0;
cert_info.path = path;
memset(&cert_obj, 0, sizeof(cert_obj));
strlcpy(cert_obj.label, certlist[i].label, sizeof(cert_obj.label));
cert_obj.flags = certlist[i].writable ? SC_PKCS15_CO_FLAG_MODIFIABLE : 0;
r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
if (r < 0) {
sc_debug(ctx, "sc_pkcs15emu_add_x509_cert(%s) failed\n", certlist[i].path);
r = SC_ERROR_INTERNAL;
goto failed;
}
}
}
for(i=0; keylist[i].id; ++i){
struct sc_pkcs15_prkey_info prkey_info;
struct sc_pkcs15_object prkey_obj;
if(keylist[i].type!=cardtype) continue;
sc_format_path(keylist[i].path, &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, &file);
sc_ctx_suppress_errors_off(ctx);
if (r < 0) continue;
if(ctx->debug >= 1) sc_debug(ctx,"Key %02X %s, %s\n",keylist[i].id,keylist[i].path,keylist[i].label);
usage = SC_PKCS15_PRKEY_USAGE_SIGN;
if (file->prop_attr[1] & 0x04) usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT;
if (file->prop_attr[1] & 0x08) usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
memset(&prkey_info, 0, sizeof(prkey_info));
prkey_info.id.len = 1;
prkey_info.id.value[0] = keylist[i].id;
prkey_info.usage = usage;
prkey_info.native = 1;
prkey_info.key_reference = keylist[i].key_reference;
prkey_info.modulus_length = 1024;
sc_format_path(keylist[i].path, &prkey_info.path);
memset(&prkey_obj, 0, sizeof(prkey_obj));
strlcpy(prkey_obj.label, keylist[i].label, sizeof(prkey_obj.label));
prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
prkey_obj.auth_id.len = 1;
prkey_obj.auth_id.value[0] = keylist[i].auth_id;
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
sc_file_free(file);
if (r < 0) {
sc_debug(ctx, "sc_pkcs15emu_add_rsa_prkey(%s) failed\n", keylist[i].path);
r = SC_ERROR_INTERNAL;
goto failed;
}
}
for(i=0; pinlist[i].id; ++i){
struct sc_pkcs15_pin_info pin_info;
struct sc_pkcs15_object pin_obj;
if(pinlist[i].type && pinlist[i].type!=cardtype) continue;
sc_format_path(pinlist[i].path, &path);
sc_ctx_suppress_errors_on(ctx);
r = sc_select_file(card, &path, &file);
sc_ctx_suppress_errors_off(ctx);
if (r < 0) continue;
if(ctx->debug >= 1) sc_debug(ctx, "PIN %02X %s, %s\n", pinlist[i].id,pinlist[i].path,pinlist[i].label);
memset(&pin_info, 0, sizeof(pin_info));
pin_info.auth_id.len = 1;
pin_info.auth_id.value[0] = pinlist[i].id;
pin_info.reference = pinlist[i].reference;
pin_info.flags = pinlist[i].flags;
pin_info.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
pin_info.min_length = pinlist[i].min_length;
pin_info.stored_length = 16;
pin_info.max_length = 16;
pin_info.pad_char = '\0';
pin_info.tries_left = file->prop_attr[3];
sc_format_path(pinlist[i].path, &pin_info.path);
memset(&pin_obj, 0, sizeof(pin_obj));
strlcpy(pin_obj.label, pinlist[i].label, sizeof(pin_obj.label));
pin_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
pin_obj.auth_id.len = pinlist[i].auth_id ? 0 : 1;
pin_obj.auth_id.value[0] = pinlist[i].auth_id;
r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
sc_file_free(file);
if (r < 0) {
sc_debug(ctx, "sc_pkcs15emu_add_pin_obj(%s) failed\n", pinlist[i].path);
r = SC_ERROR_INTERNAL;
goto failed;
}
}
/* return to MF */
sc_format_path("3F00", &path);
r = sc_select_file(card, &path, NULL);
failed:
if (r < 0)
sc_debug(ctx, "PKCS15-emulation for TCOS based preformatted failed: %s\n", sc_strerror(r));
return r;
return SC_ERROR_INTERNAL;
}

View File

@ -223,16 +223,18 @@ static int do_ls(int argc, char **argv)
}
}
ctx->suppress_errors++;
r = sc_select_file(card, &path, &file);
ctx->suppress_errors--;
if (r) {
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
return -1;
printf(" %02X%02X unable to select file, %s\n", cur[0], cur[1], sc_strerror(r));
} else {
file->id = (cur[0] << 8) | cur[1];
print_file(file);
sc_file_free(file);
}
file->id = (cur[0] << 8) | cur[1];
cur += 2;
count -= 2;
print_file(file);
sc_file_free(file);
r = sc_select_file(card, &current_path, NULL);
if (r) {
printf("unable to select parent DF: %s\n", sc_strerror(r));