- all instances struct sc_file should now be
dynamically allocated with sc_file_new() and released with sc_file_free() - improved ACL's - moved struct sc_card_error to opensc.h - moved EF(DIR) parsing and encoding to dir.c (encoding is not working yet) - removed hst-test.c and filetest.c git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@213 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
092e87969d
commit
61fc1f9327
|
@ -8,7 +8,7 @@ bin_SCRIPTS = opensc-config
|
|||
|
||||
lib_LTLIBRARIES = libopensc.la
|
||||
libopensc_la_SOURCES = asn1.c base64.c sec.c log.c sc.c card.c iso7816.c \
|
||||
pkcs15.c pkcs15-cert.c pkcs15-pin.c \
|
||||
dir.c pkcs15.c pkcs15-cert.c pkcs15-pin.c \
|
||||
pkcs15-prkey.c pkcs15-sec.c pkcs15-cache.c \
|
||||
card-setec.c card-flex.c card-gpk.c \
|
||||
card-tcos.c card-emv.c card-default.c
|
||||
|
|
|
@ -124,18 +124,20 @@ static int emv_init(struct sc_card *card)
|
|||
}
|
||||
|
||||
static int emv_select_file(struct sc_card *card, const struct sc_path *path,
|
||||
struct sc_file *file)
|
||||
struct sc_file **file)
|
||||
{
|
||||
int r;
|
||||
const struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
|
||||
const struct sc_card_operations *ops = iso_drv->ops;
|
||||
|
||||
r = ops->select_file(card, path, file);
|
||||
if (r)
|
||||
return r;
|
||||
if (file != NULL && path->len == 2 && memcmp(path->value, "\x3F\x00", 2) == 0)
|
||||
file->type = SC_FILE_TYPE_DF;
|
||||
if (file != NULL && file->namelen)
|
||||
file->type = SC_FILE_TYPE_DF;
|
||||
return r;
|
||||
(*file)->type = SC_FILE_TYPE_DF;
|
||||
if (file != NULL && (*file)->namelen)
|
||||
(*file)->type = SC_FILE_TYPE_DF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sc_card_driver * sc_get_driver(void)
|
||||
|
|
|
@ -81,16 +81,48 @@ static int flex_init(struct sc_card *card)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int ac_to_acl(u8 nibble)
|
||||
static void add_acl_entry(struct sc_file *file, unsigned int op,
|
||||
u8 nibble)
|
||||
{
|
||||
unsigned int acl_table[16] = {
|
||||
/* 0 */ SC_AC_NONE, SC_AC_CHV1, SC_AC_CHV2, SC_AC_PRO,
|
||||
/* 4 */ SC_AC_AUT, SC_AC_UNKNOWN, SC_AC_CHV1 | SC_AC_PRO,
|
||||
/* 7 */ SC_AC_CHV2 | SC_AC_PRO, SC_AC_CHV1 | SC_AC_AUT,
|
||||
/* 9 */ SC_AC_CHV2 | SC_AC_AUT, SC_AC_UNKNOWN, SC_AC_UNKNOWN,
|
||||
/* c */ SC_AC_UNKNOWN, SC_AC_UNKNOWN, SC_AC_UNKNOWN,
|
||||
/* f */ SC_AC_NEVER };
|
||||
return acl_table[nibble & 0x0F];
|
||||
switch (nibble) {
|
||||
case 0:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_NONE, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
case 1:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
|
||||
break;
|
||||
case 2:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
|
||||
break;
|
||||
case 3:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
case 4:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_AUT, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
case 6:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
|
||||
sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
case 7:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
|
||||
sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
case 8:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
|
||||
sc_file_add_acl_entry(file, op, SC_AC_AUT, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
case 9:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
|
||||
sc_file_add_acl_entry(file, op, SC_AC_AUT, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
case 15:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
default:
|
||||
sc_file_add_acl_entry(file, op, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen,
|
||||
|
@ -134,18 +166,18 @@ static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen
|
|||
}
|
||||
p += 2;
|
||||
if (file->type == SC_FILE_TYPE_DF) {
|
||||
file->acl[SC_AC_OP_LIST_FILES] = ac_to_acl(p[0] >> 4);
|
||||
file->acl[SC_AC_OP_DELETE] = ac_to_acl(p[1] >> 4);
|
||||
file->acl[SC_AC_OP_CREATE] = ac_to_acl(p[1] & 0x0F);
|
||||
add_acl_entry(file, SC_AC_OP_LIST_FILES, p[0] >> 4);
|
||||
add_acl_entry(file, SC_AC_OP_DELETE, p[1] >> 4);
|
||||
add_acl_entry(file, SC_AC_OP_CREATE, p[1] & 0x0F);
|
||||
} else { /* EF */
|
||||
file->acl[SC_AC_OP_READ] = ac_to_acl(p[0] >> 4);
|
||||
add_acl_entry(file, SC_AC_OP_READ, p[0] >> 4);
|
||||
switch (file->ef_structure) {
|
||||
case SC_FILE_EF_TRANSPARENT:
|
||||
file->acl[SC_AC_OP_UPDATE] = ac_to_acl(p[0] & 0x0F);
|
||||
add_acl_entry(file, SC_AC_OP_UPDATE, p[0] & 0x0F);
|
||||
break;
|
||||
case SC_FILE_EF_LINEAR_FIXED:
|
||||
case SC_FILE_EF_LINEAR_VARIABLE:
|
||||
file->acl[SC_AC_OP_UPDATE] = ac_to_acl(p[0] & 0x0F);
|
||||
add_acl_entry(file, SC_AC_OP_UPDATE, p[0] & 0x0F);
|
||||
break;
|
||||
case SC_FILE_EF_CYCLIC:
|
||||
#if 0
|
||||
|
@ -155,9 +187,9 @@ static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen
|
|||
break;
|
||||
}
|
||||
}
|
||||
file->acl[SC_AC_OP_REHABILITATE] = ac_to_acl(p[2] >> 4);
|
||||
file->acl[SC_AC_OP_INVALIDATE] = ac_to_acl(p[2] & 0x0F);
|
||||
p += 3; /* skip ACs */
|
||||
add_acl_entry(file, SC_AC_OP_REHABILITATE, p[2] >> 4);
|
||||
add_acl_entry(file, SC_AC_OP_INVALIDATE, p[2] & 0x0F);
|
||||
p += 3;
|
||||
if (*p++)
|
||||
file->status = SC_FILE_STATUS_ACTIVATED;
|
||||
else
|
||||
|
@ -238,11 +270,12 @@ void cache_path(struct sc_card *card, const struct sc_path *path)
|
|||
}
|
||||
|
||||
static int select_file_id(struct sc_card *card, const u8 *buf, size_t buflen,
|
||||
u8 p1, struct sc_file *file)
|
||||
u8 p1, struct sc_file **file_out)
|
||||
{
|
||||
int r, i;
|
||||
int r;
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
struct sc_file *file;
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, p1, 0);
|
||||
apdu.resp = rbuf;
|
||||
|
@ -252,14 +285,14 @@ static int select_file_id(struct sc_card *card, const u8 *buf, size_t buflen,
|
|||
apdu.lc = buflen;
|
||||
|
||||
/* No need to get file information, if file is NULL. */
|
||||
if (file == NULL)
|
||||
if (file_out == NULL)
|
||||
apdu.resplen = 0;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
SC_TEST_RET(card->ctx, r, "Card returned error");
|
||||
|
||||
if (file == NULL)
|
||||
if (file_out == NULL)
|
||||
return 0;
|
||||
|
||||
if (apdu.resplen < 14)
|
||||
|
@ -268,17 +301,20 @@ static int select_file_id(struct sc_card *card, const u8 *buf, size_t buflen,
|
|||
error(card->ctx, "unsupported: card returned FCI\n");
|
||||
return SC_ERROR_UNKNOWN_REPLY; /* FIXME */
|
||||
}
|
||||
|
||||
memset(file, 0, sizeof(struct sc_file));
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
file->acl[i] = SC_AC_UNKNOWN;
|
||||
|
||||
return parse_flex_sf_reply(card->ctx, apdu.resp, apdu.resplen, file);
|
||||
|
||||
file = sc_file_new();
|
||||
if (file == NULL)
|
||||
SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY);
|
||||
r = parse_flex_sf_reply(card->ctx, apdu.resp, apdu.resplen, file);
|
||||
if (r) {
|
||||
sc_file_free(file);
|
||||
return r;
|
||||
}
|
||||
*file_out = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flex_select_file(struct sc_card *card, const struct sc_path *path,
|
||||
struct sc_file *file)
|
||||
struct sc_file **file_out)
|
||||
{
|
||||
int r;
|
||||
const u8 *pathptr = path->value;
|
||||
|
@ -291,7 +327,7 @@ static int flex_select_file(struct sc_card *card, const struct sc_path *path,
|
|||
case SC_PATH_TYPE_PATH:
|
||||
if ((pathlen & 1) != 0) /* not divisible by 2 */
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
magic_done = check_path(card, &pathptr, &pathlen, file != NULL);
|
||||
magic_done = check_path(card, &pathptr, &pathlen, file_out != NULL);
|
||||
if (pathlen == 0)
|
||||
return 0;
|
||||
if (pathlen != 2 || memcmp(pathptr, "\x3F\x00", 2) != 0) {
|
||||
|
@ -322,7 +358,7 @@ static int flex_select_file(struct sc_card *card, const struct sc_path *path,
|
|||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
break;
|
||||
}
|
||||
r = select_file_id(card, pathptr, pathlen, p1, file);
|
||||
r = select_file_id(card, pathptr, pathlen, p1, file_out);
|
||||
if (locked)
|
||||
sc_unlock(card);
|
||||
if (r)
|
||||
|
@ -388,40 +424,43 @@ static int flex_delete_file(struct sc_card *card, const struct sc_path *path)
|
|||
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
}
|
||||
|
||||
static int acl_to_ac(unsigned int acl)
|
||||
static int acl_to_ac_nibble(const struct sc_acl_entry *e)
|
||||
{
|
||||
int i;
|
||||
unsigned int acl_table[16] = {
|
||||
/* 0 */ SC_AC_NONE, SC_AC_CHV1, SC_AC_CHV2, SC_AC_PRO,
|
||||
/* 4 */ SC_AC_AUT, SC_AC_UNKNOWN, SC_AC_CHV1 | SC_AC_PRO,
|
||||
/* 7 */ SC_AC_CHV2 | SC_AC_PRO, SC_AC_CHV1 | SC_AC_AUT,
|
||||
/* 9 */ SC_AC_CHV2 | SC_AC_AUT, SC_AC_UNKNOWN, SC_AC_UNKNOWN,
|
||||
/* c */ SC_AC_UNKNOWN, SC_AC_UNKNOWN, SC_AC_UNKNOWN,
|
||||
/* f */ SC_AC_NEVER };
|
||||
if (acl == SC_AC_NEVER)
|
||||
return 0x0f;
|
||||
else if (acl == SC_AC_UNKNOWN)
|
||||
if (e == NULL)
|
||||
return -1;
|
||||
acl &= ~SC_AC_KEY_NUM_MASK;
|
||||
for (i = 0; i < sizeof(acl_table)/sizeof(acl_table[0]); i++)
|
||||
if (acl == acl_table[i])
|
||||
return i;
|
||||
if (e->next != NULL) /* FIXME */
|
||||
return -1;
|
||||
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;
|
||||
}
|
||||
return -1;
|
||||
case SC_AC_PRO:
|
||||
return 0x03;
|
||||
case SC_AC_AUT:
|
||||
return 0x04;
|
||||
case SC_AC_NEVER:
|
||||
return 0x0f;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int acl_to_keynum(unsigned int acl)
|
||||
static int acl_to_keynum_nibble(const struct sc_acl_entry *e)
|
||||
{
|
||||
if (!(acl & SC_AC_AUT))
|
||||
while (e != NULL && e->method != SC_AC_AUT)
|
||||
e = e->next;
|
||||
if (e == NULL || e->key_ref == SC_AC_KEY_REF_NONE)
|
||||
return 0;
|
||||
switch (acl & SC_AC_KEY_NUM_MASK) {
|
||||
case SC_AC_KEY_NUM_0:
|
||||
return 0x00;
|
||||
case SC_AC_KEY_NUM_1:
|
||||
return 0x01;
|
||||
case SC_AC_KEY_NUM_2:
|
||||
return 0x02;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return e->key_ref & 0x0F;
|
||||
}
|
||||
|
||||
static int encode_file_structure(struct sc_card *card, const struct sc_file *file,
|
||||
|
@ -477,11 +516,11 @@ static int encode_file_structure(struct sc_card *card, const struct sc_file *fil
|
|||
for (i = 0; i < 6; i++) {
|
||||
if (ops[i] == -1)
|
||||
continue;
|
||||
r = acl_to_ac(file->acl[ops[i]]);
|
||||
r = acl_to_ac_nibble(file->acl[ops[i]]);
|
||||
SC_TEST_RET(card->ctx, r, "Invalid ACL value");
|
||||
/* Do some magic to get the nibbles right */
|
||||
p[8 + i/2] |= (r & 0x0F) << (((i+1) % 2) * 4);
|
||||
r = acl_to_keynum(file->acl[ops[i]]);
|
||||
r = acl_to_keynum_nibble(file->acl[ops[i]]);
|
||||
p[13 + i/2] |= (r & 0x0F) << (((i+1) % 2) * 4);
|
||||
}
|
||||
p[11] = (file->status & SC_FILE_STATUS_INVALIDATED) ? 0x00 : 0x01;
|
||||
|
@ -616,8 +655,7 @@ static int flex_verify(struct sc_card *card, unsigned int type, int ref,
|
|||
if (buflen >= SC_MAX_APDU_BUFFER_SIZE)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
switch (type) {
|
||||
case SC_AC_CHV1:
|
||||
case SC_AC_CHV2:
|
||||
case SC_AC_CHV:
|
||||
cla = 0xC0;
|
||||
ins = 0x20;
|
||||
break;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "sc-internal.h"
|
||||
#include "sc-log.h"
|
||||
#ifdef HAVE_OPENSSL
|
||||
#if defined(HAVE_OPENSSL) && 0
|
||||
#include <stdlib.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/rand.h>
|
||||
|
|
|
@ -76,14 +76,66 @@ static int setec_init(struct sc_card *card)
|
|||
|
||||
static const struct sc_card_operations *iso_ops = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int setec_create_file(struct sc_card *card, struct sc_file *file)
|
||||
{
|
||||
struct sc_file tmp;
|
||||
|
||||
tmp = *file;
|
||||
memcpy(tmp.prop_attr, "\x03\x00\x00", 3);
|
||||
tmp.prop_attr_len = 3;
|
||||
return iso_ops->create_file(card, &tmp);
|
||||
if (file->prop_attr_len == 0) {
|
||||
memcpy(file->prop_attr, "\x03\x00\x00", 3);
|
||||
file->prop_attr_len = 3;
|
||||
}
|
||||
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]]);
|
||||
|
||||
memcpy(file->sec_attr, buf, 6);
|
||||
file->sec_attr_len = 6;
|
||||
}
|
||||
|
||||
return iso_ops->create_file(card, file);
|
||||
}
|
||||
|
||||
static int setec_set_security_env(struct sc_card *card,
|
||||
|
@ -111,36 +163,66 @@ static int setec_set_security_env(struct sc_card *card,
|
|||
return iso_ops->set_security_env(card, env, se_num);
|
||||
}
|
||||
|
||||
static unsigned int byte_to_acl(u8 byte)
|
||||
static void add_acl_entry(struct sc_file *file, int op, u8 byte)
|
||||
{
|
||||
unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
|
||||
|
||||
switch (byte >> 4) {
|
||||
case 0:
|
||||
return SC_AC_NONE;
|
||||
method = SC_AC_NONE;
|
||||
break;
|
||||
case 1:
|
||||
return SC_AC_CHV1;
|
||||
method = SC_AC_CHV;
|
||||
key_ref = 1;
|
||||
break;
|
||||
case 2:
|
||||
return SC_AC_CHV2;
|
||||
method = SC_AC_CHV;
|
||||
key_ref = 2;
|
||||
break;
|
||||
case 4:
|
||||
return SC_AC_TERM;
|
||||
method = SC_AC_TERM;
|
||||
break;
|
||||
case 15:
|
||||
return SC_AC_NEVER;
|
||||
method = SC_AC_NEVER;
|
||||
break;
|
||||
default:
|
||||
method = SC_AC_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
return SC_AC_UNKNOWN;
|
||||
sc_file_add_acl_entry(file, op, method, key_ref);
|
||||
}
|
||||
|
||||
static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
int idx[6];
|
||||
|
||||
if (len < 6)
|
||||
return;
|
||||
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++)
|
||||
file->acl[i] = byte_to_acl(buf[i]);
|
||||
add_acl_entry(file, idx[i], buf[i]);
|
||||
}
|
||||
|
||||
static int setec_select_file(struct sc_card *card,
|
||||
const struct sc_path *in_path,
|
||||
struct sc_file *file)
|
||||
struct sc_file **file)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
@ -148,7 +230,7 @@ static int setec_select_file(struct sc_card *card,
|
|||
if (r)
|
||||
return r;
|
||||
if (file != NULL)
|
||||
parse_sec_attr(file, file->sec_attr, file->sec_attr_len);
|
||||
parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
|
|||
|
||||
static int tcos_select_file(struct sc_card *card,
|
||||
const struct sc_path *in_path,
|
||||
struct sc_file *file)
|
||||
struct sc_file **file)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
@ -123,7 +123,7 @@ static int tcos_select_file(struct sc_card *card,
|
|||
if (r)
|
||||
return r;
|
||||
if (file != NULL)
|
||||
parse_sec_attr(file, file->sec_attr, file->sec_attr_len);
|
||||
parse_sec_attr((*file), (*file)->sec_attr, (*file)->sec_attr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ static int _sc_pcscret_to_error(long rv)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static int sc_check_apdu(struct sc_context *ctx, const struct sc_apdu *apdu)
|
||||
{
|
||||
if (apdu->le > 256) {
|
||||
|
@ -326,6 +325,42 @@ void sc_format_apdu(struct sc_card *card, struct sc_apdu *apdu,
|
|||
return;
|
||||
}
|
||||
|
||||
static struct sc_card * sc_card_new()
|
||||
{
|
||||
struct sc_card *card;
|
||||
|
||||
card = malloc(sizeof(struct sc_card));
|
||||
if (card == NULL)
|
||||
return NULL;
|
||||
memset(card, 0, sizeof(struct sc_card));
|
||||
card->ops = malloc(sizeof(struct sc_card_operations));
|
||||
if (card->ops == NULL) {
|
||||
free(card);
|
||||
return NULL;
|
||||
}
|
||||
card->app_count = -1;
|
||||
pthread_mutex_init(&card->mutex, NULL);
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
static void sc_card_free(struct sc_card *card)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(sc_card_valid(card));
|
||||
for (i = 0; i < card->app_count; i++) {
|
||||
if (card->app[i]->label)
|
||||
free(card->app[i]->label);
|
||||
if (card->app[i]->ddo)
|
||||
free(card->app[i]->ddo);
|
||||
free(card->app[i]);
|
||||
}
|
||||
free(card->ops);
|
||||
pthread_mutex_destroy(&card->mutex);
|
||||
free(card);
|
||||
}
|
||||
|
||||
int sc_connect_card(struct sc_context *ctx,
|
||||
int reader, struct sc_card **card_out)
|
||||
{
|
||||
|
@ -352,15 +387,9 @@ int sc_connect_card(struct sc_context *ctx,
|
|||
if (!(rgReaderStates[0].dwEventState & SCARD_STATE_PRESENT))
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_CARD_NOT_PRESENT);
|
||||
|
||||
card = malloc(sizeof(struct sc_card));
|
||||
card = sc_card_new();
|
||||
if (card == NULL)
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
|
||||
memset(card, 0, sizeof(struct sc_card));
|
||||
card->ops = malloc(sizeof(struct sc_card_operations));
|
||||
if (card->ops == NULL) {
|
||||
free(card);
|
||||
SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
rv = SCardConnect(ctx->pcsc_ctx, ctx->readers[reader],
|
||||
SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY,
|
||||
&card_handle, &active_proto);
|
||||
|
@ -369,7 +398,6 @@ int sc_connect_card(struct sc_context *ctx,
|
|||
r = -1; /* FIXME: invent a real error value */
|
||||
goto err;
|
||||
}
|
||||
|
||||
card->protocol = pcsc_proto_to_opensc(active_proto);
|
||||
if (card->protocol == 0) {
|
||||
error(ctx, "Unknown protocol (%X) selected.\n", active_proto);
|
||||
|
@ -379,7 +407,6 @@ int sc_connect_card(struct sc_context *ctx,
|
|||
card->reader = reader;
|
||||
card->ctx = ctx;
|
||||
card->pcsc_card = card_handle;
|
||||
card->lock_count = 0;
|
||||
i = rgReaderStates[0].cbAtr;
|
||||
if (i >= SC_MAX_ATR_SIZE)
|
||||
i = SC_MAX_ATR_SIZE;
|
||||
|
@ -429,14 +456,13 @@ int sc_connect_card(struct sc_context *ctx,
|
|||
r = SC_ERROR_INVALID_CARD;
|
||||
goto err;
|
||||
}
|
||||
pthread_mutex_init(&card->mutex, NULL);
|
||||
card->magic = SC_CARD_MAGIC;
|
||||
*card_out = card;
|
||||
|
||||
SC_FUNC_RETURN(ctx, 1, 0);
|
||||
err:
|
||||
free(card->ops);
|
||||
free(card);
|
||||
if (card != NULL)
|
||||
sc_card_free(card);
|
||||
SC_FUNC_RETURN(ctx, 1, r);
|
||||
}
|
||||
|
||||
|
@ -454,9 +480,7 @@ int sc_disconnect_card(struct sc_card *card)
|
|||
sc_strerror(r));
|
||||
}
|
||||
SCardDisconnect(card->pcsc_card, SCARD_LEAVE_CARD);
|
||||
pthread_mutex_destroy(&card->mutex);
|
||||
free(card->ops);
|
||||
free(card);
|
||||
sc_card_free(card);
|
||||
SC_FUNC_RETURN(ctx, 1, 0);
|
||||
}
|
||||
|
||||
|
@ -676,7 +700,7 @@ int sc_update_binary(struct sc_card *card, unsigned int idx,
|
|||
|
||||
int sc_select_file(struct sc_card *card,
|
||||
const struct sc_path *in_path,
|
||||
struct sc_file *file)
|
||||
struct sc_file **file)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* dir.c: Stuff for handling EF(DIR)
|
||||
*
|
||||
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "sc-internal.h"
|
||||
#include "sc-log.h"
|
||||
#include "sc-asn1.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct app_entry {
|
||||
const char *aid;
|
||||
size_t aid_len;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
static const struct app_entry apps[] = {
|
||||
{ "\xA0\x00\x00\x00\x63PKCS-15", 12, "PKCS #15" },
|
||||
};
|
||||
|
||||
static const struct app_entry * find_app_entry(const u8 * aid, size_t aid_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(apps)/sizeof(apps[0]); i++) {
|
||||
if (apps[i].aid_len == aid_len &&
|
||||
memcmp(apps[i].aid, aid, aid_len) == 0)
|
||||
return &apps[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct sc_asn1_entry c_asn1_dirrecord[] = {
|
||||
{ "aid", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 15, 0, NULL },
|
||||
{ "label", SC_ASN1_UTF8STRING, SC_ASN1_APP | 16, SC_ASN1_OPTIONAL, NULL },
|
||||
{ "path", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 17, SC_ASN1_OPTIONAL, NULL },
|
||||
{ "ddo", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 19 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const struct sc_asn1_entry c_asn1_dir[] = {
|
||||
{ "dirRecord", SC_ASN1_STRUCT, SC_ASN1_APP | 1 | SC_ASN1_CONS, 0, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static int parse_dir_record(struct sc_card *card, u8 ** buf, size_t *buflen)
|
||||
{
|
||||
struct sc_asn1_entry asn1_dirrecord[5], asn1_dir[2];
|
||||
struct sc_app_info *app = NULL;
|
||||
const struct app_entry *ae;
|
||||
int r;
|
||||
u8 aid[128], label[128], path[128];
|
||||
u8 ddo[128];
|
||||
int aid_len = sizeof(aid), label_len = sizeof(label),
|
||||
path_len = sizeof(path), ddo_len = sizeof(ddo);
|
||||
|
||||
sc_copy_asn1_entry(c_asn1_dirrecord, asn1_dirrecord);
|
||||
sc_copy_asn1_entry(c_asn1_dir, asn1_dir);
|
||||
sc_format_asn1_entry(asn1_dir + 0, asn1_dirrecord, NULL, 0);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 0, aid, &aid_len, 0);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 1, label, &label_len, 0);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 2, path, &path_len, 0);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 3, ddo, &ddo_len, 0);
|
||||
|
||||
r = sc_asn1_decode(card->ctx, asn1_dir, *buf, *buflen, (const u8 **) buf, buflen);
|
||||
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
|
||||
return r;
|
||||
if (r) {
|
||||
error(card->ctx, "EF(DIR) parsing failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return r;
|
||||
}
|
||||
if (aid_len > SC_MAX_AID_SIZE) {
|
||||
error(card->ctx, "AID is too long.\n");
|
||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
||||
}
|
||||
app = malloc(sizeof(struct sc_app_info));
|
||||
if (app == NULL)
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
memcpy(app->aid, aid, aid_len);
|
||||
app->aid_len = aid_len;
|
||||
if (asn1_dirrecord[1].flags & SC_ASN1_PRESENT)
|
||||
app->label = strdup((char *) label);
|
||||
else
|
||||
app->label = NULL;
|
||||
if (asn1_dirrecord[2].flags & SC_ASN1_PRESENT) {
|
||||
if (path_len > SC_MAX_PATH_SIZE) {
|
||||
error(card->ctx, "Application path is too long.\n");
|
||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
||||
}
|
||||
memcpy(app->path.value, path, path_len);
|
||||
app->path.len = path_len;
|
||||
app->path.type = SC_PATH_TYPE_PATH;
|
||||
} else
|
||||
app->path.len = 0;
|
||||
if (asn1_dirrecord[3].flags & SC_ASN1_PRESENT) {
|
||||
app->ddo = malloc(ddo_len);
|
||||
if (app->ddo == NULL)
|
||||
return 0;
|
||||
memcpy(app->ddo, ddo, ddo_len);
|
||||
app->ddo_len = ddo_len;
|
||||
} else {
|
||||
app->ddo = NULL;
|
||||
app->ddo_len = 0;
|
||||
}
|
||||
ae = find_app_entry(aid, aid_len);
|
||||
if (ae != NULL)
|
||||
app->desc = ae->desc;
|
||||
else
|
||||
app->desc = NULL;
|
||||
card->app[card->app_count] = app;
|
||||
card->app_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sc_enum_apps(struct sc_card *card)
|
||||
{
|
||||
struct sc_file *file;
|
||||
struct sc_path path;
|
||||
int ef_structure;
|
||||
size_t file_size;
|
||||
int r;
|
||||
|
||||
if (card->app_count < 0)
|
||||
card->app_count = 0;
|
||||
sc_format_path("3F002F00", &path);
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r)
|
||||
return r;
|
||||
if (file->type != SC_FILE_TYPE_WORKING_EF) {
|
||||
error(card->ctx, "EF(DIR) is not a working EF.\n");
|
||||
sc_file_free(file);
|
||||
return SC_ERROR_INVALID_CARD;
|
||||
}
|
||||
ef_structure = file->ef_structure;
|
||||
file_size = file->size;
|
||||
sc_file_free(file);
|
||||
file = NULL;
|
||||
if (ef_structure == SC_FILE_EF_TRANSPARENT) {
|
||||
u8 buf[1024], *p = buf;
|
||||
size_t bufsize;
|
||||
|
||||
if (file_size > sizeof(buf))
|
||||
SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_INTERNAL);
|
||||
r = sc_read_binary(card, 0, buf, file_size, 0);
|
||||
SC_TEST_RET(card->ctx, r, "read_binary() failed");
|
||||
bufsize = file_size;
|
||||
while (bufsize > 0) {
|
||||
if (card->app_count == SC_MAX_CARD_APPS) {
|
||||
error(card->ctx, "Too many applications on card");
|
||||
break;
|
||||
}
|
||||
r = parse_dir_record(card, &p, &bufsize);
|
||||
if (r)
|
||||
break;
|
||||
}
|
||||
|
||||
} else { /* record structure */
|
||||
u8 buf[256], *p;
|
||||
int rec_nr;
|
||||
size_t rec_size;
|
||||
|
||||
for (rec_nr = 1; ; rec_nr++) {
|
||||
r = sc_read_record(card, rec_nr, buf, sizeof(buf), 0);
|
||||
if (r == SC_ERROR_RECORD_NOT_FOUND)
|
||||
break;
|
||||
SC_TEST_RET(card->ctx, r, "read_record() failed");
|
||||
if (card->app_count == SC_MAX_CARD_APPS) {
|
||||
error(card->ctx, "Too many applications on card");
|
||||
break;
|
||||
}
|
||||
rec_size = r;
|
||||
p = buf;
|
||||
parse_dir_record(card, &p, &rec_size);
|
||||
}
|
||||
}
|
||||
return card->app_count;
|
||||
}
|
||||
|
||||
const struct sc_app_info * sc_find_app_by_aid(struct sc_card *card,
|
||||
const u8 *aid, size_t aid_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(card->app_count > 0);
|
||||
for (i = 0; i < card->app_count; i++) {
|
||||
if (card->app[i]->aid_len == aid_len &&
|
||||
memcmp(card->app[i]->aid, aid, aid_len) == 0)
|
||||
return card->app[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int encode_dir_record(struct sc_context *ctx, const struct sc_app_info *app,
|
||||
u8 **buf, size_t *buflen)
|
||||
{
|
||||
struct sc_asn1_entry asn1_dirrecord[5], asn1_dir[2];
|
||||
int r;
|
||||
size_t label_len;
|
||||
|
||||
sc_copy_asn1_entry(c_asn1_dirrecord, asn1_dirrecord);
|
||||
sc_copy_asn1_entry(c_asn1_dir, asn1_dir);
|
||||
sc_format_asn1_entry(asn1_dir + 0, asn1_dirrecord, NULL, 1);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 0, (void *) app->aid, (void *) &app->aid_len, 1);
|
||||
if (app->label != NULL) {
|
||||
label_len = strlen(app->label);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 1, app->label, &label_len, 1);
|
||||
}
|
||||
if (app->path.len)
|
||||
sc_format_asn1_entry(asn1_dirrecord + 2, (void *) app->path.value,
|
||||
(void *) &app->path.len, 1);
|
||||
if (app->ddo != NULL)
|
||||
sc_format_asn1_entry(asn1_dirrecord + 3, (void *) app->ddo,
|
||||
(void *) &app->ddo_len, 1);
|
||||
r = sc_asn1_encode(ctx, asn1_dir, buf, buflen);
|
||||
if (r) {
|
||||
error(ctx, "sc_asn1_encode() failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sc_update_dir(struct sc_card *card)
|
||||
{
|
||||
struct sc_path path;
|
||||
struct sc_file *file;
|
||||
u8 *rec;
|
||||
size_t rec_size;
|
||||
int i, r;
|
||||
|
||||
sc_format_path("3F002F00", &path);
|
||||
|
||||
r = sc_select_file(card, &path, &file);
|
||||
SC_TEST_RET(card->ctx, r, "unable to select EF(DIR)");
|
||||
for (i = 0; i < card->app_count; i++) {
|
||||
r = encode_dir_record(card->ctx, card->app[i], &rec, &rec_size);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
free(rec);
|
||||
}
|
||||
return r;
|
||||
}
|
|
@ -25,12 +25,6 @@
|
|||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
struct sc_card_error {
|
||||
int SWs;
|
||||
int errorno;
|
||||
const char *errorstr;
|
||||
};
|
||||
|
||||
const static struct sc_card_error iso7816_errors[] = {
|
||||
{ 0x6200, SC_ERROR_UNKNOWN_REPLY, "State of non-volatile memory unchanged" },
|
||||
{ 0x6281, SC_ERROR_UNKNOWN_REPLY, "Part of returned data may be corrupted" },
|
||||
|
@ -291,13 +285,14 @@ static void process_fci(struct sc_context *ctx, struct sc_file *file,
|
|||
|
||||
static int iso7816_select_file(struct sc_card *card,
|
||||
const struct sc_path *in_path,
|
||||
struct sc_file *file)
|
||||
struct sc_file **file_out)
|
||||
{
|
||||
struct sc_context *ctx;
|
||||
struct sc_apdu apdu;
|
||||
u8 buf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
|
||||
int r, pathlen;
|
||||
struct sc_file *file = NULL;
|
||||
|
||||
assert(card != NULL && in_path != NULL);
|
||||
ctx = card->ctx;
|
||||
|
@ -334,14 +329,7 @@ static int iso7816_select_file(struct sc_card *card,
|
|||
apdu.data = path;
|
||||
apdu.datalen = pathlen;
|
||||
|
||||
if (file != NULL) {
|
||||
int i;
|
||||
/* initialize file to default values */
|
||||
memset(file, 0, sizeof(struct sc_file));
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
file->acl[i] = SC_AC_UNKNOWN;
|
||||
file->path = *in_path;
|
||||
|
||||
if (file_out != NULL) {
|
||||
apdu.resp = buf;
|
||||
apdu.resplen = sizeof(buf);
|
||||
apdu.le = 256;
|
||||
|
@ -353,7 +341,7 @@ static int iso7816_select_file(struct sc_card *card,
|
|||
}
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (file == NULL) {
|
||||
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));
|
||||
|
@ -365,8 +353,13 @@ static int iso7816_select_file(struct sc_card *card,
|
|||
|
||||
switch (apdu.resp[0]) {
|
||||
case 0x6F:
|
||||
if (file != NULL && apdu.resp[1] <= apdu.resplen)
|
||||
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)
|
||||
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_REPLY);
|
||||
|
@ -402,28 +395,10 @@ static int iso7816_get_challenge(struct sc_card *card, u8 *rnd, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static u8 acl_to_byte(unsigned int acl)
|
||||
{
|
||||
switch (acl) {
|
||||
case SC_AC_NONE:
|
||||
return 0x00;
|
||||
case SC_AC_CHV1:
|
||||
return 0x01;
|
||||
case SC_AC_CHV2:
|
||||
return 0x02;
|
||||
case SC_AC_TERM:
|
||||
return 0x04;
|
||||
case SC_AC_NEVER:
|
||||
return 0x0F;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static int construct_fci(const struct sc_file *file, u8 *out, size_t *outlen)
|
||||
{
|
||||
u8 *p = out;
|
||||
u8 buf[64];
|
||||
int i;
|
||||
|
||||
*p++ = 0x6F;
|
||||
p++;
|
||||
|
@ -457,28 +432,6 @@ static int construct_fci(const struct sc_file *file, u8 *out, size_t *outlen)
|
|||
if (file->sec_attr_len) {
|
||||
memcpy(buf, file->sec_attr, file->sec_attr_len);
|
||||
sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, 18, &p);
|
||||
} else {
|
||||
int idx[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]]);
|
||||
sc_asn1_put_tag(0x86, buf, 6, p, 18, &p);
|
||||
}
|
||||
out[1] = p - out - 2;
|
||||
|
||||
|
@ -556,8 +509,7 @@ static int iso7816_verify(struct sc_card *card, unsigned int type, int ref,
|
|||
if (pinlen >= SC_MAX_APDU_BUFFER_SIZE)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
switch (type) {
|
||||
case SC_AC_CHV1:
|
||||
case SC_AC_CHV2:
|
||||
case SC_AC_CHV:
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
@ -724,8 +676,7 @@ static int iso7816_change_reference_data(struct sc_card *card, unsigned int type
|
|||
if (len >= SC_MAX_APDU_BUFFER_SIZE)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
|
||||
switch (type) {
|
||||
case SC_AC_CHV1:
|
||||
case SC_AC_CHV2:
|
||||
case SC_AC_CHV:
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
@ -762,8 +713,7 @@ static int iso7816_reset_retry_counter(struct sc_card *card, unsigned int type,
|
|||
if (len >= MAX_BUFFER_SIZE)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
|
||||
switch (type) {
|
||||
case SC_AC_CHV1:
|
||||
case SC_AC_CHV2:
|
||||
case SC_AC_CHV:
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
|
|
@ -208,9 +208,8 @@ struct sc_pkcs15_card {
|
|||
struct sc_pkcs15_pin_info pin_info[SC_PKCS15_MAX_PINS];
|
||||
int pin_count;
|
||||
|
||||
/* FIXME: Move file_dir somewhere else, perhaps to sc_card */
|
||||
struct sc_file file_dir, file_app;
|
||||
struct sc_file file_tokeninfo, file_odf;
|
||||
struct sc_file *file_app;
|
||||
struct sc_file *file_tokeninfo, *file_odf;
|
||||
struct sc_pkcs15_df df[SC_PKCS15_DF_TYPE_COUNT];
|
||||
|
||||
int use_cache;
|
||||
|
|
|
@ -111,21 +111,14 @@ extern "C" {
|
|||
#define SC_FILE_STATUS_INVALIDATED 0x01
|
||||
|
||||
/* Access Control flags */
|
||||
#define SC_AC_NONE 0x00000000
|
||||
#define SC_AC_CHV1 0x00000001 /* Card Holder Verif. */
|
||||
#define SC_AC_CHV2 0x00000002
|
||||
#define SC_AC_TERM 0x00000004 /* Terminal auth. */
|
||||
#define SC_AC_PRO 0x00000008 /* Secure Messaging */
|
||||
#define SC_AC_AUT 0x00000010 /* Key auth. */
|
||||
#define SC_AC_NONE 0x00000000
|
||||
#define SC_AC_CHV 0x00000001 /* Card Holder Verif. */
|
||||
#define SC_AC_TERM 0x00000002 /* Terminal auth. */
|
||||
#define SC_AC_PRO 0x00000004 /* Secure Messaging */
|
||||
#define SC_AC_AUT 0x00000008 /* Key auth. */
|
||||
|
||||
#define SC_AC_KEY_NUM_0 0x00000000
|
||||
#define SC_AC_KEY_NUM_1 0x10000000
|
||||
#define SC_AC_KEY_NUM_2 0x20000000
|
||||
#define SC_AC_KEY_NUM_3 0x30000000
|
||||
#define SC_AC_KEY_NUM_MASK 0xF0000000
|
||||
|
||||
#define SC_AC_NEVER 0xFFFFFFFE
|
||||
#define SC_AC_UNKNOWN 0xFFFFFFFF
|
||||
#define SC_AC_UNKNOWN 0xFFFFFFFE
|
||||
#define SC_AC_NEVER 0xFFFFFFFF
|
||||
|
||||
/* Operations relating to access control (in case of DF) */
|
||||
#define SC_AC_OP_SELECT 0
|
||||
|
@ -155,6 +148,7 @@ extern "C" {
|
|||
#define SC_MAX_CARD_DRIVERS 16
|
||||
#define SC_MAX_CARD_DRIVER_SNAME_SIZE 16
|
||||
#define SC_MAX_READERS 4
|
||||
#define SC_MAX_CARD_APPS 4
|
||||
#define SC_MAX_APDU_BUFFER_SIZE 258
|
||||
#define SC_MAX_PATH_SIZE 16
|
||||
#define SC_MAX_PIN_SIZE 16
|
||||
|
@ -162,6 +156,7 @@ extern "C" {
|
|||
#define SC_MAX_SEC_ATTR_SIZE 20
|
||||
#define SC_MAX_PROP_ATTR_SIZE 16
|
||||
#define SC_MAX_OBJECT_ID_OCTETS 16
|
||||
#define SC_MAX_AID_SIZE 16
|
||||
#define SC_APDU_CHOP_SIZE 250
|
||||
|
||||
typedef unsigned char u8;
|
||||
|
@ -182,6 +177,15 @@ struct sc_path {
|
|||
int type;
|
||||
};
|
||||
|
||||
#define SC_AC_KEY_REF_NONE 0xFFFFFFFF
|
||||
|
||||
struct sc_acl_entry {
|
||||
unsigned int method;
|
||||
unsigned int key_ref;
|
||||
|
||||
struct sc_acl_entry *next;
|
||||
};
|
||||
|
||||
struct sc_file {
|
||||
struct sc_path path;
|
||||
u8 name[16]; /* DF name */
|
||||
|
@ -191,7 +195,7 @@ struct sc_file {
|
|||
size_t size; /* Size of file (in bytes) */
|
||||
int id; /* Short file id (2 bytes) */
|
||||
int status; /* Status flags */
|
||||
unsigned int acl[SC_MAX_AC_OPS]; /* Access Control List */
|
||||
struct sc_acl_entry *acl[SC_MAX_AC_OPS]; /* Access Control List */
|
||||
|
||||
int record_length; /* In case of fixed-length or cyclic EF */
|
||||
int record_count; /* Valid, if not transparent EF or DF */
|
||||
|
@ -232,6 +236,17 @@ struct sc_security_env {
|
|||
size_t key_ref_len;
|
||||
};
|
||||
|
||||
struct sc_app_info {
|
||||
u8 aid[SC_MAX_AID_SIZE];
|
||||
size_t aid_len;
|
||||
char *label;
|
||||
struct sc_path path;
|
||||
u8 *ddo;
|
||||
size_t ddo_len;
|
||||
|
||||
const char *desc; /* App description, if known */
|
||||
};
|
||||
|
||||
struct sc_card_cache {
|
||||
struct sc_path current_path;
|
||||
};
|
||||
|
@ -269,9 +284,13 @@ struct sc_card {
|
|||
int cla;
|
||||
u8 atr[SC_MAX_ATR_SIZE];
|
||||
size_t atr_len;
|
||||
|
||||
struct sc_app_info *app[SC_MAX_CARD_APPS];
|
||||
int app_count;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
int lock_count;
|
||||
|
||||
const struct sc_card_driver *driver;
|
||||
struct sc_card_operations *ops;
|
||||
void *ops_data;
|
||||
|
@ -315,7 +334,7 @@ struct sc_card_operations {
|
|||
* in ISO7816-4. Stores information about the selected file to
|
||||
* <file>, if not NULL. */
|
||||
int (*select_file)(struct sc_card *card, const struct sc_path *path,
|
||||
struct sc_file *file_out);
|
||||
struct sc_file **file_out);
|
||||
int (*get_response)(struct sc_card *card, u8 * buf, size_t count);
|
||||
int (*get_challenge)(struct sc_card *card, u8 * buf, size_t count);
|
||||
|
||||
|
@ -498,11 +517,14 @@ int sc_unlock(struct sc_card *card);
|
|||
* Does the equivalent of ISO 7816-4 command SELECT FILE.
|
||||
* @param card The card on which to issue the command
|
||||
* @param path The path, file id or name of the desired file
|
||||
* @param file If not NULL, will contain information about the selected file
|
||||
* @param file If not NULL, will receive a pointer to a new structure
|
||||
* @retval SC_SUCCESS on success
|
||||
*/
|
||||
int sc_select_file(struct sc_card *card, const struct sc_path *path,
|
||||
struct sc_file *file);
|
||||
struct sc_file **file);
|
||||
|
||||
int sc_list_files(struct sc_card *card, u8 * buf, size_t buflen);
|
||||
|
||||
/* TODO: finish writing API docs */
|
||||
int sc_read_binary(struct sc_card *card, unsigned int idx, u8 * buf,
|
||||
size_t count, unsigned long flags);
|
||||
|
@ -513,7 +535,7 @@ int sc_update_binary(struct sc_card *card, unsigned int idx, const u8 * buf,
|
|||
/**
|
||||
* Reads a record from the current (i.e. selected) file.
|
||||
* @param card The card on which to issue the command
|
||||
* @param rec_nr SC_READ_RECORD_CURRENT or a record number beginning from 1
|
||||
* @param rec_nr SC_READ_RECORD_CURRENT or a record number starting from 1
|
||||
* @param buf Pointer to a buffer for storing the data
|
||||
* @param count Number of bytes to read
|
||||
* @param flags Flags
|
||||
|
@ -546,14 +568,31 @@ int sc_create_file(struct sc_card *card, struct sc_file *file);
|
|||
int sc_delete_file(struct sc_card *card, const struct sc_path *path);
|
||||
|
||||
inline int sc_file_valid(const struct sc_file *file);
|
||||
struct sc_file * sc_file_new();
|
||||
void sc_file_free(struct sc_file *file);
|
||||
void sc_file_dup(struct sc_file **dest, const struct sc_file *src);
|
||||
|
||||
int sc_file_add_acl_entry(struct sc_file *file, unsigned int operation,
|
||||
unsigned int method, unsigned long key_ref);
|
||||
const struct sc_acl_entry * sc_file_get_acl_entry(const struct sc_file *file,
|
||||
unsigned int operation);
|
||||
void sc_file_clear_acl_entries(struct sc_file *file, unsigned int operation);
|
||||
|
||||
void sc_format_path(const char *path_in, struct sc_path *path_out);
|
||||
int sc_append_path(struct sc_path *dest, const struct sc_path *src);
|
||||
int sc_append_path_id(struct sc_path *dest, const u8 *id, size_t idlen);
|
||||
int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen);
|
||||
int sc_get_cache_dir(struct sc_context *ctx, char *buf, size_t bufsize);
|
||||
|
||||
/* Possibly only valid on Setec cards */
|
||||
int sc_list_files(struct sc_card *card, u8 * buf, size_t buflen);
|
||||
int sc_enum_apps(struct sc_card *card);
|
||||
const struct sc_app_info * sc_find_app_by_aid(struct sc_card *card,
|
||||
const u8 *aid, size_t aid_len);
|
||||
|
||||
struct sc_card_error {
|
||||
int SWs;
|
||||
int errorno;
|
||||
const char *errorstr;
|
||||
};
|
||||
|
||||
const char *sc_strerror(int sc_errno);
|
||||
|
||||
|
|
|
@ -137,8 +137,8 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card,
|
|||
struct sc_pkcs15_cert **cert_out)
|
||||
{
|
||||
int r;
|
||||
struct sc_file file;
|
||||
struct sc_pkcs15_cert *cert;
|
||||
struct sc_file *file = NULL;
|
||||
u8 *data = NULL;
|
||||
size_t len;
|
||||
|
||||
|
@ -153,18 +153,20 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card,
|
|||
sc_unlock(p15card->card);
|
||||
return r;
|
||||
}
|
||||
data = malloc(file.size);
|
||||
len = file->size;
|
||||
sc_file_free(file);
|
||||
data = malloc(len);
|
||||
if (data == NULL) {
|
||||
sc_unlock(p15card->card);
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
r = sc_read_binary(p15card->card, 0, data, file.size, 0);
|
||||
r = sc_read_binary(p15card->card, 0, data, len, 0);
|
||||
if (r < 0) {
|
||||
sc_unlock(p15card->card);
|
||||
free(data);
|
||||
return r;
|
||||
}
|
||||
len = file.size;
|
||||
len = len;
|
||||
sc_unlock(p15card->card);
|
||||
}
|
||||
cert = malloc(sizeof(struct sc_pkcs15_cert));
|
||||
|
|
|
@ -230,7 +230,6 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
|
|||
const u8 *pincode, int pinlen)
|
||||
{
|
||||
int r;
|
||||
struct sc_file file;
|
||||
struct sc_card *card;
|
||||
u8 pinbuf[SC_MAX_PIN_SIZE];
|
||||
|
||||
|
@ -242,14 +241,14 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
|
|||
card = p15card->card;
|
||||
r = sc_lock(card);
|
||||
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
|
||||
r = sc_select_file(card, &pin->path, &file);
|
||||
r = sc_select_file(card, &pin->path, NULL);
|
||||
if (r) {
|
||||
sc_unlock(card);
|
||||
return r;
|
||||
}
|
||||
memset(pinbuf, pin->pad_char, pin->stored_length);
|
||||
memcpy(pinbuf, pincode, pinlen);
|
||||
r = sc_verify(card, SC_AC_CHV1, pin->reference,
|
||||
r = sc_verify(card, SC_AC_CHV, pin->reference,
|
||||
pinbuf, pin->stored_length, &pin->tries_left);
|
||||
memset(pinbuf, 0, pinlen);
|
||||
sc_unlock(card);
|
||||
|
@ -265,7 +264,6 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
|
|||
const u8 *newpin, int newpinlen)
|
||||
{
|
||||
int r;
|
||||
struct sc_file file;
|
||||
struct sc_card *card;
|
||||
u8 pinbuf[SC_MAX_PIN_SIZE * 2];
|
||||
|
||||
|
@ -280,7 +278,7 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
|
|||
card = p15card->card;
|
||||
r = sc_lock(card);
|
||||
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
|
||||
r = sc_select_file(card, &pin->path, &file);
|
||||
r = sc_select_file(card, &pin->path, NULL);
|
||||
if (r) {
|
||||
sc_unlock(card);
|
||||
return r;
|
||||
|
@ -288,7 +286,7 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
|
|||
memset(pinbuf, pin->pad_char, pin->stored_length * 2);
|
||||
memcpy(pinbuf, oldpin, oldpinlen);
|
||||
memcpy(pinbuf + pin->stored_length, newpin, newpinlen);
|
||||
r = sc_change_reference_data(card, SC_AC_CHV1, pin->auth_id.value[0], pinbuf,
|
||||
r = sc_change_reference_data(card, SC_AC_CHV, pin->reference, pinbuf,
|
||||
pin->stored_length, pinbuf+pin->stored_length,
|
||||
pin->stored_length, &pin->tries_left);
|
||||
memset(pinbuf, 0, pin->stored_length * 2);
|
||||
|
|
|
@ -39,11 +39,10 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
|
|||
if (prkey->path.len < 2)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
if (prkey->path.len == 2) {
|
||||
path = p15card->file_app.path;
|
||||
memcpy(path.value + path.len, prkey->path.value, prkey->path.len);
|
||||
path.len += prkey->path.len;
|
||||
path = p15card->file_app->path;
|
||||
sc_append_path(&path, &prkey->path);
|
||||
file_id = prkey->path;
|
||||
} else {
|
||||
} else { /* path.len > 2 */
|
||||
path = prkey->path;
|
||||
memcpy(file_id.value, prkey->path.value + prkey->path.len - 2, 2);
|
||||
file_id.len = 2;
|
||||
|
@ -105,7 +104,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
|
|||
if (prkey->path.len < 2)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
if (prkey->path.len == 2) {
|
||||
path = p15card->file_app.path;
|
||||
path = p15card->file_app->path;
|
||||
memcpy(path.value + path.len, prkey->path.value, prkey->path.len);
|
||||
path.len += prkey->path.len;
|
||||
file_id = prkey->path;
|
||||
|
|
|
@ -114,10 +114,10 @@ void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, size_t buflen)
|
|||
card->manufacturer_id = strdup("(unknown)");
|
||||
}
|
||||
if (card->label == NULL) {
|
||||
if (asn1_tokeninfo[2].flags & SC_ASN1_PRESENT)
|
||||
card->manufacturer_id = strdup((char *) mnfid);
|
||||
if (asn1_tokeninfo[3].flags & SC_ASN1_PRESENT)
|
||||
card->label = strdup((char *) label);
|
||||
else
|
||||
card->manufacturer_id = strdup("(unknown)");
|
||||
card->label = strdup("(unknown)");
|
||||
}
|
||||
return;
|
||||
err:
|
||||
|
@ -187,91 +187,63 @@ static const struct sc_asn1_entry c_asn1_ddo[] = {
|
|||
{ "unusedPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
static const struct sc_asn1_entry c_asn1_dirrecord[] = {
|
||||
{ "aid", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 15, 0, NULL },
|
||||
{ "label", SC_ASN1_UTF8STRING, SC_ASN1_APP | 16, SC_ASN1_OPTIONAL, NULL },
|
||||
{ "path", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 17, 0, NULL },
|
||||
{ "ddo", SC_ASN1_STRUCT, SC_ASN1_APP | 19 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
/* FIXME: this should be decoded elsewhere */
|
||||
static const struct sc_asn1_entry c_asn1_dir[] = {
|
||||
{ "dirRecord", SC_ASN1_STRUCT, SC_ASN1_APP | 1 | SC_ASN1_CONS, 0, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const u8 *aidref = (const u8 *) "\xA0\x00\x00\x00\x63PKCS-15";
|
||||
static const int aidref_len = 12;
|
||||
static const u8 *pkcs15_aid = (const u8 *) "\xA0\x00\x00\x00\x63PKCS-15";
|
||||
static const size_t pkcs15_aid_len = 12;
|
||||
|
||||
static int parse_dir(const u8 * buf, size_t buflen, struct sc_pkcs15_card *card)
|
||||
static int parse_ddo(struct sc_pkcs15_card *p15card, const u8 * buf, size_t buflen)
|
||||
{
|
||||
struct sc_asn1_entry asn1_ddo[5], asn1_dirrecord[5], asn1_dir[2];
|
||||
struct sc_asn1_entry asn1_ddo[5];
|
||||
struct sc_path odf_path, ti_path;
|
||||
int r;
|
||||
u8 aid[128], label[128], path[128];
|
||||
int aid_len = sizeof(aid), label_len = sizeof(label),
|
||||
path_len = sizeof(path);
|
||||
|
||||
|
||||
sc_copy_asn1_entry(c_asn1_ddo, asn1_ddo);
|
||||
sc_copy_asn1_entry(c_asn1_dirrecord, asn1_dirrecord);
|
||||
sc_copy_asn1_entry(c_asn1_dir, asn1_dir);
|
||||
sc_format_asn1_entry(asn1_dir + 0, asn1_dirrecord, NULL, 0);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 0, aid, &aid_len, 0);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 1, label, &label_len, 0);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 2, path, &path_len, 0);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 3, asn1_ddo, NULL, 0);
|
||||
sc_format_asn1_entry(asn1_ddo + 1, &card->file_odf.path, NULL, 0);
|
||||
sc_format_asn1_entry(asn1_ddo + 2, &card->file_tokeninfo.path, NULL, 0);
|
||||
|
||||
r = sc_asn1_decode(card->card->ctx, asn1_dir, buf, buflen, NULL, NULL);
|
||||
sc_format_asn1_entry(asn1_ddo + 1, &odf_path, NULL, 0);
|
||||
sc_format_asn1_entry(asn1_ddo + 2, &ti_path, NULL, 0);
|
||||
|
||||
r = sc_asn1_decode(p15card->card->ctx, asn1_ddo, buf, buflen, NULL, NULL);
|
||||
if (r) {
|
||||
error(card->card->ctx, "EF(DIR) parsing failed: %s\n",
|
||||
error(p15card->card->ctx, "DDO parsing failed: %s\n",
|
||||
sc_strerror(r));
|
||||
return r;
|
||||
}
|
||||
if (aid_len != aidref_len || memcmp(aidref, aid, aid_len) != 0) {
|
||||
error(card->card->ctx, "AID in EF(DIR) is invalid\n");
|
||||
return -1;
|
||||
if (asn1_ddo[1].flags & SC_ASN1_PRESENT) {
|
||||
p15card->file_odf = sc_file_new();
|
||||
if (p15card->file_odf == NULL)
|
||||
goto mem_err;
|
||||
p15card->file_odf->path = odf_path;
|
||||
}
|
||||
if (asn1_ddo[2].flags & SC_ASN1_PRESENT) {
|
||||
p15card->file_tokeninfo = sc_file_new();
|
||||
if (p15card->file_tokeninfo == NULL)
|
||||
goto mem_err;
|
||||
p15card->file_tokeninfo->path = ti_path;
|
||||
}
|
||||
if (asn1_dirrecord[1].flags & SC_ASN1_PRESENT)
|
||||
card->label = strdup((char *) label);
|
||||
else
|
||||
card->label = strdup("(unknown)");
|
||||
if (path_len > SC_MAX_PATH_SIZE)
|
||||
return -1;
|
||||
memcpy(card->file_app.path.value, path, path_len);
|
||||
card->file_app.path.len = path_len;
|
||||
card->file_app.path.type = SC_PATH_TYPE_PATH;
|
||||
|
||||
return 0;
|
||||
mem_err:
|
||||
if (p15card->file_odf != NULL) {
|
||||
sc_file_free(p15card->file_odf);
|
||||
p15card->file_odf = NULL;
|
||||
}
|
||||
if (p15card->file_tokeninfo != NULL) {
|
||||
sc_file_free(p15card->file_tokeninfo);
|
||||
p15card->file_tokeninfo = NULL;
|
||||
}
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
static int encode_dir(struct sc_context *ctx, struct sc_pkcs15_card *card, u8 **buf, size_t *buflen)
|
||||
#if 0
|
||||
static int encode_ddo(struct sc_pkcs15_card *p15card, u8 **buf, size_t *buflen)
|
||||
{
|
||||
struct sc_asn1_entry asn1_ddo[5], asn1_dirrecord[5], asn1_dir[2];
|
||||
struct sc_asn1_entry asn1_ddo[5];
|
||||
int r;
|
||||
size_t label_len;
|
||||
|
||||
sc_copy_asn1_entry(c_asn1_ddo, asn1_ddo);
|
||||
sc_copy_asn1_entry(c_asn1_dirrecord, asn1_dirrecord);
|
||||
sc_copy_asn1_entry(c_asn1_dir, asn1_dir);
|
||||
sc_format_asn1_entry(asn1_dir + 0, asn1_dirrecord, NULL, 1);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 0, (void *) aidref, (void *) &aidref_len, 1);
|
||||
if (card->label != NULL) {
|
||||
label_len = strlen(card->label);
|
||||
sc_format_asn1_entry(asn1_dirrecord + 1, card->label, &label_len, 1);
|
||||
}
|
||||
if (card->file_app.path.len == 0) {
|
||||
error(ctx, "Application path not set.\n");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
sc_format_asn1_entry(asn1_dirrecord + 2, card->file_app.path.value,
|
||||
&card->file_app.path.len, 1);
|
||||
#if 0
|
||||
/* FIXME: encode DDO */
|
||||
sc_format_asn1_entry(asn1_dirrecord + 3, asn1_ddo, NULL, 0);
|
||||
|
||||
sc_format_asn1_entry(asn1_ddo + 1, &card->file_odf.path, NULL, 0);
|
||||
sc_format_asn1_entry(asn1_ddo + 2, &card->file_tokeninfo.path, NULL, 0);
|
||||
#endif
|
||||
|
||||
r = sc_asn1_encode(ctx, asn1_dir, buf, buflen);
|
||||
if (r) {
|
||||
error(ctx, "sc_asn1_encode() failed: %s\n",
|
||||
|
@ -280,17 +252,17 @@ static int encode_dir(struct sc_context *ctx, struct sc_pkcs15_card *card, u8 **
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* FIXME: This should be done using sc_update_binary(),
|
||||
* and be generally wiser */
|
||||
int sc_pkcs15_create_dir(struct sc_pkcs15_card *p15card, struct sc_card *card)
|
||||
{
|
||||
#if 0
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
u8 *buf;
|
||||
size_t bufsize;
|
||||
int r, i;
|
||||
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
sc_format_path("3F00", &path);
|
||||
r = sc_select_file(card, &path, NULL);
|
||||
|
@ -327,6 +299,7 @@ int sc_pkcs15_create_dir(struct sc_pkcs15_card *p15card, struct sc_card *card)
|
|||
r = sc_update_binary(card, 0, buf, bufsize, 0);
|
||||
free(buf);
|
||||
SC_TEST_RET(card->ctx, r, "Error updating EF(DIR)");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -376,10 +349,9 @@ static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card)
|
|||
error(card->card->ctx, "too many DF's on card\n");
|
||||
continue;
|
||||
}
|
||||
file = malloc(sizeof(struct sc_file));
|
||||
file = sc_file_new();
|
||||
if (file == NULL)
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
memset(file, 0, sizeof(struct sc_file));
|
||||
file->path = path;
|
||||
df->file[df->count] = file;
|
||||
df->count++;
|
||||
|
@ -474,7 +446,7 @@ void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card)
|
|||
for (i = 0; i < p15card->df[j].count; i++) {
|
||||
struct sc_pkcs15_object *p;
|
||||
if (p15card->df[j].file[i])
|
||||
free(p15card->df[j].file[i]);
|
||||
sc_file_free(p15card->df[j].file[i]);
|
||||
p = p15card->df[j].obj[i];
|
||||
while (p != NULL) {
|
||||
struct sc_pkcs15_object *p2 = p->next;
|
||||
|
@ -484,10 +456,19 @@ void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card)
|
|||
p = p2;
|
||||
}
|
||||
}
|
||||
if (p15card->file_app != NULL)
|
||||
sc_file_free(p15card->file_app);
|
||||
if (p15card->file_tokeninfo != NULL)
|
||||
sc_file_free(p15card->file_tokeninfo);
|
||||
if (p15card->file_odf != NULL)
|
||||
sc_file_free(p15card->file_odf);
|
||||
p15card->magic = 0;
|
||||
free(p15card->label);
|
||||
free(p15card->serial_number);
|
||||
free(p15card->manufacturer_id);
|
||||
if (p15card->label)
|
||||
free(p15card->label);
|
||||
if (p15card->serial_number)
|
||||
free(p15card->serial_number);
|
||||
if (p15card->manufacturer_id)
|
||||
free(p15card->manufacturer_id);
|
||||
free(p15card);
|
||||
}
|
||||
|
||||
|
@ -499,7 +480,6 @@ int sc_pkcs15_bind(struct sc_card *card,
|
|||
struct sc_pkcs15_card *p15card = NULL;
|
||||
struct sc_path tmppath;
|
||||
struct sc_context *ctx;
|
||||
struct sc_file file;
|
||||
|
||||
assert(sc_card_valid(card) && p15card_out != NULL);
|
||||
ctx = card->ctx;
|
||||
|
@ -509,45 +489,48 @@ int sc_pkcs15_bind(struct sc_card *card,
|
|||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
p15card->card = card;
|
||||
|
||||
sc_format_path("2F00", &tmppath);
|
||||
err = sc_lock(card);
|
||||
if (err) {
|
||||
error(ctx, "sc_lock() failed: %s\n", sc_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
err = sc_select_file(card, &tmppath, &file);
|
||||
if (err) {
|
||||
error(ctx, "Error selecting EF(DIR): %s\n", sc_strerror(err));
|
||||
err = SC_ERROR_PKCS15_APP_NOT_FOUND;
|
||||
goto error;
|
||||
}
|
||||
err = sc_read_binary(card, 0, buf, file.size, 0);
|
||||
if (err < 0) {
|
||||
error(ctx, "Error reading EF(DIR): %s\n", sc_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
if (err <= 2) {
|
||||
err = SC_ERROR_PKCS15_APP_NOT_FOUND;
|
||||
error(ctx, "Error reading EF(DIR): too few bytes read\n");
|
||||
goto error;
|
||||
}
|
||||
len = err;
|
||||
if (parse_dir(buf, len, p15card)) {
|
||||
err = SC_ERROR_PKCS15_APP_NOT_FOUND;
|
||||
error(ctx, "Error parsing EF(DIR)\n");
|
||||
goto error;
|
||||
}
|
||||
if (p15card->file_odf.path.len == 0) {
|
||||
tmppath = p15card->file_app.path;
|
||||
memcpy(tmppath.value + tmppath.len, "\x50\x31", 2);
|
||||
tmppath.len += 2;
|
||||
} else
|
||||
tmppath = p15card->file_odf.path;
|
||||
|
||||
err = sc_select_file(card, &tmppath, &file);
|
||||
if (err) /* FIXME: finish writing error stuff */
|
||||
if (card->app_count < 0) {
|
||||
err = sc_enum_apps(card);
|
||||
if (err < 0 && err != SC_ERROR_FILE_NOT_FOUND) {
|
||||
error(ctx, "unable to enumerate apps: %s\n", sc_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
p15card->file_app = sc_file_new();
|
||||
if (p15card->file_app == NULL) {
|
||||
err = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
err = sc_read_binary(card, 0, buf, file.size, 0);
|
||||
}
|
||||
sc_format_path("3F005015", &p15card->file_app->path);
|
||||
if (card->app_count > 0) {
|
||||
const struct sc_app_info *info;
|
||||
|
||||
info = sc_find_app_by_aid(card, pkcs15_aid, pkcs15_aid_len);
|
||||
if (info != NULL) {
|
||||
if (info->path.len)
|
||||
p15card->file_app->path = info->path;
|
||||
if (info->ddo != NULL)
|
||||
parse_ddo(p15card, info->ddo, info->ddo_len);
|
||||
}
|
||||
}
|
||||
if (p15card->file_odf == NULL) {
|
||||
tmppath = p15card->file_app->path;
|
||||
sc_append_path_id(&tmppath, "\x50\x31", 2);
|
||||
} else {
|
||||
tmppath = p15card->file_odf->path;
|
||||
sc_file_free(p15card->file_odf);
|
||||
p15card->file_odf = NULL;
|
||||
}
|
||||
err = sc_select_file(card, &tmppath, &p15card->file_odf);
|
||||
if (err) /* FIXME: finish writing error reporting stuff */
|
||||
goto error;
|
||||
err = sc_read_binary(card, 0, buf, p15card->file_odf->size, 0);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
if (err < 2) {
|
||||
|
@ -559,16 +542,18 @@ int sc_pkcs15_bind(struct sc_card *card,
|
|||
err = SC_ERROR_PKCS15_APP_NOT_FOUND;
|
||||
goto error;
|
||||
}
|
||||
if (p15card->file_tokeninfo.path.len == 0) {
|
||||
tmppath.len -= 2;
|
||||
memcpy(tmppath.value + tmppath.len, "\x50\x32", 2);
|
||||
tmppath.len += 2;
|
||||
} else
|
||||
tmppath = p15card->file_tokeninfo.path;
|
||||
err = sc_select_file(card, &tmppath, &file);
|
||||
if (p15card->file_tokeninfo == NULL) {
|
||||
tmppath = p15card->file_app->path;
|
||||
sc_append_path_id(&tmppath, "\x50\x32", 2);
|
||||
} else {
|
||||
tmppath = p15card->file_tokeninfo->path;
|
||||
sc_file_free(p15card->file_tokeninfo);
|
||||
p15card->file_tokeninfo = NULL;
|
||||
}
|
||||
err = sc_select_file(card, &tmppath, &p15card->file_tokeninfo);
|
||||
if (err)
|
||||
goto error;
|
||||
err = sc_read_binary(card, 0, buf, file.size, 0);
|
||||
err = sc_read_binary(card, 0, buf, p15card->file_tokeninfo->size, 0);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
if (err <= 2) {
|
||||
|
@ -583,7 +568,7 @@ int sc_pkcs15_bind(struct sc_card *card,
|
|||
sc_unlock(card);
|
||||
return 0;
|
||||
error:
|
||||
free(p15card);
|
||||
sc_pkcs15_card_free(p15card);
|
||||
sc_unlock(card);
|
||||
SC_FUNC_RETURN(ctx, 1, err);
|
||||
}
|
||||
|
@ -592,10 +577,9 @@ int sc_pkcs15_detect(struct sc_card *card)
|
|||
{
|
||||
int r;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
|
||||
sc_format_path("NA0000063504B43532D3135", &path);
|
||||
r = sc_select_file(card, &path, &file);
|
||||
r = sc_select_file(card, &path, NULL);
|
||||
if (r != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
|
@ -762,10 +746,11 @@ int sc_pkcs15_create(struct sc_pkcs15_card *p15card, struct sc_card *card)
|
|||
u8 *tokinf_buf = NULL, *odf_buf = NULL;
|
||||
size_t tokinf_size, odf_size;
|
||||
|
||||
sc_format_path("3F0050155031", &p15card->file_odf.path);
|
||||
sc_format_path("3F0050155032", &p15card->file_tokeninfo.path);
|
||||
memcpy(p15card->file_app.name, "\xA0\x00\x00\x00cPKCS-15", 12);
|
||||
p15card->file_app.namelen = 12;
|
||||
if (p15card->file_app == NULL || p15card->file_odf == NULL ||
|
||||
p15card->file_tokeninfo == NULL) {
|
||||
error(card->ctx, "Not all of the necessary files have been supplied\n");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
if (card->ctx->debug)
|
||||
debug(card->ctx, "creating EF(DIR)\n");
|
||||
r = sc_pkcs15_create_dir(p15card, card);
|
||||
|
@ -777,7 +762,7 @@ int sc_pkcs15_create(struct sc_pkcs15_card *p15card, struct sc_card *card)
|
|||
}
|
||||
if (card->ctx->debug)
|
||||
debug(card->ctx, "creating EF(TokenInfo)\n");
|
||||
r = create_and_update_file(p15card, card, &p15card->file_tokeninfo, tokinf_buf, tokinf_size);
|
||||
r = create_and_update_file(p15card, card, p15card->file_tokeninfo, tokinf_buf, tokinf_size);
|
||||
if (r) {
|
||||
sc_perror(card->ctx, r, "Error creating EF(TokenInfo)");
|
||||
goto err;
|
||||
|
@ -792,7 +777,7 @@ int sc_pkcs15_create(struct sc_pkcs15_card *p15card, struct sc_card *card)
|
|||
sc_perror(card->ctx, r, "Error encoding EF(ODF)");
|
||||
goto err;
|
||||
}
|
||||
r = create_and_update_file(p15card, card, &p15card->file_odf, odf_buf, odf_size);
|
||||
r = create_and_update_file(p15card, card, p15card->file_odf, odf_buf, odf_size);
|
||||
if (r) {
|
||||
sc_perror(card->ctx, r, "Error creating EF(ODF)");
|
||||
goto err;
|
||||
|
@ -840,8 +825,7 @@ int sc_pkcs15_parse_df(struct sc_pkcs15_card *p15card,
|
|||
const u8 *p = buf;
|
||||
size_t bufsize = sizeof(buf);
|
||||
int r, cached_file = 0;
|
||||
struct sc_file *file = df->file[file_nr];
|
||||
struct sc_path path = file->path;
|
||||
struct sc_path path = df->file[file_nr]->path;
|
||||
struct sc_pkcs15_object *obj = NULL;
|
||||
int (* func)(struct sc_pkcs15_card *, struct sc_pkcs15_object *,
|
||||
const u8 **buf, size_t *bufsize) = NULL;
|
||||
|
@ -864,25 +848,30 @@ int sc_pkcs15_parse_df(struct sc_pkcs15_card *p15card,
|
|||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
if (p15card->use_cache) {
|
||||
r = sc_pkcs15_read_cached_file(p15card, &file->path,
|
||||
r = sc_pkcs15_read_cached_file(p15card, &path,
|
||||
&bufptr, &bufsize);
|
||||
if (r == 0)
|
||||
cached_file = 1;
|
||||
}
|
||||
if (cached_file == 0) {
|
||||
r = sc_select_file(p15card->card, &path, file);
|
||||
struct sc_file *file = NULL;
|
||||
size_t file_size;
|
||||
|
||||
r = sc_select_file(p15card->card, &path, &file);
|
||||
if (r) {
|
||||
sc_perror(ctx, r, "sc_select_file() failed");
|
||||
return r;
|
||||
}
|
||||
if (file->size > sizeof(buf)) {
|
||||
file_size = file->size;
|
||||
sc_file_free(file);
|
||||
if (file_size > sizeof(buf)) {
|
||||
error(ctx, "Buffer too small to handle DF contents\n");
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
r = sc_read_binary(p15card->card, 0, buf, file->size, 0);
|
||||
r = sc_read_binary(p15card->card, 0, buf, file_size, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
bufsize = file->size;
|
||||
bufsize = file_size;
|
||||
}
|
||||
do {
|
||||
obj = malloc(sizeof(struct sc_pkcs15_object));
|
||||
|
|
|
@ -208,9 +208,8 @@ struct sc_pkcs15_card {
|
|||
struct sc_pkcs15_pin_info pin_info[SC_PKCS15_MAX_PINS];
|
||||
int pin_count;
|
||||
|
||||
/* FIXME: Move file_dir somewhere else, perhaps to sc_card */
|
||||
struct sc_file file_dir, file_app;
|
||||
struct sc_file file_tokeninfo, file_odf;
|
||||
struct sc_file *file_app;
|
||||
struct sc_file *file_tokeninfo, *file_odf;
|
||||
struct sc_pkcs15_df df[SC_PKCS15_DF_TYPE_COUNT];
|
||||
|
||||
int use_cache;
|
||||
|
|
|
@ -188,7 +188,7 @@ int sc_establish_context(struct sc_context **ctx_out)
|
|||
#if 1
|
||||
ctx->card_drivers[i++] = sc_get_tcos_driver();
|
||||
#endif
|
||||
#if 1 && defined(HAVE_OPENSSL)
|
||||
#if 0 && defined(HAVE_OPENSSL)
|
||||
ctx->card_drivers[i++] = sc_get_gpk_driver();
|
||||
#endif
|
||||
#if 1
|
||||
|
@ -345,6 +345,142 @@ const char *sc_strerror(int error)
|
|||
return errors[error];
|
||||
}
|
||||
|
||||
int sc_file_add_acl_entry(struct sc_file *file, unsigned int operation,
|
||||
unsigned int method, unsigned long key_ref)
|
||||
{
|
||||
struct sc_acl_entry *p, *new;
|
||||
|
||||
assert(file != NULL);
|
||||
assert(operation < SC_MAX_AC_OPS);
|
||||
|
||||
switch (method) {
|
||||
case SC_AC_NEVER:
|
||||
sc_file_clear_acl_entries(file, operation);
|
||||
file->acl[operation] = (struct sc_acl_entry *) 1;
|
||||
return 0;
|
||||
case SC_AC_NONE:
|
||||
sc_file_clear_acl_entries(file, operation);
|
||||
file->acl[operation] = (struct sc_acl_entry *) 2;
|
||||
return 0;
|
||||
case SC_AC_UNKNOWN:
|
||||
sc_file_clear_acl_entries(file, operation);
|
||||
file->acl[operation] = (struct sc_acl_entry *) 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new = malloc(sizeof(struct sc_acl_entry));
|
||||
if (new == NULL)
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
new->method = method;
|
||||
new->key_ref = key_ref;
|
||||
new->next = NULL;
|
||||
|
||||
p = file->acl[operation];
|
||||
if (p == NULL) {
|
||||
file->acl[operation] = new;
|
||||
return 0;
|
||||
}
|
||||
while (p->next != NULL)
|
||||
p = p->next;
|
||||
p->next = new;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct sc_acl_entry * sc_file_get_acl_entry(const struct sc_file *file,
|
||||
unsigned int operation)
|
||||
{
|
||||
struct sc_acl_entry *p;
|
||||
static const struct sc_acl_entry e_never = {
|
||||
SC_AC_NEVER, SC_AC_KEY_REF_NONE, NULL
|
||||
};
|
||||
static const struct sc_acl_entry e_none = {
|
||||
SC_AC_NONE, SC_AC_KEY_REF_NONE, NULL
|
||||
};
|
||||
static const struct sc_acl_entry e_unknown = {
|
||||
SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE, NULL
|
||||
};
|
||||
|
||||
assert(file != NULL);
|
||||
assert(operation < SC_MAX_AC_OPS);
|
||||
|
||||
p = file->acl[operation];
|
||||
if (p == (struct sc_acl_entry *) 1)
|
||||
return &e_never;
|
||||
if (p == (struct sc_acl_entry *) 2)
|
||||
return &e_none;
|
||||
if (p == (struct sc_acl_entry *) 3)
|
||||
return &e_unknown;
|
||||
|
||||
return file->acl[operation];
|
||||
}
|
||||
|
||||
void sc_file_clear_acl_entries(struct sc_file *file, unsigned int operation)
|
||||
{
|
||||
struct sc_acl_entry *e;
|
||||
|
||||
assert(file != NULL);
|
||||
assert(operation < SC_MAX_AC_OPS);
|
||||
|
||||
e = file->acl[operation];
|
||||
if (e == (struct sc_acl_entry *) 1 ||
|
||||
e == (struct sc_acl_entry *) 2 ||
|
||||
e == (struct sc_acl_entry *) 3) {
|
||||
file->acl[operation] = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
while (e != NULL) {
|
||||
struct sc_acl_entry *tmp = e->next;
|
||||
free(e);
|
||||
e = tmp;
|
||||
}
|
||||
file->acl[operation] = NULL;
|
||||
}
|
||||
|
||||
struct sc_file * sc_file_new()
|
||||
{
|
||||
struct sc_file *file = malloc(sizeof(struct sc_file));
|
||||
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
memset(file, 0, sizeof(struct sc_file));
|
||||
file->magic = SC_FILE_MAGIC;
|
||||
return file;
|
||||
}
|
||||
|
||||
void sc_file_free(struct sc_file *file)
|
||||
{
|
||||
int i;
|
||||
assert(sc_file_valid(file));
|
||||
file->magic = 0;
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
sc_file_clear_acl_entries(file, i);
|
||||
free(file);
|
||||
}
|
||||
|
||||
void sc_file_dup(struct sc_file **dest, const struct sc_file *src)
|
||||
{
|
||||
struct sc_file *newf;
|
||||
const struct sc_acl_entry *e;
|
||||
int op;
|
||||
|
||||
assert(sc_file_valid(src));
|
||||
*dest = NULL;
|
||||
newf = sc_file_new();
|
||||
if (newf == NULL)
|
||||
return;
|
||||
*dest = newf;
|
||||
|
||||
*newf = *src;
|
||||
for (op = 0; op < SC_MAX_AC_OPS; op++) {
|
||||
newf->acl[op] = NULL;
|
||||
e = sc_file_get_acl_entry(src, op);
|
||||
if (e != NULL)
|
||||
sc_file_add_acl_entry(newf, op, e->method, e->key_ref);
|
||||
}
|
||||
}
|
||||
|
||||
inline int sc_file_valid(const struct sc_file *file) {
|
||||
#ifndef NDEBUG
|
||||
assert(file != NULL);
|
||||
|
|
|
@ -3,16 +3,13 @@
|
|||
INCLUDES = @CFLAGS_PCSC@ @CFLAGS_OPENSC@
|
||||
LDFLAGS = @LDFLAGS@ @LIBOPENSC@
|
||||
|
||||
noinst_PROGRAMS = base64 hst-test lottery p15dump \
|
||||
pintest prngtest filetest
|
||||
noinst_PROGRAMS = base64 lottery p15dump pintest prngtest
|
||||
|
||||
SRC = sc-test.c
|
||||
INC = sc-test.h
|
||||
|
||||
base64_SOURCES = base64.c $(SRC) $(INC)
|
||||
hst_test_SOURCES = hst-test.c $(SRC) $(INC)
|
||||
lottery_SOURCES = lottery.c $(SRC) $(INC)
|
||||
p15dump_SOURCES = p15dump.c $(SRC) $(INC)
|
||||
pintest_SOURCES = pintest.c $(SRC) $(INC)
|
||||
prngtest_SOURCES = prngtest.c $(SRC) $(INC)
|
||||
filetest_SOURCES = filetest.c $(SRC) $(INC)
|
||||
|
|
|
@ -110,7 +110,7 @@ char *getpin(const char *prompt)
|
|||
int verify_pin(int pin)
|
||||
{
|
||||
char prompt[50];
|
||||
int r, type, tries_left = -1;
|
||||
int r, tries_left = -1;
|
||||
|
||||
if (pincode == NULL) {
|
||||
sprintf(prompt, "Please enter CHV%d: ", pin);
|
||||
|
@ -118,13 +118,9 @@ int verify_pin(int pin)
|
|||
if (pincode == NULL || strlen((char *) pincode) == 0)
|
||||
return -1;
|
||||
}
|
||||
if (pin == 1)
|
||||
type = SC_AC_CHV1;
|
||||
else if (pin == 2)
|
||||
type = SC_AC_CHV2;
|
||||
else
|
||||
if (pin != 1 && pin != 2)
|
||||
return -3;
|
||||
r = sc_verify(card, type, pin, pincode, 8, &tries_left);
|
||||
r = sc_verify(card, SC_AC_CHV, pin, pincode, 8, &tries_left);
|
||||
if (r) {
|
||||
memset(pincode, 0, 8);
|
||||
free(pincode);
|
||||
|
@ -138,7 +134,7 @@ int verify_pin(int pin)
|
|||
int select_app_df(void)
|
||||
{
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
char str[80];
|
||||
int r;
|
||||
|
||||
|
@ -151,10 +147,11 @@ int select_app_df(void)
|
|||
fprintf(stderr, "Unable to select application DF: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
if (file.type != SC_FILE_TYPE_DF) {
|
||||
if (file->type != SC_FILE_TYPE_DF) {
|
||||
fprintf(stderr, "Selected application DF is not a DF.\n");
|
||||
return -1;
|
||||
}
|
||||
sc_file_free(file);
|
||||
if (opt_pin_num >= 0)
|
||||
return verify_pin(opt_pin_num);
|
||||
else
|
||||
|
@ -335,7 +332,7 @@ int read_public_key(RSA *rsa)
|
|||
{
|
||||
int r;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
u8 buf[2048], *p = buf;
|
||||
size_t bufsize, keysize;
|
||||
|
||||
|
@ -348,7 +345,8 @@ int read_public_key(RSA *rsa)
|
|||
fprintf(stderr, "Unable to select public key file: %s\n", sc_strerror(r));
|
||||
return 2;
|
||||
}
|
||||
bufsize = file.size;
|
||||
bufsize = file->size;
|
||||
sc_file_free(file);
|
||||
r = sc_read_binary(card, 0, buf, bufsize, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Unable to read public key file: %s\n", sc_strerror(r));
|
||||
|
@ -380,7 +378,9 @@ int read_private_key(RSA *rsa)
|
|||
{
|
||||
int r;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
const struct sc_acl_entry *e;
|
||||
|
||||
u8 buf[2048], *p = buf;
|
||||
size_t bufsize, keysize;
|
||||
|
||||
|
@ -393,9 +393,11 @@ int read_private_key(RSA *rsa)
|
|||
fprintf(stderr, "Unable to select private key file: %s\n", sc_strerror(r));
|
||||
return 2;
|
||||
}
|
||||
if (file.acl[SC_AC_OP_READ] == SC_AC_NEVER)
|
||||
e = sc_file_get_acl_entry(file, SC_AC_OP_READ);
|
||||
if (e == NULL || e->method == SC_AC_NEVER)
|
||||
return 10;
|
||||
bufsize = file.size;
|
||||
bufsize = file->size;
|
||||
sc_file_free(file);
|
||||
r = sc_read_binary(card, 0, buf, bufsize, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Unable to read private key file: %s\n", sc_strerror(r));
|
||||
|
@ -471,7 +473,6 @@ int list_keys(void)
|
|||
{
|
||||
int r, i, idx = 0;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
u8 buf[2048], *p = buf;
|
||||
size_t keysize;
|
||||
int mod_lens[] = { 512, 768, 1024, 2048 };
|
||||
|
@ -481,7 +482,7 @@ int list_keys(void)
|
|||
if (r)
|
||||
return 1;
|
||||
sc_format_path("I1012", &path);
|
||||
r = sc_select_file(card, &path, &file);
|
||||
r = sc_select_file(card, &path, NULL);
|
||||
if (r) {
|
||||
fprintf(stderr, "Unable to select public key file: %s\n", sc_strerror(r));
|
||||
return 2;
|
||||
|
@ -568,7 +569,7 @@ int generate_key(void)
|
|||
|
||||
int create_key_files(void)
|
||||
{
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
int mod_lens[] = { 512, 768, 1024, 2048 };
|
||||
int sizes[] = { 163, 243, 323, 643 };
|
||||
int size = -1;
|
||||
|
@ -587,35 +588,41 @@ int create_key_files(void)
|
|||
if (!quiet)
|
||||
printf("Creating key files for %d keys.\n", opt_key_count);
|
||||
|
||||
memset(&file, 0, sizeof(file));
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
file.acl[i] = SC_AC_NONE;
|
||||
file.type = SC_FILE_TYPE_WORKING_EF;
|
||||
file.ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||
file = sc_file_new();
|
||||
file->type = SC_FILE_TYPE_WORKING_EF;
|
||||
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||
|
||||
file->id = 0x0012;
|
||||
file->size = opt_key_count * size + 3;
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 1);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_INVALIDATE, SC_AC_CHV, 1);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_REHABILITATE, SC_AC_CHV, 1);
|
||||
|
||||
file.id = 0x0012;
|
||||
file.size = opt_key_count * size + 3;
|
||||
file.acl[SC_AC_OP_READ] = SC_AC_NEVER;
|
||||
file.acl[SC_AC_OP_UPDATE] = SC_AC_CHV1;
|
||||
file.acl[SC_AC_OP_INVALIDATE] = SC_AC_CHV1;
|
||||
file.acl[SC_AC_OP_REHABILITATE] = SC_AC_CHV1;
|
||||
|
||||
if (select_app_df())
|
||||
return 1;
|
||||
r = sc_create_file(card, &file);
|
||||
r = sc_create_file(card, file);
|
||||
sc_file_free(file);
|
||||
if (r) {
|
||||
fprintf(stderr, "Unable to create private key file: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
file.id = 0x1012;
|
||||
file.size = opt_key_count * (size + 4) + 3;
|
||||
file.acl[SC_AC_OP_READ] = SC_AC_NONE;
|
||||
file.acl[SC_AC_OP_UPDATE] = SC_AC_CHV1;
|
||||
file.acl[SC_AC_OP_INVALIDATE] = SC_AC_CHV1;
|
||||
file.acl[SC_AC_OP_REHABILITATE] = SC_AC_CHV1;
|
||||
|
||||
file = sc_file_new();
|
||||
file->type = SC_FILE_TYPE_WORKING_EF;
|
||||
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||
|
||||
file->id = 0x1012;
|
||||
file->size = opt_key_count * (size + 4) + 3;
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, SC_AC_KEY_REF_NONE);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 1);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_INVALIDATE, SC_AC_CHV, 1);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_REHABILITATE, SC_AC_CHV, 1);
|
||||
|
||||
if (select_app_df())
|
||||
return 1;
|
||||
r = sc_create_file(card, &file);
|
||||
r = sc_create_file(card, file);
|
||||
sc_file_free(file);
|
||||
if (r) {
|
||||
fprintf(stderr, "Unable to create public key file: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
|
@ -785,13 +792,12 @@ int update_public_key(const u8 *key, size_t keysize)
|
|||
{
|
||||
int r, idx = 0;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
|
||||
r = select_app_df();
|
||||
if (r)
|
||||
return 1;
|
||||
sc_format_path("I1012", &path);
|
||||
r = sc_select_file(card, &path, &file);
|
||||
r = sc_select_file(card, &path, NULL);
|
||||
if (r) {
|
||||
fprintf(stderr, "Unable to select public key file: %s\n", sc_strerror(r));
|
||||
return 2;
|
||||
|
@ -809,13 +815,12 @@ int update_private_key(const u8 *key, size_t keysize)
|
|||
{
|
||||
int r, idx = 0;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
|
||||
r = select_app_df();
|
||||
if (r)
|
||||
return 1;
|
||||
sc_format_path("I0012", &path);
|
||||
r = sc_select_file(card, &path, &file);
|
||||
r = sc_select_file(card, &path, NULL);
|
||||
if (r) {
|
||||
fprintf(stderr, "Unable to select private key file: %s\n", sc_strerror(r));
|
||||
return 2;
|
||||
|
@ -897,39 +902,46 @@ int create_file(struct sc_file *file)
|
|||
|
||||
int create_app_df(struct sc_path *path, size_t size)
|
||||
{
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
int i;
|
||||
|
||||
memset(&file, 0, sizeof(file));
|
||||
file.type = SC_FILE_TYPE_DF;
|
||||
file.size = size;
|
||||
file.path = *path;
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
file.acl[i] = SC_AC_NONE;
|
||||
file.acl[SC_AC_OP_CREATE] = SC_AC_CHV2;
|
||||
file.acl[SC_AC_OP_DELETE] = SC_AC_CHV2;
|
||||
file.status = SC_FILE_STATUS_ACTIVATED;
|
||||
return create_file(&file);
|
||||
file = sc_file_new();
|
||||
|
||||
file->type = SC_FILE_TYPE_DF;
|
||||
file->size = size;
|
||||
file->path = *path;
|
||||
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES, SC_AC_NONE, SC_AC_KEY_REF_NONE);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, 2);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_DELETE, SC_AC_CHV, 2);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_INVALIDATE, SC_AC_CHV, 2);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_REHABILITATE, SC_AC_CHV, 2);
|
||||
|
||||
file->status = SC_FILE_STATUS_ACTIVATED;
|
||||
|
||||
i = create_file(file);
|
||||
sc_file_free(file);
|
||||
return i;
|
||||
}
|
||||
|
||||
int new_pkcs15_df(struct sc_pkcs15_card *p15card, int df_type, struct sc_file *file)
|
||||
{
|
||||
struct sc_pkcs15_df *df = &p15card->df[df_type];
|
||||
struct sc_file *newfile;
|
||||
struct sc_file *newfile = NULL;
|
||||
int c = df->count;
|
||||
|
||||
if (c >= SC_PKCS15_MAX_DFS)
|
||||
return -1;
|
||||
file->acl[SC_AC_OP_UPDATE] = SC_AC_CHV2;
|
||||
file->acl[SC_AC_OP_INVALIDATE] = SC_AC_NEVER;
|
||||
file->acl[SC_AC_OP_REHABILITATE] = SC_AC_NEVER;
|
||||
newfile = malloc(sizeof(struct sc_file));
|
||||
sc_file_dup(&newfile, file);
|
||||
if (newfile == NULL)
|
||||
return -1;
|
||||
sc_file_add_acl_entry(newfile, SC_AC_OP_LIST_FILES, SC_AC_NONE, SC_AC_KEY_REF_NONE);
|
||||
sc_file_add_acl_entry(newfile, SC_AC_OP_UPDATE, SC_AC_CHV, 2);
|
||||
sc_file_add_acl_entry(newfile, SC_AC_OP_INVALIDATE, SC_AC_CHV, 2);
|
||||
sc_file_add_acl_entry(newfile, SC_AC_OP_REHABILITATE, SC_AC_CHV, 2);
|
||||
df->file[c] = newfile;
|
||||
memcpy(newfile, file, sizeof(struct sc_file));
|
||||
|
||||
df->count++;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -938,9 +950,9 @@ int create_pin_file(const struct sc_path *inpath, int chv, const char *key_id)
|
|||
char prompt[40], *pin, *puk;
|
||||
char buf[30], *p = buf;
|
||||
struct sc_path file_id, path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
size_t len;
|
||||
int r, i;
|
||||
int r;
|
||||
|
||||
file_id = *inpath;
|
||||
if (file_id.len < 2)
|
||||
|
@ -1014,21 +1026,23 @@ int create_pin_file(const struct sc_path *inpath, int chv, const char *key_id)
|
|||
*p++ = opt_puk_attempts;
|
||||
*p++ = opt_puk_attempts;
|
||||
len = p - buf;
|
||||
file.type = SC_FILE_TYPE_WORKING_EF;
|
||||
file.ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
file.acl[i] = SC_AC_NONE;
|
||||
file.acl[SC_AC_OP_READ] = SC_AC_NEVER;
|
||||
|
||||
file = sc_file_new();
|
||||
file->type = SC_FILE_TYPE_WORKING_EF;
|
||||
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
|
||||
if (inpath->len == 2 && inpath->value[0] == 0x3F &&
|
||||
inpath->value[1] == 0x00)
|
||||
file.acl[SC_AC_OP_UPDATE] = SC_AC_AUT | SC_AC_KEY_NUM_1;
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_AUT, 1);
|
||||
else
|
||||
file.acl[SC_AC_OP_UPDATE] = SC_AC_CHV2;
|
||||
file.acl[SC_AC_OP_INVALIDATE] = SC_AC_AUT | SC_AC_KEY_NUM_1;
|
||||
file.acl[SC_AC_OP_REHABILITATE] = SC_AC_AUT | SC_AC_KEY_NUM_1;
|
||||
file.size = len;
|
||||
file.id = (file_id.value[0] << 8) | file_id.value[1];
|
||||
r = sc_create_file(card, &file);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 2);
|
||||
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_INVALIDATE, SC_AC_AUT, 1);
|
||||
sc_file_add_acl_entry(file, SC_AC_OP_REHABILITATE, SC_AC_AUT, 1);
|
||||
file->size = len;
|
||||
file->id = (file_id.value[0] << 8) | file_id.value[1];
|
||||
r = sc_create_file(card, file);
|
||||
sc_file_free(file);
|
||||
if (r) {
|
||||
fprintf(stderr, "PIN file creation failed: %s\n", sc_strerror(r));
|
||||
return r;
|
||||
|
@ -1071,12 +1085,12 @@ int add_object(struct sc_pkcs15_card *p15card,
|
|||
int create_pkcs15()
|
||||
{
|
||||
struct sc_pkcs15_card *p15card;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
struct sc_path path;
|
||||
struct sc_pkcs15_cert_info cert;
|
||||
struct sc_pkcs15_pin_info pin;
|
||||
struct sc_pkcs15_prkey_info prkey;
|
||||
int i, r, file_no;
|
||||
int r, file_no;
|
||||
|
||||
p15card = sc_pkcs15_card_new();
|
||||
if (p15card == NULL)
|
||||
|
@ -1086,34 +1100,37 @@ int create_pkcs15()
|
|||
p15card->serial_number = strdup("1234");
|
||||
p15card->flags = SC_PKCS15_CARD_FLAG_EID_COMPLIANT;
|
||||
p15card->version = 1;
|
||||
sc_format_path("3F005015", &p15card->file_app.path);
|
||||
p15card->file_app = sc_file_new();
|
||||
sc_format_path("3F005015", &p15card->file_app->path);
|
||||
p15card->card = card;
|
||||
memset(&file, 0, sizeof(file));
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
file.acl[i] = SC_AC_NONE;
|
||||
file.size = 32;
|
||||
|
||||
sc_format_path("3F0050155031", &file.path);
|
||||
p15card->file_tokeninfo = file;
|
||||
file = sc_file_new();
|
||||
file->size = 32; /* reserve 32 additional bytes in each DF */
|
||||
|
||||
sc_format_path("3F0050155031", &file.path);
|
||||
p15card->file_odf = file;
|
||||
sc_format_path("3F0050155032", &file->path);
|
||||
sc_file_dup(&p15card->file_tokeninfo, file);
|
||||
|
||||
sc_format_path("3F0050154403", &file.path);
|
||||
file_no = new_pkcs15_df(p15card, SC_PKCS15_CDF, &file);
|
||||
sc_format_path("3F0050155031", &file->path);
|
||||
sc_file_dup(&p15card->file_odf, file);
|
||||
|
||||
sc_format_path("3F0050154403", &file->path);
|
||||
file_no = new_pkcs15_df(p15card, SC_PKCS15_CDF, file);
|
||||
if (file_no < 0)
|
||||
return 1;
|
||||
|
||||
sc_format_path("3F0050154402", &file.path);
|
||||
file_no = new_pkcs15_df(p15card, SC_PKCS15_PRKDF, &file);
|
||||
sc_format_path("3F0050154402", &file->path);
|
||||
file_no = new_pkcs15_df(p15card, SC_PKCS15_PRKDF, file);
|
||||
if (file_no < 0)
|
||||
return 1;
|
||||
|
||||
sc_format_path("3F0050154401", &file.path);
|
||||
file_no = new_pkcs15_df(p15card, SC_PKCS15_AODF, &file);
|
||||
sc_format_path("3F0050154401", &file->path);
|
||||
file_no = new_pkcs15_df(p15card, SC_PKCS15_AODF, file);
|
||||
if (file_no < 0)
|
||||
return 1;
|
||||
|
||||
sc_file_free(file);
|
||||
file = NULL;
|
||||
|
||||
memset(&cert, 0, sizeof(cert));
|
||||
strcpy(cert.com_attr.label, "Authentication certificate");
|
||||
sc_pkcs15_format_id("45", &cert.id);
|
||||
|
@ -1180,12 +1197,12 @@ int create_pkcs15()
|
|||
add_object(p15card, &p15card->df[SC_PKCS15_AODF], file_no,
|
||||
SC_PKCS15_TYPE_AUTH_PIN, &pin, sizeof(pin)),
|
||||
|
||||
r = create_app_df(&p15card->file_app.path, 5000);
|
||||
r = create_app_df(&p15card->file_app->path, 5000);
|
||||
if (r) {
|
||||
fprintf(stderr, "Unable to create app DF: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
r = create_pin_file(&p15card->file_app.path, 1, " (key 1)");
|
||||
r = create_pin_file(&p15card->file_app->path, 1, " (key 1)");
|
||||
if (r)
|
||||
return 1;
|
||||
sc_format_path("3F004B02", &path);
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
int opt_reader = 0, opt_debug = 0;
|
||||
const char *opt_driver = NULL;
|
||||
|
||||
struct sc_file current_file;
|
||||
struct sc_file *current_file = NULL;
|
||||
struct sc_path current_path;
|
||||
struct sc_context *ctx = NULL;
|
||||
struct sc_card *card = NULL;
|
||||
|
@ -68,6 +68,8 @@ const int nr_cmds = sizeof(cmds)/sizeof(cmds[0]);
|
|||
|
||||
void die(int ret)
|
||||
{
|
||||
if (current_file != NULL)
|
||||
sc_file_free(current_file);
|
||||
if (card) {
|
||||
sc_unlock(card);
|
||||
sc_disconnect_card(card);
|
||||
|
@ -100,10 +102,10 @@ void check_ret(int r, int op, const char *err, const struct sc_file *file)
|
|||
{
|
||||
fprintf(stderr, "%s: %s\n", err, sc_strerror(r));
|
||||
if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
|
||||
fprintf(stderr, "ACL for operation: %s\n", acl_to_str(file->acl[op]));
|
||||
fprintf(stderr, "ACL for operation: %s\n", acl_to_str(sc_file_get_acl_entry(file, op)));
|
||||
}
|
||||
|
||||
int arg_to_path(const char *arg, struct sc_path *path)
|
||||
int arg_to_path(const char *arg, struct sc_path *path, int is_id)
|
||||
{
|
||||
int buf[2];
|
||||
u8 cbuf[2];
|
||||
|
@ -118,10 +120,13 @@ int arg_to_path(const char *arg, struct sc_path *path)
|
|||
}
|
||||
cbuf[0] = buf[0];
|
||||
cbuf[1] = buf[1];
|
||||
if (cbuf[0] == 0x3F && cbuf[1] == 0x00) {
|
||||
if ((cbuf[0] == 0x3F && cbuf[1] == 0x00) || is_id) {
|
||||
path->len = 2;
|
||||
memcpy(path->value, cbuf, 2);
|
||||
path->type = SC_PATH_TYPE_PATH;
|
||||
if (is_id)
|
||||
path->type = SC_PATH_TYPE_FILE_ID;
|
||||
else
|
||||
path->type = SC_PATH_TYPE_PATH;
|
||||
} else {
|
||||
*path = current_path;
|
||||
sc_append_path_id(path, cbuf, 2);
|
||||
|
@ -174,26 +179,27 @@ int do_ls()
|
|||
|
||||
r = sc_list_files(card, buf, sizeof(buf));
|
||||
if (r < 0) {
|
||||
check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", ¤t_file);
|
||||
check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", current_file);
|
||||
return -1;
|
||||
}
|
||||
count = r;
|
||||
printf("FileID\tType Size\n");
|
||||
while (count >= 2) {
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file = NULL;
|
||||
|
||||
path = current_path;
|
||||
sc_append_path_id(&path, cur, 2);
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", ¤t_file);
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
||||
return -1;
|
||||
}
|
||||
file.id = (cur[0] << 8) | cur[1];
|
||||
file->id = (cur[0] << 8) | cur[1];
|
||||
cur += 2;
|
||||
count -= 2;
|
||||
print_file(&file);
|
||||
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));
|
||||
|
@ -206,7 +212,7 @@ int do_ls()
|
|||
int do_cd(const char *arg)
|
||||
{
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
int r;
|
||||
|
||||
if (strcmp(arg, "..") == 0) {
|
||||
|
@ -216,25 +222,28 @@ int do_cd(const char *arg)
|
|||
}
|
||||
path = current_path;
|
||||
path.len -= 2;
|
||||
r = sc_select_file(card, &path, ¤t_file);
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
printf("unable to go up: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
sc_file_free(current_file);
|
||||
current_file = file;
|
||||
current_path = path;
|
||||
return 0;
|
||||
}
|
||||
if (arg_to_path(arg, &path) != 0) {
|
||||
if (arg_to_path(arg, &path, 0) != 0) {
|
||||
printf("Usage: cd <file_id>\n");
|
||||
return -1;
|
||||
}
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select DF", ¤t_file);
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select DF", current_file);
|
||||
return -1;
|
||||
}
|
||||
if (file.type != SC_FILE_TYPE_DF) {
|
||||
if (file->type != SC_FILE_TYPE_DF) {
|
||||
printf("Error: file is not a DF.\n");
|
||||
sc_file_free(file);
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent file: %s\n", sc_strerror(r));
|
||||
|
@ -243,7 +252,8 @@ int do_cd(const char *arg)
|
|||
return -1;
|
||||
}
|
||||
current_path = path;
|
||||
current_file = file;
|
||||
sc_file_free(current_file);
|
||||
current_file = file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -299,7 +309,7 @@ int do_cat(const char *arg)
|
|||
{
|
||||
int r, error = 0;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
int not_current = 1;
|
||||
|
||||
if (strlen(arg) == 0) {
|
||||
|
@ -307,21 +317,22 @@ int do_cat(const char *arg)
|
|||
file = current_file;
|
||||
not_current = 0;
|
||||
} else {
|
||||
if (arg_to_path(arg, &path) != 0) {
|
||||
if (arg_to_path(arg, &path, 0) != 0) {
|
||||
printf("Usage: cat [file_id]\n");
|
||||
return -1;
|
||||
}
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", ¤t_file);
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (file.ef_structure == SC_FILE_EF_TRANSPARENT)
|
||||
read_and_print_binary_file(&file);
|
||||
if (file->ef_structure == SC_FILE_EF_TRANSPARENT)
|
||||
read_and_print_binary_file(file);
|
||||
else
|
||||
read_and_print_record_file(&file);
|
||||
read_and_print_record_file(file);
|
||||
if (not_current) {
|
||||
sc_file_free(file);
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent file: %s\n", sc_strerror(r));
|
||||
|
@ -333,7 +344,7 @@ int do_cat(const char *arg)
|
|||
|
||||
int do_info(const char *arg)
|
||||
{
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
struct sc_path path;
|
||||
int r, i;
|
||||
const char *st;
|
||||
|
@ -344,7 +355,7 @@ int do_info(const char *arg)
|
|||
file = current_file;
|
||||
not_current = 0;
|
||||
} else {
|
||||
if (arg_to_path(arg, &path) != 0) {
|
||||
if (arg_to_path(arg, &path, 0) != 0) {
|
||||
printf("Usage: info [file_id]\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -354,7 +365,7 @@ int do_info(const char *arg)
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
switch (file.type) {
|
||||
switch (file->type) {
|
||||
case SC_FILE_TYPE_WORKING_EF:
|
||||
case SC_FILE_TYPE_INTERNAL_EF:
|
||||
st = "Elementary File";
|
||||
|
@ -366,7 +377,7 @@ int do_info(const char *arg)
|
|||
st = "Unknown File";
|
||||
break;
|
||||
}
|
||||
printf("\n%s ID %04X\n\n", st, file.id);
|
||||
printf("\n%s ID %04X\n\n", st, file->id);
|
||||
printf("%-15s", "File path:");
|
||||
for (i = 0; i < path.len; i++) {
|
||||
for (i = 0; i < path.len; i++) {
|
||||
|
@ -375,23 +386,23 @@ int do_info(const char *arg)
|
|||
printf("%02X", path.value[i]);
|
||||
}
|
||||
}
|
||||
printf("\n%-15s%d bytes\n", "File size:", file.size);
|
||||
printf("\n%-15s%d bytes\n", "File size:", file->size);
|
||||
|
||||
if (file.type == SC_FILE_TYPE_DF) {
|
||||
if (file->type == SC_FILE_TYPE_DF) {
|
||||
const char *ops[] = {
|
||||
"SELECT", "LOCK", "DELETE", "CREATE", "REHABILITATE",
|
||||
"INVALIDATE", "LIST FILES"
|
||||
};
|
||||
if (file.namelen) {
|
||||
if (file->namelen) {
|
||||
printf("%-15s", "DF name:");
|
||||
print_binary(stdout, file.name, file.namelen);
|
||||
print_binary(stdout, file->name, file->namelen);
|
||||
printf("\n");
|
||||
}
|
||||
for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
|
||||
char buf[80];
|
||||
|
||||
sprintf(buf, "ACL for %s:", ops[i]);
|
||||
printf("%-25s%s\n", buf, acl_to_str(file.acl[i]));
|
||||
printf("%-25s%s\n", buf, acl_to_str(sc_file_get_acl_entry(file, i)));
|
||||
}
|
||||
} else {
|
||||
const char *structs[] = {
|
||||
|
@ -403,28 +414,29 @@ int do_info(const char *arg)
|
|||
"READ", "UPDATE", "WRITE", "ERASE", "REHABILITATE",
|
||||
"INVALIDATE"
|
||||
};
|
||||
printf("%-15s%s\n", "EF structure:", structs[file.ef_structure]);
|
||||
printf("%-15s%s\n", "EF structure:", structs[file->ef_structure]);
|
||||
for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
|
||||
char buf[80];
|
||||
|
||||
sprintf(buf, "ACL for %s:", ops[i]);
|
||||
printf("%-25s%s\n", buf, acl_to_str(file.acl[i]));
|
||||
printf("%-25s%s\n", buf, acl_to_str(sc_file_get_acl_entry(file, i)));
|
||||
}
|
||||
}
|
||||
if (file.prop_attr_len) {
|
||||
if (file->prop_attr_len) {
|
||||
printf("%-25s", "Proprietary attributes:");
|
||||
for (i = 0; i < file.prop_attr_len; i++)
|
||||
printf("%02X ", file.prop_attr[i]);
|
||||
for (i = 0; i < file->prop_attr_len; i++)
|
||||
printf("%02X ", file->prop_attr[i]);
|
||||
printf("\n");
|
||||
}
|
||||
if (file.sec_attr_len) {
|
||||
if (file->sec_attr_len) {
|
||||
printf("%-25s", "Security attributes:");
|
||||
for (i = 0; i < file.sec_attr_len; i++)
|
||||
printf("%02X ", file.sec_attr[i]);
|
||||
for (i = 0; i < file->sec_attr_len; i++)
|
||||
printf("%02X ", file->sec_attr[i]);
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
if (not_current) {
|
||||
sc_file_free(file);
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent file: %s\n", sc_strerror(r));
|
||||
|
@ -440,7 +452,7 @@ int create_file(struct sc_file *file)
|
|||
|
||||
r = sc_create_file(card, file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_CREATE, "CREATE FILE failed", ¤t_file);
|
||||
check_ret(r, SC_AC_OP_CREATE, "CREATE FILE failed", current_file);
|
||||
return -1;
|
||||
}
|
||||
/* Make sure we're back in the parent directory, because on some cards
|
||||
|
@ -456,25 +468,25 @@ int create_file(struct sc_file *file)
|
|||
int do_create(const char *arg, const char *arg2)
|
||||
{
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
unsigned int size;
|
||||
int i;
|
||||
int r;
|
||||
|
||||
if (arg_to_path(arg, &path) != 0)
|
||||
if (arg_to_path(arg, &path, 1) != 0)
|
||||
goto usage;
|
||||
/* %z isn't supported everywhere */
|
||||
if (sscanf(arg2, "%d", &size) != 1)
|
||||
goto usage;
|
||||
memset(&file, 0, sizeof(file));
|
||||
file.id = (path.value[0] << 8) | path.value[1];
|
||||
file.type = SC_FILE_TYPE_WORKING_EF;
|
||||
file.ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
file.acl[i] = SC_AC_NONE;
|
||||
file.size = (size_t) size;
|
||||
file.status = SC_FILE_STATUS_ACTIVATED;
|
||||
file = sc_file_new();
|
||||
file->id = (path.value[0] << 8) | path.value[1];
|
||||
file->type = SC_FILE_TYPE_WORKING_EF;
|
||||
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||
file->size = (size_t) size;
|
||||
file->status = SC_FILE_STATUS_ACTIVATED;
|
||||
|
||||
return create_file(&file);
|
||||
r = create_file(file);
|
||||
sc_file_free(file);
|
||||
return r;
|
||||
usage:
|
||||
printf("Usage: create <file_id> <file_size>\n");
|
||||
return -1;
|
||||
|
@ -483,23 +495,23 @@ usage:
|
|||
int do_mkdir(const char *arg, const char *arg2)
|
||||
{
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
unsigned int size;
|
||||
int i;
|
||||
int r;
|
||||
|
||||
if (arg_to_path(arg, &path) != 0)
|
||||
if (arg_to_path(arg, &path, 1) != 0)
|
||||
goto usage;
|
||||
if (sscanf(arg2, "%d", &size) != 1)
|
||||
goto usage;
|
||||
memset(&file, 0, sizeof(file));
|
||||
file.id = (path.value[0] << 8) | path.value[1];
|
||||
file.type = SC_FILE_TYPE_DF;
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
file.acl[i] = SC_AC_NONE;
|
||||
file.size = size;
|
||||
file.status = SC_FILE_STATUS_ACTIVATED;
|
||||
|
||||
return create_file(&file);
|
||||
file = sc_file_new();
|
||||
file->id = (path.value[0] << 8) | path.value[1];
|
||||
file->type = SC_FILE_TYPE_DF;
|
||||
file->size = size;
|
||||
file->status = SC_FILE_STATUS_ACTIVATED;
|
||||
|
||||
r = create_file(file);
|
||||
sc_file_free(file);
|
||||
return r;
|
||||
usage:
|
||||
printf("Usage: mkdir <file_id> <df_size>\n");
|
||||
return -1;
|
||||
|
@ -510,11 +522,14 @@ int do_delete(const char *arg)
|
|||
struct sc_path path;
|
||||
int r;
|
||||
|
||||
if (arg_to_path(arg, &path) != 0)
|
||||
if (arg_to_path(arg, &path, 1) != 0)
|
||||
goto usage;
|
||||
if (path.len != 2)
|
||||
goto usage;
|
||||
path.type = SC_PATH_TYPE_FILE_ID;
|
||||
r = sc_delete_file(card, &path);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_DELETE, "DELETE FILE failed", ¤t_file);
|
||||
check_ret(r, SC_AC_OP_DELETE, "DELETE FILE failed", current_file);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -558,7 +573,7 @@ int do_verify(const char *arg, const char *arg2)
|
|||
}
|
||||
switch (type) {
|
||||
case 0:
|
||||
type = SC_AC_CHV1;
|
||||
type = SC_AC_CHV;
|
||||
break;
|
||||
case 1:
|
||||
type = SC_AC_AUT;
|
||||
|
@ -596,11 +611,11 @@ int do_get(const char *arg, const char *arg2)
|
|||
size_t count = 0;
|
||||
unsigned int idx = 0;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
const char *filename;
|
||||
FILE *outf = NULL;
|
||||
|
||||
if (arg_to_path(arg, &path) != 0)
|
||||
if (arg_to_path(arg, &path, 0) != 0)
|
||||
goto usage;
|
||||
if (strlen(arg2))
|
||||
filename = arg2;
|
||||
|
@ -615,16 +630,16 @@ int do_get(const char *arg, const char *arg2)
|
|||
}
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", ¤t_file);
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
||||
return -1;
|
||||
}
|
||||
count = file.size;
|
||||
count = file->size;
|
||||
while (count) {
|
||||
int c = count > sizeof(buf) ? sizeof(buf) : count;
|
||||
|
||||
r = sc_read_binary(card, idx, buf, c, 0);
|
||||
if (r < 0) {
|
||||
check_ret(r, SC_AC_OP_READ, "read failed", &file);
|
||||
check_ret(r, SC_AC_OP_READ, "read failed", file);
|
||||
error = 1;
|
||||
goto err;
|
||||
}
|
||||
|
@ -639,6 +654,7 @@ int do_get(const char *arg, const char *arg2)
|
|||
}
|
||||
printf("Total of %d bytes read.\n", idx);
|
||||
err:
|
||||
sc_file_free(file);
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent file: %s\n", sc_strerror(r));
|
||||
|
@ -659,11 +675,11 @@ int do_put(const char *arg, const char *arg2)
|
|||
size_t count = 0;
|
||||
unsigned int idx = 0;
|
||||
struct sc_path path;
|
||||
struct sc_file file;
|
||||
struct sc_file *file;
|
||||
const char *filename;
|
||||
FILE *outf = NULL;
|
||||
|
||||
if (arg_to_path(arg, &path) != 0)
|
||||
if (arg_to_path(arg, &path, 0) != 0)
|
||||
goto usage;
|
||||
if (strlen(arg2))
|
||||
filename = arg2;
|
||||
|
@ -678,10 +694,10 @@ int do_put(const char *arg, const char *arg2)
|
|||
}
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", ¤t_file);
|
||||
check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
|
||||
return -1;
|
||||
}
|
||||
count = file.size;
|
||||
count = file->size;
|
||||
while (count) {
|
||||
int c = count > sizeof(buf) ? sizeof(buf) : count;
|
||||
|
||||
|
@ -695,7 +711,7 @@ int do_put(const char *arg, const char *arg2)
|
|||
count = c = r;
|
||||
r = sc_update_binary(card, idx, buf, c, 0);
|
||||
if (r < 0) {
|
||||
check_ret(r, SC_AC_OP_READ, "update failed", &file);
|
||||
check_ret(r, SC_AC_OP_READ, "update failed", file);
|
||||
error = 1;
|
||||
goto err;
|
||||
}
|
||||
|
@ -709,6 +725,7 @@ int do_put(const char *arg, const char *arg2)
|
|||
}
|
||||
printf("Total of %d bytes written.\n", idx);
|
||||
err:
|
||||
sc_file_free(file);
|
||||
r = sc_select_file(card, ¤t_path, NULL);
|
||||
if (r) {
|
||||
printf("unable to select parent file: %s\n", sc_strerror(r));
|
||||
|
@ -888,7 +905,7 @@ int main(int argc, char * const argv[])
|
|||
}
|
||||
|
||||
sc_format_path("3F00", ¤t_path);
|
||||
r = sc_select_file(card, ¤t_path, ¤t_file);
|
||||
r = sc_select_file(card, ¤t_path, ¤t_file);
|
||||
if (r) {
|
||||
printf("unable to select MF: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
|
|
|
@ -192,19 +192,19 @@ int print_file(struct sc_card *card, const struct sc_file *file, const struct sc
|
|||
|
||||
int enum_dir(struct sc_path path, int depth)
|
||||
{
|
||||
struct sc_file file;
|
||||
int r;
|
||||
struct sc_file *file;
|
||||
int r, file_type;
|
||||
u8 files[MAX_BUFFER_SIZE];
|
||||
|
||||
file.magic = 0; /* make sure the file is invalid */
|
||||
r = sc_select_file(card, &path, &file);
|
||||
if (r) {
|
||||
fprintf(stderr, "SELECT FILE failed: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
if (sc_file_valid(&file))
|
||||
print_file(card, &file, &path, depth);
|
||||
if (!sc_file_valid(&file) || file.type == SC_FILE_TYPE_DF) {
|
||||
print_file(card, file, &path, depth);
|
||||
file_type = file->type;
|
||||
sc_file_free(file);
|
||||
if (file->type == SC_FILE_TYPE_DF) {
|
||||
int i;
|
||||
|
||||
r = sc_list_files(card, files, sizeof(files));
|
||||
|
|
|
@ -290,7 +290,8 @@ int change_pin(void)
|
|||
|
||||
int read_and_cache_file(const struct sc_path *path)
|
||||
{
|
||||
struct sc_file tmpfile;
|
||||
struct sc_file *tmpfile;
|
||||
const struct sc_acl_entry *e;
|
||||
u8 buf[16384];
|
||||
int r;
|
||||
|
||||
|
@ -304,21 +305,23 @@ int read_and_cache_file(const struct sc_path *path)
|
|||
fprintf(stderr, "sc_select_file() failed: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
if (tmpfile.acl[SC_AC_OP_READ] != SC_AC_NONE) {
|
||||
e = sc_file_get_acl_entry(tmpfile, SC_AC_OP_READ);
|
||||
if (e != NULL && e->method != SC_AC_NONE) {
|
||||
if (!quiet)
|
||||
printf("Skipping; ACL for read operation is not NONE.\n");
|
||||
return -1;
|
||||
}
|
||||
r = sc_read_binary(card, 0, buf, tmpfile.size, 0);
|
||||
r = sc_read_binary(card, 0, buf, tmpfile->size, 0);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "sc_read_binary() failed: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
r = sc_pkcs15_cache_file(p15card, path, buf, tmpfile.size);
|
||||
r = sc_pkcs15_cache_file(p15card, path, buf, tmpfile->size);
|
||||
if (r) {
|
||||
fprintf(stderr, "Unable to cache file: %s\n", sc_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
sc_file_free(tmpfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,28 +94,48 @@ void print_usage_and_die(const char *pgmname)
|
|||
exit(2);
|
||||
}
|
||||
|
||||
const char * acl_to_str(unsigned int acl)
|
||||
const char * acl_to_str(const struct sc_acl_entry *e)
|
||||
{
|
||||
static char line[80];
|
||||
static char line[80], buf[10];
|
||||
unsigned int acl;
|
||||
|
||||
if (acl == SC_AC_UNKNOWN)
|
||||
if (e == NULL)
|
||||
return "N/A";
|
||||
if (acl == SC_AC_NEVER)
|
||||
return "NEVR";
|
||||
if (acl == SC_AC_NONE)
|
||||
return "NONE";
|
||||
line[0] = 0;
|
||||
if (acl & SC_AC_CHV1)
|
||||
strcat(line, "CHV1 ");
|
||||
if (acl & SC_AC_CHV2)
|
||||
strcat(line, "CHV2 ");
|
||||
if (acl & SC_AC_TERM)
|
||||
strcat(line, "TERM ");
|
||||
if (acl & SC_AC_PRO)
|
||||
strcat(line, "PROT ");
|
||||
if (acl & SC_AC_AUT)
|
||||
strcat(line, "AUTH ");
|
||||
|
||||
while (e != NULL) {
|
||||
acl = e->method;
|
||||
|
||||
switch (acl) {
|
||||
case SC_AC_UNKNOWN:
|
||||
return "N/A";
|
||||
case SC_AC_NEVER:
|
||||
return "NEVR";
|
||||
case SC_AC_NONE:
|
||||
return "NONE";
|
||||
case SC_AC_CHV:
|
||||
strcpy(buf, "CHV");
|
||||
if (e->key_ref != SC_AC_KEY_REF_NONE)
|
||||
sprintf(buf + 3, "%d", e->key_ref);
|
||||
break;
|
||||
case SC_AC_TERM:
|
||||
strcpy(buf, "TERM");
|
||||
break;
|
||||
case SC_AC_PRO:
|
||||
strcpy(buf, "PROT");
|
||||
break;
|
||||
case SC_AC_AUT:
|
||||
strcpy(buf, "AUTH");
|
||||
if (e->key_ref != SC_AC_KEY_REF_NONE)
|
||||
sprintf(buf + 4, "%d", e->key_ref);
|
||||
break;
|
||||
default:
|
||||
strcpy(buf, "????");
|
||||
break;
|
||||
}
|
||||
strcat(line, buf);
|
||||
strcat(line, " ");
|
||||
e = e->next;
|
||||
}
|
||||
line[strlen(line)-1] = 0; /* get rid of trailing space */
|
||||
return line;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,6 @@ void print_binary(FILE *f, const u8 *buf, int count);
|
|||
void hex_dump(FILE *f, const u8 *in, int len, const char *sep);
|
||||
void hex_dump_asc(FILE *f, const u8 *in, size_t count, int addr);
|
||||
void print_usage_and_die(const char *pgmname);
|
||||
const char * acl_to_str(unsigned int acl);
|
||||
const char * acl_to_str(const struct sc_acl_entry *e);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue