- Improved support for MioCOS cards
- Removed PKCS #15 creation from cryptoflex-tool - Added PIN pad character option to profile.c git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@282 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
c94fb9a1d5
commit
7d2171c1d2
|
@ -36,7 +36,7 @@ struct flex_private_data {
|
|||
static struct sc_card_operations flex_ops;
|
||||
static const struct sc_card_driver flex_drv = {
|
||||
"Schlumberger Multiflex/Cryptoflex",
|
||||
"slb",
|
||||
"flex",
|
||||
&flex_ops
|
||||
};
|
||||
|
||||
|
@ -81,7 +81,7 @@ static int flex_init(struct sc_card *card)
|
|||
}
|
||||
|
||||
static void add_acl_entry(struct sc_file *file, unsigned int op,
|
||||
u8 nibble)
|
||||
u8 nibble, int is_mf)
|
||||
{
|
||||
switch (nibble) {
|
||||
case 0:
|
||||
|
@ -97,7 +97,10 @@ static void add_acl_entry(struct sc_file *file, unsigned int op,
|
|||
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);
|
||||
if (is_mf)
|
||||
sc_file_add_acl_entry(file, op, SC_AC_AUT, 1);
|
||||
else
|
||||
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);
|
||||
|
@ -129,7 +132,7 @@ static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen
|
|||
{
|
||||
const u8 *p = buf + 2;
|
||||
u8 b1, b2;
|
||||
int left;
|
||||
int left, is_mf = 0;
|
||||
|
||||
if (buflen < 14)
|
||||
return -1;
|
||||
|
@ -139,6 +142,8 @@ static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen
|
|||
b1 = *p++;
|
||||
b2 = *p++;
|
||||
file->id = (b1 << 8) + b2;
|
||||
if (file->id == 0x3F00)
|
||||
is_mf = 1;
|
||||
switch (*p) {
|
||||
case 0x01:
|
||||
file->type = SC_FILE_TYPE_WORKING_EF;
|
||||
|
@ -165,18 +170,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) {
|
||||
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);
|
||||
add_acl_entry(file, SC_AC_OP_LIST_FILES, p[0] >> 4, is_mf);
|
||||
add_acl_entry(file, SC_AC_OP_DELETE, p[1] >> 4, is_mf);
|
||||
add_acl_entry(file, SC_AC_OP_CREATE, p[1] & 0x0F, is_mf);
|
||||
} else { /* EF */
|
||||
add_acl_entry(file, SC_AC_OP_READ, p[0] >> 4);
|
||||
add_acl_entry(file, SC_AC_OP_READ, p[0] >> 4, 0);
|
||||
switch (file->ef_structure) {
|
||||
case SC_FILE_EF_TRANSPARENT:
|
||||
add_acl_entry(file, SC_AC_OP_UPDATE, p[0] & 0x0F);
|
||||
add_acl_entry(file, SC_AC_OP_UPDATE, p[0] & 0x0F, 0);
|
||||
break;
|
||||
case SC_FILE_EF_LINEAR_FIXED:
|
||||
case SC_FILE_EF_LINEAR_VARIABLE:
|
||||
add_acl_entry(file, SC_AC_OP_UPDATE, p[0] & 0x0F);
|
||||
add_acl_entry(file, SC_AC_OP_UPDATE, p[0] & 0x0F, 0);
|
||||
break;
|
||||
case SC_FILE_EF_CYCLIC:
|
||||
#if 0
|
||||
|
@ -186,8 +191,8 @@ static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen
|
|||
break;
|
||||
}
|
||||
}
|
||||
add_acl_entry(file, SC_AC_OP_REHABILITATE, p[2] >> 4);
|
||||
add_acl_entry(file, SC_AC_OP_INVALIDATE, p[2] & 0x0F);
|
||||
add_acl_entry(file, SC_AC_OP_REHABILITATE, p[2] >> 4, is_mf);
|
||||
add_acl_entry(file, SC_AC_OP_INVALIDATE, p[2] & 0x0F, is_mf);
|
||||
p += 3;
|
||||
if (*p++)
|
||||
file->status = SC_FILE_STATUS_ACTIVATED;
|
||||
|
@ -268,6 +273,27 @@ void cache_path(struct sc_card *card, const struct sc_path *path)
|
|||
}
|
||||
}
|
||||
|
||||
static int get_flex_ac_keys(struct sc_card *card, struct sc_file *file)
|
||||
{
|
||||
#if 0
|
||||
struct sc_apdu apdu;
|
||||
u8 rbuf[3];
|
||||
int r;
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xC4, 0x00, 0x00);
|
||||
apdu.cla = 0xF0;
|
||||
apdu.le = 3;
|
||||
apdu.resplen = 3;
|
||||
apdu.resp = rbuf;
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.sw1 != 0x90 && apdu.sw2 != 0x00)
|
||||
return 0;
|
||||
debug(card->ctx, "AC Keys: %02X %02X %02X\n", rbuf[0], rbuf[1], rbuf[2]);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int select_file_id(struct sc_card *card, const u8 *buf, size_t buflen,
|
||||
u8 p1, struct sc_file **file_out)
|
||||
{
|
||||
|
@ -308,6 +334,8 @@ static int select_file_id(struct sc_card *card, const u8 *buf, size_t buflen,
|
|||
sc_file_free(file);
|
||||
return r;
|
||||
}
|
||||
r = get_flex_ac_keys(card, file);
|
||||
|
||||
*file_out = file;
|
||||
return 0;
|
||||
}
|
||||
|
@ -513,13 +541,15 @@ static int encode_file_structure(struct sc_card *card, const struct sc_file *fil
|
|||
p[8] = p[9] = p[10] = 0;
|
||||
p[13] = p[14] = p[15] = 0; /* Key numbers */
|
||||
for (i = 0; i < 6; i++) {
|
||||
const struct sc_acl_entry *entry;
|
||||
if (ops[i] == -1)
|
||||
continue;
|
||||
r = acl_to_ac_nibble(file->acl[ops[i]]);
|
||||
entry = sc_file_get_acl_entry(file, ops[i]);
|
||||
r = acl_to_ac_nibble(entry);
|
||||
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_nibble(file->acl[ops[i]]);
|
||||
r = acl_to_keynum_nibble(entry);
|
||||
p[13 + i/2] |= (r & 0x0F) << (((i+1) % 2) * 4);
|
||||
}
|
||||
p[11] = (file->status & SC_FILE_STATUS_INVALIDATED) ? 0x00 : 0x01;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* card-miocos.c: Support for MioCOS cards by Miotec
|
||||
* card-miocos.c: Support for PKI cards by Miotec
|
||||
*
|
||||
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
||||
*
|
||||
|
@ -20,13 +20,20 @@
|
|||
|
||||
#include "sc-internal.h"
|
||||
#include "sc-log.h"
|
||||
#include <string.h>
|
||||
|
||||
static const char *miocos_atrs[] = {
|
||||
/* MioCOS 1.1 Test Card */
|
||||
"3B:9D:94:40:23:00:68:10:11:4D:69:6F:43:4F:53:00:90:00",
|
||||
NULL
|
||||
static struct sc_atr_table miocos_atrs[] = {
|
||||
{ "\x3B\x9D\x94\x40\x23\x00\x68\x10\x11\x4D\x69\x6F\x43\x4F"
|
||||
"\x53\x00\x90\x00", 18 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
struct miocos_priv_data {
|
||||
int type;
|
||||
};
|
||||
|
||||
#define DRVDATA(card) ((struct miocos_priv_data *) ((card)->drv_data))
|
||||
|
||||
static struct sc_card_operations miocos_ops;
|
||||
static const struct sc_card_driver miocos_drv = {
|
||||
"MioCOS 1.1 cards",
|
||||
|
@ -41,32 +48,35 @@ static int miocos_finish(struct sc_card *card)
|
|||
|
||||
static int miocos_match_card(struct sc_card *card)
|
||||
{
|
||||
int i, match = -1;
|
||||
int i;
|
||||
|
||||
for (i = 0; miocos_atrs[i] != NULL; i++) {
|
||||
u8 defatr[SC_MAX_ATR_SIZE];
|
||||
size_t len = sizeof(defatr);
|
||||
const char *atrp = miocos_atrs[i];
|
||||
|
||||
if (sc_hex_to_bin(atrp, defatr, &len))
|
||||
continue;
|
||||
if (len != card->atr_len)
|
||||
continue;
|
||||
if (memcmp(card->atr, defatr, len) != 0)
|
||||
continue;
|
||||
match = i;
|
||||
break;
|
||||
}
|
||||
if (match == -1)
|
||||
i = _sc_match_atr(card, miocos_atrs, NULL);
|
||||
if (i < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int miocos_init(struct sc_card *card)
|
||||
{
|
||||
card->drv_data = NULL;
|
||||
int i, id;
|
||||
struct miocos_priv_data *priv = NULL;
|
||||
|
||||
i = _sc_match_atr(card, miocos_atrs, &id);
|
||||
if (i < 0)
|
||||
return 0;
|
||||
priv = malloc(sizeof(struct miocos_priv_data));
|
||||
if (priv == NULL)
|
||||
return SC_ERROR_OUT_OF_MEMORY;
|
||||
card->drv_data = priv;
|
||||
card->cla = 0x00;
|
||||
if (1) {
|
||||
unsigned long flags;
|
||||
|
||||
flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
|
||||
flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
|
||||
|
||||
_sc_card_add_rsa_alg(card, 1024, flags, -1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -98,41 +108,128 @@ static u8 acl_to_byte(const struct sc_acl_entry *e)
|
|||
return 0x00;
|
||||
}
|
||||
|
||||
static int encode_file_structure(struct sc_card *card, const struct sc_file *file,
|
||||
u8 *buf, size_t *buflen)
|
||||
{
|
||||
u8 *p = buf;
|
||||
const int df_ops[8] = {
|
||||
SC_AC_OP_DELETE, SC_AC_OP_CREATE,
|
||||
-1, /* CREATE AC */ -1, /* UPDATE AC */ -1, -1, -1, -1
|
||||
};
|
||||
const int ef_ops[8] = {
|
||||
SC_AC_OP_DELETE, -1, SC_AC_OP_READ,
|
||||
SC_AC_OP_UPDATE, -1, -1, SC_AC_OP_INVALIDATE,
|
||||
SC_AC_OP_REHABILITATE
|
||||
};
|
||||
const int key_ops[8] = {
|
||||
SC_AC_OP_DELETE, -1, -1,
|
||||
SC_AC_OP_UPDATE, SC_AC_OP_CRYPTO, -1, SC_AC_OP_INVALIDATE,
|
||||
SC_AC_OP_REHABILITATE
|
||||
};
|
||||
const int *ops;
|
||||
int i;
|
||||
|
||||
*p++ = file->id >> 8;
|
||||
*p++ = file->id & 0xFF;
|
||||
switch (file->type) {
|
||||
case SC_FILE_TYPE_DF:
|
||||
*p++ = 0x20;
|
||||
break;
|
||||
case SC_FILE_TYPE_WORKING_EF:
|
||||
switch (file->ef_structure) {
|
||||
case SC_FILE_EF_TRANSPARENT:
|
||||
*p++ = 0x40;
|
||||
break;
|
||||
case SC_FILE_EF_LINEAR_FIXED:
|
||||
*p++ = 0x41;
|
||||
break;
|
||||
case SC_FILE_EF_CYCLIC:
|
||||
*p++ = 0x43;
|
||||
break;
|
||||
default:
|
||||
error(card->ctx, "Invalid EF structure\n");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
break;
|
||||
case SC_FILE_TYPE_INTERNAL_EF:
|
||||
*p++ = 0x44;
|
||||
break;
|
||||
default:
|
||||
error(card->ctx, "Unknown file type\n");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
if (file->type == SC_FILE_TYPE_DF) {
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
} else {
|
||||
*p++ = file->size >> 8;
|
||||
*p++ = file->size & 0xFF;
|
||||
}
|
||||
switch (file->type) {
|
||||
case SC_FILE_TYPE_WORKING_EF:
|
||||
ops = ef_ops;
|
||||
break;
|
||||
case SC_FILE_TYPE_INTERNAL_EF:
|
||||
ops = key_ops;
|
||||
break;
|
||||
case SC_FILE_TYPE_DF:
|
||||
ops = df_ops;
|
||||
break;
|
||||
default:
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
u8 nibble;
|
||||
|
||||
if (ops[i] == -1)
|
||||
nibble = 0x00;
|
||||
else
|
||||
nibble = acl_to_byte(sc_file_get_acl_entry(file, ops[i]));
|
||||
if ((i & 1) == 0)
|
||||
*p = nibble << 4;
|
||||
else
|
||||
*p++ = nibble & 0x0F;
|
||||
}
|
||||
if (file->type == SC_FILE_TYPE_WORKING_EF &&
|
||||
file->ef_structure != SC_FILE_EF_TRANSPARENT)
|
||||
*p++ = file->record_length;
|
||||
else
|
||||
*p++ = 0;
|
||||
if (file->status & SC_FILE_STATUS_INVALIDATED)
|
||||
*p++ = 0;
|
||||
else
|
||||
*p++ = 0x01;
|
||||
if (file->type == SC_FILE_TYPE_DF && file->namelen) {
|
||||
assert(file->namelen <= 16);
|
||||
memcpy(p, file->name, file->namelen);
|
||||
p += file->namelen;
|
||||
}
|
||||
*buflen = p - buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int miocos_create_file(struct sc_card *card, struct sc_file *file)
|
||||
{
|
||||
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];
|
||||
struct sc_apdu apdu;
|
||||
u8 sbuf[32];
|
||||
size_t buflen;
|
||||
int r;
|
||||
|
||||
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]]);
|
||||
r = encode_file_structure(card, file, sbuf, &buflen);
|
||||
if (r)
|
||||
return r;
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
|
||||
apdu.data = sbuf;
|
||||
apdu.datalen = buflen;
|
||||
apdu.lc = buflen;
|
||||
|
||||
memcpy(file->sec_attr, buf, 6);
|
||||
file->sec_attr_len = 6;
|
||||
}
|
||||
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");
|
||||
|
||||
return iso_ops->create_file(card, file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int miocos_set_security_env(struct sc_card *card,
|
||||
|
@ -143,21 +240,21 @@ static int miocos_set_security_env(struct sc_card *card,
|
|||
struct sc_security_env tmp;
|
||||
|
||||
tmp = *env;
|
||||
tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
|
||||
tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
|
||||
tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
|
||||
if (tmp.algorithm != SC_ALGORITHM_RSA) {
|
||||
error(card->ctx, "Only RSA algorithm supported.\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
tmp.algorithm_ref = 0x00;
|
||||
if (tmp.algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
|
||||
tmp.algorithm_ref = 0x00;
|
||||
/* potential FIXME: return an error, if an unsupported
|
||||
* pad or hash was requested, although this shouldn't happen.
|
||||
*/
|
||||
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
|
||||
tmp.algorithm_ref = 0x02;
|
||||
#if 0
|
||||
if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
|
||||
tmp.algorithm_ref |= 0x10;
|
||||
#endif
|
||||
return iso_ops->set_security_env(card, &tmp, se_num);
|
||||
|
||||
tmp.algorithm_ref |= 0x10;
|
||||
return iso_ops->set_security_env(card, &tmp, se_num);
|
||||
}
|
||||
return iso_ops->set_security_env(card, env, se_num);
|
||||
}
|
||||
|
@ -194,29 +291,45 @@ static void add_acl_entry(struct sc_file *file, int op, u8 byte)
|
|||
static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
int idx[6];
|
||||
const int df_ops[8] = {
|
||||
SC_AC_OP_DELETE, SC_AC_OP_CREATE,
|
||||
-1, /* CREATE AC */ -1, /* UPDATE AC */ -1, -1, -1, -1
|
||||
};
|
||||
const int ef_ops[8] = {
|
||||
SC_AC_OP_DELETE, -1, SC_AC_OP_READ,
|
||||
SC_AC_OP_UPDATE, -1, -1, SC_AC_OP_INVALIDATE,
|
||||
SC_AC_OP_REHABILITATE
|
||||
};
|
||||
const int key_ops[8] = {
|
||||
SC_AC_OP_DELETE, -1, -1,
|
||||
SC_AC_OP_UPDATE, SC_AC_OP_CRYPTO, -1, SC_AC_OP_INVALIDATE,
|
||||
SC_AC_OP_REHABILITATE
|
||||
};
|
||||
const int *ops;
|
||||
|
||||
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];
|
||||
if (len < 4)
|
||||
return;
|
||||
switch (file->type) {
|
||||
case SC_FILE_TYPE_WORKING_EF:
|
||||
ops = ef_ops;
|
||||
break;
|
||||
case SC_FILE_TYPE_INTERNAL_EF:
|
||||
ops = key_ops;
|
||||
break;
|
||||
case SC_FILE_TYPE_DF:
|
||||
ops = df_ops;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (ops[i] == -1)
|
||||
continue;
|
||||
if ((i & 1) == 0)
|
||||
add_acl_entry(file, ops[i], buf[i / 2] >> 4);
|
||||
else
|
||||
add_acl_entry(file, ops[i], buf[i / 2] & 0x0F);
|
||||
}
|
||||
for (i = 0; i < 6; i++)
|
||||
add_acl_entry(file, idx[i], buf[i]);
|
||||
}
|
||||
|
||||
static int miocos_select_file(struct sc_card *card,
|
||||
|
@ -249,6 +362,26 @@ static int miocos_list_files(struct sc_card *card, u8 *buf, size_t buflen)
|
|||
return apdu.resplen;
|
||||
}
|
||||
|
||||
static int miocos_delete_file(struct sc_card *card, const struct sc_path *path)
|
||||
{
|
||||
int r;
|
||||
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);
|
||||
}
|
||||
r = sc_select_file(card, path, NULL);
|
||||
SC_TEST_RET(card->ctx, r, "Unable to select file to be deleted");
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
|
||||
|
||||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
return sc_check_sw(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();
|
||||
|
@ -263,6 +396,7 @@ static const struct sc_card_driver * sc_get_driver(void)
|
|||
miocos_ops.set_security_env = miocos_set_security_env;
|
||||
miocos_ops.select_file = miocos_select_file;
|
||||
miocos_ops.list_files = miocos_list_files;
|
||||
miocos_ops.delete_file = miocos_delete_file;
|
||||
|
||||
return &miocos_drv;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ extern "C" {
|
|||
#define SC_AC_OP_REHABILITATE 4
|
||||
#define SC_AC_OP_INVALIDATE 5
|
||||
#define SC_AC_OP_LIST_FILES 6
|
||||
#define SC_AC_OP_CRYPTO 7
|
||||
|
||||
/* Operations relating to access control (in case of EF) */
|
||||
#define SC_AC_OP_READ 0
|
||||
|
@ -137,7 +138,7 @@ extern "C" {
|
|||
#define SC_AC_OP_ERASE 3
|
||||
/* rehab and invalidate are the same as in DF case */
|
||||
|
||||
#define SC_MAX_AC_OPS 7
|
||||
#define SC_MAX_AC_OPS 8
|
||||
|
||||
/* sc_*_record() flags */
|
||||
#define SC_RECORD_EF_ID_MASK 0x0001F
|
||||
|
|
|
@ -23,6 +23,6 @@ pkcs15_crypt_LDADD = @GETOPTSRC@
|
|||
cryptoflex_tool_SOURCES = cryptoflex-tool.c util.c
|
||||
cryptoflex_tool_LDADD = @GETOPTSRC@ @LIBCRYPTO@
|
||||
pkcs15_init_SOURCES = pkcs15-init.c profile.c util.c \
|
||||
pkcs15-gpk.c pkcs15-miocos.c
|
||||
pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c
|
||||
pkcs15_init_LDADD = @GETOPTSRC@ @LIBCRYPTO@
|
||||
noinst_HEADERS = util.h profile.h pkcs15-init.h
|
||||
|
|
|
@ -42,7 +42,6 @@ const char *opt_appdf = NULL, *opt_prkeyf = NULL, *opt_pubkeyf = NULL;
|
|||
u8 *pincode = NULL;
|
||||
|
||||
const struct option options[] = {
|
||||
{ "create-pkcs15", 0, 0, 'C' },
|
||||
{ "list-keys", 0, 0, 'l' },
|
||||
{ "create-key-files", 1, 0, 'c' },
|
||||
{ "create-pin-file", 1, 0, 'P' },
|
||||
|
@ -62,7 +61,6 @@ const struct option options[] = {
|
|||
};
|
||||
|
||||
const char *option_help[] = {
|
||||
"Creates a new PKCS #15 structure",
|
||||
"Lists all keys in a public key file",
|
||||
"Creates new RSA key files for <arg> keys",
|
||||
"Creates a new CHV<arg> file",
|
||||
|
@ -1066,169 +1064,6 @@ int create_pin_file(const struct sc_path *inpath, int chv, const char *key_id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int add_object(struct sc_pkcs15_card *p15card,
|
||||
struct sc_pkcs15_df *df, int file_nr,
|
||||
unsigned int type, void *data, size_t datalen)
|
||||
{
|
||||
struct sc_pkcs15_object *obj;
|
||||
|
||||
obj = malloc(sizeof(*obj));
|
||||
if (obj == NULL)
|
||||
return -1;
|
||||
obj->type = type;
|
||||
obj->data = malloc(datalen);
|
||||
if (obj->data == NULL) {
|
||||
free(obj);
|
||||
return -1;
|
||||
}
|
||||
memcpy(obj->data, data, datalen);
|
||||
return sc_pkcs15_add_object(p15card, df, file_nr, obj);
|
||||
}
|
||||
|
||||
int create_pkcs15()
|
||||
{
|
||||
#if 0
|
||||
struct sc_pkcs15_card *p15card;
|
||||
struct sc_file *file;
|
||||
struct sc_path path;
|
||||
struct sc_pkcs15_object obj;
|
||||
struct sc_pkcs15_cert_info cert;
|
||||
struct sc_pkcs15_pin_info pin;
|
||||
struct sc_pkcs15_prkey_info prkey;
|
||||
int r, file_no;
|
||||
|
||||
p15card = sc_pkcs15_card_new();
|
||||
if (p15card == NULL)
|
||||
return 1;
|
||||
p15card->label = strdup("OpenSC Test Card");
|
||||
p15card->manufacturer_id = strdup("OpenSC Project");
|
||||
p15card->serial_number = strdup("1234");
|
||||
p15card->flags = SC_PKCS15_CARD_FLAG_EID_COMPLIANT;
|
||||
p15card->version = 1;
|
||||
p15card->file_app = sc_file_new();
|
||||
sc_format_path("3F005015", &p15card->file_app->path);
|
||||
p15card->card = card;
|
||||
|
||||
file = sc_file_new();
|
||||
file->size = 32; /* reserve 32 additional bytes in each DF */
|
||||
|
||||
sc_format_path("3F0050155032", &file->path);
|
||||
sc_file_dup(&p15card->file_tokeninfo, 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);
|
||||
if (file_no < 0)
|
||||
return 1;
|
||||
|
||||
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);
|
||||
sc_format_path("3F0050154301", &cert.path);
|
||||
add_object(p15card, &p15card->df[SC_PKCS15_CDF], file_no,
|
||||
SC_PKCS15_TYPE_CERT_X509, &cert, sizeof(cert)),
|
||||
|
||||
strcpy(cert.com_attr.label, "Non-repudiation certificate");
|
||||
sc_pkcs15_format_id("46", &cert.id);
|
||||
sc_format_path("3F0050154302", &cert.path);
|
||||
add_object(p15card, &p15card->df[SC_PKCS15_CDF], file_no,
|
||||
SC_PKCS15_TYPE_CERT_X509, &cert, sizeof(cert)),
|
||||
|
||||
memset(&prkey, 0, sizeof(prkey));
|
||||
prkey.modulus_length = opt_mod_length;
|
||||
prkey.com_attr.flags = 1;
|
||||
prkey.native = 1;
|
||||
|
||||
strcpy(prkey.com_attr.label, "Authentication key");
|
||||
sc_pkcs15_format_id("45", &prkey.id);
|
||||
sc_pkcs15_format_id("01", &prkey.com_attr.auth_id);
|
||||
sc_format_path("0012", &prkey.path);
|
||||
prkey.key_reference = 0;
|
||||
prkey.usage = SC_PKCS15_PRKEY_USAGE_SIGN;
|
||||
prkey.access_flags = 0x1D;
|
||||
add_object(p15card, &p15card->df[SC_PKCS15_PRKDF], file_no,
|
||||
SC_PKCS15_TYPE_PRKEY_RSA, &prkey, sizeof(prkey)),
|
||||
|
||||
strcpy(prkey.com_attr.label, "Non-repudiation key");
|
||||
sc_pkcs15_format_id("46", &prkey.id);
|
||||
sc_pkcs15_format_id("02", &prkey.com_attr.auth_id);
|
||||
sc_format_path("3F004B020012", &prkey.path);
|
||||
prkey.key_reference = 0;
|
||||
prkey.usage = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
|
||||
prkey.access_flags = 0x1D;
|
||||
add_object(p15card, &p15card->df[SC_PKCS15_PRKDF], file_no,
|
||||
SC_PKCS15_TYPE_PRKEY_RSA, &prkey, sizeof(prkey)),
|
||||
|
||||
memset(&pin, 0, sizeof(pin));
|
||||
pin.com_attr.flags = 0x03;
|
||||
pin.magic = SC_PKCS15_PIN_MAGIC;
|
||||
|
||||
strcpy(pin.com_attr.label, "Authentication PIN");
|
||||
sc_pkcs15_format_id("01", &pin.auth_id);
|
||||
sc_format_path("3F005015", &pin.path);
|
||||
pin.reference = 1;
|
||||
pin.flags = 0x32;
|
||||
pin.min_length = 4;
|
||||
pin.stored_length = 8;
|
||||
pin.pad_char = 0x00;
|
||||
pin.type = 1;
|
||||
add_object(p15card, &p15card->df[SC_PKCS15_AODF], file_no,
|
||||
SC_PKCS15_TYPE_AUTH_PIN, &pin, sizeof(pin)),
|
||||
|
||||
strcpy(pin.com_attr.label, "Non-repuditiation PIN");
|
||||
sc_pkcs15_format_id("02", &pin.auth_id);
|
||||
sc_format_path("3F004B02", &pin.path);
|
||||
pin.reference = 1;
|
||||
pin.flags = 0x32;
|
||||
pin.min_length = 4;
|
||||
pin.stored_length = 8;
|
||||
pin.pad_char = 0x00;
|
||||
pin.type = 1;
|
||||
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);
|
||||
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)");
|
||||
if (r)
|
||||
return 1;
|
||||
sc_format_path("3F004B02", &path);
|
||||
r = create_app_df(&path, 1000);
|
||||
if (r) {
|
||||
fprintf(stderr, "Unable to create DF for key 2: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
r = create_pin_file(&path, 1, " (key 2)");
|
||||
if (r)
|
||||
return 1;
|
||||
r = sc_pkcs15_create(p15card, card);
|
||||
sc_pkcs15_card_free(p15card);
|
||||
if (r) {
|
||||
fprintf(stderr, "PKCS #15 structure creation failed: %s\n", sc_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_pin()
|
||||
{
|
||||
struct sc_path path;
|
||||
|
@ -1256,19 +1091,14 @@ int main(int argc, char * const argv[])
|
|||
int do_list_keys = 0;
|
||||
int do_store_key = 0;
|
||||
int do_create_pin_file = 0;
|
||||
int do_create_pkcs15 = 0;
|
||||
|
||||
while (1) {
|
||||
c = getopt_long(argc, argv, "P:Cvslgc:Rk:r:p:u:e:m:dqa:", options, &long_optind);
|
||||
c = getopt_long(argc, argv, "P:vslgc:Rk:r:p:u:e:m:dqa:", options, &long_optind);
|
||||
if (c == -1)
|
||||
break;
|
||||
if (c == '?')
|
||||
print_usage_and_die("cryptoflex-tool");
|
||||
switch (c) {
|
||||
case 'C':
|
||||
do_create_pkcs15 = 1;
|
||||
action_count++;
|
||||
break;
|
||||
case 'l':
|
||||
do_list_keys = 1;
|
||||
action_count++;
|
||||
|
@ -1366,11 +1196,6 @@ int main(int argc, char * const argv[])
|
|||
err = 1;
|
||||
goto end;
|
||||
}
|
||||
if (do_create_pkcs15) {
|
||||
if ((err = create_pkcs15()) != 0)
|
||||
goto end;
|
||||
action_count--;
|
||||
}
|
||||
if (do_create_pin_file) {
|
||||
if ((err = create_pin()) != 0)
|
||||
goto end;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# PKCS #15 r/w profile for GPK cards
|
||||
#
|
||||
CardInfo
|
||||
Label "OpenSC Card"
|
||||
Manufacturer "OpenSC Project"
|
||||
MinPinLength 1
|
||||
MaxPinLength 8
|
||||
PinEncoding ascii-numeric
|
||||
PinPadChar 0x2d # '-'
|
||||
PrKeyAccessFlags RSA 0x1D
|
||||
|
||||
# This is the AAK (ie. transport key) required for
|
||||
# creating files in the MF
|
||||
Key AUT1 0x0001 "=Muscle00"
|
||||
|
||||
EF chv1file
|
||||
FileID 0000
|
||||
Path 50154B01
|
||||
Structure transparent
|
||||
Size 23
|
||||
ACL *=NEVER UPDATE=AUT1
|
||||
|
||||
EF chv2file
|
||||
FileID 0000
|
||||
Path 50154B02
|
||||
Structure transparent
|
||||
Size 23
|
||||
ACL *=NEVER UPDATE=AUT1
|
||||
|
||||
EF template-private-key
|
||||
FileID 0012 # This is the base FileID
|
||||
Structure transparent
|
||||
ACL *=NEVER UPDATE=AUT1
|
||||
|
||||
EF template-public-key
|
||||
FileID 1012
|
||||
Structure transparent
|
||||
ACL *=NONE
|
||||
|
||||
# CVH1. 3 attempts for the PIN, and 10 for the PUK
|
||||
PIN CHV1
|
||||
File chv1file
|
||||
Reference 0x1
|
||||
Attempts 3 10
|
||||
|
||||
# CVH2. 3 attempts for the PIN, and 10 for the PUK
|
||||
PIN CHV2
|
||||
File chv2file
|
||||
Reference 0x1
|
||||
Attempts 3 10
|
|
@ -1,97 +0,0 @@
|
|||
#
|
||||
# PKCS 15 r/w profile for GPK cards
|
||||
#
|
||||
CardInfo
|
||||
Label "OpenSC Card"
|
||||
Manufacturer "OpenSC Project"
|
||||
MinPinLength 0
|
||||
MaxPinLength 8
|
||||
#PinEncoding
|
||||
|
||||
# This is the secure messaging key required for
|
||||
# creating files in the MF
|
||||
#Key PRO 0x0001 "=TEST KEYTEST KEY"
|
||||
|
||||
# This is the application DF
|
||||
DF
|
||||
Path 3F005015
|
||||
AID A0:00:00:00:63:50:4B:43:53:2D:31:35
|
||||
ACL *=NONE
|
||||
|
||||
EF pinfile
|
||||
Path 3F0050150000
|
||||
Structure 0x21 # GPK specific
|
||||
RecordLength 8
|
||||
Size 32
|
||||
ACL *=NEVER
|
||||
|
||||
EF PKCS15-DIR
|
||||
Path 3F002F00
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-ODF
|
||||
Path 3F0050155031
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-TokenInfo
|
||||
Path 3F0050155032
|
||||
ACL *=NONE
|
||||
|
||||
EF PKCS15-AODF
|
||||
Path 3F0050154401
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV2
|
||||
|
||||
EF PKCS15-PrKDF
|
||||
Path 3F0050154402
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV2
|
||||
|
||||
EF PKCS15-CDF
|
||||
Path 3F0050154403
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV2
|
||||
|
||||
# Private key files.
|
||||
# GPK private key files will never let you read the private key
|
||||
# part, so it's okay to set READ=NONE. What's more, we need
|
||||
# read access so we're able to update the file.
|
||||
EF pk1
|
||||
Path 3F005015000E
|
||||
Structure 0x2C # GPK specific
|
||||
ACL *=NEVER READ=NEVER UPDATE=CHV2 WRITE=CHV2
|
||||
|
||||
EF pk2
|
||||
Path 3F005015000F
|
||||
Structure 0x2C # GPK specific
|
||||
ACL *=NEVER READ=NEVER UPDATE=CHV2 WRITE=CHV2
|
||||
|
||||
# CVH1. 7 attempts for the PIN, and 3 for the PUK
|
||||
# Reference 0x8 means "PIN0 in the local EFsc" in GPK parlance
|
||||
PIN CHV1
|
||||
File pinfile
|
||||
Label "Authentication PIN"
|
||||
Reference 0x8
|
||||
Attempts 7 3
|
||||
AuthID 01
|
||||
|
||||
# CVH2. 7 attempts for the PIN, and 3 for the PUK
|
||||
# Reference 0xA means "PIN2 in the local EFsc" in GPK parlance
|
||||
PIN CHV2
|
||||
File pinfile
|
||||
Label "Non-repudiation PIN"
|
||||
Reference 0xA
|
||||
Attempts 7 3
|
||||
Offset 16
|
||||
AuthID 02
|
||||
|
||||
PrivateKey AuthKey
|
||||
Label "Authentication Key"
|
||||
File pk1
|
||||
ID 45
|
||||
AuthID 01 # Requires CHV1
|
||||
KeyUsage sign
|
||||
|
||||
PrivateKey SignKey
|
||||
Label "Non-repudiation Key"
|
||||
File pk2
|
||||
ID 46
|
||||
AuthID 02 # Requires CHV2
|
||||
KeyUsage NonRepudiation
|
|
@ -0,0 +1,57 @@
|
|||
#
|
||||
# PKCS 15 r/w profile for MioCOS cards
|
||||
#
|
||||
CardInfo
|
||||
Label "OpenSC Card"
|
||||
Manufacturer "OpenSC Project"
|
||||
MinPinLength 4
|
||||
MaxPinLength 8
|
||||
PinEncoding ascii-numeric
|
||||
PrKeyAccessFlags RSA 0x1D
|
||||
PrKeyAccessFlags DSA 0x12
|
||||
|
||||
# This is the secure messaging key required for
|
||||
# creating files in the MF
|
||||
# Key PRO 0x0001 "=TEST KEYTEST KEY"
|
||||
|
||||
# Note: many commands use the short file ID (i.e. the lower 5 bits
|
||||
# of the FID) so you must be careful when picking FIDs for the
|
||||
# public key and PIN files.
|
||||
|
||||
# Currently we do not support PIN files that can be updated
|
||||
# by CHV2. Far too messy.
|
||||
EF pinfile
|
||||
FileID 0000
|
||||
Structure 0x21 # GPK specific
|
||||
RecordLength 8
|
||||
Size 32
|
||||
ACL *=NEVER
|
||||
|
||||
# Private key files.
|
||||
# GPK private key files will never let you read the private key
|
||||
# part, so it's okay to set READ=NONE. What's more, we need
|
||||
# read access so we're able to update the file.
|
||||
EF template-private-key
|
||||
FileID 0006 # This is the base FileID
|
||||
Structure 0x2C # GPK specific
|
||||
ACL *=NEVER READ=NONE UPDATE=CHV2 WRITE=CHV2
|
||||
|
||||
EF template-public-key
|
||||
FileID 8000
|
||||
Structure transparent
|
||||
ACL *=NONE
|
||||
|
||||
# CVH1. 7 attempts for the PIN, and 3 for the PUK
|
||||
# Reference 0x8 means "PIN0 in the local EFsc" in GPK parlance
|
||||
PIN CHV1
|
||||
File pinfile
|
||||
Reference 0x8
|
||||
Attempts 7 3
|
||||
|
||||
# CVH2. 7 attempts for the PIN, and 3 for the PUK
|
||||
# Reference 0xA means "PIN2 in the local EFsc" in GPK parlance
|
||||
PIN CHV2
|
||||
File pinfile
|
||||
Reference 0xA
|
||||
Attempts 7 3
|
||||
Offset 16
|
|
@ -465,7 +465,7 @@ int do_create(const char *arg, const char *arg2)
|
|||
struct sc_path path;
|
||||
struct sc_file *file;
|
||||
unsigned int size;
|
||||
int r;
|
||||
int r, i;
|
||||
|
||||
if (arg_to_path(arg, &path, 1) != 0)
|
||||
goto usage;
|
||||
|
@ -478,7 +478,9 @@ int do_create(const char *arg, const char *arg2)
|
|||
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||
file->size = (size_t) size;
|
||||
file->status = SC_FILE_STATUS_ACTIVATED;
|
||||
|
||||
for (i = 0; i < SC_MAX_AC_OPS; i++)
|
||||
sc_file_add_acl_entry(file, i, SC_AC_NONE, SC_AC_KEY_REF_NONE);
|
||||
|
||||
r = create_file(file);
|
||||
sc_file_free(file);
|
||||
return r;
|
||||
|
|
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
* Cryptoflex specific operation for PKCS #15 initialization
|
||||
*
|
||||
* Copyright (C) 2002 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <openssl/bn.h>
|
||||
#include "opensc.h"
|
||||
#include "cardctl.h"
|
||||
#include "pkcs15-init.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* Update the contents of a PIN file
|
||||
*/
|
||||
static int cflex_update_pin(struct sc_card *card, struct pin_info *info)
|
||||
{
|
||||
u8 buffer[23], *p = buffer;
|
||||
int r;
|
||||
size_t len;
|
||||
|
||||
if (!info->attempt[1]) {
|
||||
error("Cryptoflex needs a PUK code");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
memset(p, 0xFF, 3);
|
||||
p += 3;
|
||||
memset(p, '-', 8);
|
||||
strncpy(p, info->secret[0], 8);
|
||||
p += 8;
|
||||
*p++ = info->attempt[0];
|
||||
*p++ = info->attempt[0];
|
||||
memset(p, '-', 8);
|
||||
strncpy(p, info->secret[0], 8);
|
||||
p += 8;
|
||||
*p++ = info->attempt[1];
|
||||
*p++ = info->attempt[1];
|
||||
len = 23;
|
||||
|
||||
r = sc_update_binary(card, 0, buffer, len, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the PIN file and write the PINs
|
||||
*/
|
||||
static int cflex_store_pin(struct sc_profile *profile, struct sc_card *card,
|
||||
struct pin_info *info)
|
||||
{
|
||||
struct sc_file *pinfile;
|
||||
int r;
|
||||
|
||||
sc_file_dup(&pinfile, info->file->file);
|
||||
|
||||
/* Now create the file */
|
||||
if ((r = sc_pkcs15init_create_file(profile, pinfile)) < 0)
|
||||
goto out;
|
||||
|
||||
/* If messing with the PIN file requires any sort of
|
||||
* authentication, send it to the card now */
|
||||
if ((r = sc_select_file(card, &pinfile->path, NULL)) < 0
|
||||
|| (r = sc_pkcs15init_authenticate(profile, pinfile, SC_AC_OP_UPDATE)) < 0)
|
||||
goto out;
|
||||
|
||||
r = cflex_update_pin(card, info);
|
||||
|
||||
out: sc_file_free(pinfile);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the Application DF and store the PINs
|
||||
*
|
||||
*/
|
||||
static int cflex_init_app(struct sc_profile *profile, struct sc_card *card)
|
||||
{
|
||||
struct pin_info *pin1, *pin2;
|
||||
|
||||
pin1 = sc_profile_find_pin(profile, "CHV1");
|
||||
pin2 = sc_profile_find_pin(profile, "CHV2");
|
||||
if (pin1 == NULL) {
|
||||
fprintf(stderr, "No CHV1 defined\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* XXX TODO:
|
||||
* if the CHV2 pin file is required to create files
|
||||
* in the application DF, create that file first */
|
||||
|
||||
/* Create the application DF */
|
||||
if (sc_pkcs15init_create_file(profile, profile->df_info.file))
|
||||
return 1;
|
||||
|
||||
/* Store CHV2 */
|
||||
if (pin2) {
|
||||
if (cflex_store_pin(profile, card, pin2))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Store CHV1 */
|
||||
if (cflex_store_pin(profile, card, pin1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a file
|
||||
*/
|
||||
static int cflex_allocate_file(struct sc_profile *profile, struct sc_card *card,
|
||||
unsigned int type, unsigned int num,
|
||||
struct sc_file **out)
|
||||
{
|
||||
struct file_info *templ;
|
||||
struct sc_file *file;
|
||||
struct sc_path *p;
|
||||
char name[64], *tag, *desc;
|
||||
|
||||
desc = tag = NULL;
|
||||
while (1) {
|
||||
switch (type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
desc = "RSA private key";
|
||||
tag = "private-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
||||
desc = "RSA public key";
|
||||
tag = "public-key";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_CERT:
|
||||
desc = "certificate";
|
||||
tag = "data";
|
||||
break;
|
||||
case SC_PKCS15_TYPE_DATA_OBJECT:
|
||||
desc = "data object";
|
||||
tag = "data";
|
||||
break;
|
||||
}
|
||||
if (tag)
|
||||
break;
|
||||
/* If this is a specific type such as
|
||||
* SC_PKCS15_TYPE_CERT_FOOBAR, fall back to
|
||||
* the generic class (SC_PKCS15_TYPE_CERT)
|
||||
*/
|
||||
if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) {
|
||||
error("File type not supported by card driver");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
type &= SC_PKCS15_TYPE_CLASS_MASK;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "template-%s", tag);
|
||||
if (!(templ = sc_profile_find_file(profile, name))) {
|
||||
error("Profile doesn't define %s template (%s)\n",
|
||||
desc, name);
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Now construct file from template */
|
||||
sc_file_dup(&file, templ->file);
|
||||
file->id += num;
|
||||
|
||||
p = &file->path;
|
||||
*p = profile->df_info.file->path;
|
||||
p->value[p->len++] = file->id >> 8;
|
||||
p->value[p->len++] = file->id;
|
||||
|
||||
*out = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Create the PK file
|
||||
*/
|
||||
static int gpk_pkfile_create(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *file)
|
||||
{
|
||||
struct sc_file *found = NULL;
|
||||
int r;
|
||||
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_select_file(card, &file->path, &found);
|
||||
card->ctx->log_errors = 1;
|
||||
if (r == SC_ERROR_FILE_NOT_FOUND) {
|
||||
r = sc_pkcs15init_create_file(profile, file);
|
||||
if (r >= 0)
|
||||
r = sc_select_file(card, &file->path, &found);
|
||||
} else {
|
||||
/* XXX: make sure the file has correct type and size? */
|
||||
}
|
||||
|
||||
if (r >= 0)
|
||||
r = sc_pkcs15init_authenticate(profile, file, SC_AC_OP_UPDATE);
|
||||
if (found)
|
||||
sc_file_free(found);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the public key record for a signature only public key
|
||||
*/
|
||||
static int
|
||||
gpk_pkfile_init_public(struct sc_card *card, struct sc_file *file,
|
||||
unsigned int algo, unsigned int bits,
|
||||
unsigned int usage, struct sc_acl_entry *acl)
|
||||
{
|
||||
u8 sysrec[7], buffer[256];
|
||||
unsigned int npins, n;
|
||||
int r;
|
||||
|
||||
/* Set up the system record */
|
||||
memset(sysrec, 0, sizeof(sysrec));
|
||||
|
||||
/* XXX: How to map keyUsage to sysrec[2]?
|
||||
* 0x00 sign & unwrap
|
||||
* 0x10 sign only
|
||||
* 0x20 unwrap only
|
||||
* 0x30 CA key
|
||||
* Which PKCS15 key usage values map to which flag?
|
||||
*/
|
||||
sysrec[2] = 0x00; /* no restriction for now */
|
||||
|
||||
/* Set the key type and algorithm */
|
||||
if ((r = gpk_pkfile_keybits(bits, &sysrec[1])) < 0
|
||||
|| (r = gpk_pkfile_keyalgo(algo, &sysrec[5])) < 0)
|
||||
return r;
|
||||
|
||||
/* Set PIN protection if requested. */
|
||||
for (npins = 0; acl; acl = acl->next) {
|
||||
if (acl->method == SC_AC_NONE
|
||||
|| acl->method == SC_AC_NEVER)
|
||||
continue;
|
||||
if (acl->method == SC_AC_CHV) {
|
||||
if (++npins >= 2) {
|
||||
error("Too many pins for PrKEY file!\n");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
sysrec[2] += 0x40;
|
||||
sysrec[3] >>= 4;
|
||||
sysrec[3] |= acl->key_ref << 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* compute checksum - yet another slightly different
|
||||
* checksum algorithm courtesy of Gemplus */
|
||||
/* XXX: This is different from what the GPK reference
|
||||
* manual says which tells you to start with 0xA5 -- but
|
||||
* maybe that's just for the GPK8000 */
|
||||
for (sysrec[6] = 0xFF, n = 0; n < 6; n++)
|
||||
sysrec[6] ^= sysrec[n];
|
||||
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_read_record(card, 1, buffer, sizeof(buffer),
|
||||
SC_RECORD_BY_REC_NR);
|
||||
card->ctx->log_errors = 1;
|
||||
if (r >= 0) {
|
||||
if (r != 7 || buffer[0] != 0) {
|
||||
error("first record of public key file is not Lsys0");
|
||||
return SC_ERROR_OBJECT_NOT_VALID;
|
||||
}
|
||||
|
||||
r = sc_update_record(card, 1, sysrec, sizeof(sysrec),
|
||||
SC_RECORD_BY_REC_NR);
|
||||
} else {
|
||||
r = sc_append_record(card, sysrec, sizeof(sysrec), 0);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_update_public(struct sc_card *card, struct pkpart *part)
|
||||
{
|
||||
struct pkcomp *pe;
|
||||
unsigned char buffer[256];
|
||||
unsigned int m, n, tag;
|
||||
int r = 0, found;
|
||||
|
||||
if (card->ctx->debug > 1)
|
||||
printf("Updating public key elements\n");
|
||||
|
||||
/* If we've been given a key with public parts, write them now */
|
||||
for (n = 2; n < 256; n++) {
|
||||
card->ctx->log_errors = 0;
|
||||
r = sc_read_record(card, n, buffer, sizeof(buffer),
|
||||
SC_RECORD_BY_REC_NR);
|
||||
card->ctx->log_errors = 1;
|
||||
if (r < 0) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for bad record */
|
||||
if (r < 2) {
|
||||
error("key file format error: "
|
||||
"record %u too small (%u bytes)\n",
|
||||
n, r);
|
||||
return SC_ERROR_OBJECT_NOT_VALID;
|
||||
}
|
||||
|
||||
tag = buffer[0];
|
||||
|
||||
for (m = 0, found = 0; m < part->count; m++) {
|
||||
pe = part->components + m;
|
||||
if (pe->tag == tag) {
|
||||
r = sc_update_record(card, n,
|
||||
pe->data, pe->size,
|
||||
SC_RECORD_BY_REC_NR);
|
||||
if (r < 0)
|
||||
return r;
|
||||
pe->tag = 0; /* mark as stored */
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && card->ctx->debug)
|
||||
printf("GPK unknown PK tag %u\n", tag);
|
||||
}
|
||||
|
||||
/* Write all remaining elements */
|
||||
for (m = 0; r >= 0 && m < part->count; m++) {
|
||||
pe = part->components + m;
|
||||
if (pe->tag != 0)
|
||||
r = sc_append_record(card, pe->data, pe->size, 0);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_init_private(struct sc_card *card,
|
||||
struct sc_file *file, unsigned int privlen)
|
||||
{
|
||||
struct sc_cardctl_gpk_pkinit args;
|
||||
|
||||
if (card->ctx->debug > 1)
|
||||
printf("Initializing private key portion of file\n");
|
||||
args.file = file;
|
||||
args.privlen = privlen;
|
||||
return sc_card_ctl(card, SC_CARDCTL_GPK_PKINIT, &args);
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_load_private(struct sc_card *card, struct sc_file *file,
|
||||
u8 *data, unsigned int len, unsigned int datalen)
|
||||
{
|
||||
struct sc_cardctl_gpk_pkload args;
|
||||
|
||||
args.file = file;
|
||||
args.data = data;
|
||||
args.len = len;
|
||||
args.datalen = datalen;
|
||||
return sc_card_ctl(card, SC_CARDCTL_GPK_PKLOAD, &args);
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_pkfile_update_private(struct sc_profile *profile,
|
||||
struct sc_card *card, struct sc_file *file,
|
||||
struct pkpart *part)
|
||||
{
|
||||
struct auth_info *sm;
|
||||
unsigned int m, size, nb, cks;
|
||||
struct pkcomp *pe;
|
||||
u8 data[256];
|
||||
int r = 0;
|
||||
|
||||
if (card->ctx->debug > 1)
|
||||
printf("Updating private key elements\n");
|
||||
|
||||
/* We must set a secure messaging key before each Load Private Key
|
||||
* command. Any key will do...
|
||||
* The GPK _is_ weird. */
|
||||
sm = sc_profile_find_key(profile, SC_AC_PRO, -1);
|
||||
if (sm == NULL) {
|
||||
error("No secure messaging key defined by profile");
|
||||
return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
||||
}
|
||||
|
||||
for (m = 0; m < part->count; m++) {
|
||||
pe = part->components + m;
|
||||
|
||||
if (pe->size + 8 > sizeof(data))
|
||||
return SC_ERROR_BUFFER_TOO_SMALL;
|
||||
memcpy(data, pe->data, pe->size);
|
||||
size = pe->size;
|
||||
|
||||
r = sc_verify(card, SC_AC_PRO,
|
||||
sm->ref, sm->key, sm->key_len, NULL);
|
||||
if (r < 0)
|
||||
break;
|
||||
|
||||
/* Pad out data to a multiple of 8 and checksum.
|
||||
* The GPK manual is a bit unclear about whether you
|
||||
* checksum first and then pad, or vice versa.
|
||||
* The following code does seem to work though: */
|
||||
for (nb = 0, cks = 0xff; nb < size; nb++)
|
||||
cks ^= data[nb];
|
||||
data[nb++] = cks;
|
||||
while (nb & 7)
|
||||
data[nb++] = 0;
|
||||
|
||||
r = gpk_pkfile_load_private(card, file, data, size, nb);
|
||||
if (r < 0)
|
||||
break;
|
||||
pe++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Sum up the size of the public key elements
|
||||
* Each element is type + tag + bignum
|
||||
*/
|
||||
static void
|
||||
gpk_compute_publen(struct pkpart *part)
|
||||
{
|
||||
unsigned int n, publen = 8; /* length of sysrec0 */
|
||||
|
||||
for (n = 0; n < part->count; n++)
|
||||
publen += 2 + part->components[n].size;
|
||||
part->size = (publen + 3) & ~3UL;
|
||||
}
|
||||
|
||||
/* Sum up the size of the private key elements
|
||||
* Each element is type + tag + bignum + checksum, padded to a multiple
|
||||
* of eight
|
||||
*/
|
||||
static void
|
||||
gpk_compute_privlen(struct pkpart *part)
|
||||
{
|
||||
unsigned int n, privlen = 8;
|
||||
|
||||
for (n = 0; n < part->count; n++)
|
||||
privlen += (3 + part->components[n].size + 7) & ~7UL;
|
||||
part->size = privlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert BIGNUM to GPK representation, optionally zero padding to size.
|
||||
* Note OpenSSL stores BIGNUMs big endian while the GPK wants them
|
||||
* little endian
|
||||
*/
|
||||
static void
|
||||
gpk_bn2bin(const BIGNUM *bn, unsigned char *dest, unsigned int size)
|
||||
{
|
||||
u8 temp[256], *src;
|
||||
unsigned int n, len;
|
||||
|
||||
assert(BN_num_bytes(bn) <= sizeof(temp));
|
||||
len = BN_bn2bin(bn, temp);
|
||||
|
||||
assert(len <= size);
|
||||
for (n = 0, src = temp + len - 1; n < len; n++)
|
||||
dest[n] = *src--;
|
||||
for (; n < size; n++)
|
||||
dest[n] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a BIGNUM component, optionally padding out the number to size bytes
|
||||
*/
|
||||
static void
|
||||
gpk_add_bignum(struct pkpart *part, unsigned int tag, BIGNUM *bn, size_t size)
|
||||
{
|
||||
struct pkcomp *comp;
|
||||
|
||||
if (size == 0)
|
||||
size = BN_num_bytes(bn);
|
||||
|
||||
comp = &part->components[part->count++];
|
||||
memset(comp, 0, sizeof(*comp));
|
||||
comp->tag = tag;
|
||||
comp->size = size + 1;
|
||||
comp->data = malloc(size + 1);
|
||||
|
||||
/* Add the tag */
|
||||
comp->data[0] = tag;
|
||||
|
||||
/* Add the BIGNUM */
|
||||
gpk_bn2bin(bn, comp->data + 1, size);
|
||||
|
||||
/* printf("TAG 0x%02x, len=%u\n", tag, comp->size); */
|
||||
}
|
||||
|
||||
int
|
||||
gpk_encode_rsa_key(RSA *rsa, struct pkdata *p, unsigned int usage)
|
||||
{
|
||||
if (!rsa->n || !rsa->e) {
|
||||
error("incomplete RSA public key");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
/* Make sure the exponent is 0x10001 because that's
|
||||
* the only exponent supported by GPK4000 and GPK8000 */
|
||||
if (!BN_is_word(rsa->e, RSA_F4)) {
|
||||
error("unsupported RSA exponent");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->algo = SC_ALGORITHM_RSA;
|
||||
p->usage = usage;
|
||||
p->bits = BN_num_bits(rsa->n);
|
||||
p->bytes = BN_num_bytes(rsa->n);
|
||||
|
||||
/* Set up the list of public elements */
|
||||
gpk_add_bignum(&p->public, 0x01, rsa->n, 0);
|
||||
gpk_add_bignum(&p->public, 0x07, rsa->e, 0);
|
||||
|
||||
/* Set up the list of private elements */
|
||||
if (!rsa->p || !rsa->q || !rsa->dmp1 || !rsa->dmq1 || !rsa->iqmp) {
|
||||
/* No or incomplete CRT information */
|
||||
if (!rsa->d) {
|
||||
error("incomplete RSA private key");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
gpk_add_bignum(&p->private, 0x04, rsa->d, 0);
|
||||
} else if (5 * (p->bytes / 2) < 256) {
|
||||
/* All CRT elements are stored in one record */
|
||||
struct pkcomp *comp;
|
||||
unsigned int K = p->bytes / 2;
|
||||
u8 *crtbuf;
|
||||
|
||||
crtbuf = malloc(5 * K + 1);
|
||||
|
||||
crtbuf[0] = 0x05;
|
||||
gpk_bn2bin(rsa->p, crtbuf + 1, K);
|
||||
gpk_bn2bin(rsa->q, crtbuf + 1 + 1 * K, K);
|
||||
gpk_bn2bin(rsa->iqmp, crtbuf + 1 + 2 * K, K);
|
||||
gpk_bn2bin(rsa->dmp1, crtbuf + 1 + 3 * K, K);
|
||||
gpk_bn2bin(rsa->dmq1, crtbuf + 1 + 4 * K, K);
|
||||
|
||||
comp = &p->private.components[p->private.count++];
|
||||
comp->tag = 0x05;
|
||||
comp->size = 5 * K + 1;
|
||||
comp->data = crtbuf;
|
||||
} else {
|
||||
/* CRT elements stored in individual records.
|
||||
* Make sure they're all fixed length even if they're
|
||||
* shorter */
|
||||
gpk_add_bignum(&p->private, 0x51, rsa->p, p->bytes/2);
|
||||
gpk_add_bignum(&p->private, 0x52, rsa->q, p->bytes/2);
|
||||
gpk_add_bignum(&p->private, 0x53, rsa->iqmp, p->bytes/2);
|
||||
gpk_add_bignum(&p->private, 0x54, rsa->dmp1, p->bytes/2);
|
||||
gpk_add_bignum(&p->private, 0x55, rsa->dmq1, p->bytes/2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode a DSA key.
|
||||
* Confusingly, the GPK manual says that the GPK8000 can handle
|
||||
* DSA with 512 as well as 1024 bits, but all byte sizes shown
|
||||
* in the tables are 512 bits only...
|
||||
*/
|
||||
int
|
||||
gpk_encode_dsa_key(DSA *dsa, struct pkdata *p, unsigned int usage)
|
||||
{
|
||||
if (!dsa->p || !dsa->q || !dsa->g || !dsa->pub_key || !dsa->priv_key) {
|
||||
error("incomplete DSA public key");
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->algo = SC_ALGORITHM_RSA;
|
||||
p->usage = usage;
|
||||
p->bits = BN_num_bits(dsa->p);
|
||||
p->bytes = BN_num_bytes(dsa->p);
|
||||
|
||||
/* Make sure the key is either 512 or 1024 bits */
|
||||
if (p->bytes <= 64) {
|
||||
p->bits = 512;
|
||||
p->bytes = 64;
|
||||
} else if (p->bytes <= 128) {
|
||||
p->bits = 1024;
|
||||
p->bytes = 128;
|
||||
} else {
|
||||
error("incompatible DSA key size (%u bits)", p->bits);
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
||||
/* Set up the list of public elements */
|
||||
gpk_add_bignum(&p->public, 0x09, dsa->p, 0);
|
||||
gpk_add_bignum(&p->public, 0x0a, dsa->q, 0);
|
||||
gpk_add_bignum(&p->public, 0x0b, dsa->g, 0);
|
||||
gpk_add_bignum(&p->public, 0x0c, dsa->pub_key, 0);
|
||||
|
||||
/* Set up the list of private elements */
|
||||
gpk_add_bignum(&p->private, 0x0d, dsa->priv_key, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gpk_store_pk(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_file *file, struct pkdata *p,
|
||||
struct sc_acl_entry *key_acl)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* Compute length of private/public key parts */
|
||||
gpk_compute_publen(&p->public);
|
||||
gpk_compute_privlen(&p->private);
|
||||
|
||||
if (card->ctx->debug)
|
||||
printf("Storing pk: %u bits, pub %u bytes, priv %u bytes\n",
|
||||
p->bits, p->bytes, p->private.size);
|
||||
|
||||
/* Strange, strange, strange... when I create the public part with
|
||||
* the exact size of 8 + PK elements, the card refuses to store
|
||||
* the last record even though there's enough room in the file.
|
||||
* XXX: Check why */
|
||||
file->size = p->public.size + 8 + p->private.size + 8;
|
||||
r = gpk_pkfile_create(profile, card, file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Put the system record */
|
||||
r = gpk_pkfile_init_public(card, file, p->algo,
|
||||
p->bits, p->usage, key_acl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Put the public key elements */
|
||||
r = gpk_pkfile_update_public(card, &p->public);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Create the private key part */
|
||||
r = gpk_pkfile_init_private(card, file, p->private.size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Now store the private key elements */
|
||||
r = gpk_pkfile_update_private(profile, card, file, &p->private);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a RSA key on the card
|
||||
*/
|
||||
static int gpk_store_rsa_key(struct sc_profile *profile, struct sc_card *card,
|
||||
struct sc_key_template *info, RSA *rsa)
|
||||
{
|
||||
struct pkdata data;
|
||||
int r;
|
||||
|
||||
if ((r = gpk_encode_rsa_key(rsa, &data, info->pkcs15.priv.usage)) < 0)
|
||||
return r;
|
||||
return gpk_store_pk(profile, card, info->file, &data, info->key_acl);
|
||||
}
|
||||
#endif
|
||||
|
||||
void bind_cflex_operations(struct pkcs15_init_operations *ops)
|
||||
{
|
||||
ops->init_app = cflex_init_app;
|
||||
ops->allocate_file = cflex_allocate_file;
|
||||
// ops->store_rsa = gpk_store_rsa_key;
|
||||
}
|
|
@ -272,6 +272,8 @@ bind_operations(struct pkcs15_init_operations *ops, const char *driver)
|
|||
bind_gpk_operations(ops);
|
||||
else if (!strcasecmp(driver, "MioCOS"))
|
||||
bind_miocos_operations(ops);
|
||||
else if (!strcasecmp(driver, "flex"))
|
||||
bind_cflex_operations(ops);
|
||||
else
|
||||
fatal("Don't know how to handle %s cards", driver);
|
||||
}
|
||||
|
|
|
@ -49,5 +49,6 @@ extern int sc_pkcs15init_authenticate(struct sc_profile *,
|
|||
/* Card specific stuff */
|
||||
extern void bind_gpk_operations(struct pkcs15_init_operations *);
|
||||
extern void bind_miocos_operations(struct pkcs15_init_operations *);
|
||||
extern void bind_cflex_operations(struct pkcs15_init_operations *);
|
||||
|
||||
#endif /* PKCS15_INIT_H */
|
||||
|
|
|
@ -506,6 +506,12 @@ do_default_pin_type(int argc, char **argv)
|
|||
&parser.profile->pin_encoding, pinTypeNames);
|
||||
}
|
||||
|
||||
static int
|
||||
do_pin_pad_char(int argc, char **argv)
|
||||
{
|
||||
return get_uint(argv[0], &parser.profile->pin_pad_char);
|
||||
}
|
||||
|
||||
static int
|
||||
do_card_label(int argc, char **argv)
|
||||
{
|
||||
|
@ -533,7 +539,7 @@ do_default_access_flags(int argc, char **argv)
|
|||
if (!strcasecmp(argv[0], "DSA")) {
|
||||
flags = &parser.profile->dsa_access_flags;
|
||||
} else {
|
||||
parse_error("Unknown alforithm \"%s\"", argv[0]);
|
||||
parse_error("Unknown algorithm \"%s\"", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
argc--, argv++;
|
||||
|
@ -1136,6 +1142,7 @@ static struct command commands[] = {
|
|||
{ "MaxPinLength", PARSE_CARDINFO, 1, 1, do_maxpinlength },
|
||||
{ "MinPinLength", PARSE_CARDINFO, 1, 1, do_minpinlength },
|
||||
{ "PinEncoding", PARSE_CARDINFO, 1, 1, do_default_pin_type },
|
||||
{ "PinPadChar", PARSE_CARDINFO, 1, 1, do_pin_pad_char },
|
||||
{ "Key", PARSE_CARDINFO, 3, 3, do_key },
|
||||
{ "Label", PARSE_CARDINFO, 1, 1, do_card_label },
|
||||
{ "Manufacturer", PARSE_CARDINFO, 1, 1, do_card_manufacturer},
|
||||
|
|
Loading…
Reference in New Issue