- pretty much finished the DER encoder

- added delete and create file support for 'flex cards
- PKCS #15 DF's are now stored more flexibly; this makes
  adding new types of DF's (such as PuKDF's) easier
- added 'get' and 'put' commands to opensc-explorer


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@160 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
jey 2002-01-13 23:56:13 +00:00
parent 921bbce7f5
commit 452b9d4193
15 changed files with 877 additions and 184 deletions

View File

@ -116,6 +116,24 @@ void sc_copy_asn1_entry(const struct sc_asn1_entry *src,
dest->name = NULL;
}
size_t sc_count_bit_string_size(const void * buf, size_t bufsize)
{
const u8 *p = (const u8 *) buf + bufsize - 1;
u8 c;
size_t skip = 0;
int i;
while (p >= (const u8 *) buf && *p == 0) {
skip += 8;
p--;
}
if (p < (const u8 *) buf)
return 0;
c = *p;
for (i = 0; (c >> (7-i)) == 0; i++);
return bufsize * 8 - (skip + i);
}
static void sc_asn1_print_octet_string(const u8 * buf, size_t buflen)
{
int i;
@ -403,10 +421,41 @@ int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen,
return decode_bit_string(inbuf, inlen, outbuf, outlen, 0);
}
static int encode_bit_string(const u8 * inbuf, size_t inlen, u8 **outbuf,
static int encode_bit_string(const u8 * inbuf, size_t bits_left, u8 **outbuf,
size_t *outlen, int invert)
{
return SC_ERROR_NOT_SUPPORTED;
const u8 *in = inbuf;
u8 *out;
size_t bytes;
int skipped = 0;
bytes = (bits_left + 7)/8 + 1;
*outbuf = out = malloc(bytes);
if (out == NULL)
return SC_ERROR_OUT_OF_MEMORY;
*outlen = bytes;
out += 1;
while (bits_left) {
int i, bits_to_go = 8;
*out = 0;
if (bits_left < 8) {
bits_to_go = bits_left;
skipped = 8 - bits_left;
}
if (invert) {
for (i = 0; i < bits_to_go; i++)
*out |= ((*in >> i) & 1) << (7 - i);
} else {
*out = *in;
if (bits_left < 8)
return SC_ERROR_NOT_SUPPORTED; /* FIXME */
}
bits_left -= bits_to_go;
}
out = *outbuf;
out[0] = skipped;
return 0;
}
int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out)
@ -425,18 +474,25 @@ int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out)
static int asn1_encode_integer(int in, u8 ** obj, size_t * objsize)
{
int i = sizeof(in) * 8;
u8 *p;
int i = sizeof(in) * 8, skip = 1;
u8 *p, b;
*obj = p = malloc(sizeof(in));
if (*obj == NULL)
return SC_ERROR_OUT_OF_MEMORY;
*objsize = sizeof(in);
do {
i -= 8;
*p++ = (in >> i) & 0xFF;
b = in >> i;
if (b == 0 && skip)
continue;
skip = 0;
*p++ = b;
} while (i > 0);
*objsize = p - *obj;
if (*objsize == 0) {
*objsize = 1;
(*obj)[0] = 0;
}
return 0;
}
@ -679,15 +735,17 @@ static int asn1_encode_p15_object(struct sc_context *ctx, const struct sc_pkcs15
int r;
const struct sc_pkcs15_common_obj_attr *com_attr = obj->com_attr;
struct sc_asn1_entry asn1_c_attr[6], asn1_p15_obj[5];
size_t flags_len = sizeof(com_attr->flags);
size_t flags_len;
size_t label_len = strlen(com_attr->label);
sc_copy_asn1_entry(c_asn1_com_obj_attr, asn1_c_attr);
sc_copy_asn1_entry(c_asn1_p15_obj, asn1_p15_obj);
if (label_len != 0)
sc_format_asn1_entry(asn1_c_attr + 0, (void *) com_attr->label, &label_len, 1);
if (com_attr->flags)
if (com_attr->flags) {
flags_len = sc_count_bit_string_size(&com_attr->flags, sizeof(com_attr->flags));
sc_format_asn1_entry(asn1_c_attr + 1, (void *) &com_attr->flags, &flags_len, 1);
}
if (com_attr->auth_id.len)
sc_format_asn1_entry(asn1_c_attr + 2, (void *) &com_attr->auth_id, NULL, 1);
if (com_attr->user_consent)
@ -964,7 +1022,7 @@ static int asn1_encode_entry(struct sc_context *ctx, const struct sc_asn1_entry
case SC_ASN1_BIT_STRING_NI:
case SC_ASN1_BIT_STRING:
assert(len != NULL);
if (entry->type == SC_ASN1_BIT_STRING_NI)
if (entry->type == SC_ASN1_BIT_STRING)
r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 1);
else
r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 0);
@ -980,8 +1038,8 @@ static int asn1_encode_entry(struct sc_context *ctx, const struct sc_asn1_entry
buflen = *len;
memcpy(buf, parm, buflen);
break;
#if 0
case SC_ASN1_OBJECT:
#if 0
case SC_ASN1_OBJECT:
if (parm != NULL)
r = sc_asn1_decode_object_id(obj, objlen, (struct sc_object_id *) parm);
break;
@ -1028,7 +1086,6 @@ static int asn1_encode_entry(struct sc_context *ctx, const struct sc_asn1_entry
return 0;
}
static int asn1_encode(struct sc_context *ctx, const struct sc_asn1_entry *asn1,
u8 **ptr, size_t *size, int depth)
{

View File

@ -22,7 +22,7 @@
#include "sc-log.h"
static const char *flex_atrs[] = {
"3B:95:94:40:FF:63:01:01:02:01", /* CryptoFlex 16k */
"3B:95:94:40:FF:63:01:01:02:01", /* Cryptoflex 16k */
"3B:19:14:55:90:01:02:02:00:05:04:B0",
NULL
};
@ -30,7 +30,7 @@ static const char *flex_atrs[] = {
static struct sc_card_operations flex_ops;
static const struct sc_card_driver flex_drv = {
NULL,
"Schlumberger Multiflex/CryptoFlex",
"Schlumberger Multiflex/Cryptoflex",
"slb",
&flex_ops
};
@ -240,7 +240,7 @@ static int flex_select_file(struct sc_card *card, const struct sc_path *path,
return SC_ERROR_UNKNOWN_REPLY;
if (apdu.resp[0] == 0x6F) {
error(card->ctx, "unsupported: Multiflex returned FCI\n");
error(card->ctx, "unsupported: card returned FCI\n");
return SC_ERROR_UNKNOWN_REPLY; /* FIXME */
}
@ -284,6 +284,146 @@ static int flex_list_files(struct sc_card *card, u8 *buf, size_t buflen)
return count;
}
static int flex_delete_file(struct sc_card *card, const struct sc_path *path)
{
int r;
u8 sbuf[2];
struct sc_apdu apdu;
SC_FUNC_CALLED(card->ctx, 1);
if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2) {
error(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
}
sbuf[0] = path->value[0];
sbuf[1] = path->value[1];
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
apdu.cla = 0xF0; /* Override CLA byte */
apdu.lc = 2;
apdu.datalen = 2;
apdu.data = sbuf;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
}
static int acl_to_ac(unsigned int acl)
{
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 };
for (i = 0; i < sizeof(acl_table)/sizeof(acl_table[0]); i++)
if (acl == acl_table[i])
return i;
return -1;
}
static int encode_file_structure(struct sc_card *card, const struct sc_file *file,
u8 *buf, size_t *buflen)
{
u8 *p = buf;
int r, r2;
p[0] = 0xFF;
p[1] = 0xFF;
p[2] = file->size >> 8;
p[3] = file->size & 0xFF;
p[4] = file->id >> 8;
p[5] = file->id & 0xFF;
if (file->type == SC_FILE_TYPE_DF)
p[6] = 0x38;
else
switch (file->ef_structure) {
case SC_FILE_EF_TRANSPARENT:
p[6] = 0x01;
break;
case SC_FILE_EF_LINEAR_FIXED:
p[6] = 0x02;
break;
case SC_FILE_EF_LINEAR_VARIABLE:
p[6] = 0x04;
break;
case SC_FILE_EF_CYCLIC:
p[6] = 0x06;
break;
default:
return -1;
}
p[7] = 0xFF; /* allow Decrease and Increase */
if (file->type == SC_FILE_TYPE_DF) {
r = acl_to_ac(file->acl[SC_AC_OP_LIST_FILES]);
SC_TEST_RET(card->ctx, r, "Invalid ACL value");
p[8] = (r & 0x0F) << 8;
r = acl_to_ac(file->acl[SC_AC_OP_DELETE]);
SC_TEST_RET(card->ctx, r, "Invalid ACL value");
r2 = acl_to_ac(file->acl[SC_AC_OP_CREATE]);
SC_TEST_RET(card->ctx, r2, "Invalid ACL value");
p[9] = ((r & 0x0F) << 8) | (r2 & 0x0F);
p[10] = 0;
} else {
r = acl_to_ac(file->acl[SC_AC_OP_READ]);
SC_TEST_RET(card->ctx, r, "Invalid ACL value");
r2 = acl_to_ac(file->acl[SC_AC_OP_UPDATE]);
SC_TEST_RET(card->ctx, r2, "Invalid ACL value");
p[8] = ((r & 0x0F) << 8) | (r2 & 0x0F);
p[9] = 0; /* FIXME */
r = acl_to_ac(file->acl[SC_AC_OP_INVALIDATE]);
SC_TEST_RET(card->ctx, r, "Invalid ACL value");
r2 = acl_to_ac(file->acl[SC_AC_OP_REHABILITATE]);
SC_TEST_RET(card->ctx, r2, "Invalid ACL value");
p[10] = ((r & 0x0F) << 8) | (r2 & 0x0F);
}
p[11] = (file->status & SC_FILE_STATUS_INVALIDATED) ? 0x00 : 0x01;
if (file->type != SC_FILE_TYPE_DF &&
(file->ef_structure == SC_FILE_EF_LINEAR_FIXED ||
file->ef_structure == SC_FILE_EF_CYCLIC))
p[12] = 0x04;
else
p[12] = 0x03;
p[13] = p[14] = p[15] = 0; /* FIXME */
if (p[12] == 0x04) {
p[16] = file->record_length;
*buflen = 17;
} else
*buflen = 16;
return 0;
}
static int flex_create_file(struct sc_card *card, const struct sc_file *file)
{
u8 sbuf[18];
size_t sendlen;
int r, rec_nr;
struct sc_apdu apdu;
r = encode_file_structure(card, file, sbuf, &sendlen);
if (r) {
error(card->ctx, "File structure encoding failed.\n");
return SC_ERROR_INVALID_ARGUMENTS;
}
if (file->type != SC_FILE_TYPE_DF && file->ef_structure != SC_FILE_EF_TRANSPARENT)
rec_nr = file->record_count;
else
rec_nr = 0;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, rec_nr);
apdu.cla = 0xF0;
apdu.data = sbuf;
apdu.datalen = sendlen;
apdu.lc = sendlen;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
}
static const struct sc_card_driver * sc_get_driver(void)
{
const struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
@ -294,6 +434,8 @@ static const struct sc_card_driver * sc_get_driver(void)
flex_ops.finish = flex_finish;
flex_ops.select_file = flex_select_file;
flex_ops.list_files = flex_list_files;
flex_ops.delete_file = flex_delete_file;
flex_ops.create_file = flex_create_file;
return &flex_drv;
}

View File

@ -620,6 +620,45 @@ int sc_write_binary(struct sc_card *card, unsigned int idx,
SC_FUNC_RETURN(card->ctx, 2, r);
}
int sc_update_binary(struct sc_card *card, unsigned int idx,
const u8 *buf, size_t count, unsigned long flags)
{
int r;
assert(card != NULL && card->ops != NULL && buf != NULL);
if (card->ctx->debug >= 2)
debug(card->ctx, "sc_update_binary: %d bytes at index %d\n", count, idx);
if (card->ops->update_binary == NULL)
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED);
if (count > SC_APDU_CHOP_SIZE && !(card->caps & SC_CARD_CAP_APDU_EXT)) {
int bytes_written = 0;
const u8 *p = buf;
r = sc_lock(card);
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
while (count > 0) {
int n = count > SC_APDU_CHOP_SIZE ? SC_APDU_CHOP_SIZE : count;
r = sc_update_binary(card, idx, p, n, flags);
if (r < 0) {
sc_unlock(card);
SC_TEST_RET(card->ctx, r, "sc_read_binary() failed");
}
p += r;
idx += r;
bytes_written += r;
count -= r;
if (r == 0) {
sc_unlock(card);
SC_FUNC_RETURN(card->ctx, 2, bytes_written);
}
}
sc_unlock(card);
SC_FUNC_RETURN(card->ctx, 2, bytes_written);
}
r = card->ops->update_binary(card, idx, buf, count, flags);
SC_FUNC_RETURN(card->ctx, 2, r);
}
int sc_select_file(struct sc_card *card,
const struct sc_path *in_path,
struct sc_file *file)

View File

@ -32,6 +32,7 @@
/* Internal use only */
int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2);
size_t sc_count_bit_string_size(const void * buf, size_t bufsize);
/* Default timeout value for SCardGetStatusChange */
#ifndef SC_CUSTOM_STATUS_TIMEOUT

View File

@ -98,6 +98,30 @@ static int iso7816_write_binary(struct sc_card *card,
SC_FUNC_RETURN(card->ctx, 3, count);
}
static int iso7816_update_binary(struct sc_card *card,
unsigned int idx, const u8 *buf,
size_t count, unsigned long flags)
{
struct sc_apdu apdu;
int r;
if (count > SC_APDU_CHOP_SIZE) {
error(card->ctx, "Too large buffer supplied\n");
return SC_ERROR_CMD_TOO_LONG;
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD6,
(idx >> 8) & 0x7F, idx & 0xFF);
apdu.lc = count;
apdu.datalen = count;
apdu.data = buf;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
SC_TEST_RET(card->ctx, sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2),
"Card returned error");
SC_FUNC_RETURN(card->ctx, 3, count);
}
static unsigned int byte_to_acl(u8 byte)
{
switch (byte >> 4) {
@ -538,6 +562,7 @@ const struct sc_card_driver * sc_get_iso7816_driver(void)
iso_ops.read_binary = iso7816_read_binary;
iso_ops.read_record = iso7816_read_record;
iso_ops.write_binary = iso7816_write_binary;
iso_ops.update_binary = iso7816_update_binary;
iso_ops.select_file = iso7816_select_file;
iso_ops.get_challenge = iso7816_get_challenge;
iso_ops.create_file = iso7816_create_file;

View File

@ -34,10 +34,7 @@ extern "C" {
#define SC_PKCS15_MAX_PRKEYS 2
#define SC_PKCS15_MAX_LABEL_SIZE 32
#define SC_PKCS15_MAX_ID_SIZE 16
#define SC_PKCS15_MAX_CDFS 4 /* Certificate Directory
* Files */
#define SC_PKCS15_MAX_AODFS 4 /* Authentication Object
* Directory Files */
#define SC_PKCS15_MAX_DFS 4
#define SC_PKCS15_MAX_CERTS 4 /* Total certificates */
struct sc_pkcs15_id {
@ -45,6 +42,8 @@ struct sc_pkcs15_id {
size_t len;
};
#define SC_PKCS15_CO_FLAG_OBJECT_SEEN 0x80000000 /* for PKCS #11 module */
struct sc_pkcs15_common_obj_attr {
char label[SC_PKCS15_MAX_LABEL_SIZE]; /* zero terminated */
int flags;
@ -137,14 +136,33 @@ struct sc_pkcs15_prkey_info {
int modulus_length;
};
#define SC_PKCS15_PRKDF 0
#define SC_PKCS15_PUKDF 1
#define SC_PKCS15_PUKDF_TRUSTED 2
#define SC_PKCS15_SKDF 3
#define SC_PKCS15_CDF 4
#define SC_PKCS15_CDF_TRUSTED 5
#define SC_PKCS15_CDF_USEFUL 6
#define SC_PKCS15_DODF 7
#define SC_PKCS15_AODF 8
#define SC_PKCS15_DF_TYPE_COUNT 9
struct sc_pkcs15_df {
struct sc_file *file[SC_PKCS15_MAX_DFS];
int count, record_length;
};
struct sc_pkcs15_card {
struct sc_card *card;
char *label;
/* fields from TokenInfo: */
int version;
char *serial_number, *manufacturer_id;
int flags;
unsigned long flags;
struct sc_pkcs15_algorithm_info alg_info[1];
/* FIXME: this could be done better with some C pre-processor
* magic */
struct sc_pkcs15_cert_info cert_info[SC_PKCS15_MAX_CERTS];
int cert_count;
struct sc_pkcs15_prkey_info prkey_info[SC_PKCS15_MAX_PRKEYS];
@ -152,15 +170,10 @@ 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;
/* in app DF */
struct sc_file file_tokeninfo, file_odf;
struct sc_file file_prkdf;
struct sc_file file_cdf[SC_PKCS15_MAX_CDFS];
int cdf_count;
struct sc_file file_aodf[SC_PKCS15_MAX_AODFS];
int aodf_count;
struct sc_file file_dodf;
struct sc_pkcs15_df df[SC_PKCS15_DF_TYPE_COUNT];
int use_cache;
};

View File

@ -182,6 +182,9 @@ struct sc_file {
int status; /* Status flags */
unsigned int 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 */
u8 sec_attr[SC_MAX_SEC_ATTR_SIZE];
size_t sec_attr_len;
u8 prop_attr[SC_MAX_PROP_ATTR_SIZE];
@ -458,6 +461,8 @@ int sc_read_binary(struct sc_card *card, unsigned int idx, u8 * buf,
size_t count, unsigned long flags);
int sc_write_binary(struct sc_card *card, unsigned int idx, const u8 * buf,
size_t count, unsigned long flags);
int sc_update_binary(struct sc_card *card, unsigned int idx, const u8 * buf,
size_t count, unsigned long flags);
int sc_read_record(struct sc_card *card, unsigned int rec_nr, u8 * buf,
size_t count, unsigned long flags);
int sc_get_challenge(struct sc_card *card, u8 * rndout, size_t len);

View File

@ -389,7 +389,7 @@ int sc_pkcs15_create_cdf(struct sc_pkcs15_card *p15card,
bufsize += tmpsize;
}
sc_hex_dump(p15card->card->ctx, buf, bufsize, str, sizeof(str));
printf("\n%s\n", str);
printf("CDF:\n%s\n", str);
return 0;
}
@ -445,15 +445,26 @@ static int get_certs_from_file(struct sc_pkcs15_card *card,
int sc_pkcs15_enum_certificates(struct sc_pkcs15_card *card)
{
int r = 0, i;
int r = 0, i, j, type;
const int df_types[] = {
SC_PKCS15_CDF, SC_PKCS15_CDF_TRUSTED, SC_PKCS15_CDF_USEFUL
};
const int nr_types = sizeof(df_types)/sizeof(df_types[0]);
assert(card != NULL);
if (card->cert_count)
return card->cert_count; /* already enumerated */
r = sc_lock(card->card);
SC_TEST_RET(card->card->ctx, r, "sc_lock() failed");
for (i = 0; i < card->cdf_count; i++) {
r = get_certs_from_file(card, &card->file_cdf[i]);
for (j = 0; j < nr_types; j++) {
type = df_types[j];
for (i = 0; i < card->df[type].count; i++) {
r = get_certs_from_file(card, card->df[type].file[i]);
if (r != 0)
break;
}
if (r != 0)
break;
}

View File

@ -1,5 +1,5 @@
/*
* pkcs15-pin.c: PKCS#15 PIN functions
* pkcs15-pin.c: PKCS #15 PIN functions
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
*
@ -133,8 +133,12 @@ static int get_pins_from_file(struct sc_pkcs15_card *card,
int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card)
{
int r, i;
int r, i, j;
struct sc_context *ctx = p15card->card->ctx;
const int df_types[] = {
SC_PKCS15_AODF
};
const int nr_types = sizeof(df_types)/sizeof(df_types[0]);
assert(p15card != NULL);
SC_FUNC_CALLED(ctx, 1);
@ -149,10 +153,11 @@ int sc_pkcs15_enum_pins(struct sc_pkcs15_card *p15card)
p15card->pin_count = 0;
r = sc_lock(p15card->card);
SC_TEST_RET(p15card->card->ctx, r, "sc_lock() failed");
for (i = 0; i < p15card->aodf_count; i++) {
r = get_pins_from_file(p15card, &p15card->file_aodf[i]);
if (r != 0)
break;
for (j = 0; r == 0 && j < nr_types; j++) {
int type = df_types[j];
for (i = 0; r == 0 && i < p15card->df[type].count; i++)
r = get_pins_from_file(p15card, p15card->df[type].file[i]);
}
sc_unlock(p15card->card);
if (r != 0)

View File

@ -130,17 +130,24 @@ static int get_prkeys_from_file(struct sc_pkcs15_card *card,
int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card)
{
int r, i;
assert(card != NULL);
int r, i, j;
struct sc_context *ctx = card->card->ctx;
const int df_types[] = {
SC_PKCS15_PRKDF
};
const int nr_types = sizeof(df_types)/sizeof(df_types[0]);
assert(card != NULL);
SC_FUNC_CALLED(ctx, 1);
if (card->prkey_count)
return card->prkey_count; /* already enumerated */
r = sc_lock(card->card);
SC_TEST_RET(card->card->ctx, r, "sc_lock() failed");
for (i = 0; i < 1; i++) {
r = get_prkeys_from_file(card, &card->file_prkdf);
if (r != 0)
break;
for (j = 0; r == 0 && j < nr_types; j++) {
int type = df_types[j];
for (i = 0; r == 0 && i < card->df[type].count; i++)
r = get_prkeys_from_file(card, card->df[type].file[i]);
}
sc_unlock(card->card);
if (r != 0)

View File

@ -55,6 +55,23 @@ void sc_pkcs15_print_card(const struct sc_pkcs15_card *card)
printf("\n");
}
static const struct sc_asn1_entry c_asn1_toki[] = {
{ "version", SC_ASN1_INTEGER, ASN1_INTEGER, 0, NULL },
{ "serialNumber", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, NULL },
{ "manufacturerID", SC_ASN1_UTF8STRING, ASN1_UTF8STRING, SC_ASN1_OPTIONAL, NULL },
{ "label", SC_ASN1_UTF8STRING, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL },
{ "tokenflags", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, 0, NULL },
{ "seInfo", SC_ASN1_SEQUENCE, SC_ASN1_CONS | ASN1_SEQUENCE, SC_ASN1_OPTIONAL, NULL },
{ "recordInfo", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL },
{ "supportedAlgorithms", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_CTX | 2, SC_ASN1_OPTIONAL, NULL },
{ NULL }
};
static const struct sc_asn1_entry c_asn1_tokeninfo[] = {
{ "TokenInfo", SC_ASN1_STRUCT, SC_ASN1_CONS | ASN1_SEQUENCE, 0, NULL },
{ NULL }
};
void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, size_t buflen)
{
int i, r;
@ -62,25 +79,20 @@ void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, size_t buflen)
int serial_len = sizeof(serial);
u8 mnfid[128];
int mnfid_len = sizeof(mnfid);
u8 label[128];
int label_len = sizeof(label);
int flags_len = sizeof(card->flags);
struct sc_asn1_entry asn1_toki[9], asn1_tokeninfo[2];
struct sc_asn1_entry asn1_tokeninfo[] = {
{ "version", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &card->version },
{ "serialNumber", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, serial, &serial_len },
{ "manufacturerID", SC_ASN1_UTF8STRING, ASN1_UTF8STRING, SC_ASN1_OPTIONAL, mnfid, &mnfid_len },
{ "label", SC_ASN1_UTF8STRING, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL },
{ "tokenflags", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, 0, &card->flags, &flags_len },
{ "seInfo", SC_ASN1_SEQUENCE, SC_ASN1_CONS | ASN1_SEQUENCE, SC_ASN1_OPTIONAL, NULL },
{ "recordInfo", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL },
{ "supportedAlgorithms", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_CTX | 2, SC_ASN1_OPTIONAL, NULL },
{ NULL }
};
buf = sc_asn1_verify_tag(card->card->ctx, buf, buflen, SC_ASN1_CONS | ASN1_SEQUENCE, &buflen);
if (buf == NULL) {
error(card->card->ctx, "invalid EF(TokenInfo)\n");
goto err;
}
sc_copy_asn1_entry(c_asn1_toki, asn1_toki);
sc_copy_asn1_entry(c_asn1_tokeninfo, asn1_tokeninfo);
sc_format_asn1_entry(asn1_toki + 0, &card->version, NULL, 0);
sc_format_asn1_entry(asn1_toki + 1, serial, &serial_len, 0);
sc_format_asn1_entry(asn1_toki + 2, mnfid, &mnfid_len, 0);
sc_format_asn1_entry(asn1_toki + 3, label, &label_len, 0);
sc_format_asn1_entry(asn1_toki + 4, &card->flags, &flags_len, 0);
sc_format_asn1_entry(asn1_tokeninfo, asn1_toki, NULL, 0);
r = sc_asn1_decode(card->card->ctx, asn1_tokeninfo, buf, buflen, NULL, NULL);
if (r) {
error(card->card->ctx, "ASN.1 parsing failed: %s\n", sc_strerror(r));
@ -101,6 +113,12 @@ void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, size_t buflen)
else
card->manufacturer_id = strdup("(unknown)");
}
if (card->label == NULL) {
if (asn1_tokeninfo[2].flags & SC_ASN1_PRESENT)
card->manufacturer_id = strdup((char *) mnfid);
else
card->manufacturer_id = strdup("(unknown)");
}
return;
err:
if (card->serial_number == NULL)
@ -110,35 +128,115 @@ err:
return;
}
int encode_tokeninfo(struct sc_pkcs15_card *card, u8 ** buf, size_t *buflen)
{
int i, r;
u8 serial[128];
int serial_len = 0;
int mnfid_len;
int label_len;
int flags_len;
int version = card->version;
struct sc_asn1_entry asn1_toki[9], asn1_tokeninfo[2];
sc_copy_asn1_entry(c_asn1_toki, asn1_toki);
sc_copy_asn1_entry(c_asn1_tokeninfo, asn1_tokeninfo);
version--;
sc_format_asn1_entry(asn1_toki + 0, &version, NULL, 1);
if (card->serial_number != NULL) {
if (strlen(card->serial_number)/2 > sizeof(serial))
return SC_ERROR_BUFFER_TOO_SMALL;
for (i = 0; card->serial_number[i] != 0; i += 2) {
int c;
if (sscanf(&card->serial_number[i], "%02X", &c) != 1)
return SC_ERROR_INVALID_ARGUMENTS;
serial[i/2] = c & 0xFF;
serial_len++;
}
sc_format_asn1_entry(asn1_toki + 1, serial, &serial_len, 1);
}
if (card->manufacturer_id != NULL) {
mnfid_len = strlen(card->manufacturer_id);
sc_format_asn1_entry(asn1_toki + 2, card->manufacturer_id, &mnfid_len, 1);
}
if (card->label != NULL) {
label_len = strlen(card->label);
sc_format_asn1_entry(asn1_toki + 3, card->label, &label_len, 1);
}
if (card->flags) {
flags_len = sc_count_bit_string_size(&card->flags, sizeof(card->flags));
sc_format_asn1_entry(asn1_toki + 4, &card->flags, &flags_len, 1);
}
sc_format_asn1_entry(asn1_tokeninfo, asn1_toki, NULL, 1);
r = sc_asn1_encode(card->card->ctx, asn1_tokeninfo, buf, buflen);
if (r) {
error(card->card->ctx, "sc_asn1_encode() failed: %s\n", sc_strerror(r));
return r;
}
return 0;
}
int sc_pkcs15_create_tokeninfo(struct sc_pkcs15_card *card)
{
int r;
u8 *buf;
size_t buflen;
u8 line[10240];
r = encode_tokeninfo(card, &buf, &buflen);
if (r) {
error(card->card->ctx, "Error encoding EF(TokenInfo): %s\n", sc_strerror(r));
return r;
}
sc_hex_dump(card->card->ctx, buf, buflen, line, sizeof(line));
printf("%s\n", line);
return 0;
}
static const struct sc_asn1_entry c_asn1_ddo[] = {
{ "oid", SC_ASN1_OBJECT, ASN1_OBJECT, 0, NULL },
{ "odfPath", SC_ASN1_PATH, SC_ASN1_CONS | ASN1_SEQUENCE, SC_ASN1_OPTIONAL, NULL },
{ "tokenInfoPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL },
{ "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 int parse_dir(const u8 * buf, size_t buflen, struct sc_pkcs15_card *card)
{
const u8 *aidref = (const u8 *) "\xA0\x00\x00\x00\x63PKCS-15";
const int aidref_len = 12;
struct sc_asn1_entry asn1_ddo[5], asn1_dirrecord[5], asn1_dir[2];
int r;
u8 aid[128], label[128], path[128];
int aid_len = sizeof(aid), label_len = sizeof(label),
path_len = sizeof(path);
struct sc_asn1_entry asn1_ddo[] = {
{ "oid", SC_ASN1_OBJECT, ASN1_OBJECT, 0, NULL },
{ "odfPath", SC_ASN1_PATH, SC_ASN1_CONS | ASN1_SEQUENCE, SC_ASN1_OPTIONAL, &card->file_odf.path },
{ "tokenInfoPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, &card->file_tokeninfo.path },
{ "unusedPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL },
{ NULL }
};
struct sc_asn1_entry asn1_dir[] = {
{ "aid", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 15, 0, aid, &aid_len },
{ "label", SC_ASN1_UTF8STRING, SC_ASN1_APP | 16, SC_ASN1_OPTIONAL, label, &label_len },
{ "path", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 17, 0, path, &path_len },
{ "ddo", SC_ASN1_STRUCT, SC_ASN1_APP | 19 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, asn1_ddo },
{ NULL }
};
buf = sc_asn1_verify_tag(card->card->ctx, buf, buflen, SC_ASN1_APP | 1 | SC_ASN1_CONS, &buflen);
if (buf == NULL) {
error(card->card->ctx, "No [APPLICATION 1] tag in EF(DIR)\n");
return -1;
}
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);
if (r) {
error(card->card->ctx, "EF(DIR) parsing failed: %s\n",
@ -149,7 +247,7 @@ static int parse_dir(const u8 * buf, size_t buflen, struct sc_pkcs15_card *card)
error(card->card->ctx, "AID in EF(DIR) is invalid\n");
return -1;
}
if (asn1_dir[1].flags & SC_ASN1_PRESENT)
if (asn1_dirrecord[1].flags & SC_ASN1_PRESENT)
card->label = strdup((char *) label);
else
card->label = strdup("(unknown)");
@ -162,61 +260,193 @@ static int parse_dir(const u8 * buf, size_t buflen, struct sc_pkcs15_card *card)
return 0;
}
static int encode_dir(struct sc_pkcs15_card *card, u8 **buf, size_t *buflen)
{
struct sc_asn1_entry asn1_ddo[5], asn1_dirrecord[5], asn1_dir[2];
struct sc_context *ctx = card->card->ctx;
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(card->card->ctx, "sc_asn1_encode() failed: %s\n",
sc_strerror(r));
return r;
}
return 0;
}
/* 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 = p15card->card;
struct sc_path path;
u8 *buf;
size_t bufsize;
int r;
u8 line[10240];
SC_FUNC_CALLED(card->ctx, 1);
sc_format_path("3F00", &path);
r = sc_select_file(card, &path, NULL);
SC_TEST_RET(card->ctx, r, "sc_select_file(MF) failed");
r = encode_dir(p15card, &buf, &bufsize);
SC_TEST_RET(card->ctx, r, "EF(DIR) encoding failed");
sc_hex_dump(p15card->card->ctx, buf, bufsize, line, sizeof(line));
free(buf);
printf("%s", line);
return 0;
}
static const struct sc_asn1_entry c_asn1_odf[] = {
{ "privateKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, NULL },
{ "certificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, 0, NULL },
{ "trustedCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 5 | SC_ASN1_CONS, 0, NULL },
{ "dataObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 7 | SC_ASN1_CONS, 0, NULL },
{ "authObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 8 | SC_ASN1_CONS, 0, NULL },
{ NULL }
};
static const int odf_indexes[] = {
SC_PKCS15_PRKDF,
SC_PKCS15_CDF,
SC_PKCS15_CDF_TRUSTED,
SC_PKCS15_DODF,
SC_PKCS15_AODF,
};
static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card)
{
const u8 *p = buf;
size_t left = buflen;
int r;
int r, i;
struct sc_path path;
struct sc_asn1_entry asn1_obj_or_path[] = {
{ "path", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_SEQUENCE, 0, &path },
{ NULL }
};
struct sc_asn1_entry asn1_odf[] = {
{ "privateKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ "certificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ "trustedCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 5 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ "dataObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 7 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ "authObjects", SC_ASN1_STRUCT, SC_ASN1_CTX | 8 | SC_ASN1_CONS, 0, asn1_obj_or_path },
{ NULL }
};
struct sc_asn1_entry asn1_odf[6];
sc_copy_asn1_entry(c_asn1_odf, asn1_odf);
for (i = 0; asn1_odf[i].name != NULL; i++)
sc_format_asn1_entry(asn1_odf + i, asn1_obj_or_path, NULL, 0);
while (left > 0) {
struct sc_pkcs15_df *df = NULL;
struct sc_file *file;
r = sc_asn1_decode_choice(card->card->ctx, asn1_odf, p, left, &p, &left);
if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
break;
if (r < 0)
return r;
switch (r) {
case 0:
if (card->file_prkdf.path.len)
error(card->card->ctx, "warning: card has too many PrKDF's\n");
card->file_prkdf.path = path;
break;
case 1:
case 2:
if (card->cdf_count == SC_PKCS15_MAX_CDFS) {
error(card->card->ctx, "too many CDFs on card\n");
df = &card->df[odf_indexes[r]];
if (df->count == SC_PKCS15_MAX_DFS) {
error(card->card->ctx, "too many DF's on card\n");
continue;
}
file = malloc(sizeof(struct sc_file));
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++;
}
return 0;
}
static int encode_odf(struct sc_pkcs15_card *card, u8 **buf, size_t *buflen)
{
struct sc_path path;
struct sc_asn1_entry asn1_obj_or_path[] = {
{ "path", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_SEQUENCE, 0, &path },
};
struct sc_asn1_entry *asn1_paths = NULL;
struct sc_asn1_entry *asn1_odf = NULL;
int df_count = 0, i, r, c = 0;
const int nr_indexes = sizeof(odf_indexes)/sizeof(odf_indexes[0]);
for (i = 0; i < SC_PKCS15_DF_TYPE_COUNT; i++)
df_count += card->df[i].count;
asn1_odf = malloc(sizeof(struct sc_asn1_entry) * (df_count + 1));
if (asn1_odf == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
asn1_paths = malloc(sizeof(struct sc_asn1_entry) * (df_count * 2));
if (asn1_paths == NULL) {
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
for (i = 0; i < SC_PKCS15_DF_TYPE_COUNT; i++) {
struct sc_pkcs15_df *df = &card->df[i];
int j, type = -1;
if (!df->count)
continue;
for (j = 0; j < nr_indexes; j++)
if (odf_indexes[j] == i) {
type = j;
break;
}
card->file_cdf[card->cdf_count].path = path;
card->cdf_count++;
break;
case 3:
if (card->file_dodf.path.len)
error(card->card->ctx, "warning: card has too many DODF's\n");
card->file_dodf.path = path;
break;
case 4:
if (card->aodf_count == SC_PKCS15_MAX_AODFS) {
error(card->card->ctx, "too many AODFs on card\n");
break;
}
card->file_aodf[card->aodf_count].path = path;
card->aodf_count++;
break;
if (type == -1) {
error(card->card->ctx, "Unsupported DF type.\n");
continue;
}
for (j = 0; j < df->count; j++) {
asn1_odf[c] = c_asn1_odf[type];
sc_format_asn1_entry(asn1_odf + c, asn1_paths + 2*c, NULL, 1);
sc_copy_asn1_entry(asn1_obj_or_path, asn1_paths + 2*c);
sc_format_asn1_entry(asn1_paths + 2*c, &df->file[j]->path, NULL, 1);
c++;
}
}
asn1_odf[df_count].name = NULL;
r = sc_asn1_encode(card->card->ctx, asn1_odf, buf, buflen);
err:
if (asn1_paths != NULL)
free(asn1_paths);
if (asn1_odf != NULL)
free(asn1_odf);
return r;
}
int sc_pkcs15_create_odf(struct sc_pkcs15_card *p15card)
{
u8 *buf;
size_t buflen;
u8 line[10240];
int r;
r = encode_odf(p15card, &buf, &buflen);
SC_TEST_RET(p15card->card->ctx, r, "ODF encoding failed");
sc_hex_dump(p15card->card->ctx, buf, buflen, line, sizeof(line));
printf("ODF:\n%s", line);
return 0;
}
@ -235,6 +465,7 @@ int sc_pkcs15_bind(struct sc_card *card,
struct sc_path tmppath;
const struct sc_pkcs15_defaults *defaults = NULL;
struct sc_context *ctx;
struct sc_file file;
assert(sc_card_valid(card) && p15card_out != NULL);
ctx = card->ctx;
@ -251,13 +482,13 @@ int sc_pkcs15_bind(struct sc_card *card,
error(ctx, "sc_lock() failed: %s\n", sc_strerror(err));
goto error;
}
err = sc_select_file(card, &tmppath, &p15card->file_dir);
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, p15card->file_dir.size, 0);
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;
@ -283,10 +514,10 @@ int sc_pkcs15_bind(struct sc_card *card,
} else
tmppath = p15card->file_odf.path;
err = sc_select_file(card, &tmppath, &p15card->file_odf);
err = sc_select_file(card, &tmppath, &file);
if (err) /* FIXME: finish writing error stuff */
goto error;
err = sc_read_binary(card, 0, buf, p15card->file_odf.size, 0);
err = sc_read_binary(card, 0, buf, file.size, 0);
if (err < 0)
goto error;
if (err < 2) {
@ -308,10 +539,10 @@ int sc_pkcs15_bind(struct sc_card *card,
defaults->defaults_func(p15card, defaults->arg);
tmppath = p15card->file_tokeninfo.path;
}
err = sc_select_file(card, &tmppath, &p15card->file_tokeninfo);
err = sc_select_file(card, &tmppath, &file);
if (err)
goto error;
err = sc_read_binary(card, 0, buf, p15card->file_tokeninfo.size, 0);
err = sc_read_binary(card, 0, buf, file.size, 0);
if (err < 0)
goto error;
if (err <= 2) {
@ -346,8 +577,14 @@ int sc_pkcs15_detect(struct sc_card *card)
int sc_pkcs15_unbind(struct sc_pkcs15_card *p15card)
{
int i, j;
assert(p15card != NULL);
SC_FUNC_CALLED(p15card->card->ctx, 1);
for (j = 0; j < SC_PKCS15_DF_TYPE_COUNT; j++)
for (i = 0; i < p15card->df[j].count; i++)
if (p15card->df[j].file[i])
free(p15card->df[j].file[i]);
free(p15card->label);
free(p15card->serial_number);
free(p15card->manufacturer_id);

View File

@ -34,10 +34,7 @@ extern "C" {
#define SC_PKCS15_MAX_PRKEYS 2
#define SC_PKCS15_MAX_LABEL_SIZE 32
#define SC_PKCS15_MAX_ID_SIZE 16
#define SC_PKCS15_MAX_CDFS 4 /* Certificate Directory
* Files */
#define SC_PKCS15_MAX_AODFS 4 /* Authentication Object
* Directory Files */
#define SC_PKCS15_MAX_DFS 4
#define SC_PKCS15_MAX_CERTS 4 /* Total certificates */
struct sc_pkcs15_id {
@ -45,6 +42,8 @@ struct sc_pkcs15_id {
size_t len;
};
#define SC_PKCS15_CO_FLAG_OBJECT_SEEN 0x80000000 /* for PKCS #11 module */
struct sc_pkcs15_common_obj_attr {
char label[SC_PKCS15_MAX_LABEL_SIZE]; /* zero terminated */
int flags;
@ -137,14 +136,33 @@ struct sc_pkcs15_prkey_info {
int modulus_length;
};
#define SC_PKCS15_PRKDF 0
#define SC_PKCS15_PUKDF 1
#define SC_PKCS15_PUKDF_TRUSTED 2
#define SC_PKCS15_SKDF 3
#define SC_PKCS15_CDF 4
#define SC_PKCS15_CDF_TRUSTED 5
#define SC_PKCS15_CDF_USEFUL 6
#define SC_PKCS15_DODF 7
#define SC_PKCS15_AODF 8
#define SC_PKCS15_DF_TYPE_COUNT 9
struct sc_pkcs15_df {
struct sc_file *file[SC_PKCS15_MAX_DFS];
int count, record_length;
};
struct sc_pkcs15_card {
struct sc_card *card;
char *label;
/* fields from TokenInfo: */
int version;
char *serial_number, *manufacturer_id;
int flags;
unsigned long flags;
struct sc_pkcs15_algorithm_info alg_info[1];
/* FIXME: this could be done better with some C pre-processor
* magic */
struct sc_pkcs15_cert_info cert_info[SC_PKCS15_MAX_CERTS];
int cert_count;
struct sc_pkcs15_prkey_info prkey_info[SC_PKCS15_MAX_PRKEYS];
@ -152,15 +170,10 @@ 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;
/* in app DF */
struct sc_file file_tokeninfo, file_odf;
struct sc_file file_prkdf;
struct sc_file file_cdf[SC_PKCS15_MAX_CDFS];
int cdf_count;
struct sc_file file_aodf[SC_PKCS15_MAX_AODFS];
int aodf_count;
struct sc_file file_dodf;
struct sc_pkcs15_df df[SC_PKCS15_DF_TYPE_COUNT];
int use_cache;
};

View File

@ -32,6 +32,7 @@
/* Internal use only */
int sc_sw_to_errorcode(struct sc_card *card, int sw1, int sw2);
size_t sc_count_bit_string_size(const void * buf, size_t bufsize);
/* Default timeout value for SCardGetStatusChange */
#ifndef SC_CUSTOM_STATUS_TIMEOUT

View File

@ -42,10 +42,7 @@ const char *option_help[] = { NULL };
const char *cmds[] = {
"ls", "cd", "debug", "cat", "info", "create", "delete",
"verify"
};
const char *cmdusage[] = {
"", "", "", "", "", "", "", "<key type> <key ref>"
"verify", "put", "get"
};
const int nr_cmds = sizeof(cmds)/sizeof(cmds[0]);
@ -87,6 +84,22 @@ void check_ret(int r, int op, const char *err, const struct sc_file *file)
fprintf(stderr, "ACL for operation: %s\n", acl_to_str(file->acl[op]));
}
int arg_to_path(const char *arg, struct sc_path *path)
{
char buf[6];
if (strlen(arg) != 4) {
printf("Wrong ID length.\n");
return -1;
}
strcpy(buf, "I");
strcat(buf, arg);
sc_format_path(buf, path);
if (path->len != 2)
return -1;
return 0;
}
void print_file(const struct sc_file *file)
{
const char *st;
@ -164,7 +177,6 @@ int do_cd(const char *arg)
{
struct sc_path path;
struct sc_file file;
char buf[6];
int r;
if (strcmp(arg, "..") == 0) {
@ -182,15 +194,7 @@ int do_cd(const char *arg)
current_path = path;
return 0;
}
if (strlen(arg) != 4) {
printf("Usage: cd <file_id>\n");
return -1;
}
strcpy(buf, "I");
strcat(buf, arg);
sc_format_path(buf, &path);
if (path.len != 2) {
if (arg_to_path(arg, &path) != 0) {
printf("Usage: cd <file_id>\n");
return -1;
}
@ -215,7 +219,6 @@ int do_cd(const char *arg)
return 0;
}
int do_cat(const char *arg)
{
u8 buf[256];
@ -231,14 +234,7 @@ int do_cat(const char *arg)
file = current_file;
not_current = 0;
} else {
if (strlen(arg) != 4) {
printf("Usage: cat [file_id]\n");
return -1;
}
strcpy((char *) buf, "I");
strcat((char *) buf, arg);
sc_format_path((char *) buf, &path);
if (path.len != 2) {
if (arg_to_path(arg, &path) != 0) {
printf("Usage: cat [file_id]\n");
return -1;
}
@ -291,17 +287,9 @@ int do_info(const char *arg)
file = current_file;
not_current = 0;
} else {
char buf[6];
struct sc_path tmppath;
if (strlen(arg) != 4) {
printf("Usage: info [file_id]\n");
return -1;
}
strcpy(buf, "I");
strcat(buf, arg);
sc_format_path(buf, &tmppath);
if (tmppath.len != 2) {
if (arg_to_path(arg, &tmppath) != 0) {
printf("Usage: info [file_id]\n");
return -1;
}
@ -359,8 +347,24 @@ int do_info(const char *arg)
"Linear fixed, SIMPLE-TLV", "Linear variable",
"Cyclic", "Cyclic, SIMPLE-TLV",
};
const char *ops[] = {
"READ", "UPDATE", "WRITE", "ERASE", "REHABILITATE",
"INVALIDATE"
};
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]));
}
}
if (file.prop_attr_len) {
printf("%-25s", "Proprietary attributes:");
for (i = 0; i < file.prop_attr_len; i++)
printf("%02X ", file.prop_attr[i]);
printf("\n");
}
printf("\n");
if (not_current) {
r = sc_select_file(card, &current_path, NULL);
@ -374,18 +378,12 @@ int do_info(const char *arg)
int do_create(const char *arg, const char *arg2)
{
char buf[6];
struct sc_path path;
struct sc_file file;
size_t size;
int i, r;
if (strlen(arg) != 4)
goto usage;
strcpy(buf, "I");
strcat(buf, arg);
sc_format_path(buf, &path);
if (path.len != 2)
if (arg_to_path(arg, &path) != 0)
goto usage;
if (sscanf(arg2, "%d", &size) != 1)
goto usage;
@ -396,12 +394,20 @@ int do_create(const char *arg, const char *arg2)
for (i = 0; i < SC_MAX_AC_OPS; i++)
file.acl[i] = SC_AC_NONE;
file.size = size;
file.status = SC_FILE_STATUS_ACTIVATED;
r = sc_create_file(card, &file);
if (r) {
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
* CREATE FILE also selects the newly created file. */
r = sc_select_file(card, &current_path, NULL);
if (r) {
printf("unable to select parent file: %s\n", sc_strerror(r));
die(1);
}
return 0;
usage:
printf("Usage: create <file_id> <file_size>\n");
@ -410,16 +416,10 @@ usage:
int do_delete(const char *arg)
{
char buf[6];
struct sc_path path;
int r;
if (strlen(arg) != 4)
goto usage;
strcpy(buf, "I");
strcat(buf, arg);
sc_format_path(buf, &path);
if (path.len != 2)
if (arg_to_path(arg, &path) != 0)
goto usage;
r = sc_delete_file(card, &path);
if (r) {
@ -490,6 +490,139 @@ usage:
return -1;
}
int do_get(const char *arg, const char *arg2)
{
u8 buf[256];
int r, error = 0;
size_t count = 0;
unsigned int idx = 0;
struct sc_path path;
struct sc_file file;
const char *filename;
FILE *outf = NULL;
if (arg_to_path(arg, &path) != 0)
goto usage;
if (strlen(arg2))
filename = arg2;
else {
sprintf(buf, "%02X%02X", path.value[0], path.value[1]);
filename = buf;
}
outf = fopen(filename, "w");
if (outf == NULL) {
perror(filename);
return -1;
}
r = sc_select_file(card, &path, &file);
if (r) {
check_ret(r, SC_AC_OP_SELECT, "unable to select file", &current_file);
return -1;
}
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);
error = 1;
goto err;
}
if (r != c) {
printf("expecting %d, got only %d bytes.\n", c, r);
error = 1;
goto err;
}
fwrite(buf, c, 1, outf);
idx += c;
count -= c;
}
printf("Total of %d bytes read.\n", idx);
err:
r = sc_select_file(card, &current_path, NULL);
if (r) {
printf("unable to select parent file: %s\n", sc_strerror(r));
die(1);
}
if (outf)
fclose(outf);
return -error;
usage:
printf("Usage: get <file id> [output file]\n");
return -1;
}
int do_put(const char *arg, const char *arg2)
{
u8 buf[256];
int r, error = 0;
size_t count = 0;
unsigned int idx = 0;
struct sc_path path;
struct sc_file file;
const char *filename;
FILE *outf = NULL;
if (arg_to_path(arg, &path) != 0)
goto usage;
if (strlen(arg2))
filename = arg2;
else {
sprintf(buf, "%02X%02X", path.value[0], path.value[1]);
filename = buf;
}
outf = fopen(filename, "r");
if (outf == NULL) {
perror(filename);
return -1;
}
r = sc_select_file(card, &path, &file);
if (r) {
check_ret(r, SC_AC_OP_SELECT, "unable to select file", &current_file);
return -1;
}
count = file.size;
while (count) {
int c = count > sizeof(buf) ? sizeof(buf) : count;
r = fread(buf, 1, c, outf);
if (r < 0) {
perror("fread");
error = 1;
goto err;
}
if (r != c)
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);
error = 1;
goto err;
}
if (r != c) {
printf("expecting %d, wrote only %d bytes.\n", c, r);
error = 1;
goto err;
}
idx += c;
count -= c;
}
printf("Total of %d bytes written.\n", idx);
err:
r = sc_select_file(card, &current_path, NULL);
if (r) {
printf("unable to select parent file: %s\n", sc_strerror(r));
die(1);
}
if (outf)
fclose(outf);
return -error;
usage:
printf("Usage: put <file id> [output file]\n");
return -1;
}
int handle_cmd(int cmd, const char *arg, const char *arg2)
{
int i;
@ -519,6 +652,10 @@ int handle_cmd(int cmd, const char *arg, const char *arg2)
return do_delete(arg);
case 7:
return do_verify(arg, arg2);
case 8:
return do_put(arg, arg2);
case 9:
return do_get(arg, arg2);
default:
printf("Don't know how to handle command.\n");
}

View File

@ -96,7 +96,7 @@ const char * acl_to_str(unsigned int acl)
static char line[80];
if (acl == SC_AC_UNKNOWN)
return "UNKN";
return "N/A";
if (acl == SC_AC_NEVER)
return "NEVR";
if (acl == SC_AC_NONE)