- 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:
jey 2002-02-20 09:56:47 +00:00
parent 092e87969d
commit 61fc1f9327
24 changed files with 1123 additions and 549 deletions

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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>

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

263
src/libopensc/dir.c Normal file
View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -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));

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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", &current_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", &current_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, &current_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, &current_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", &current_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, &current_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", &current_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, &current_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, &current_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", &current_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", &current_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", &current_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, &current_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", &current_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, &current_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", &current_path);
r = sc_select_file(card, &current_path, &current_file);
r = sc_select_file(card, &current_path, &current_file);
if (r) {
printf("unable to select MF: %s\n", sc_strerror(r));
return 1;

View File

@ -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));

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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