2001-12-22 20:43:09 +00:00
|
|
|
|
/*
|
2002-02-26 11:27:49 +00:00
|
|
|
|
* card-setcos.c: Support for PKI cards by Setec
|
2001-12-22 20:43:09 +00:00
|
|
|
|
*
|
2002-04-05 14:46:44 +00:00
|
|
|
|
* Copyright (C) 2001, 2002 Juha Yrj<EFBFBD>l<EFBFBD> <juha.yrjola@iki.fi>
|
2005-02-09 11:37:25 +00:00
|
|
|
|
* Copyright (C) 2005 Antti Tapaninen <aet@cc.hut.fi>
|
2001-12-22 20:43:09 +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
|
|
|
|
|
*/
|
|
|
|
|
|
2002-04-05 10:44:51 +00:00
|
|
|
|
#include "internal.h"
|
2002-03-09 17:54:16 +00:00
|
|
|
|
#include <stdlib.h>
|
2002-03-08 05:59:57 +00:00
|
|
|
|
#include <string.h>
|
2001-12-22 20:43:09 +00:00
|
|
|
|
|
2005-02-06 19:40:40 +00:00
|
|
|
|
static struct sc_atr_table setcos_atrs[] = {
|
2005-02-09 11:37:25 +00:00
|
|
|
|
/* some Nokia branded SC */
|
2005-02-10 10:07:13 +00:00
|
|
|
|
{ "3B:1F:11:00:67:80:42:46:49:53:45:10:52:66:FF:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_GENERIC },
|
2005-02-06 19:40:40 +00:00
|
|
|
|
/* RSA SecurID 3100 */
|
2005-02-10 10:07:13 +00:00
|
|
|
|
{ "3B:9F:94:40:1E:00:67:16:43:46:49:53:45:10:52:66:FF:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_PKI },
|
2005-02-09 11:37:25 +00:00
|
|
|
|
|
|
|
|
|
/* FINEID 1016 (SetCOS 4.3.1B3/PKCS#15, VRK) */
|
2005-02-10 10:07:13 +00:00
|
|
|
|
{ "3b:9f:94:40:1e:00:67:00:43:46:49:53:45:10:52:66:ff:81:90:00", "ff:ff:ff:ff:ff:ff:ff:00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID },
|
2005-02-09 14:05:55 +00:00
|
|
|
|
/* FINEID 2032 (EIDApplet/7816-15, VRK test) */
|
2005-02-10 10:07:13 +00:00
|
|
|
|
{ "3b:6b:00:ff:80:62:00:a2:56:46:69:6e:45:49:44", "ff:ff:00:ff:ff:ff:00:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID },
|
2005-02-09 11:37:25 +00:00
|
|
|
|
/* FINEID 2132 (EIDApplet/7816-15, OPK/EMV test) */
|
2005-02-10 10:07:13 +00:00
|
|
|
|
{ "3b:64:00:ff:80:62:00:a2", "ff:ff:00:ff:ff:ff:00:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID },
|
2005-02-09 11:37:25 +00:00
|
|
|
|
/* FINEID 2064 (EIDApplet/7816-15, VRK) */
|
2005-02-10 10:07:13 +00:00
|
|
|
|
{ "3b:7b:00:00:00:80:62:00:51:56:46:69:6e:45:49:44", "ff:ff:00:ff:ff:ff:ff:f0:ff:ff:ff:ff:ff:ff:ff:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID },
|
2005-02-09 11:37:25 +00:00
|
|
|
|
/* FINEID 2164 (EIDApplet/7816-15, OPK/EMV) */
|
2005-02-10 10:07:13 +00:00
|
|
|
|
{ "3b:64:00:00:80:62:00:51", "ff:ff:ff:ff:ff:ff:f0:ff", NULL, SC_CARD_TYPE_SETCOS_FINEID },
|
2005-02-09 11:37:25 +00:00
|
|
|
|
/* FINEID 2264 (EIDApplet/7816-15, OPK/EMV/AVANT) */
|
2005-02-10 10:07:13 +00:00
|
|
|
|
{ "3b:6e:00:00:00:62:00:00:57:41:56:41:4e:54:10:81:90:00", NULL, NULL, SC_CARD_TYPE_SETCOS_FINEID },
|
2002-03-08 05:59:57 +00:00
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
static struct sc_card_operations setcos_ops;
|
2003-02-20 12:51:07 +00:00
|
|
|
|
static struct sc_card_driver setcos_drv = {
|
2005-02-09 14:47:46 +00:00
|
|
|
|
"Setec cards",
|
2002-02-26 11:27:49 +00:00
|
|
|
|
"setcos",
|
|
|
|
|
&setcos_ops
|
2001-12-22 20:43:09 +00:00
|
|
|
|
};
|
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
static int setcos_finish(struct sc_card *card)
|
2001-12-22 20:43:09 +00:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-09 11:37:25 +00:00
|
|
|
|
static int match_hist_bytes(struct sc_card *card, const char *str, size_t len)
|
|
|
|
|
{
|
|
|
|
|
const char *src = (const char *) card->slot->atr_info.hist_bytes;
|
|
|
|
|
size_t srclen = card->slot->atr_info.hist_bytes_len;
|
|
|
|
|
size_t offset = 0;
|
|
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
len = strlen(str);
|
|
|
|
|
if (srclen < len)
|
|
|
|
|
return 0;
|
|
|
|
|
while (srclen - offset > len) {
|
|
|
|
|
if (memcmp(src + offset, str, len) == 0) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
offset++;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
static int setcos_match_card(struct sc_card *card)
|
2001-12-22 20:43:09 +00:00
|
|
|
|
{
|
2002-03-08 05:59:57 +00:00
|
|
|
|
int i;
|
2001-12-22 20:43:09 +00:00
|
|
|
|
|
2005-02-06 19:40:40 +00:00
|
|
|
|
i = _sc_match_atr(card, setcos_atrs, &card->type);
|
|
|
|
|
if (i < 0) {
|
2005-02-09 11:37:25 +00:00
|
|
|
|
/* Unknown card, but has the FinEID application for sure */
|
|
|
|
|
if (match_hist_bytes(card, "FinEID", 0)) {
|
2005-02-10 10:07:13 +00:00
|
|
|
|
card->type = SC_CARD_TYPE_SETCOS_FINEID;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
return 1;
|
2005-02-09 11:37:25 +00:00
|
|
|
|
}
|
|
|
|
|
if (match_hist_bytes(card, "FISE", 0)) {
|
2005-02-10 10:07:13 +00:00
|
|
|
|
card->type = SC_CARD_TYPE_SETCOS_GENERIC;
|
2005-02-09 11:37:25 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2002-03-08 05:59:57 +00:00
|
|
|
|
return 0;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
}
|
2001-12-22 20:43:09 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-09 11:37:25 +00:00
|
|
|
|
static int select_fineid_app(sc_card_t * card)
|
|
|
|
|
{
|
|
|
|
|
sc_path_t app;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
/* Regular PKCS#15 AID */
|
|
|
|
|
sc_format_path ("A000000063504B43532D3135", &app);
|
|
|
|
|
app.type = SC_PATH_TYPE_DF_NAME;
|
|
|
|
|
card->ctx->suppress_errors++;
|
|
|
|
|
r = sc_select_file (card, &app, NULL);
|
|
|
|
|
card->ctx->suppress_errors--;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
static int setcos_init(struct sc_card *card)
|
2001-12-22 20:43:09 +00:00
|
|
|
|
{
|
2003-05-28 20:52:33 +00:00
|
|
|
|
card->name = "SetCOS";
|
2002-06-03 15:05:58 +00:00
|
|
|
|
card->cla = 0x80;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
|
2005-02-09 11:37:25 +00:00
|
|
|
|
/* Handle unknown or forced cards */
|
|
|
|
|
if (card->type < 0) {
|
2005-02-11 20:09:34 +00:00
|
|
|
|
card->type = SC_CARD_TYPE_SETCOS_GENERIC;
|
2005-02-10 10:07:13 +00:00
|
|
|
|
#if 0
|
2005-02-09 11:37:25 +00:00
|
|
|
|
/* Hmm. For now, assume it's a bank card with FinEID application */
|
2005-02-14 09:13:05 +00:00
|
|
|
|
if (match_hist_bytes(card, "AVANT", 0))
|
2005-02-10 10:07:13 +00:00
|
|
|
|
card->type = SC_CARD_TYPE_SETCOS_FINEID;
|
2005-02-09 11:37:25 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
2005-02-10 10:07:13 +00:00
|
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_FINEID) {
|
2005-02-09 11:37:25 +00:00
|
|
|
|
card->cla = 0x00;
|
|
|
|
|
select_fineid_app(card);
|
|
|
|
|
}
|
2005-02-10 10:07:13 +00:00
|
|
|
|
if (card->type == SC_CARD_TYPE_SETCOS_PKI || card->type == SC_CARD_TYPE_SETCOS_FINEID) {
|
2002-03-08 05:59:57 +00:00
|
|
|
|
unsigned long flags;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
|
2002-03-08 05:59:57 +00:00
|
|
|
|
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-08 05:59:57 +00:00
|
|
|
|
}
|
2001-12-22 20:43:09 +00:00
|
|
|
|
|
2003-01-15 13:20:02 +00:00
|
|
|
|
/* State that we have an RNG */
|
|
|
|
|
card->caps |= SC_CARD_CAP_RNG;
|
|
|
|
|
|
2001-12-22 20:43:09 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-20 21:20:09 +00:00
|
|
|
|
static const struct sc_card_operations *iso_ops = NULL;
|
2002-01-10 23:02:48 +00:00
|
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
|
static u8 acl_to_byte(const struct sc_acl_entry *e)
|
|
|
|
|
{
|
|
|
|
|
switch (e->method) {
|
|
|
|
|
case SC_AC_NONE:
|
|
|
|
|
return 0x00;
|
|
|
|
|
case SC_AC_CHV:
|
|
|
|
|
switch (e->key_ref) {
|
|
|
|
|
case 1:
|
|
|
|
|
return 0x01;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
return 0x02;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return 0x00;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SC_AC_TERM:
|
|
|
|
|
return 0x04;
|
|
|
|
|
case SC_AC_NEVER:
|
|
|
|
|
return 0x0F;
|
|
|
|
|
}
|
|
|
|
|
return 0x00;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
static int setcos_create_file(struct sc_card *card, struct sc_file *file)
|
2002-01-10 23:02:48 +00:00
|
|
|
|
{
|
2002-04-02 21:26:42 +00:00
|
|
|
|
if (file->prop_attr_len == 0)
|
2002-04-03 12:59:53 +00:00
|
|
|
|
sc_file_set_prop_attr(file, (const u8 *) "\x03\x00\x00", 3);
|
2002-02-20 09:56:47 +00:00
|
|
|
|
if (file->sec_attr_len == 0) {
|
|
|
|
|
int idx[6], i;
|
|
|
|
|
u8 buf[6];
|
|
|
|
|
|
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
|
const int df_idx[6] = {
|
|
|
|
|
SC_AC_OP_SELECT, SC_AC_OP_LOCK, SC_AC_OP_DELETE,
|
|
|
|
|
SC_AC_OP_CREATE, SC_AC_OP_REHABILITATE,
|
|
|
|
|
SC_AC_OP_INVALIDATE
|
|
|
|
|
};
|
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
|
idx[i] = df_idx[i];
|
|
|
|
|
} else {
|
|
|
|
|
const int ef_idx[6] = {
|
|
|
|
|
SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
|
|
|
|
|
SC_AC_OP_ERASE, SC_AC_OP_REHABILITATE,
|
|
|
|
|
SC_AC_OP_INVALIDATE
|
|
|
|
|
};
|
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
|
idx[i] = ef_idx[i];
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
|
buf[i] = acl_to_byte(file->acl[idx[i]]);
|
|
|
|
|
|
2002-03-28 14:13:36 +00:00
|
|
|
|
sc_file_set_sec_attr(file, buf, 6);
|
2002-02-20 09:56:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return iso_ops->create_file(card, file);
|
2002-01-20 21:20:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-06-03 15:05:58 +00:00
|
|
|
|
static int setcos_set_security_env2(struct sc_card *card,
|
|
|
|
|
const struct sc_security_env *env,
|
|
|
|
|
int se_num)
|
|
|
|
|
{
|
|
|
|
|
struct sc_apdu apdu;
|
|
|
|
|
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
|
|
|
|
u8 *p;
|
|
|
|
|
int r, locked = 0;
|
|
|
|
|
|
|
|
|
|
assert(card != NULL && env != NULL);
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
|
|
|
|
|
switch (env->operation) {
|
|
|
|
|
case SC_SEC_OPERATION_DECIPHER:
|
|
|
|
|
apdu.p1 = 0x41; /* Should be 0x81 */
|
|
|
|
|
apdu.p2 = 0xB8;
|
|
|
|
|
break;
|
|
|
|
|
case SC_SEC_OPERATION_SIGN:
|
|
|
|
|
apdu.p1 = 0x81; /* Should be 0x41 */
|
|
|
|
|
apdu.p2 = 0xB6;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
}
|
|
|
|
|
apdu.le = 0;
|
|
|
|
|
p = sbuf;
|
|
|
|
|
if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
|
|
|
|
|
*p++ = 0x80; /* algorithm reference */
|
|
|
|
|
*p++ = 0x01;
|
|
|
|
|
*p++ = env->algorithm_ref & 0xFF;
|
|
|
|
|
}
|
|
|
|
|
if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) {
|
|
|
|
|
*p++ = 0x81;
|
|
|
|
|
*p++ = env->file_ref.len;
|
|
|
|
|
memcpy(p, env->file_ref.value, env->file_ref.len);
|
|
|
|
|
p += env->file_ref.len;
|
|
|
|
|
}
|
|
|
|
|
if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
|
|
|
|
|
if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC)
|
|
|
|
|
*p++ = 0x83;
|
|
|
|
|
else
|
|
|
|
|
*p++ = 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;
|
|
|
|
|
if (se_num > 0) {
|
|
|
|
|
r = sc_lock(card);
|
|
|
|
|
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
|
|
|
|
|
locked = 1;
|
|
|
|
|
}
|
|
|
|
|
if (apdu.datalen != 0) {
|
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
|
|
|
|
if (r) {
|
|
|
|
|
sc_perror(card->ctx, r, "APDU transmit failed");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
|
if (r) {
|
|
|
|
|
sc_perror(card->ctx, r, "Card returned error");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (se_num <= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num);
|
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
|
|
|
|
sc_unlock(card);
|
|
|
|
|
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
|
|
|
|
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
|
err:
|
|
|
|
|
if (locked)
|
|
|
|
|
sc_unlock(card);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
static int setcos_set_security_env(struct sc_card *card,
|
2002-01-20 21:20:09 +00:00
|
|
|
|
const struct sc_security_env *env,
|
|
|
|
|
int se_num)
|
|
|
|
|
{
|
|
|
|
|
if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
|
|
|
|
|
struct sc_security_env tmp;
|
|
|
|
|
|
|
|
|
|
tmp = *env;
|
2002-03-08 05:59:57 +00:00
|
|
|
|
tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
|
|
|
|
|
if (tmp.algorithm != SC_ALGORITHM_RSA) {
|
2003-08-25 14:21:18 +00:00
|
|
|
|
sc_error(card->ctx, "Only RSA algorithm supported.\n");
|
2002-01-20 21:20:09 +00:00
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
|
}
|
2005-02-10 10:07:13 +00:00
|
|
|
|
if (!(card->type == SC_CARD_TYPE_SETCOS_PKI ||
|
|
|
|
|
card->type == SC_CARD_TYPE_SETCOS_FINEID)) {
|
2003-08-25 14:21:18 +00:00
|
|
|
|
sc_error(card->ctx, "Card does not support RSA.\n");
|
2002-03-08 05:59:57 +00:00
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
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-01-20 21:20:09 +00:00
|
|
|
|
tmp.algorithm_ref = 0x02;
|
|
|
|
|
if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
|
2002-03-08 05:59:57 +00:00
|
|
|
|
tmp.algorithm_ref |= 0x10;
|
2002-06-03 15:05:58 +00:00
|
|
|
|
return setcos_set_security_env2(card, &tmp, se_num);
|
2002-01-20 21:20:09 +00:00
|
|
|
|
}
|
2005-02-11 20:09:34 +00:00
|
|
|
|
return setcos_set_security_env2(card, env, se_num);
|
2002-01-10 23:02:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-02-20 09:56:47 +00:00
|
|
|
|
static void add_acl_entry(struct sc_file *file, int op, u8 byte)
|
2002-02-11 15:55:34 +00:00
|
|
|
|
{
|
2002-02-20 09:56:47 +00:00
|
|
|
|
unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
|
|
|
|
|
|
2002-02-11 15:55:34 +00:00
|
|
|
|
switch (byte >> 4) {
|
|
|
|
|
case 0:
|
2002-02-20 09:56:47 +00:00
|
|
|
|
method = SC_AC_NONE;
|
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
|
case 1:
|
2002-02-20 09:56:47 +00:00
|
|
|
|
method = SC_AC_CHV;
|
|
|
|
|
key_ref = 1;
|
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
|
case 2:
|
2002-02-20 09:56:47 +00:00
|
|
|
|
method = SC_AC_CHV;
|
|
|
|
|
key_ref = 2;
|
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
|
case 4:
|
2002-02-20 09:56:47 +00:00
|
|
|
|
method = SC_AC_TERM;
|
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
|
case 15:
|
2002-02-20 09:56:47 +00:00
|
|
|
|
method = SC_AC_NEVER;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
method = SC_AC_UNKNOWN;
|
|
|
|
|
break;
|
2002-02-11 15:55:34 +00:00
|
|
|
|
}
|
2002-02-20 09:56:47 +00:00
|
|
|
|
sc_file_add_acl_entry(file, op, method, key_ref);
|
2002-02-11 15:55:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2002-02-20 09:56:47 +00:00
|
|
|
|
int idx[6];
|
|
|
|
|
|
2002-02-11 15:55:34 +00:00
|
|
|
|
if (len < 6)
|
|
|
|
|
return;
|
2002-02-20 09:56:47 +00:00
|
|
|
|
if (file->type == SC_FILE_TYPE_DF) {
|
|
|
|
|
const int df_idx[6] = {
|
|
|
|
|
SC_AC_OP_SELECT, SC_AC_OP_LOCK, SC_AC_OP_DELETE,
|
|
|
|
|
SC_AC_OP_CREATE, SC_AC_OP_REHABILITATE,
|
|
|
|
|
SC_AC_OP_INVALIDATE
|
|
|
|
|
};
|
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
|
idx[i] = df_idx[i];
|
|
|
|
|
} else {
|
|
|
|
|
const int ef_idx[6] = {
|
|
|
|
|
SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_WRITE,
|
|
|
|
|
SC_AC_OP_ERASE, SC_AC_OP_REHABILITATE,
|
|
|
|
|
SC_AC_OP_INVALIDATE
|
|
|
|
|
};
|
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
|
idx[i] = ef_idx[i];
|
|
|
|
|
}
|
2002-02-11 15:55:34 +00:00
|
|
|
|
for (i = 0; i < 6; i++)
|
2002-02-20 09:56:47 +00:00
|
|
|
|
add_acl_entry(file, idx[i], buf[i]);
|
2002-02-11 15:55:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
static int setcos_select_file(struct sc_card *card,
|
2002-02-11 15:55:34 +00:00
|
|
|
|
const struct sc_path *in_path,
|
2002-02-20 09:56:47 +00:00
|
|
|
|
struct sc_file **file)
|
2002-02-11 15:55:34 +00:00
|
|
|
|
{
|
|
|
|
|
int r;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
|
2002-02-11 15:55:34 +00:00
|
|
|
|
r = iso_ops->select_file(card, in_path, file);
|
|
|
|
|
if (r)
|
|
|
|
|
return r;
|
|
|
|
|
if (file != NULL)
|
2002-02-20 09:56:47 +00:00
|
|
|
|
parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
|
2002-02-11 15:55:34 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
static int setcos_list_files(struct sc_card *card, u8 *buf, size_t buflen)
|
2002-02-26 11:23:25 +00:00
|
|
|
|
{
|
|
|
|
|
struct sc_apdu apdu;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xAA, 0, 0);
|
|
|
|
|
apdu.resp = buf;
|
|
|
|
|
apdu.resplen = buflen;
|
|
|
|
|
apdu.le = buflen > 256 ? 256 : buflen;
|
|
|
|
|
r = sc_transmit_apdu(card, &apdu);
|
|
|
|
|
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
|
|
|
|
if (apdu.resplen == 0)
|
|
|
|
|
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
|
|
|
|
return apdu.resplen;
|
|
|
|
|
}
|
|
|
|
|
|
2003-02-20 12:51:07 +00:00
|
|
|
|
static struct sc_card_driver * sc_get_driver(void)
|
2001-12-22 20:43:09 +00:00
|
|
|
|
{
|
2003-02-20 12:51:07 +00:00
|
|
|
|
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
2001-12-22 20:43:09 +00:00
|
|
|
|
|
2002-02-26 11:27:49 +00:00
|
|
|
|
setcos_ops = *iso_drv->ops;
|
|
|
|
|
setcos_ops.match_card = setcos_match_card;
|
|
|
|
|
setcos_ops.init = setcos_init;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
setcos_ops.finish = setcos_finish;
|
2002-01-20 21:20:09 +00:00
|
|
|
|
if (iso_ops == NULL)
|
2005-02-11 20:09:34 +00:00
|
|
|
|
iso_ops = iso_drv->ops;
|
2002-02-26 11:27:49 +00:00
|
|
|
|
setcos_ops.create_file = setcos_create_file;
|
|
|
|
|
setcos_ops.set_security_env = setcos_set_security_env;
|
|
|
|
|
setcos_ops.select_file = setcos_select_file;
|
|
|
|
|
setcos_ops.list_files = setcos_list_files;
|
2005-02-11 20:09:34 +00:00
|
|
|
|
|
|
|
|
|
return &setcos_drv;
|
2001-12-22 20:43:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 1
|
2003-02-20 12:51:07 +00:00
|
|
|
|
struct sc_card_driver * sc_get_setcos_driver(void)
|
2001-12-22 20:43:09 +00:00
|
|
|
|
{
|
|
|
|
|
return sc_get_driver();
|
|
|
|
|
}
|
|
|
|
|
#endif
|