2002-02-26 11:23:25 +00:00
|
|
|
/*
|
2002-03-09 15:11:46 +00:00
|
|
|
* card-miocos.c: Support for PKI cards by Miotec
|
2002-02-26 11:23:25 +00:00
|
|
|
*
|
2006-12-19 21:32:31 +00:00
|
|
|
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
2002-02-26 11:23:25 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
2015-04-22 21:55:33 +00:00
|
|
|
#if HAVE_CONFIG_H
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
2015-04-22 21:55:33 +00:00
|
|
|
#endif
|
2010-03-04 08:14:36 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2002-04-05 10:44:51 +00:00
|
|
|
#include "internal.h"
|
2002-04-14 12:43:47 +00:00
|
|
|
#include "asn1.h"
|
2002-04-04 20:40:40 +00:00
|
|
|
#include "cardctl.h"
|
2002-02-26 11:23:25 +00:00
|
|
|
|
2005-02-06 19:40:40 +00:00
|
|
|
static struct sc_atr_table miocos_atrs[] = {
|
2002-04-14 12:43:47 +00:00
|
|
|
/* Test card with 32 kB memory */
|
2005-09-07 08:33:55 +00:00
|
|
|
{ "3B:9D:94:40:23:00:68:10:11:4D:69:6F:43:4F:53:00:90:00", NULL, NULL, SC_CARD_TYPE_MIOCOS_GENERIC, 0, NULL },
|
2002-04-14 12:43:47 +00:00
|
|
|
/* Test card with 64 kB memory */
|
2005-09-07 08:33:55 +00:00
|
|
|
{ "3B:9D:94:40:23:00:68:20:01:4D:69:6F:43:4F:53:00:90:00", NULL, NULL, SC_CARD_TYPE_MIOCOS_GENERIC, 0, NULL },
|
|
|
|
{ NULL, NULL, NULL, 0, 0, NULL }
|
2002-02-26 11:23:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct sc_card_operations miocos_ops;
|
2003-02-20 12:51:07 +00:00
|
|
|
static struct sc_card_driver miocos_drv = {
|
2005-02-09 14:47:46 +00:00
|
|
|
"MioCOS 1.1",
|
2002-02-26 11:23:25 +00:00
|
|
|
"miocos",
|
2005-09-07 08:33:55 +00:00
|
|
|
&miocos_ops,
|
|
|
|
NULL, 0, NULL
|
2002-02-26 11:23:25 +00:00
|
|
|
};
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_match_card(sc_card_t *card)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
2002-03-09 15:11:46 +00:00
|
|
|
int i;
|
2002-02-26 11:23:25 +00:00
|
|
|
|
2005-02-06 19:40:40 +00:00
|
|
|
i = _sc_match_atr(card, miocos_atrs, &card->type);
|
2002-03-09 15:11:46 +00:00
|
|
|
if (i < 0)
|
2002-02-26 11:23:25 +00:00
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_init(sc_card_t *card)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
2003-05-28 20:52:33 +00:00
|
|
|
card->name = "MioCOS";
|
2002-02-26 11:23:25 +00:00
|
|
|
card->cla = 0x00;
|
2005-02-10 10:07:13 +00:00
|
|
|
|
|
|
|
if (1) {
|
2002-03-09 15:11:46 +00:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
|
|
|
|
flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
|
|
|
|
|
2002-03-10 11:48:57 +00:00
|
|
|
_sc_card_add_rsa_alg(card, 1024, flags, 0);
|
2002-03-09 15:11:46 +00:00
|
|
|
}
|
2002-02-26 11:23:25 +00:00
|
|
|
|
2003-05-15 15:42:45 +00:00
|
|
|
/* read_binary and friends shouldn't do more than 244 bytes
|
2003-05-14 12:25:13 +00:00
|
|
|
* per operation */
|
2010-09-09 18:58:44 +00:00
|
|
|
card->max_send_size = 244;
|
|
|
|
card->max_recv_size = 244;
|
2003-05-14 12:25:13 +00:00
|
|
|
|
2002-02-26 11:23:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct sc_card_operations *iso_ops = NULL;
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int acl_to_byte(const sc_acl_entry_t *e)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
|
|
|
switch (e->method) {
|
|
|
|
case SC_AC_NONE:
|
|
|
|
return 0x00;
|
|
|
|
case SC_AC_CHV:
|
|
|
|
case SC_AC_TERM:
|
2002-04-14 12:43:47 +00:00
|
|
|
case SC_AC_AUT:
|
|
|
|
if (e->key_ref == SC_AC_KEY_REF_NONE)
|
|
|
|
return -1;
|
|
|
|
if (e->key_ref < 1 || e->key_ref > 14)
|
|
|
|
return -1;
|
|
|
|
return e->key_ref;
|
2002-02-26 11:23:25 +00:00
|
|
|
case SC_AC_NEVER:
|
|
|
|
return 0x0F;
|
|
|
|
}
|
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
|
2002-03-09 15:11:46 +00:00
|
|
|
u8 *buf, size_t *buflen)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
2002-03-09 15:11:46 +00:00
|
|
|
u8 *p = buf;
|
|
|
|
const int df_ops[8] = {
|
|
|
|
SC_AC_OP_DELETE, SC_AC_OP_CREATE,
|
2002-04-19 17:02:49 +00:00
|
|
|
/* RFU */ -1, /* CREATE AC */ SC_AC_OP_CREATE,
|
|
|
|
/* UPDATE AC */ SC_AC_OP_CREATE, -1, -1, -1
|
2002-03-09 15:11:46 +00:00
|
|
|
};
|
|
|
|
const int ef_ops[8] = {
|
2002-04-19 17:02:49 +00:00
|
|
|
/* DELETE */ SC_AC_OP_UPDATE, -1, SC_AC_OP_READ,
|
2002-03-09 15:11:46 +00:00
|
|
|
SC_AC_OP_UPDATE, -1, -1, SC_AC_OP_INVALIDATE,
|
|
|
|
SC_AC_OP_REHABILITATE
|
|
|
|
};
|
|
|
|
const int key_ops[8] = {
|
2002-04-19 17:02:49 +00:00
|
|
|
/* DELETE */ SC_AC_OP_UPDATE, -1, -1,
|
2002-03-09 15:11:46 +00:00
|
|
|
SC_AC_OP_UPDATE, SC_AC_OP_CRYPTO, -1, SC_AC_OP_INVALIDATE,
|
|
|
|
SC_AC_OP_REHABILITATE
|
|
|
|
};
|
|
|
|
const int *ops;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
*p++ = file->id >> 8;
|
|
|
|
*p++ = file->id & 0xFF;
|
|
|
|
switch (file->type) {
|
|
|
|
case SC_FILE_TYPE_DF:
|
|
|
|
*p++ = 0x20;
|
2002-04-04 20:40:40 +00:00
|
|
|
ops = df_ops;
|
2002-03-09 15:11:46 +00:00
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_WORKING_EF:
|
|
|
|
switch (file->ef_structure) {
|
|
|
|
case SC_FILE_EF_TRANSPARENT:
|
|
|
|
*p++ = 0x40;
|
|
|
|
break;
|
|
|
|
case SC_FILE_EF_LINEAR_FIXED:
|
|
|
|
*p++ = 0x41;
|
|
|
|
break;
|
|
|
|
case SC_FILE_EF_CYCLIC:
|
|
|
|
*p++ = 0x43;
|
|
|
|
break;
|
|
|
|
default:
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Invalid EF structure\n");
|
2002-03-09 15:11:46 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
2002-02-26 11:23:25 +00:00
|
|
|
}
|
2002-04-04 20:40:40 +00:00
|
|
|
ops = ef_ops;
|
2002-03-09 15:11:46 +00:00
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_INTERNAL_EF:
|
|
|
|
*p++ = 0x44;
|
2002-04-04 20:40:40 +00:00
|
|
|
ops = key_ops;
|
2002-03-09 15:11:46 +00:00
|
|
|
break;
|
|
|
|
default:
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unknown file type\n");
|
2002-03-09 15:11:46 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
*p++ = 0;
|
|
|
|
*p++ = 0;
|
|
|
|
} else {
|
|
|
|
*p++ = file->size >> 8;
|
|
|
|
*p++ = file->size & 0xFF;
|
|
|
|
}
|
2002-03-12 13:00:57 +00:00
|
|
|
if (file->sec_attr_len == 4) {
|
|
|
|
memcpy(p, file->sec_attr, 4);
|
|
|
|
p += 4;
|
|
|
|
} else for (i = 0; i < 8; i++) {
|
2002-03-09 15:11:46 +00:00
|
|
|
u8 nibble;
|
2002-02-26 11:23:25 +00:00
|
|
|
|
2002-03-09 15:11:46 +00:00
|
|
|
if (ops[i] == -1)
|
|
|
|
nibble = 0x00;
|
2002-04-14 12:43:47 +00:00
|
|
|
else {
|
|
|
|
int byte = acl_to_byte(sc_file_get_acl_entry(file, ops[i]));
|
|
|
|
if (byte < 0) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Invalid ACL\n");
|
2002-04-14 12:43:47 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
nibble = byte;
|
|
|
|
}
|
2002-03-09 15:11:46 +00:00
|
|
|
if ((i & 1) == 0)
|
|
|
|
*p = nibble << 4;
|
2002-04-04 20:40:40 +00:00
|
|
|
else {
|
|
|
|
*p |= nibble & 0x0F;
|
|
|
|
p++;
|
|
|
|
}
|
2002-03-09 15:11:46 +00:00
|
|
|
}
|
|
|
|
if (file->type == SC_FILE_TYPE_WORKING_EF &&
|
|
|
|
file->ef_structure != SC_FILE_EF_TRANSPARENT)
|
|
|
|
*p++ = file->record_length;
|
|
|
|
else
|
|
|
|
*p++ = 0;
|
|
|
|
if (file->status & SC_FILE_STATUS_INVALIDATED)
|
|
|
|
*p++ = 0;
|
|
|
|
else
|
|
|
|
*p++ = 0x01;
|
|
|
|
if (file->type == SC_FILE_TYPE_DF && file->namelen) {
|
|
|
|
assert(file->namelen <= 16);
|
|
|
|
memcpy(p, file->name, file->namelen);
|
|
|
|
p += file->namelen;
|
2002-02-26 11:23:25 +00:00
|
|
|
}
|
2002-03-09 15:11:46 +00:00
|
|
|
*buflen = p - buf;
|
2002-02-26 11:23:25 +00:00
|
|
|
|
2002-03-09 15:11:46 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_create_file(sc_card_t *card, sc_file_t *file)
|
2002-03-09 15:11:46 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_apdu_t apdu;
|
2002-03-09 15:11:46 +00:00
|
|
|
u8 sbuf[32];
|
|
|
|
size_t buflen;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = encode_file_structure(card, file, sbuf, &buflen);
|
|
|
|
if (r)
|
|
|
|
return r;
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
|
|
|
|
apdu.data = sbuf;
|
|
|
|
apdu.datalen = buflen;
|
|
|
|
apdu.lc = buflen;
|
|
|
|
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
|
2002-04-05 14:46:44 +00:00
|
|
|
if (apdu.sw1 == 0x6A && apdu.sw2 == 0x89)
|
|
|
|
return SC_ERROR_FILE_ALREADY_EXISTS;
|
2002-03-09 15:11:46 +00:00
|
|
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Card returned error");
|
2002-03-09 15:11:46 +00:00
|
|
|
|
|
|
|
return 0;
|
2002-02-26 11:23:25 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_set_security_env(sc_card_t *card,
|
|
|
|
const sc_security_env_t *env,
|
2002-02-26 11:23:25 +00:00
|
|
|
int se_num)
|
|
|
|
{
|
|
|
|
if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_security_env_t tmp;
|
2002-02-26 11:23:25 +00:00
|
|
|
|
|
|
|
tmp = *env;
|
2002-03-09 15:11:46 +00:00
|
|
|
tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
|
2002-02-26 11:23:25 +00:00
|
|
|
tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
|
|
|
|
if (tmp.algorithm != SC_ALGORITHM_RSA) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Only RSA algorithm supported.\n");
|
2002-02-26 11:23:25 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
2002-03-09 15:11:46 +00:00
|
|
|
tmp.algorithm_ref = 0x00;
|
|
|
|
/* potential FIXME: return an error, if an unsupported
|
|
|
|
* pad or hash was requested, although this shouldn't happen.
|
|
|
|
*/
|
|
|
|
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
|
2002-02-26 11:23:25 +00:00
|
|
|
tmp.algorithm_ref = 0x02;
|
|
|
|
if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
|
2002-03-09 15:11:46 +00:00
|
|
|
tmp.algorithm_ref |= 0x10;
|
2002-06-03 15:05:58 +00:00
|
|
|
return iso_ops->set_security_env(card, &tmp, se_num);
|
2002-02-26 11:23:25 +00:00
|
|
|
}
|
2002-06-03 15:05:58 +00:00
|
|
|
return iso_ops->set_security_env(card, env, se_num);
|
2002-02-26 11:23:25 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static void add_acl_entry(sc_file_t *file, int op, u8 byte)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
|
|
|
unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
|
|
|
|
|
2002-04-14 12:43:47 +00:00
|
|
|
switch (byte) {
|
2002-02-26 11:23:25 +00:00
|
|
|
case 0:
|
|
|
|
method = SC_AC_NONE;
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
method = SC_AC_NEVER;
|
|
|
|
break;
|
|
|
|
default:
|
2002-04-14 12:43:47 +00:00
|
|
|
method = SC_AC_CHV;
|
|
|
|
key_ref = byte;
|
2002-02-26 11:23:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
sc_file_add_acl_entry(file, op, method, key_ref);
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static void parse_sec_attr(sc_file_t *file, const u8 *buf, size_t len)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
|
|
|
int i;
|
2002-03-09 15:11:46 +00:00
|
|
|
const int df_ops[8] = {
|
|
|
|
SC_AC_OP_DELETE, SC_AC_OP_CREATE,
|
|
|
|
-1, /* CREATE AC */ -1, /* UPDATE AC */ -1, -1, -1, -1
|
|
|
|
};
|
|
|
|
const int ef_ops[8] = {
|
|
|
|
SC_AC_OP_DELETE, -1, SC_AC_OP_READ,
|
|
|
|
SC_AC_OP_UPDATE, -1, -1, SC_AC_OP_INVALIDATE,
|
|
|
|
SC_AC_OP_REHABILITATE
|
|
|
|
};
|
|
|
|
const int key_ops[8] = {
|
|
|
|
SC_AC_OP_DELETE, -1, -1,
|
|
|
|
SC_AC_OP_UPDATE, SC_AC_OP_CRYPTO, -1, SC_AC_OP_INVALIDATE,
|
|
|
|
SC_AC_OP_REHABILITATE
|
|
|
|
};
|
|
|
|
const int *ops;
|
2002-02-26 11:23:25 +00:00
|
|
|
|
2002-03-09 15:11:46 +00:00
|
|
|
if (len < 4)
|
|
|
|
return;
|
|
|
|
switch (file->type) {
|
|
|
|
case SC_FILE_TYPE_WORKING_EF:
|
|
|
|
ops = ef_ops;
|
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_INTERNAL_EF:
|
|
|
|
ops = key_ops;
|
|
|
|
break;
|
|
|
|
case SC_FILE_TYPE_DF:
|
|
|
|
ops = df_ops;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
if (ops[i] == -1)
|
|
|
|
continue;
|
|
|
|
if ((i & 1) == 0)
|
2002-06-14 12:52:56 +00:00
|
|
|
add_acl_entry(file, ops[i], (u8)(buf[i / 2] >> 4));
|
2002-03-09 15:11:46 +00:00
|
|
|
else
|
2002-06-14 12:52:56 +00:00
|
|
|
add_acl_entry(file, ops[i], (u8)(buf[i / 2] & 0x0F));
|
2002-02-26 11:23:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_get_acl(sc_card_t *card, sc_file_t *file)
|
2002-04-14 12:43:47 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_apdu_t apdu;
|
2002-04-14 12:43:47 +00:00
|
|
|
u8 rbuf[256];
|
|
|
|
const u8 *seq = rbuf;
|
|
|
|
size_t left;
|
2013-05-25 02:22:28 +00:00
|
|
|
int r;
|
2004-12-21 15:00:57 +00:00
|
|
|
unsigned int i;
|
2002-04-14 12:43:47 +00:00
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x01);
|
|
|
|
apdu.resp = rbuf;
|
|
|
|
apdu.resplen = sizeof(rbuf);
|
|
|
|
apdu.le = sizeof(rbuf);
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
|
2002-04-14 12:43:47 +00:00
|
|
|
if (apdu.resplen == 0)
|
|
|
|
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
left = apdu.resplen;
|
|
|
|
seq = sc_asn1_skip_tag(card->ctx, &seq, &left,
|
|
|
|
SC_ASN1_SEQUENCE | SC_ASN1_CONS, &left);
|
|
|
|
if (seq == NULL)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to process reply");
|
2002-04-14 12:43:47 +00:00
|
|
|
for (i = 1; i < 15; i++) {
|
|
|
|
int j;
|
|
|
|
const u8 *tag;
|
|
|
|
size_t taglen;
|
|
|
|
|
|
|
|
tag = sc_asn1_skip_tag(card->ctx, &seq, &left,
|
|
|
|
SC_ASN1_CTX | i, &taglen);
|
|
|
|
if (tag == NULL || taglen == 0)
|
|
|
|
continue;
|
|
|
|
for (j = 0; j < SC_MAX_AC_OPS; j++) {
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_acl_entry_t *e;
|
2002-04-14 12:43:47 +00:00
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
e = (sc_acl_entry_t *) sc_file_get_acl_entry(file, j);
|
2002-04-14 12:43:47 +00:00
|
|
|
if (e == NULL)
|
|
|
|
continue;
|
|
|
|
if (e->method != SC_AC_CHV)
|
|
|
|
continue;
|
|
|
|
if (e->key_ref != i)
|
|
|
|
continue;
|
|
|
|
switch (tag[0]) {
|
|
|
|
case 0x01:
|
|
|
|
e->method = SC_AC_CHV;
|
|
|
|
break;
|
|
|
|
case 0x02:
|
|
|
|
e->method = SC_AC_AUT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
e->method = SC_AC_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_select_file(sc_card_t *card,
|
|
|
|
const sc_path_t *in_path,
|
|
|
|
sc_file_t **file)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
|
|
|
int r;
|
2002-03-28 14:13:36 +00:00
|
|
|
|
2002-02-26 11:23:25 +00:00
|
|
|
r = iso_ops->select_file(card, in_path, file);
|
|
|
|
if (r)
|
|
|
|
return r;
|
2015-10-14 20:16:44 +00:00
|
|
|
if (file != NULL && *file != NULL) {
|
2002-02-26 11:23:25 +00:00
|
|
|
parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
|
2002-04-14 12:43:47 +00:00
|
|
|
miocos_get_acl(card, *file);
|
|
|
|
}
|
|
|
|
|
2002-02-26 11:23:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_list_files(sc_card_t *card, u8 *buf, size_t buflen)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_apdu_t apdu;
|
2002-02-26 11:23:25 +00:00
|
|
|
int r;
|
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0);
|
|
|
|
apdu.resp = buf;
|
|
|
|
apdu.resplen = buflen;
|
|
|
|
apdu.le = buflen > 256 ? 256 : buflen;
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
|
2002-02-26 11:23:25 +00:00
|
|
|
if (apdu.resplen == 0)
|
|
|
|
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
return apdu.resplen;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_delete_file(sc_card_t *card, const sc_path_t *path)
|
2002-03-09 15:11:46 +00:00
|
|
|
{
|
|
|
|
int r;
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_apdu_t apdu;
|
2002-03-09 15:11:46 +00:00
|
|
|
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2002-03-09 15:11:46 +00:00
|
|
|
if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "File type has to be SC_PATH_TYPE_FILE_ID\n");
|
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2002-03-09 15:11:46 +00:00
|
|
|
}
|
|
|
|
r = sc_select_file(card, path, NULL);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to select file to be deleted");
|
2002-03-09 15:11:46 +00:00
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
|
2002-04-06 15:04:14 +00:00
|
|
|
apdu.cla = 0xA0;
|
|
|
|
|
2002-03-09 15:11:46 +00:00
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
|
2002-03-09 15:11:46 +00:00
|
|
|
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
}
|
|
|
|
|
2002-04-04 20:40:40 +00:00
|
|
|
static int miocos_create_ac(sc_card_t *card,
|
|
|
|
struct sc_cardctl_miocos_ac_info *ac)
|
|
|
|
{
|
2005-03-08 20:59:35 +00:00
|
|
|
sc_apdu_t apdu;
|
2002-04-04 20:40:40 +00:00
|
|
|
u8 sbuf[20];
|
|
|
|
int miocos_type, r;
|
|
|
|
size_t sendsize;
|
|
|
|
|
|
|
|
if (ac->max_tries > 15)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2002-04-04 20:40:40 +00:00
|
|
|
switch (ac->type) {
|
|
|
|
case SC_CARDCTL_MIOCOS_AC_PIN:
|
|
|
|
if (ac->max_unblock_tries > 15)
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
|
2002-04-04 20:40:40 +00:00
|
|
|
miocos_type = 0x01;
|
|
|
|
sbuf[0] = (ac->max_tries << 4) | ac->max_tries;
|
|
|
|
sbuf[1] = 0xFF; /* FIXME... */
|
|
|
|
memcpy(sbuf + 2, ac->key_value, 8);
|
|
|
|
sbuf[10] = (ac->max_unblock_tries << 4) | ac->max_unblock_tries;
|
|
|
|
sbuf[11] = 0xFF;
|
|
|
|
memcpy(sbuf + 12, ac->unblock_value, 8);
|
|
|
|
sendsize = 20;
|
|
|
|
break;
|
|
|
|
default:
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "AC type %d not supported\n", ac->type);
|
2002-04-04 20:40:40 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x1E, miocos_type,
|
|
|
|
ac->ref);
|
|
|
|
apdu.lc = sendsize;
|
|
|
|
apdu.datalen = sendsize;
|
|
|
|
apdu.data = sbuf;
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
|
2002-04-04 20:40:40 +00:00
|
|
|
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int miocos_card_ctl(sc_card_t *card, unsigned long cmd,
|
2002-04-04 20:40:40 +00:00
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case SC_CARDCTL_MIOCOS_CREATE_AC:
|
|
|
|
return miocos_create_ac(card, (struct sc_cardctl_miocos_ac_info *) arg);
|
|
|
|
}
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "card_ctl command 0x%X not supported\n", cmd);
|
2002-04-04 20:40:40 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-20 12:51:07 +00:00
|
|
|
static struct sc_card_driver * sc_get_driver(void)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
2003-02-20 12:51:07 +00:00
|
|
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
2002-02-26 11:23:25 +00:00
|
|
|
|
|
|
|
miocos_ops = *iso_drv->ops;
|
|
|
|
miocos_ops.match_card = miocos_match_card;
|
|
|
|
miocos_ops.init = miocos_init;
|
|
|
|
if (iso_ops == NULL)
|
|
|
|
iso_ops = iso_drv->ops;
|
|
|
|
miocos_ops.create_file = miocos_create_file;
|
|
|
|
miocos_ops.set_security_env = miocos_set_security_env;
|
|
|
|
miocos_ops.select_file = miocos_select_file;
|
|
|
|
miocos_ops.list_files = miocos_list_files;
|
2002-03-09 15:11:46 +00:00
|
|
|
miocos_ops.delete_file = miocos_delete_file;
|
2002-04-04 20:40:40 +00:00
|
|
|
miocos_ops.card_ctl = miocos_card_ctl;
|
2002-02-26 11:23:25 +00:00
|
|
|
|
|
|
|
return &miocos_drv;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 1
|
2003-02-20 12:51:07 +00:00
|
|
|
struct sc_card_driver * sc_get_miocos_driver(void)
|
2002-02-26 11:23:25 +00:00
|
|
|
{
|
|
|
|
return sc_get_driver();
|
|
|
|
}
|
|
|
|
#endif
|