diff --git a/src/libopensc/card-tcos.c b/src/libopensc/card-tcos.c index db0cc372..ec6eec40 100644 --- a/src/libopensc/card-tcos.c +++ b/src/libopensc/card-tcos.c @@ -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ä + * Copyright (C) 2007 Peter Koch * Copyright (C) 2002 g10 Code GmbH + * Copyright (C) 2001 Juha Yrjölä * * 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 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+1select_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; jsize = (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; ictx, 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; ictx, 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(offsetctx, 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(); -} diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h index 6ee65a83..53a6817d 100644 --- a/src/libopensc/cards.h +++ b/src/libopensc/cards.h @@ -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, diff --git a/src/libopensc/pkcs15-tcos.c b/src/libopensc/pkcs15-tcos.c index f26c00ac..4d4528c9 100644 --- a/src/libopensc/pkcs15-tcos.c +++ b/src/libopensc/pkcs15-tcos.c @@ -1,9 +1,7 @@ /* * PKCS15 emulation layer for TCOS based preformatted cards * - * Copyright (C) 2006, Peter Koch - * Copyright (C) 2004, Antonino Iacono - * Copyright (C) 2003, Olaf Kirch + * Copyright (C) 2007, Peter Koch * * 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 #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;idebug>=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;idebug>=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; } diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c index f809c4cd..02edb687 100644 --- a/src/tools/opensc-explorer.c +++ b/src/tools/opensc-explorer.c @@ -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, ¤t_path, NULL); if (r) { printf("unable to select parent DF: %s\n", sc_strerror(r));