Improved myeid driver (by Aventra)
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3788 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
6cd345d316
commit
12213dee5c
|
@ -25,23 +25,19 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static enum LOAD_KEY {
|
||||
LOAD_KEY_MODULUS = 0x80,
|
||||
LOAD_KEY_PUBLIC_EXPONENT = 0x81,
|
||||
LOAD_KEY_PRIME_P = 0x83,
|
||||
LOAD_KEY_PRIME_Q = 0x84,
|
||||
LOAD_KEY_DP1 = 0x85,
|
||||
LOAD_KEY_DQ1 = 0x86,
|
||||
LOAD_KEY_INVQ = 0x87
|
||||
};
|
||||
#define LOAD_KEY_MODULUS 0x80
|
||||
#define LOAD_KEY_PUBLIC_EXPONENT 0x81
|
||||
#define LOAD_KEY_PRIME_P 0x83
|
||||
#define LOAD_KEY_PRIME_Q 0x84
|
||||
#define LOAD_KEY_DP1 0x85
|
||||
#define LOAD_KEY_DQ1 0x86
|
||||
#define LOAD_KEY_INVQ 0x87
|
||||
|
||||
static struct sc_card_operations myeid_ops;
|
||||
static struct sc_card_driver myeid_drv = {
|
||||
"MyEID cards with PKCS#15 applet",
|
||||
"myeid",
|
||||
&myeid_ops,
|
||||
NULL, 0, NULL
|
||||
&myeid_ops
|
||||
};
|
||||
|
||||
static const char *myeid_atrs[] = {
|
||||
|
@ -93,6 +89,7 @@ static int myeid_init(struct sc_card *card)
|
|||
/* State that we have an RNG */
|
||||
card->caps |= SC_CARD_CAP_RNG;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -107,9 +104,9 @@ static int acl_to_byte(const struct sc_acl_entry *e)
|
|||
case SC_AC_TERM:
|
||||
case SC_AC_AUT:
|
||||
if (e->key_ref == SC_AC_KEY_REF_NONE)
|
||||
return -1;
|
||||
return 0x00;
|
||||
if (e->key_ref < 1 || e->key_ref > 14)
|
||||
return -1;
|
||||
return 0x00;
|
||||
return e->key_ref;
|
||||
case SC_AC_NEVER:
|
||||
return 0x0F;
|
||||
|
@ -182,28 +179,28 @@ static int myeid_select_file(struct sc_card *card, const struct sc_path *in_path
|
|||
struct sc_file **file)
|
||||
{
|
||||
int r;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
r = iso_ops->select_file(card, in_path, file);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (file != NULL) {
|
||||
if (r == 0 && file != NULL) {
|
||||
parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
static int myeid_read_binary(struct sc_card *card, unsigned int idx,
|
||||
u8 * buf, size_t count, unsigned long flags)
|
||||
{
|
||||
return iso_ops->read_binary(card, idx, buf, count, flags);
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, iso_ops->read_binary(card, idx, buf, count, flags));
|
||||
}
|
||||
|
||||
static int myeid_list_files(struct sc_card *card, u8 *buf, size_t buflen)
|
||||
{
|
||||
struct sc_apdu apdu;
|
||||
int r;
|
||||
int r,i;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0xA1);
|
||||
apdu.resp = buf;
|
||||
|
@ -225,9 +222,10 @@ static int myeid_process_fci(struct sc_card *card, struct sc_file *file,
|
|||
const u8 *tag = NULL;
|
||||
int r ;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
r = iso_ops->process_fci(card, file, buf, buflen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
|
||||
if(file->type == SC_FILE_EF_UNKNOWN)
|
||||
{
|
||||
|
@ -237,16 +235,23 @@ static int myeid_process_fci(struct sc_card *card, struct sc_file *file,
|
|||
file->type = SC_FILE_TYPE_INTERNAL_EF;
|
||||
}
|
||||
}
|
||||
if(file->sec_attr_len >= 3)
|
||||
{
|
||||
sc_debug(card->ctx, "id (%X) sec_attr (%X %X %X) \n", file->id,
|
||||
file->sec_attr[0],file->sec_attr[1],file->sec_attr[2]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
SC_FUNC_RETURN(card->ctx, 1, 0);
|
||||
}
|
||||
|
||||
static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
|
||||
u8 *out, size_t *outlen)
|
||||
{
|
||||
const sc_acl_entry_t *read, *update, *delete;
|
||||
u8 buf[40];
|
||||
int i;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
/* PrivateKey
|
||||
* 0E0000019 6217 81020400 820111 83024B01 8603000000 85028000 8A0100 RESULT 6984
|
||||
* 6217 81020400 820111 83024B01 8603000000 85021000 8A0100 */
|
||||
|
@ -283,6 +288,41 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
|
|||
buf[15] = file->sec_attr[0];
|
||||
buf[16] = file->sec_attr[1];
|
||||
buf[17] = file->sec_attr[2];
|
||||
|
||||
sc_debug(card->ctx, "id (%X), sec_attr %X %X %X\n", file->id,
|
||||
file->sec_attr[0],file->sec_attr[1],file->sec_attr[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete = sc_file_get_acl_entry(file, SC_AC_OP_DELETE);
|
||||
|
||||
switch (file->type) {
|
||||
case SC_FILE_TYPE_WORKING_EF:
|
||||
|
||||
read = sc_file_get_acl_entry(file, SC_AC_OP_READ);
|
||||
update = sc_file_get_acl_entry(file, SC_AC_OP_UPDATE);
|
||||
|
||||
buf[15] = (acl_to_byte(read) << 4) | acl_to_byte(update);
|
||||
buf[16] = (acl_to_byte(delete)<< 4) | 0x0F;
|
||||
break;
|
||||
case SC_FILE_TYPE_INTERNAL_EF:
|
||||
|
||||
read = sc_file_get_acl_entry(file, SC_AC_OP_CRYPTO);
|
||||
update = sc_file_get_acl_entry(file, SC_AC_OP_UPDATE);
|
||||
|
||||
buf[15] = (acl_to_byte(read) << 4) | acl_to_byte(update);
|
||||
buf[16] = (acl_to_byte(delete)<< 4) | 0x0F;
|
||||
break;
|
||||
case SC_FILE_TYPE_DF:
|
||||
|
||||
update = sc_file_get_acl_entry(file, SC_AC_OP_CREATE);
|
||||
|
||||
buf[15] = (acl_to_byte(update) << 4) | acl_to_byte(update);
|
||||
buf[16] = (acl_to_byte(delete) << 4) | 0x0F;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Proprietary Information */
|
||||
|
@ -312,10 +352,10 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
|
|||
{
|
||||
buf[25] = 0x84;
|
||||
buf[26] = (u8)file->namelen;
|
||||
|
||||
for(i=0;i < (int)file->namelen;i++)
|
||||
{
|
||||
buf[i + 26] = file->name[i];
|
||||
}
|
||||
|
||||
buf[1] = 0x19 + file->namelen + 2;
|
||||
}
|
||||
break;
|
||||
|
@ -327,7 +367,7 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
|
|||
*outlen = buf[1]+2;
|
||||
memcpy(out, buf, *outlen);
|
||||
|
||||
return 0;
|
||||
SC_FUNC_RETURN(card->ctx, 1, 0);
|
||||
}
|
||||
|
||||
static int myeid_create_file(struct sc_card *card, struct sc_file *file)
|
||||
|
@ -337,9 +377,12 @@ static int myeid_create_file(struct sc_card *card, struct sc_file *file)
|
|||
size_t buflen;
|
||||
int r;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
r = encode_file_structure(card, file, sbuf, &buflen);
|
||||
if (r)
|
||||
return r;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
|
||||
apdu.data = sbuf;
|
||||
apdu.datalen = buflen;
|
||||
|
@ -348,44 +391,48 @@ static int myeid_create_file(struct sc_card *card, struct sc_file *file)
|
|||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
if (apdu.sw1 == 0x6A && apdu.sw2 == 0x89)
|
||||
return SC_ERROR_FILE_ALREADY_EXISTS;
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_FILE_ALREADY_EXISTS);
|
||||
|
||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
SC_TEST_RET(card->ctx, r, "Card returned error");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no record oriented file services */
|
||||
static int myeid_read_record_unsupp(struct sc_card *card, unsigned int rec_nr,
|
||||
u8 *buf, size_t count, unsigned long flags)
|
||||
{
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static int myeid_wrupd_record_unsupp(struct sc_card *card, unsigned int rec_nr,
|
||||
const u8 *buf, size_t count, unsigned long flags)
|
||||
{
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static int myeid_append_record_unsupp(struct sc_card *card, const u8 *buf,
|
||||
size_t count, unsigned long flags)
|
||||
{
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
|
||||
static int myeid_write_binary(struct sc_card *card, unsigned int idx,
|
||||
const u8 *buf, size_t count, unsigned long flags)
|
||||
{
|
||||
return iso_ops->write_binary(card, idx, buf, count, flags);
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, iso_ops->write_binary(card, idx, buf, count, flags));
|
||||
}
|
||||
|
||||
|
||||
static int myeid_update_binary(struct sc_card *card, unsigned int idx,
|
||||
const u8 *buf, size_t count, unsigned long flags)
|
||||
{
|
||||
return iso_ops->update_binary(card, idx, buf, count, flags);
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, iso_ops->update_binary(card, idx, buf, count, flags));
|
||||
}
|
||||
|
||||
static int myeid_delete_file(struct sc_card *card, const struct sc_path *path)
|
||||
|
@ -408,9 +455,33 @@ static int myeid_delete_file(struct sc_card *card, const struct sc_path *path)
|
|||
r = sc_transmit_apdu(card, &apdu);
|
||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||
|
||||
return sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
SC_FUNC_RETURN(card->ctx, 1, sc_check_sw(card, apdu.sw1, apdu.sw2));
|
||||
}
|
||||
|
||||
static int myeid_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
|
||||
int *tries_left)
|
||||
{
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
sc_debug(card->ctx, "ref (%d), pin1 len(%d), pin2 len (%d)\n",
|
||||
data->pin_reference, data->pin1.len, data->pin2.len);
|
||||
|
||||
if(data->pin1.len > 8 || data->pin2.len > 8)
|
||||
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_PIN_LENGTH);
|
||||
|
||||
data->flags |= SC_PIN_CMD_NEED_PADDING;
|
||||
if(data->cmd == SC_PIN_CMD_VERIFY)
|
||||
{
|
||||
u8 buf[8];
|
||||
memset(buf, 0xFF, sizeof(buf));
|
||||
memcpy(&buf[0], (u8 *)data->pin1.data, data->pin1.len); /* copy pin*/
|
||||
data->pin1.data = buf;
|
||||
data->pin1.len = 8;
|
||||
|
||||
}
|
||||
|
||||
SC_FUNC_RETURN(card->ctx, 1, iso_ops->pin_cmd(card, data, tries_left));
|
||||
}
|
||||
|
||||
static int myeid_set_security_env2(sc_card_t *card, const sc_security_env_t *env,
|
||||
int se_num)
|
||||
|
@ -421,7 +492,7 @@ static int myeid_set_security_env2(sc_card_t *card, const sc_security_env_t *env
|
|||
int r, locked = 0;
|
||||
|
||||
assert(card != NULL && env != NULL);
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC)
|
||||
{
|
||||
|
@ -504,12 +575,14 @@ static int myeid_set_security_env2(sc_card_t *card, const sc_security_env_t *env
|
|||
err:
|
||||
if (locked)
|
||||
sc_unlock(card);
|
||||
return r;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
static int myeid_set_security_env(struct sc_card *card,
|
||||
const struct sc_security_env *env, int se_num)
|
||||
{
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
if (env->flags & SC_SEC_ENV_ALG_PRESENT)
|
||||
{
|
||||
sc_security_env_t tmp;
|
||||
|
@ -543,6 +616,8 @@ static int myeid_compute_signature(struct sc_card *card, const u8 * data,
|
|||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
assert(card != NULL && data != NULL && out != NULL);
|
||||
if (datalen > 256)
|
||||
SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
@ -592,6 +667,8 @@ static int myeid_decipher(struct sc_card *card, const u8 * crgram,
|
|||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
assert(card != NULL && crgram != NULL && out != NULL);
|
||||
SC_FUNC_CALLED(card->ctx, 2);
|
||||
if (crgram_len > 256)
|
||||
|
@ -736,6 +813,7 @@ static int myeid_loadkey(sc_card_t *card, int mode, u8* value, int value_len)
|
|||
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
int r, len;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
len = 0;
|
||||
if(value_len == 0 || value == NULL)
|
||||
return 0;
|
||||
|
@ -798,7 +876,6 @@ static int myeid_loadkey(sc_card_t *card, int mode, u8* value, int value_len)
|
|||
|
||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
|
||||
}
|
||||
|
||||
/* Generate or store a key */
|
||||
|
@ -807,8 +884,9 @@ static int myeid_generate_store_key(struct sc_card *card,
|
|||
{
|
||||
struct sc_apdu apdu;
|
||||
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
int r,len;
|
||||
int r=0,len;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
/* Setup key-generation paramters */
|
||||
if (data->op_type == OP_TYPE_GENERATE)
|
||||
{
|
||||
|
@ -834,8 +912,6 @@ static int myeid_generate_store_key(struct sc_card *card,
|
|||
|
||||
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
|
||||
SC_TEST_RET(card->ctx, r, "GENERATE_KEY returned error");
|
||||
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -853,10 +929,10 @@ static int myeid_generate_store_key(struct sc_card *card,
|
|||
data->mod, data->mod_len)) >= 0 &&
|
||||
(r=myeid_loadkey(card, LOAD_KEY_PUBLIC_EXPONENT,
|
||||
data->pubexp, data->pubexp_len)) >= 0)
|
||||
return r;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
return r;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
static int myeid_activate_card(struct sc_card *card)
|
||||
|
@ -865,6 +941,7 @@ static int myeid_activate_card(struct sc_card *card)
|
|||
u8 sbuf[] ="\xA0\x00\x00\x00\x63\x50\x4B\x43\x53\x2D\x31\x35";
|
||||
sc_apdu_t apdu;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x44, 0x04, 0x00);
|
||||
apdu.cla = 0x00;
|
||||
apdu.data = sbuf;
|
||||
|
@ -886,6 +963,7 @@ static int myeid_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
|
|||
sc_apdu_t apdu;
|
||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0xA0);
|
||||
apdu.resp = rbuf;
|
||||
apdu.resplen = sizeof(rbuf);
|
||||
|
@ -910,28 +988,38 @@ static int myeid_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
|
|||
/* copy and return serial number */
|
||||
memcpy(serial, &card->serialnr, sizeof(*serial));
|
||||
|
||||
return SC_SUCCESS;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
static int myeid_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
|
||||
{
|
||||
int r = SC_ERROR_NOT_SUPPORTED;
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
switch(cmd) {
|
||||
case SC_CARDCTL_MYEID_PUTDATA:
|
||||
return myeid_putdata(card,
|
||||
r = myeid_putdata(card,
|
||||
(struct sc_cardctl_myeid_data_obj*) ptr);
|
||||
break;
|
||||
case SC_CARDCTL_MYEID_GETDATA:
|
||||
return myeid_getdata(card,
|
||||
r = myeid_getdata(card,
|
||||
(struct sc_cardctl_myeid_data_obj*) ptr);
|
||||
break;
|
||||
case SC_CARDCTL_MYEID_GENERATE_KEY:
|
||||
return myeid_generate_store_key(card,
|
||||
r = myeid_generate_store_key(card,
|
||||
(struct sc_cardctl_myeid_gen_store_key_info *) ptr);
|
||||
break;
|
||||
case SC_CARDCTL_MYEID_ACTIVATE_CARD:
|
||||
return myeid_activate_card(card);
|
||||
r = myeid_activate_card(card);
|
||||
break;
|
||||
case SC_CARDCTL_GET_SERIALNR:
|
||||
return myeid_get_serialnr(card, (sc_serial_number_t *)ptr);
|
||||
r = myeid_get_serialnr(card, (sc_serial_number_t *)ptr);
|
||||
break;
|
||||
case SC_CARDCTL_LIFECYCLE_SET:
|
||||
case SC_CARDCTL_LIFECYCLE_GET:
|
||||
break;
|
||||
}
|
||||
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
/* "The PINs are "global" in a PKCS#15 sense, meaning that they remain valid
|
||||
|
@ -941,7 +1029,8 @@ static int myeid_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
|
|||
*/
|
||||
static int myeid_logout(struct sc_card *card)
|
||||
{
|
||||
return 0; /* Can't */
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, 0);
|
||||
}
|
||||
|
||||
static struct sc_card_driver * sc_get_driver(void)
|
||||
|
@ -971,7 +1060,7 @@ static struct sc_card_driver * sc_get_driver(void)
|
|||
myeid_ops.logout = myeid_logout;
|
||||
myeid_ops.process_fci = myeid_process_fci;
|
||||
myeid_ops.card_ctl = myeid_card_ctl;
|
||||
|
||||
myeid_ops.pin_cmd = myeid_pin_cmd;
|
||||
return &myeid_drv;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,77 @@
|
|||
#
|
||||
# PKCS15 r/w profile for MyEID cards
|
||||
#
|
||||
|
||||
cardinfo {
|
||||
label = "MyEID";
|
||||
manufacturer = "Aventra Ltd.";
|
||||
min-pin-length = 4;
|
||||
max-pin-length = 8;
|
||||
pin-encoding = ascii-numeric;
|
||||
pin-pad-char = 0x00;
|
||||
pin-pad-char = 0xFF;
|
||||
}
|
||||
|
||||
#
|
||||
# The following controls some aspects of the PKCS15 we put onto
|
||||
# the card.
|
||||
#
|
||||
pkcs15 {
|
||||
# Put certificates into the CDF itself?
|
||||
direct-certificates = no;
|
||||
# Put the DF length into the ODF file?
|
||||
encode-df-length = no;
|
||||
# Have a lastUpdate field in the EF(TokenInfo)?
|
||||
do-last-update = no;
|
||||
}
|
||||
|
||||
option default {
|
||||
macros {
|
||||
#protected = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
#unprotected = READ=NONE, UPDATE=CHV1, DELETE=CHV1;
|
||||
|
||||
unusedspace-size = 512;
|
||||
odf-size = 256;
|
||||
aodf-size = 384;
|
||||
cdf-size = 512;
|
||||
prkdf-size = 1485;
|
||||
pukdf-size = 1200;
|
||||
dodf-size = 256;
|
||||
}
|
||||
}
|
||||
|
||||
# Define reasonable limits for PINs and PUK
|
||||
# Note that we do not set a file path or reference
|
||||
# here; that is done dynamically.
|
||||
PIN user-pin {
|
||||
reference = 1;
|
||||
auth-id = 1;
|
||||
min-length = 4;
|
||||
max-length = 8;
|
||||
attempts = 3;
|
||||
flags = initialized, needs-padding;
|
||||
}
|
||||
|
||||
PIN user-puk {
|
||||
min-length = 4;
|
||||
max-length = 8;
|
||||
attempts = 10;
|
||||
flags = needs-padding;
|
||||
}
|
||||
|
||||
PIN so-pin {
|
||||
reference = 2;
|
||||
auth-id = 2;
|
||||
min-length = 4;
|
||||
max-length = 8;
|
||||
attempts = 4;
|
||||
flags = initialized, soPin, needs-padding;
|
||||
}
|
||||
|
||||
PIN so-puk {
|
||||
min-length = 4;
|
||||
max-length = 8;
|
||||
attempts = 9;
|
||||
flags = needs-padding;
|
||||
}
|
||||
|
||||
# Additional filesystem info.
|
||||
|
@ -22,32 +79,114 @@ PIN user-puk {
|
|||
# main profile.
|
||||
filesystem {
|
||||
DF MF {
|
||||
path = 3F00;
|
||||
type = DF;
|
||||
acl = DELETE=CHV2; #Erase PIN
|
||||
|
||||
# This is the DIR file
|
||||
EF DIR {
|
||||
file-id = 2F00;
|
||||
structure = transparent;
|
||||
size = 128;
|
||||
acl = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
DF PKCS15-AppDF {
|
||||
type = DF;
|
||||
file-id = 5015;
|
||||
acl = DELETE=NONE, CREATE=CHV1;
|
||||
|
||||
EF PKCS15-ODF {
|
||||
file-id = 5031;
|
||||
structure = transparent;
|
||||
size = $odf-size;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
EF PKCS15-TokenInfo {
|
||||
file-id = 5032;
|
||||
structure = transparent;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
EF PKCS15-UnusedSpace {
|
||||
file-id = 5033;
|
||||
structure = transparent;
|
||||
size = $unusedspace-size;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
EF PKCS15-AODF {
|
||||
file-id = 4401;
|
||||
structure = transparent;
|
||||
size = $aodf-size;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
EF PKCS15-PrKDF {
|
||||
file-id = 4402;
|
||||
structure = transparent;
|
||||
size = $prkdf-size;
|
||||
acl = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
EF PKCS15-PuKDF {
|
||||
file-id = 4403;
|
||||
structure = transparent;
|
||||
size = $pukdf-size;
|
||||
acl = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
EF PKCS15-CDF {
|
||||
file-id = 4404;
|
||||
structure = transparent;
|
||||
size = $cdf-size;
|
||||
acl = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
EF PKCS15-DODF {
|
||||
file-id = 4405;
|
||||
structure = transparent;
|
||||
size = $dodf-size;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
EF template-private-key {
|
||||
type = internal-ef;
|
||||
file-id = 4B01; # This is the base FileID
|
||||
size = 266; # 266 is enough for 1024-bit keys
|
||||
ACL = *=NEVER, CRYPTO=$PIN, UPDATE=$PIN;
|
||||
file-id = 4B01;
|
||||
size = 1024;
|
||||
ACL = CRYPTO=CHV1, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
EF template-public-key {
|
||||
structure = transparent;
|
||||
file-id = 5501;
|
||||
ACL = *=NEVER, READ=NONE, UPDATE=$PIN;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
EF template-certificate {
|
||||
file-id = 4301;
|
||||
ACL = *=NEVER, READ=NONE, UPDATE=$PIN;
|
||||
structure = transparent;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
template key-domain {
|
||||
# This is a dummy entry - pkcs15-init insists that
|
||||
# this is present
|
||||
EF private-key {
|
||||
file-id = 4B00;
|
||||
type = internal-ef;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
EF public-key {
|
||||
file-id = 4300;
|
||||
structure = transparent;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
|
||||
# Certificate template
|
||||
EF certificate {
|
||||
file-id = 5300;
|
||||
structure = transparent;
|
||||
ACL = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
|
||||
}
|
||||
EF template-extractable-key {
|
||||
file-id = 7000;
|
||||
ACL = *=NEVER, READ=$PIN, UPDATE=$PIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Define an SO pin
|
||||
# This PIN is not used yet.
|
||||
#PIN sopin {
|
||||
# file = sopinfile;
|
||||
# reference = 0;
|
||||
#}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -31,7 +32,7 @@
|
|||
#include "keycache.h"
|
||||
#include "profile.h"
|
||||
|
||||
#define MYEID_MAX_PINS 5
|
||||
#define MYEID_MAX_PINS 14
|
||||
|
||||
unsigned char MYEID_DEFAULT_PUBKEY[] = {0x01, 0x00, 0x01};
|
||||
#define MYEID_DEFAULT_PUBKEY_LEN sizeof(MYEID_DEFAULT_PUBKEY)
|
||||
|
@ -44,7 +45,26 @@ static int myeid_create_pin_internal(sc_profile_t *, sc_card_t *,
|
|||
int, sc_pkcs15_pin_info_t *, const u8 *, size_t,
|
||||
const u8 *, size_t);
|
||||
|
||||
static int myeid_puk_retries(sc_profile_t *, int);
|
||||
static int myeid_puk_retries(sc_profile_t *profile, sc_pkcs15_pin_info_t *pin_info);
|
||||
|
||||
static int acl_to_byte(const struct sc_acl_entry *e)
|
||||
{
|
||||
switch (e->method) {
|
||||
case SC_AC_NONE:
|
||||
return 0x00;
|
||||
case SC_AC_CHV:
|
||||
case SC_AC_TERM:
|
||||
case SC_AC_AUT:
|
||||
if (e->key_ref == SC_AC_KEY_REF_NONE)
|
||||
return 0x00;
|
||||
if (e->key_ref < 1 || e->key_ref > MYEID_MAX_PINS)
|
||||
return 0x00;
|
||||
return e->key_ref;
|
||||
case SC_AC_NEVER:
|
||||
return 0x0F;
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
/*
|
||||
* Erase the card.
|
||||
|
@ -52,17 +72,17 @@ static int myeid_puk_retries(sc_profile_t *, int);
|
|||
static int myeid_erase_card(sc_profile_t *profile, sc_card_t *card)
|
||||
{
|
||||
struct sc_cardctl_myeid_data_obj data_obj;
|
||||
sc_pkcs15_pin_info_t pin_info;
|
||||
sc_pkcs15_pin_info_t sopin_info, pin_info;
|
||||
|
||||
u8 data[8];
|
||||
int r;
|
||||
|
||||
/* Just delete the entire MF */
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
/* The SO pin has pin reference 1 -- not that it matters much
|
||||
* because pkcs15-init will ask to enter all pins, even if we
|
||||
* did a --so-pin on the command line. */
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info);
|
||||
sc_keycache_set_pin_name(NULL, pin_info.reference, SC_PKCS15INIT_SO_PIN);
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin_info);
|
||||
|
||||
/* Select parent DF and verify PINs/key as necessary */
|
||||
r = sc_pkcs15init_authenticate(profile, card, profile->mf_info->file, SC_AC_OP_DELETE);
|
||||
|
@ -71,23 +91,72 @@ static int myeid_erase_card(sc_profile_t *profile, sc_card_t *card)
|
|||
|
||||
data[0]= 0xFF;
|
||||
data[1]= 0xFF;
|
||||
data[2]= 0x33;
|
||||
data[2]= 0x11;
|
||||
data[3]= 0x3F;
|
||||
data[4]= 0xFF;
|
||||
data[5]= 0x33;
|
||||
data[6]= 0x3F;
|
||||
data[5]= 0x11;
|
||||
data[6]= 0xFF;
|
||||
data[7]= 0xFF;
|
||||
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &pin_info);
|
||||
if(pin_info.reference > 0 && pin_info.reference <= MYEID_MAX_PINS &&
|
||||
sopin_info.reference > 0 && sopin_info.reference <= MYEID_MAX_PINS)
|
||||
{
|
||||
data[2] = (pin_info.reference << 4)| pin_info.reference;
|
||||
data[3] = (sopin_info.reference << 4) | 0x0F;
|
||||
data[5] = data[2];
|
||||
}
|
||||
|
||||
data_obj.P1 = 0x01;
|
||||
data_obj.P2 = 0xE0;
|
||||
data_obj.Data = data;
|
||||
data_obj.DataLen = 0x08;
|
||||
|
||||
sc_debug(card->ctx, "so_pin(%d), user pin (%d)\n",
|
||||
sopin_info.reference, pin_info.reference);
|
||||
|
||||
r = sc_card_ctl(card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
|
||||
|
||||
return r;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
static int myeid_init_card(sc_profile_t *profile,
|
||||
sc_card_t *card)
|
||||
{
|
||||
struct sc_path path;
|
||||
sc_file_t *file;
|
||||
int r;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
|
||||
sc_format_path("3F00", &path);
|
||||
r = sc_select_file(card, &path, NULL);
|
||||
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a DF
|
||||
*/
|
||||
static int myeid_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df)
|
||||
{
|
||||
int r=0;
|
||||
struct sc_file *file;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
if (!profile || !card || !df)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
|
||||
sc_debug(card->ctx, "id (%x)\n",df->id);
|
||||
|
||||
if(df->id == 0x5015)
|
||||
{
|
||||
sc_debug(card->ctx, "only Select (%x)\n",df->id);
|
||||
r = sc_select_file(card, &df->path, NULL);
|
||||
}
|
||||
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
/*
|
||||
* Select the PIN reference
|
||||
*/
|
||||
|
@ -95,20 +164,27 @@ static int myeid_select_pin_reference(sc_profile_t *profile, sc_card_t *card,
|
|||
sc_pkcs15_pin_info_t *pin_info)
|
||||
{
|
||||
sc_pkcs15_pin_info_t pin_info_prof;
|
||||
int type;
|
||||
|
||||
pin_info_prof.reference = 1; /* Default SO PIN ref. */
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info_prof);
|
||||
|
||||
/* For the SO pin, we take the first available pin reference = 1 */
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
|
||||
pin_info->reference = pin_info_prof.reference;
|
||||
/* sc_pkcs15init_create_pin() starts checking if 0 is an acceptable
|
||||
* pin reference, which isn't for the myeid cards. And since the
|
||||
* value 1 has been assigned to the SO pin, we'll jump to 2. */
|
||||
else if (pin_info->reference == 0)
|
||||
pin_info->reference = pin_info_prof.reference + 1;
|
||||
{
|
||||
type = SC_PKCS15INIT_SO_PIN;
|
||||
sc_debug(card->ctx, "PIN_FLAG_SO_PIN, ref (%d), tries_left (%d)\n",
|
||||
pin_info->reference,pin_info->tries_left);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = SC_PKCS15INIT_USER_PIN;
|
||||
sc_debug(card->ctx, "PIN_FLAG_PIN, ref (%d), tries_left (%d)\n",
|
||||
pin_info->reference, pin_info->tries_left);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pin_info->reference <= 0 || pin_info->reference > MYEID_MAX_PINS)
|
||||
pin_info->reference = 1;
|
||||
|
||||
SC_FUNC_RETURN(card->ctx, 1, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -138,6 +214,7 @@ static int myeid_new_file(sc_profile_t *profile, sc_card_t *card,
|
|||
char name[64], *tag;
|
||||
int r;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
if (type == SC_PKCS15_TYPE_PRKEY_RSA)
|
||||
tag = "private-key";
|
||||
else if (type == SC_PKCS15_TYPE_PUBKEY_RSA)
|
||||
|
@ -178,21 +255,23 @@ static int myeid_new_file(sc_profile_t *profile, sc_card_t *card,
|
|||
}
|
||||
|
||||
*out = file;
|
||||
return 0;
|
||||
SC_FUNC_RETURN(card->ctx, 1, 0);
|
||||
}
|
||||
|
||||
static int myeid_encode_private_key(sc_profile_t *profile, sc_card_t *card,
|
||||
struct sc_pkcs15_prkey_rsa *rsa, u8 *key,
|
||||
size_t *keysize, int key_ref)
|
||||
{
|
||||
return 0;
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, 0);
|
||||
}
|
||||
|
||||
static int myeid_encode_public_key(sc_profile_t *profile, sc_card_t *card,
|
||||
struct sc_pkcs15_prkey_rsa *rsa, u8 *key,
|
||||
size_t *keysize, int key_ref)
|
||||
{
|
||||
return 0;
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
SC_FUNC_RETURN(card->ctx, 1, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -232,9 +311,13 @@ static int myeid_generate_store_key(sc_profile_t *profile, sc_card_t *card,
|
|||
sc_pkcs15_prkey_info_t *info)
|
||||
{
|
||||
struct sc_cardctl_myeid_gen_store_key_info args;
|
||||
struct sc_cardctl_myeid_data_obj data_obj;
|
||||
unsigned char raw_pubkey[256];
|
||||
int r;
|
||||
unsigned int mod_len;
|
||||
sc_file_t *prkf = NULL;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
/* Parameter check */
|
||||
if ( (keybits < 1024) || (keybits > 2048) || (keybits & 0X7)) {
|
||||
sc_error(card->ctx,
|
||||
|
@ -303,7 +386,7 @@ done:
|
|||
if (prkf)
|
||||
sc_file_free(prkf);
|
||||
|
||||
return r;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -314,36 +397,30 @@ static int myeid_create_pin_internal(sc_profile_t *profile, sc_card_t *card,
|
|||
const u8 *pin, size_t pin_len,
|
||||
const u8 *puk, size_t puk_len)
|
||||
{
|
||||
u8 data[19];
|
||||
u8 data[20];
|
||||
int so_pin_ref;
|
||||
int r;
|
||||
int r,type, puk_tries;
|
||||
struct sc_cardctl_myeid_data_obj data_obj;
|
||||
sc_file_t *pinfile = NULL;
|
||||
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
sc_debug(card->ctx, "pin (%d), pin_len (%d), puk_len(%d) \n",
|
||||
pin_info->reference, pin_len, puk_len);
|
||||
|
||||
if (pin_info->reference >= MYEID_MAX_PINS)
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
if (pin == NULL || puk == NULL || pin_len < 4 || puk_len < 4)
|
||||
return SC_ERROR_INVALID_PIN_LENGTH;
|
||||
|
||||
/* Verify required access rights if needed (i.e. if the
|
||||
* pin file isn't in the CREATE life cycle state). */
|
||||
if (!ignore_ac)
|
||||
{
|
||||
/* Re-ink the SO pin to the MF because there is the pin file */
|
||||
so_pin_ref = sc_keycache_find_named_pin(&profile->df_info->file->path,
|
||||
SC_PKCS15INIT_SO_PIN);
|
||||
if (so_pin_ref >= 0)
|
||||
sc_keycache_set_pin_name(&profile->mf_info->file->path,
|
||||
so_pin_ref, SC_PKCS15INIT_SO_PIN);
|
||||
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
|
||||
type = SC_PKCS15INIT_SO_PIN;
|
||||
else
|
||||
type = SC_PKCS15INIT_USER_PIN;
|
||||
|
||||
r = sc_profile_get_file(profile, "pinfile", &pinfile);
|
||||
if (r >= 0)
|
||||
r = sc_pkcs15init_authenticate(profile, card, pinfile, SC_AC_OP_UPDATE);
|
||||
sc_file_free(pinfile);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
sc_debug(card->ctx, "pin type (%s)\n",
|
||||
(type == SC_PKCS15INIT_SO_PIN) ? "SO_PIN": "USER_PIN");
|
||||
|
||||
memset(data, 0xFF, sizeof(data));
|
||||
/* Make command to add a pin-record */
|
||||
data_obj.P1 = 01;
|
||||
data_obj.P2 = pin_info->reference; /* myeid pin number */
|
||||
|
@ -351,40 +428,40 @@ static int myeid_create_pin_internal(sc_profile_t *profile, sc_card_t *card,
|
|||
memcpy(&data[0], (u8 *)pin, pin_len); /* copy pin*/
|
||||
memcpy(&data[8], (u8 *)puk, puk_len); /* copy puk */
|
||||
|
||||
|
||||
/* Optional PIN locking
|
||||
* data[17] = pin_info->tries_left & 0x0F;
|
||||
* data[18] = myeid_puk_retries(profile, pin_info->reference) & 0x0F;
|
||||
*/
|
||||
|
||||
data[16] = 0x00;
|
||||
data[17] = 0x00;
|
||||
data[18] = 0x00;
|
||||
data[19] = 0x00; /* FIXME, array is only 0..18 */
|
||||
|
||||
data_obj.Data = data;
|
||||
data_obj.DataLen = 0x10;
|
||||
data_obj.DataLen = 16;
|
||||
|
||||
puk_tries = myeid_puk_retries(profile, pin_info);
|
||||
if(pin_info->tries_left > 0 && pin_info->tries_left < 15 &&
|
||||
puk_tries > 0 && puk_tries < 15)
|
||||
{
|
||||
/* Optional PIN locking */
|
||||
data[16] = (pin_info->tries_left & 0x0F);
|
||||
data[17] = (puk_tries & 0x0F);
|
||||
data_obj.DataLen = 19;
|
||||
}
|
||||
|
||||
r = sc_card_ctl(card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
|
||||
|
||||
return r;
|
||||
SC_FUNC_RETURN(card->ctx, 1, r);
|
||||
}
|
||||
|
||||
static int myeid_puk_retries(sc_profile_t *profile, int pin_ref)
|
||||
static int myeid_puk_retries(sc_profile_t *profile, sc_pkcs15_pin_info_t *pin_info)
|
||||
{
|
||||
sc_pkcs15_pin_info_t pin_info;
|
||||
sc_pkcs15_pin_info_t puk_info;
|
||||
|
||||
pin_info.reference = 1; /* Default SO PIN ref. */
|
||||
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info);
|
||||
|
||||
/* If pin_ref is the SO PIN, get the SO PUK info, otherwise the User PUK info */
|
||||
sc_profile_get_pin_info(profile,
|
||||
pin_ref == pin_info.reference ?
|
||||
(pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) ?
|
||||
SC_PKCS15INIT_SO_PUK : SC_PKCS15INIT_USER_PUK,
|
||||
&pin_info);
|
||||
&puk_info);
|
||||
|
||||
if ((pin_info.tries_left < 0) || (pin_info.tries_left > 15))
|
||||
return 3; /* Little extra safety */
|
||||
return pin_info.tries_left;
|
||||
if ((puk_info.tries_left < 0) || (puk_info.tries_left >= 15))
|
||||
return -1;
|
||||
return puk_info.tries_left;
|
||||
}
|
||||
|
||||
/* For Myeid, all objects are files that can be deleted in any order */
|
||||
|
@ -392,13 +469,14 @@ static int myeid_delete_object(struct sc_profile *profile,
|
|||
struct sc_card *card, unsigned int type,
|
||||
const void *data, const sc_path_t *path)
|
||||
{
|
||||
SC_FUNC_CALLED(card->ctx, 1);
|
||||
return sc_pkcs15init_delete_by_path(profile, card, path);
|
||||
}
|
||||
|
||||
static struct sc_pkcs15init_operations sc_pkcs15init_myeid_operations = {
|
||||
myeid_erase_card,
|
||||
NULL, /* init_card */
|
||||
NULL, /* create_dir */
|
||||
myeid_init_card, /* init_card */
|
||||
myeid_create_dir, /* create_dir */
|
||||
NULL, /* create_domain */
|
||||
myeid_select_pin_reference,
|
||||
myeid_create_pin,
|
||||
|
|
Loading…
Reference in New Issue