opensc/src/pkcs15init/pkcs15-myeid.c

714 lines
22 KiB
C
Raw Normal View History

/*
* MyEID specific operations for PKCS15 initialization
*
* Copyright (C) 2008-2009 Aventra Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "libopensc/opensc.h"
#include "libopensc/cardctl.h"
#include "libopensc/log.h"
#include "pkcs15-init.h"
#include "profile.h"
#undef KEEP_AC_NONE_FOR_INIT_APPLET
#define MYEID_MAX_PINS 14
unsigned char MYEID_DEFAULT_PUBKEY[] = {0x01, 0x00, 0x01};
#define MYEID_DEFAULT_PUBKEY_LEN sizeof(MYEID_DEFAULT_PUBKEY)
/* For Myeid, all objects are files that can be deleted in any order */
static int
myeid_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
2012-11-28 10:52:43 +00:00
struct sc_pkcs15_object *object, const struct sc_path *path) {
LOG_FUNC_CALLED(p15card->card->ctx);
return sc_pkcs15init_delete_by_path(profile, p15card, path);
}
/*
* Get 'Initialize Applet' data
* using the ACLs defined in card profile.
*/
static int
myeid_get_init_applet_data(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
2012-11-28 10:52:43 +00:00
unsigned char *data, size_t data_len) {
struct sc_context *ctx = p15card->card->ctx;
struct sc_file *tmp_file = NULL;
const struct sc_acl_entry *entry = NULL;
int r;
LOG_FUNC_CALLED(ctx);
if (data_len < 8)
LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Cannot get init applet data");
*(data + 0) = 0xFF;
*(data + 1) = 0xFF;
/* MF acls */
sc_file_dup(&tmp_file, profile->mf_info->file);
if (tmp_file == NULL)
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate MF file");
r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file);
LOG_TEST_RET(ctx, r, "MF fixup failed");
/* AC 'Create DF' and 'Create EF' */
2012-11-28 10:52:43 +00:00
*(data + 2) = 0x00; /* 'NONE' */
entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_CREATE);
if (entry->method == SC_AC_CHV)
2012-11-28 10:52:43 +00:00
*(data + 2) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx'. */
else if (entry->method == SC_AC_NEVER)
2012-11-28 10:52:43 +00:00
*(data + 2) = 0xFF; /* 'NEVER'. */
/* AC 'INITIALISE APPLET'. */
2012-11-28 10:52:43 +00:00
*(data + 3) = 0x0F; /* 'NONE' */
#ifndef KEEP_AC_NONE_FOR_INIT_APPLET
2012-11-28 10:52:43 +00:00
entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_DELETE);
if (entry->method == SC_AC_CHV)
*(data + 3) = (entry->key_ref << 4) | 0xF;
else if (entry->method == SC_AC_NEVER)
*(data + 3) = 0xFF;
#endif
*(data + 4) = 0xFF;
sc_file_free(tmp_file);
tmp_file = NULL;
/* Application DF (5015) acls */
sc_file_dup(&tmp_file, profile->df_info->file);
if (tmp_file == NULL)
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate Application DF file");
r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file);
LOG_TEST_RET(ctx, r, "Application DF fixup failed");
/* AC 'Create DF' and 'Create EF' */
2012-11-28 10:52:43 +00:00
*(data + 5) = 0x00; /* 'NONE' */
entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_CREATE);
if (entry->method == SC_AC_CHV)
2012-11-28 10:52:43 +00:00
*(data + 5) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx' */
else if (entry->method == SC_AC_NEVER)
2012-11-28 10:52:43 +00:00
*(data + 5) = 0xFF; /* 'NEVER'. */
/* AC 'Self delete' */
2012-11-28 10:52:43 +00:00
*(data + 6) = 0x0F; /* 'NONE' */
entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_DELETE);
if (entry->method == SC_AC_CHV)
2012-11-28 10:52:43 +00:00
*(data + 6) = (entry->key_ref << 4) | 0xF; /* 'CHVx' */
else if (entry->method == SC_AC_NEVER)
2012-11-28 10:52:43 +00:00
*(data + 6) = 0xFF; /* 'NEVER'. */
*(data + 7) = 0xFF;
sc_file_free(tmp_file);
LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
}
/*
* Erase the card.
*/
static int
2012-11-28 10:52:43 +00:00
myeid_erase_card(struct sc_profile *profile, struct sc_pkcs15_card *p15card) {
struct sc_context *ctx = p15card->card->ctx;
struct sc_cardctl_myeid_data_obj data_obj;
struct sc_file *mf = NULL;
unsigned char data[8];
int r;
LOG_FUNC_CALLED(ctx);
2012-11-28 10:52:43 +00:00
r = myeid_get_init_applet_data(profile, p15card, data, sizeof (data));
LOG_TEST_RET(ctx, r, "Get init applet date error");
/* Select parent DF and verify PINs/key as necessary */
r = sc_select_file(p15card->card, sc_get_mf_path(), &mf);
LOG_TEST_RET(ctx, r, "Cannot select MF");
/* ACLs are not actives if file is not in the operational state */
if (mf->status == SC_FILE_STATUS_ACTIVATED)
r = sc_pkcs15init_authenticate(profile, p15card, mf, SC_AC_OP_DELETE);
LOG_TEST_RET(ctx, r, "'DELETE' authentication failed on MF");
2012-11-28 10:52:43 +00:00
data_obj.P1 = 0x01;
data_obj.P2 = 0xE0;
data_obj.Data = data;
data_obj.DataLen = sizeof (data);
r = sc_card_ctl(p15card->card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
LOG_FUNC_RETURN(p15card->card->ctx, r);
}
2012-11-28 10:52:43 +00:00
static int
myeid_init_card(sc_profile_t *profile,
2012-11-28 10:52:43 +00:00
sc_pkcs15_card_t *p15card) {
struct sc_path path;
struct sc_file *file = NULL;
2012-11-28 10:52:43 +00:00
u8 rbuf[256];
int r;
LOG_FUNC_CALLED(p15card->card->ctx);
p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION | SC_PKCS15_TOKEN_EID_COMPLIANT;
2012-11-28 10:52:43 +00:00
r = sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &rbuf);
LOG_TEST_RET(p15card->card->ctx, r, "Get applet info failed");
sc_format_path("3F00", &path);
r = sc_select_file(p15card->card, &path, &file);
if (file)
sc_file_free(file);
LOG_FUNC_RETURN(p15card->card->ctx, r);
}
/*
* Create a DF
*/
static int
2012-11-28 10:52:43 +00:00
myeid_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) {
struct sc_context *ctx = p15card->card->ctx;
struct sc_file *file = NULL;
2012-11-28 10:52:43 +00:00
int r = 0, ii;
static const char *create_dfs[] = {
"PKCS15-PrKDF",
"PKCS15-PuKDF",
"PKCS15-CDF",
"PKCS15-CDF-TRUSTED",
"PKCS15-DODF",
NULL
};
static const int create_dfs_val[] = {
2012-11-28 10:52:43 +00:00
SC_PKCS15_PRKDF,
SC_PKCS15_PUKDF,
SC_PKCS15_CDF,
SC_PKCS15_CDF_TRUSTED,
SC_PKCS15_DODF
};
if (!profile || !p15card || !df)
return SC_ERROR_INVALID_ARGUMENTS;
LOG_FUNC_CALLED(ctx);
2012-11-28 10:52:43 +00:00
sc_log(ctx, "id (%x)", df->id);
2012-11-28 10:52:43 +00:00
if (df->id == 0x5015) {
sc_log(ctx, "Select (%x)", df->id);
r = sc_select_file(p15card->card, &df->path, NULL);
2012-11-28 10:52:43 +00:00
for (ii = 0; create_dfs[ii]; ii++) {
sc_log(ctx, "Create '%s'", create_dfs[ii]);
2012-11-28 10:52:43 +00:00
if (sc_profile_get_file(profile, create_dfs[ii], &file)) {
sc_log(ctx, "Inconsistent profile: cannot find %s", create_dfs[ii]);
LOG_FUNC_RETURN(ctx, SC_ERROR_INCONSISTENT_PROFILE);
}
r = sc_pkcs15init_add_object(p15card, profile, create_dfs_val[ii], NULL);
if (r != SC_ERROR_FILE_ALREADY_EXISTS)
LOG_TEST_RET(ctx, r, "Failed to create MyEID xDF file");
}
}
LOG_FUNC_RETURN(p15card->card->ctx, r);
}
/*
* Select the PIN reference
*/
static int
myeid_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
2012-11-28 10:52:43 +00:00
sc_pkcs15_auth_info_t *auth_info) {
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
return SC_ERROR_OBJECT_NOT_VALID;
2012-11-28 10:52:43 +00:00
if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
sc_log(p15card->card->ctx,
"PIN_FLAG_SO_PIN, ref (%d), tries_left (%d)",
auth_info->attrs.pin.reference, auth_info->tries_left);
} else {
sc_log(p15card->card->ctx,
"PIN_FLAG_PIN, ref (%d), tries_left (%d)",
auth_info->attrs.pin.reference, auth_info->tries_left);
}
if (auth_info->attrs.pin.reference <= 0 || auth_info->attrs.pin.reference > MYEID_MAX_PINS)
auth_info->attrs.pin.reference = 1;
LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
}
/*
* Create a new PIN
*/
static int
myeid_create_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
struct sc_file *df, struct sc_pkcs15_object *pin_obj,
const unsigned char *pin, size_t pin_len,
2012-11-28 10:52:43 +00:00
const unsigned char *puk, size_t puk_len) {
struct sc_context *ctx = p15card->card->ctx;
2012-11-28 10:52:43 +00:00
unsigned char data[20];
struct sc_cardctl_myeid_data_obj data_obj;
2012-11-28 10:52:43 +00:00
struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data;
struct sc_pkcs15_auth_info puk_ainfo;
int r;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "PIN('%s',ref:%i,flags:0x%X,pin_len:%d,puk_len:%d)\n",
2012-11-28 10:52:43 +00:00
pin_obj->label, auth_info->attrs.pin.reference, auth_info->attrs.pin.flags, pin_len, puk_len);
if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
return SC_ERROR_OBJECT_NOT_VALID;
if (auth_info->attrs.pin.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;
sc_profile_get_pin_info(profile, (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
? SC_PKCS15INIT_SO_PUK : SC_PKCS15INIT_USER_PUK,
&puk_ainfo);
2012-11-28 10:52:43 +00:00
memset(data, 0, sizeof (data));
/* Make command to add a pin-record */
data_obj.P1 = 0x01;
2012-11-28 10:52:43 +00:00
data_obj.P2 = auth_info->attrs.pin.reference; /* myeid pin number */
memset(data, auth_info->attrs.pin.pad_char, 8);
2012-11-28 10:52:43 +00:00
memcpy(&data[0], (u8 *) pin, pin_len); /* copy pin */
memset(&data[8], puk_ainfo.attrs.pin.pad_char, 8);
2012-11-28 10:52:43 +00:00
memcpy(&data[8], (u8 *) puk, puk_len); /* copy puk */
2012-11-28 10:52:43 +00:00
if (auth_info->tries_left > 0 && auth_info->tries_left < 15)
data[16] = auth_info->tries_left;
else
2012-11-28 10:52:43 +00:00
data[16] = 5; /* default value */
2012-11-28 10:52:43 +00:00
if (puk_ainfo.tries_left > 0 && puk_ainfo.tries_left < 15)
data[17] = puk_ainfo.tries_left;
else
2012-11-28 10:52:43 +00:00
data[17] = 5; /* default value */
data[18] = 0x00;
2012-11-28 10:52:43 +00:00
data_obj.Data = data;
data_obj.DataLen = 19;
r = sc_card_ctl(p15card->card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
LOG_TEST_RET(ctx, r, "Initialize PIN failed");
LOG_FUNC_RETURN(ctx, r);
}
/*
* Setup file struct & path: get correct template from the profile, construct full path
* num = number of objects of this type already on the card
*/
static int
myeid_new_file(sc_profile_t *profile, sc_card_t *card,
unsigned int type, unsigned int num,
2012-11-28 10:52:43 +00:00
sc_file_t **out) {
sc_file_t *file;
sc_path_t *p;
char name[64];
const char *tag;
int r;
LOG_FUNC_CALLED(card->ctx);
2012-11-28 10:52:43 +00:00
if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == SC_PKCS15_TYPE_PRKEY_EC)
tag = "private-key";
2012-11-28 10:52:43 +00:00
else if (type == SC_PKCS15_TYPE_PUBKEY_RSA || type == SC_PKCS15_TYPE_PUBKEY_EC)
tag = "public-key";
else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_CERT)
tag = "certificate";
else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_DATA_OBJECT)
tag = "data";
2012-11-28 10:52:43 +00:00
else {
sc_log(card->ctx, "Unsupported file type");
return SC_ERROR_INVALID_ARGUMENTS;
}
/* Get template from profile */
2012-11-28 10:52:43 +00:00
snprintf(name, sizeof (name), "template-%s", tag);
if (sc_profile_get_file(profile, name, &file) < 0) {
sc_log(card->ctx, "Profile doesn't define %s", name);
return SC_ERROR_NOT_SUPPORTED;
}
/* Auto-increment FID for next object */
file->id += num;
p = &file->path;
*p = profile->df_info->file->path;
p->value[p->len++] = (u8) (file->id / 256);
p->value[p->len++] = (u8) (file->id % 256);
/* Increment FID until there's no file with such path */
r = sc_select_file(card, p, NULL);
2012-11-28 10:52:43 +00:00
while (r == 0) {
file->id++;
p->value[p->len - 2] = (u8) (file->id / 256);
p->value[p->len - 1] = (u8) (file->id % 256);
r = sc_select_file(card, p, NULL);
}
*out = file;
LOG_FUNC_RETURN(card->ctx, 0);
}
static int
myeid_encode_private_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa, u8 *key,
2012-11-28 10:52:43 +00:00
size_t *keysize, int key_ref) {
LOG_FUNC_CALLED(card->ctx);
LOG_FUNC_RETURN(card->ctx, 0);
}
static int
myeid_encode_public_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa, u8 *key,
2012-11-28 10:52:43 +00:00
size_t *keysize, int key_ref) {
LOG_FUNC_CALLED(card->ctx);
LOG_FUNC_RETURN(card->ctx, 0);
}
/*
* Store a private key
*/
static int
myeid_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
2012-11-28 10:52:43 +00:00
struct sc_pkcs15_object *object) {
struct sc_context *ctx = p15card->card->ctx;
struct sc_card *card = p15card->card;
2012-11-28 10:52:43 +00:00
struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data;
struct sc_file *file = NULL;
int keybits = key_info->modulus_length, r;
LOG_FUNC_CALLED(card->ctx);
2012-11-28 10:52:43 +00:00
/* Check that the card supports the requested modulus length */
2012-11-28 10:52:43 +00:00
switch (object->type) {
case SC_PKCS15_TYPE_PRKEY_RSA:
if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS,
"Unsupported RSA key size");
break;
case SC_PKCS15_TYPE_PRKEY_EC:
if (sc_card_find_ec_alg(p15card->card, keybits) == NULL)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS,
"Unsupported EC key size");
break;
default:
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS,
"Unsupported key type");
break;
}
2012-11-28 10:52:43 +00:00
sc_log(ctx, "create MyEID private key ID:%s", sc_pkcs15_print_id(&key_info->id));
/* Get the private key file */
2012-11-28 10:52:43 +00:00
r = myeid_new_file(profile, card, object->type, key_info->key_reference, &file);
LOG_TEST_RET(ctx, r, "Cannot get new MyEID private key file");
sc_log(ctx, "Key file size %d", keybits);
file->size = keybits;
2012-11-28 10:52:43 +00:00
if (object->type == SC_PKCS15_TYPE_PRKEY_RSA)
file->ef_structure = SC_CARDCTL_MYEID_KEY_RSA;
else if (object->type == SC_PKCS15_TYPE_PRKEY_EC)
file->ef_structure = SC_CARDCTL_MYEID_KEY_EC;
memcpy(&key_info->path.value, &file->path.value, file->path.len);
key_info->key_reference = file->path.value[file->path.len - 1] & 0xFF;
2012-11-28 10:52:43 +00:00
sc_log(ctx, "Path of MyEID private key file to create %s",
sc_print_path(&file->path));
/* Now create the key file */
r = sc_pkcs15init_create_file(profile, p15card, file);
sc_file_free(file);
LOG_TEST_RET(ctx, r, "Cannot create MyEID private key file");
LOG_FUNC_RETURN(ctx, r);
}
/*
* Store a private key
*/
static int
myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
struct sc_pkcs15_object *object,
2012-11-28 10:52:43 +00:00
struct sc_pkcs15_prkey *prkey) {
struct sc_context *ctx = p15card->card->ctx;
struct sc_card *card = p15card->card;
2012-11-28 10:52:43 +00:00
struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data;
struct sc_cardctl_myeid_gen_store_key_info args;
struct sc_file *file = NULL;
int r, keybits = key_info->modulus_length;
LOG_FUNC_CALLED(ctx);
2012-11-28 10:52:43 +00:00
switch (object->type) {
case SC_PKCS15_TYPE_PRKEY_RSA:
if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size");
break;
case SC_PKCS15_TYPE_PRKEY_EC:
if (sc_card_find_ec_alg(p15card->card, keybits) == NULL)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size");
if(key_info->field_length != 0)
keybits = key_info->field_length;
else
key_info->field_length = keybits;
break;
default:
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Store key failed: Unsupported key type");
break;
}
sc_log(ctx, "store MyEID key with ID:%s and path:%s",
sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path));
r = sc_select_file(card, &key_info->path, &file);
LOG_TEST_RET(ctx, r, "Cannot store MyEID key: select key file failed");
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
LOG_TEST_RET(ctx, r, "No authorisation to store MyEID private key");
if (file)
sc_file_free(file);
/* Fill in data structure */
2012-11-28 10:52:43 +00:00
memset(&args, 0, sizeof (args));
args.op_type = OP_TYPE_STORE;
if(object->type == SC_PKCS15_TYPE_PRKEY_RSA) {
//args.key_len_bits = keybits;
args.key_type = SC_CARDCTL_MYEID_KEY_RSA;
args.pubexp_len = prkey->u.rsa.exponent.len;
args.pubexp = prkey->u.rsa.exponent.data;
args.primep_len = prkey->u.rsa.p.len;
args.primep = prkey->u.rsa.p.data;
args.primeq_len = prkey->u.rsa.q.len;
args.primeq = prkey->u.rsa.q.data;
2012-11-28 10:52:43 +00:00
args.dp1_len = prkey->u.rsa.dmp1.len;
args.dp1 = prkey->u.rsa.dmp1.data;
args.dq1_len = prkey->u.rsa.dmq1.len;
args.dq1 = prkey->u.rsa.dmq1.data;
args.invq_len = prkey->u.rsa.iqmp.len;
args.invq = prkey->u.rsa.iqmp.data;
args.key_len_bits = prkey->u.rsa.modulus.len;
args.mod = prkey->u.rsa.modulus.data;
}
else {
args.key_type = SC_CARDCTL_MYEID_KEY_EC;
args.d = prkey->u.ec.privateD.data;
args.d_len = prkey->u.ec.privateD.len;
args.ecpublic_point = prkey->u.ec.ecpointQ.value;
args.ecpublic_point_len = prkey->u.ec.ecpointQ.len;
args.key_len_bits = prkey->u.ec.params.field_length;
}
/* Store RSA key */
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args);
LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed");
LOG_FUNC_RETURN(ctx, r);
}
static int
myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
struct sc_pkcs15_object *object,
2012-11-28 10:52:43 +00:00
struct sc_pkcs15_pubkey *pubkey) {
struct sc_context *ctx = p15card->card->ctx;
struct sc_card *card = p15card->card;
2012-11-28 10:52:43 +00:00
struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data;
struct sc_cardctl_myeid_gen_store_key_info args;
struct sc_file *file = NULL;
int r;
size_t keybits = key_info->modulus_length;
unsigned char raw_pubkey[256];
LOG_FUNC_CALLED(ctx);
2012-11-28 10:52:43 +00:00
if (object->type != SC_PKCS15_TYPE_PRKEY_RSA && object->type != SC_PKCS15_TYPE_PRKEY_EC)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: only RSA and EC supported");
/* Check that the card supports the requested modulus length */
2012-11-28 10:52:43 +00:00
switch (object->type) {
case SC_PKCS15_TYPE_PRKEY_RSA:
if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size");
break;
case SC_PKCS15_TYPE_PRKEY_EC:
if (sc_card_find_ec_alg(p15card->card, keybits) == NULL)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size");
if(key_info->field_length != 0)
keybits = key_info->field_length;
else
key_info->field_length = keybits;
break;
default:
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported key type");
break;
}
2012-11-28 10:52:43 +00:00
sc_log(ctx, "Generate key with ID:%s and path:%s",
sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path));
r = sc_select_file(card, &key_info->path, &file);
2012-11-28 10:52:43 +00:00
LOG_TEST_RET(ctx, r, "Cannot generate key: failed to select key file");
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_GENERATE);
2012-11-28 10:52:43 +00:00
LOG_TEST_RET(ctx, r, "No authorisation to generate private key");
/* Fill in data structure */
2012-11-28 10:52:43 +00:00
memset(&args, 0, sizeof (args));
args.key_len_bits = keybits;
args.op_type = OP_TYPE_GENERATE;
if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) {
args.key_type = SC_CARDCTL_MYEID_KEY_RSA;
args.pubexp_len = MYEID_DEFAULT_PUBKEY_LEN;
args.pubexp = MYEID_DEFAULT_PUBKEY;
} else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) {
args.key_type = SC_CARDCTL_MYEID_KEY_EC;
}
/* Generate RSA key */
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args);
LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed");
/* Keypair generation -> collect public key info */
2012-11-28 10:52:43 +00:00
if (pubkey != NULL) {
struct sc_cardctl_myeid_data_obj data_obj;
2012-11-28 10:52:43 +00:00
if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) {
pubkey->algorithm = SC_ALGORITHM_RSA;
pubkey->u.rsa.modulus.len = (keybits + 7) / 8;
pubkey->u.rsa.modulus.data = malloc(pubkey->u.rsa.modulus.len);
pubkey->u.rsa.exponent.len = MYEID_DEFAULT_PUBKEY_LEN;
pubkey->u.rsa.exponent.data = malloc(MYEID_DEFAULT_PUBKEY_LEN);
memcpy(pubkey->u.rsa.exponent.data, MYEID_DEFAULT_PUBKEY, MYEID_DEFAULT_PUBKEY_LEN);
/* Get public key modulus */
r = sc_select_file(card, &file->path, NULL);
LOG_TEST_RET(ctx, r, "Cannot get key modulus: select key file failed");
data_obj.P1 = 0x01;
data_obj.P2 = 0x01;
data_obj.Data = raw_pubkey;
data_obj.DataLen = sizeof (raw_pubkey);
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj);
LOG_TEST_RET(ctx, r, "Cannot get RSA key modulus: 'MYEID_GETDATA' failed");
if ((data_obj.DataLen * 8) != key_info->modulus_length)
LOG_TEST_RET(ctx, SC_ERROR_PKCS15INIT, "Cannot get RSA key modulus: invalid key-size");
memcpy(pubkey->u.rsa.modulus.data, raw_pubkey, pubkey->u.rsa.modulus.len);
}
else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) {
pubkey->algorithm = SC_ALGORITHM_EC;
r = sc_select_file(card, &file->path, NULL);
LOG_TEST_RET(ctx, r, "Cannot get public key: select key file failed");
data_obj.P1 = 0x01;
data_obj.P2 = 0x86; /* Get public EC key (Q) */
data_obj.Data = raw_pubkey;
data_obj.DataLen = sizeof (raw_pubkey);
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj);
LOG_TEST_RET(ctx, r, "Cannot get EC public key: 'MYEID_GETDATA' failed");
ECC ecpointQ Fixes The original ECC code in OpenSC stored the ecpointQ as a DER encoded OCTET STRING. Shortly before 0.13.0, code changes where made to store the ecpointQ as raw data without the DER encoding. Only some of the code was changed to support this but not all, and the comments that said the ecpointQ was in DER where not changed either. Some card drivers continued to work, using the original code in all place, while some cards failed, as they where using a mixture of original code and 0.13.0 code. This commit fixes these problems. The ecpointQ is stored in raw format A new structure type sc_pkcs15_u8 is defined. The ecpointQ are changed to use the struct sc_pkcs15_u8. This was done to avoid the confusion of using struct sc_pkcs15_der to hold non-DER encoded data. (There may be other uses for this too...) Comments are change is many places. sc_pkcs15_decode_pubkey_ec was fixed to store the raw ecpointQ correctly. sc_pkcs15_pubkey_from_spki was change to get the sc_ec_params from the alg_id and fix up u.ec.params. Unfortunately the OpenSC code has two places EC parameters are stored. They can get out of sync, or there may still be code that looks in the wrng oplace. o(TODO get it to only only place.) The u.ec.params.field_length is now set in a number of places, as this is need in many of the PKCS#11 routines. framework-pkcs15.c will now correctly return the DER encode ecpointQ, for the CKA_EC_POINT attribute using pubkey->data which has the DER encoding for the ecpointQ. framework-pkcs15.c will look for the EC parameters in either the u.ec.params.der, or in the alg_id->params. (TODO get it to only only place.) pkcs15-myeid.c has some comments, as it looks like the code is storing a TLV rather then a DER encoding of the ecpointQ. With the wrong encoding PKCS#11 will return the wrong attribute for CKA_ECDSA_PARAMS. pkcs15-piv.c is changed so emulation of a pubkey taken from a certificate will work correctly.
2013-11-06 22:09:29 +00:00
/*
* TODO DEE - this looks like a bug...
* pubkey->u.ec.ecpointQ.value is just value. "04||X||Y"
* pubkey->data.value should be DER OCTET STRING
* but
* pubkey->data.value looks like TLV with TAG if 0x86
* and single byte length.
* Could call sc_pkcs15_encode_pubkey
* to set pubkey->data.value
*/
2012-11-28 10:52:43 +00:00
pubkey->u.ec.ecpointQ.value = malloc(data_obj.DataLen - 2);
pubkey->u.ec.ecpointQ.len = data_obj.DataLen - 2;
pubkey->data.value = malloc(data_obj.DataLen);
pubkey->data.len = data_obj.DataLen;
pubkey->u.ec.params.field_length = keybits;
/* Omit the first 2 bytes (0x86??) */
memcpy(pubkey->u.ec.ecpointQ.value, data_obj.Data + 2, data_obj.DataLen - 2);
memcpy(pubkey->data.value, data_obj.Data, data_obj.DataLen);
}
}
if (file)
sc_file_free(file);
LOG_FUNC_RETURN(ctx, r);
}
/* Finish initialization. After this ACL is in affect */
2012-11-28 10:52:43 +00:00
static int myeid_finalize_card(sc_card_t *card) {
LOG_FUNC_CALLED(card->ctx);
LOG_FUNC_RETURN(card->ctx, sc_card_ctl(card, SC_CARDCTL_MYEID_ACTIVATE_CARD, NULL));
}
/*
* Create a new PIN
*/
static struct sc_pkcs15init_operations sc_pkcs15init_myeid_operations = {
myeid_erase_card,
2012-11-28 10:52:43 +00:00
myeid_init_card, /* init_card */
myeid_create_dir, /* create_dir */
NULL, /* create_domain */
myeid_select_pin_reference,
myeid_create_pin,
2012-11-28 10:52:43 +00:00
NULL, /* select_key_reference */
myeid_create_key,
myeid_store_key,
myeid_generate_key,
myeid_encode_private_key,
myeid_encode_public_key,
myeid_finalize_card,
2012-11-28 10:52:43 +00:00
myeid_delete_object, /* delete_object */
NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */
NULL /* sanity_check */
};
2012-11-28 10:52:43 +00:00
struct sc_pkcs15init_operations *sc_pkcs15init_get_myeid_ops(void) {
return &sc_pkcs15init_myeid_operations;
}