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:
aj 2009-10-23 13:08:32 +00:00
parent 6cd345d316
commit 12213dee5c
3 changed files with 443 additions and 137 deletions

View File

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

View File

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

View File

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