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:
parent
1667798217
commit
513a3dde0a
|
@ -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,13 +229,11 @@ 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;
|
||||
|
||||
switch ( (commandbyte & 0xfe) )
|
||||
{
|
||||
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;
|
||||
|
@ -248,8 +259,6 @@ static unsigned int map_operations (int commandbyte )
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 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,
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
if (pathlen >= 2 && memcmp(path, "\x3F\x00", 2) == 0) path += 2, pathlen -= 2;
|
||||
if (pathlen == 0) apdu.p1 = 0;
|
||||
break;
|
||||
}
|
||||
path += 2;
|
||||
pathlen -= 2;
|
||||
}
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
switch (apdu.resp[0]) {
|
||||
case 0x6F:
|
||||
file = sc_file_new();
|
||||
if (file == NULL)
|
||||
SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
|
||||
if (file == NULL) SC_FUNC_RETURN(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;
|
||||
|
||||
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;
|
||||
|
||||
switch (type) {
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
file->size=0;
|
||||
for(j=0; j<len; ++j) file->size = (file->size<<8) | d[j];
|
||||
break;
|
||||
case 0x00: /* proprietary coding */
|
||||
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
||||
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_FUNC_RETURN(card->ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
||||
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;
|
||||
|
||||
parse_sec_attr(card, file, file->sec_attr, file->sec_attr_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
if (file) {
|
||||
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) {
|
||||
if ((r=sc_transmit_apdu(card, &apdu))) {
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
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 (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,17 +733,16 @@ 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;
|
||||
|
@ -896,8 +756,3 @@ static struct sc_card_driver * sc_get_driver(void)
|
|||
|
||||
return &tcos_drv;
|
||||
}
|
||||
|
||||
struct sc_card_driver * sc_get_tcos_driver(void)
|
||||
{
|
||||
return sc_get_driver();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
extern int sc_pkcs15emu_tcos_init_ex(sc_pkcs15_card_t *,
|
||||
sc_pkcs15emu_opt_t *);
|
||||
|
||||
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",
|
||||
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_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
|
||||
SC_PKCS15_PIN_FLAG_INITIALIZED},
|
||||
{1, 5, 0, 6, 0x81, "DF065081", "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}
|
||||
};
|
||||
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;
|
||||
sc_path_t path;
|
||||
sc_file_t *file;
|
||||
sc_serial_number_t serialnr;
|
||||
char serial[30];
|
||||
int i, j, found, r, usage, cardtype;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
sc_bin_to_hex(serialnr.value, serialnr.len , serial, sizeof(serial), 0);
|
||||
serial[19] = '\0';
|
||||
set_string(&p15card->serial_number, 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_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);
|
||||
|
||||
/* 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];
|
||||
|
||||
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;
|
||||
}
|
||||
int r;
|
||||
|
||||
memset(&cert_info, 0, sizeof(cert_info));
|
||||
cert_info.id.len = 1;
|
||||
cert_info.id.value[0] = certlist[i].id;
|
||||
cert_info.id.value[0] = id;
|
||||
cert_info.authority = 0;
|
||||
cert_info.path = path;
|
||||
sc_format_path(path, &cert_info.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;
|
||||
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 < 0) {
|
||||
sc_debug(ctx, "sc_pkcs15emu_add_x509_cert(%s) failed\n", certlist[i].path);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto failed;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
for(i=0; keylist[i].id; ++i){
|
||||
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;
|
||||
|
||||
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;
|
||||
int r, can_sign, can_crypt;
|
||||
|
||||
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.id.value[0] = id;
|
||||
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);
|
||||
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, keylist[i].label, sizeof(prkey_obj.label));
|
||||
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] = keylist[i].auth_id;
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
for(i=0; pinlist[i].id; ++i){
|
||||
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;
|
||||
|
||||
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);
|
||||
int r;
|
||||
|
||||
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.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 = pinlist[i].min_length;
|
||||
pin_info.min_length = 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);
|
||||
sc_format_path(path, &pin_info.path);
|
||||
|
||||
memset(&pin_obj, 0, sizeof(pin_obj));
|
||||
strlcpy(pin_obj.label, pinlist[i].label, sizeof(pin_obj.label));
|
||||
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 = pinlist[i].auth_id ? 0 : 1;
|
||||
pin_obj.auth_id.value[0] = pinlist[i].auth_id;
|
||||
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);
|
||||
sc_file_free(file);
|
||||
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
|
||||
);
|
||||
} 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
|
||||
);
|
||||
}
|
||||
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
|
||||
);
|
||||
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_serial_number_t serialnr;
|
||||
char serial[30];
|
||||
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 && card->type!=SC_CARD_TYPE_TCOS_V2 && card->type!=SC_CARD_TYPE_TCOS_V3) return SC_ERROR_WRONG_CARD;
|
||||
|
||||
// get the card serial number
|
||||
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serialnr);
|
||||
if (r < 0) {
|
||||
sc_debug(ctx, "sc_pkcs15emu_add_pin_obj(%s) failed\n", pinlist[i].path);
|
||||
r = SC_ERROR_INTERNAL;
|
||||
goto failed;
|
||||
}
|
||||
sc_debug(ctx, "unable to get ICCSN\n");
|
||||
return SC_ERROR_WRONG_CARD;
|
||||
}
|
||||
sc_bin_to_hex(serialnr.value, serialnr.len , serial, sizeof(serial), 0);
|
||||
serial[19] = '\0';
|
||||
p15card->serial_number = strdup(serial);
|
||||
|
||||
/* return to MF */
|
||||
sc_format_path("3F00", &path);
|
||||
r = sc_select_file(card, &path, NULL);
|
||||
sc_ctx_suppress_errors_on(ctx);
|
||||
|
||||
failed:
|
||||
if (r < 0)
|
||||
sc_debug(ctx, "PKCS15-emulation for TCOS based preformatted failed: %s\n", sc_strerror(r));
|
||||
return r;
|
||||
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;
|
||||
|
||||
sc_ctx_suppress_errors_off(ctx);
|
||||
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
cur += 2;
|
||||
count -= 2;
|
||||
print_file(file);
|
||||
sc_file_free(file);
|
||||
}
|
||||
cur += 2;
|
||||
count -= 2;
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent DF: %s\n", sc_strerror(r));
|
||||
|
|
Loading…
Reference in New Issue