2009-10-03 07:48:28 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2009-10-25 20:22:11 +00:00
|
|
|
#include <assert.h>
|
2009-10-03 07:48:28 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
2010-03-04 08:14:36 +00:00
|
|
|
|
|
|
|
#include "libopensc/opensc.h"
|
|
|
|
#include "libopensc/cardctl.h"
|
|
|
|
#include "libopensc/log.h"
|
2009-10-03 07:48:28 +00:00
|
|
|
#include "pkcs15-init.h"
|
|
|
|
#include "profile.h"
|
2016-08-07 11:08:19 +00:00
|
|
|
#include "libopensc/asn1.h"
|
2017-04-17 11:23:44 +00:00
|
|
|
#include "pkcs11/pkcs11.h"
|
2009-10-03 07:48:28 +00:00
|
|
|
|
2010-09-27 07:50:14 +00:00
|
|
|
#undef KEEP_AC_NONE_FOR_INIT_APPLET
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2009-10-25 20:22:11 +00:00
|
|
|
#define MYEID_MAX_PINS 14
|
2016-08-07 11:08:19 +00:00
|
|
|
#define MYEID_MAX_RSA_KEY_LEN 2048
|
2009-10-03 07:48:28 +00:00
|
|
|
|
|
|
|
unsigned char MYEID_DEFAULT_PUBKEY[] = {0x01, 0x00, 0x01};
|
|
|
|
#define MYEID_DEFAULT_PUBKEY_LEN sizeof(MYEID_DEFAULT_PUBKEY)
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
/* For Myeid, all objects are files that can be deleted in any order */
|
2012-04-02 21:40:05 +00:00
|
|
|
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) {
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(p15card->card->ctx);
|
2010-02-21 16:21:57 +00:00
|
|
|
return sc_pkcs15init_delete_by_path(profile, p15card, path);
|
2010-02-02 09:44:46 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
/*
|
|
|
|
* Get 'Initialize Applet' data
|
2015-02-15 12:59:11 +00:00
|
|
|
* using the ACLs defined in card profile.
|
2010-02-21 16:21:57 +00:00
|
|
|
*/
|
|
|
|
static int
|
2012-04-02 21:40:05 +00:00
|
|
|
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) {
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_file *tmp_file = NULL;
|
|
|
|
const struct sc_acl_entry *entry = NULL;
|
|
|
|
int r;
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
if (data_len < 8)
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Cannot get init applet data");
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
*(data + 0) = 0xFF;
|
|
|
|
*(data + 1) = 0xFF;
|
|
|
|
|
|
|
|
/* MF acls */
|
|
|
|
sc_file_dup(&tmp_file, profile->mf_info->file);
|
|
|
|
if (tmp_file == NULL)
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate MF file");
|
2015-05-07 20:04:25 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file);
|
2015-05-07 20:04:25 +00:00
|
|
|
if (r < 0)
|
|
|
|
sc_file_free(tmp_file);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "MF fixup failed");
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
/* 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);
|
2010-02-21 16:21:57 +00:00
|
|
|
if (entry->method == SC_AC_CHV)
|
2012-11-28 10:52:43 +00:00
|
|
|
*(data + 2) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx'. */
|
2010-02-21 16:21:57 +00:00
|
|
|
else if (entry->method == SC_AC_NEVER)
|
2012-11-28 10:52:43 +00:00
|
|
|
*(data + 2) = 0xFF; /* 'NEVER'. */
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
/* AC 'INITIALISE APPLET'. */
|
2012-11-28 10:52:43 +00:00
|
|
|
*(data + 3) = 0x0F; /* 'NONE' */
|
2010-02-21 16:21:57 +00:00
|
|
|
#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);
|
2010-02-21 16:21:57 +00:00
|
|
|
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)
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate Application DF file");
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file);
|
2015-05-07 20:04:25 +00:00
|
|
|
if (r < 0)
|
|
|
|
sc_file_free(tmp_file);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Application DF fixup failed");
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
/* 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);
|
2010-02-21 16:21:57 +00:00
|
|
|
if (entry->method == SC_AC_CHV)
|
2012-11-28 10:52:43 +00:00
|
|
|
*(data + 5) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx' */
|
2010-02-21 16:21:57 +00:00
|
|
|
else if (entry->method == SC_AC_NEVER)
|
2012-11-28 10:52:43 +00:00
|
|
|
*(data + 5) = 0xFF; /* 'NEVER'. */
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
/* 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);
|
2010-02-21 16:21:57 +00:00
|
|
|
if (entry->method == SC_AC_CHV)
|
2012-11-28 10:52:43 +00:00
|
|
|
*(data + 6) = (entry->key_ref << 4) | 0xF; /* 'CHVx' */
|
2010-02-21 16:21:57 +00:00
|
|
|
else if (entry->method == SC_AC_NEVER)
|
2012-11-28 10:52:43 +00:00
|
|
|
*(data + 6) = 0xFF; /* 'NEVER'. */
|
|
|
|
*(data + 7) = 0xFF;
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2015-05-07 20:04:25 +00:00
|
|
|
sc_file_free(tmp_file);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
|
2010-02-02 09:44:46 +00:00
|
|
|
}
|
|
|
|
|
2009-10-03 07:48:28 +00:00
|
|
|
/*
|
|
|
|
* Erase the card.
|
|
|
|
*/
|
2012-04-02 21:40:05 +00:00
|
|
|
static int
|
2012-11-28 10:52:43 +00:00
|
|
|
myeid_erase_card(struct sc_profile *profile, struct sc_pkcs15_card *p15card) {
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2009-10-03 07:48:28 +00:00
|
|
|
struct sc_cardctl_myeid_data_obj data_obj;
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_file *mf = NULL;
|
|
|
|
unsigned char data[8];
|
2009-10-03 07:48:28 +00:00
|
|
|
int r;
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2009-10-03 07:48:28 +00:00
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
r = myeid_get_init_applet_data(profile, p15card, data, sizeof (data));
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Get init applet date error");
|
2009-10-03 07:48:28 +00:00
|
|
|
|
|
|
|
/* Select parent DF and verify PINs/key as necessary */
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_select_file(p15card->card, sc_get_mf_path(), &mf);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot select MF");
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
/* 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);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "'DELETE' authentication failed on MF");
|
2012-04-02 21:40:05 +00:00
|
|
|
|
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);
|
2009-11-13 11:19:46 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_card_ctl(p15card->card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
|
2009-10-03 07:48:28 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, r);
|
2009-10-25 20:22:11 +00:00
|
|
|
}
|
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
|
|
|
|
|
2012-04-02 21:40:05 +00:00
|
|
|
static int
|
|
|
|
myeid_init_card(sc_profile_t *profile,
|
2012-11-28 10:52:43 +00:00
|
|
|
sc_pkcs15_card_t *p15card) {
|
2010-09-04 20:46:07 +00:00
|
|
|
struct sc_path path;
|
|
|
|
struct sc_file *file = NULL;
|
2012-11-28 10:52:43 +00:00
|
|
|
u8 rbuf[256];
|
2009-10-25 20:22:11 +00:00
|
|
|
int r;
|
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(p15card->card->ctx);
|
2009-10-25 20:22:11 +00:00
|
|
|
|
2011-02-16 10:46:06 +00:00
|
|
|
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");
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
sc_format_path("3F00", &path);
|
|
|
|
r = sc_select_file(p15card->card, &path, &file);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2017-01-05 19:21:44 +00:00
|
|
|
sc_file_free(file);
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, r);
|
2009-10-03 07:48:28 +00:00
|
|
|
}
|
|
|
|
|
2009-10-25 20:22:11 +00:00
|
|
|
/*
|
|
|
|
* Create a DF
|
|
|
|
*/
|
2012-04-02 21:40:05 +00:00
|
|
|
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) {
|
2015-02-15 12:59:11 +00:00
|
|
|
struct sc_context *ctx = NULL;
|
2011-01-19 14:47:54 +00:00
|
|
|
struct sc_file *file = NULL;
|
2012-11-28 10:52:43 +00:00
|
|
|
int r = 0, ii;
|
|
|
|
static const char *create_dfs[] = {
|
2011-01-19 14:47:54 +00:00
|
|
|
"PKCS15-PrKDF",
|
|
|
|
"PKCS15-PuKDF",
|
2017-04-14 07:42:30 +00:00
|
|
|
"PKCS15-SKDF",
|
2011-01-19 14:47:54 +00:00
|
|
|
"PKCS15-CDF",
|
2011-04-15 17:11:38 +00:00
|
|
|
"PKCS15-CDF-TRUSTED",
|
2011-01-19 14:47:54 +00:00
|
|
|
"PKCS15-DODF",
|
|
|
|
NULL
|
|
|
|
};
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2011-04-15 17:11:38 +00:00
|
|
|
static const int create_dfs_val[] = {
|
2012-11-28 10:52:43 +00:00
|
|
|
SC_PKCS15_PRKDF,
|
|
|
|
SC_PKCS15_PUKDF,
|
2017-04-14 07:42:30 +00:00
|
|
|
SC_PKCS15_SKDF,
|
2012-11-28 10:52:43 +00:00
|
|
|
SC_PKCS15_CDF,
|
|
|
|
SC_PKCS15_CDF_TRUSTED,
|
|
|
|
SC_PKCS15_DODF
|
2011-04-15 17:11:38 +00:00
|
|
|
};
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2015-01-22 19:29:33 +00:00
|
|
|
if (!profile || !p15card || !p15card->card || !df)
|
2009-10-25 20:22:11 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
2015-01-22 19:29:33 +00:00
|
|
|
ctx = p15card->card->ctx;
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2012-11-28 10:52:43 +00:00
|
|
|
sc_log(ctx, "id (%x)", df->id);
|
2009-10-25 20:22:11 +00:00
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
if (df->id == 0x5015) {
|
|
|
|
sc_log(ctx, "Select (%x)", df->id);
|
2010-09-04 20:46:07 +00:00
|
|
|
r = sc_select_file(p15card->card, &df->path, NULL);
|
2011-01-19 14:47:54 +00:00
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
for (ii = 0; create_dfs[ii]; ii++) {
|
2012-08-14 13:37:24 +00:00
|
|
|
sc_log(ctx, "Create '%s'", create_dfs[ii]);
|
2011-04-15 17:11:38 +00:00
|
|
|
|
2015-10-09 15:37:22 +00:00
|
|
|
r = sc_profile_get_file(profile, create_dfs[ii], &file);
|
2017-01-05 19:21:44 +00:00
|
|
|
sc_file_free(file);
|
2015-10-09 15:37:22 +00:00
|
|
|
if (r) {
|
2012-08-14 13:37:24 +00:00
|
|
|
sc_log(ctx, "Inconsistent profile: cannot find %s", create_dfs[ii]);
|
|
|
|
LOG_FUNC_RETURN(ctx, SC_ERROR_INCONSISTENT_PROFILE);
|
2011-01-19 14:47:54 +00:00
|
|
|
}
|
2011-04-15 17:11:38 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, create_dfs_val[ii], NULL);
|
|
|
|
|
2011-01-19 14:47:54 +00:00
|
|
|
if (r != SC_ERROR_FILE_ALREADY_EXISTS)
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to create MyEID xDF file");
|
2011-01-19 14:47:54 +00:00
|
|
|
}
|
2009-10-25 20:22:11 +00:00
|
|
|
}
|
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, r);
|
2009-10-25 20:22:11 +00:00
|
|
|
}
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2009-10-03 07:48:28 +00:00
|
|
|
/*
|
|
|
|
* Select the PIN reference
|
|
|
|
*/
|
2012-04-02 21:40:05 +00:00
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
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) {
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
|
2011-06-05 15:46:25 +00:00
|
|
|
|
|
|
|
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);
|
2009-10-25 20:22:11 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-06-05 15:46:25 +00:00
|
|
|
if (auth_info->attrs.pin.reference <= 0 || auth_info->attrs.pin.reference > MYEID_MAX_PINS)
|
|
|
|
auth_info->attrs.pin.reference = 1;
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
|
2009-10-03 07:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new PIN
|
|
|
|
*/
|
2012-04-02 21:40:05 +00:00
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
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) {
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2012-11-28 10:52:43 +00:00
|
|
|
unsigned char data[20];
|
2010-02-21 16:21:57 +00:00
|
|
|
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;
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(ctx,
|
|
|
|
"PIN('%s',ref:%i,flags:0x%X,pin_len:%"SC_FORMAT_LEN_SIZE_T"u,puk_len:%"SC_FORMAT_LEN_SIZE_T"u)\n",
|
|
|
|
pin_obj->label, auth_info->attrs.pin.reference,
|
|
|
|
auth_info->attrs.pin.flags, pin_len, puk_len);
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2011-06-05 15:46:25 +00:00
|
|
|
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)
|
2010-02-21 16:21:57 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
if (pin == NULL || puk == NULL || pin_len < 4 || puk_len < 4)
|
|
|
|
return SC_ERROR_INVALID_PIN_LENGTH;
|
|
|
|
|
2012-04-02 21:40:05 +00:00
|
|
|
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,
|
2011-06-05 15:46:25 +00:00
|
|
|
&puk_ainfo);
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
memset(data, 0, sizeof (data));
|
2010-02-21 16:21:57 +00:00
|
|
|
/* 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 */
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2011-06-05 15:46:25 +00:00
|
|
|
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 */
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2011-06-05 15:46:25 +00:00
|
|
|
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 */
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
if (auth_info->tries_left > 0 && auth_info->tries_left < 15)
|
2011-06-05 15:46:25 +00:00
|
|
|
data[16] = auth_info->tries_left;
|
2010-02-21 16:21:57 +00:00
|
|
|
else
|
2012-11-28 10:52:43 +00:00
|
|
|
data[16] = 5; /* default value */
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
if (puk_ainfo.tries_left > 0 && puk_ainfo.tries_left < 15)
|
2011-06-05 15:46:25 +00:00
|
|
|
data[17] = puk_ainfo.tries_left;
|
2010-02-21 16:21:57 +00:00
|
|
|
else
|
2012-11-28 10:52:43 +00:00
|
|
|
data[17] = 5; /* default value */
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
data[18] = 0x00;
|
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
data_obj.Data = data;
|
2010-02-21 16:21:57 +00:00
|
|
|
data_obj.DataLen = 19;
|
|
|
|
|
|
|
|
r = sc_card_ctl(p15card->card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Initialize PIN failed");
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2009-10-03 07:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup file struct & path: get correct template from the profile, construct full path
|
|
|
|
* num = number of objects of this type already on the card
|
|
|
|
*/
|
2012-04-02 21:40:05 +00:00
|
|
|
static int
|
2010-02-02 09:44:46 +00:00
|
|
|
myeid_new_file(sc_profile_t *profile, sc_card_t *card,
|
2012-04-02 21:40:05 +00:00
|
|
|
unsigned int type, unsigned int num,
|
2012-11-28 10:52:43 +00:00
|
|
|
sc_file_t **out) {
|
2009-10-03 07:48:28 +00:00
|
|
|
sc_file_t *file;
|
|
|
|
sc_path_t *p;
|
2010-04-02 12:13:41 +00:00
|
|
|
char name[64];
|
2017-04-14 07:42:30 +00:00
|
|
|
const char *tag = NULL;
|
2009-10-03 07:48:28 +00:00
|
|
|
int r;
|
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2017-04-14 07:42:30 +00:00
|
|
|
switch (type) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_EC:
|
2009-10-03 07:48:28 +00:00
|
|
|
tag = "private-key";
|
2017-04-14 07:42:30 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY_RSA:
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY_EC:
|
2009-10-03 07:48:28 +00:00
|
|
|
tag = "public-key";
|
2017-04-14 07:42:30 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_SKEY_GENERIC:
|
|
|
|
case SC_PKCS15_TYPE_SKEY_DES:
|
|
|
|
case SC_PKCS15_TYPE_SKEY_3DES:
|
|
|
|
tag = "secret-key";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
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";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tag) {
|
2012-08-14 13:37:24 +00:00
|
|
|
sc_log(card->ctx, "Unsupported file type");
|
2009-10-03 07:48:28 +00:00
|
|
|
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) {
|
2012-08-14 13:37:24 +00:00
|
|
|
sc_log(card->ctx, "Profile doesn't define %s", name);
|
2009-10-03 07:48:28 +00:00
|
|
|
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) {
|
2009-10-03 07:48:28 +00:00
|
|
|
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;
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(card->ctx, 0);
|
2009-10-03 07:48:28 +00:00
|
|
|
}
|
|
|
|
|
2012-04-02 21:40:05 +00:00
|
|
|
static int
|
2010-02-02 09:44:46 +00:00
|
|
|
myeid_encode_private_key(sc_profile_t *profile, sc_card_t *card,
|
2012-04-02 21:40:05 +00:00
|
|
|
struct sc_pkcs15_prkey_rsa *rsa, u8 *key,
|
2012-11-28 10:52:43 +00:00
|
|
|
size_t *keysize, int key_ref) {
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
|
|
|
LOG_FUNC_RETURN(card->ctx, 0);
|
2009-10-03 07:48:28 +00:00
|
|
|
}
|
|
|
|
|
2012-04-02 21:40:05 +00:00
|
|
|
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) {
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
|
|
|
LOG_FUNC_RETURN(card->ctx, 0);
|
2009-10-03 07:48:28 +00:00
|
|
|
}
|
|
|
|
|
2017-04-17 11:23:44 +00:00
|
|
|
/*
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
_add_supported_algo(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object,
|
|
|
|
unsigned operations, unsigned mechanism, const struct sc_object_id *oid)
|
|
|
|
{
|
|
|
|
struct sc_supported_algo_info *algo;
|
|
|
|
algo = sc_pkcs15_get_supported_algo(p15card, operations, mechanism);
|
|
|
|
if (!algo) {
|
|
|
|
unsigned ref = 1, ii;
|
|
|
|
|
|
|
|
for (ii=0;ii<SC_MAX_SUPPORTED_ALGORITHMS && p15card->tokeninfo->supported_algos[ii].reference; ii++)
|
|
|
|
if (p15card->tokeninfo->supported_algos[ii].reference >= ref)
|
|
|
|
ref = p15card->tokeninfo->supported_algos[ii].reference + 1;
|
|
|
|
if (ii < SC_MAX_SUPPORTED_ALGORITHMS) {
|
|
|
|
algo = &p15card->tokeninfo->supported_algos[ii];
|
|
|
|
algo->reference = ref;
|
|
|
|
algo->mechanism = mechanism;
|
|
|
|
algo->operations = operations;
|
|
|
|
algo->algo_id = *oid;
|
|
|
|
profile->dirty = 1;
|
|
|
|
profile->pkcs15.do_last_update = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
sc_pkcs15_add_supported_algo_ref(object, algo);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
myeid_fixup_supported_algos(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object)
|
|
|
|
{
|
|
|
|
static const struct sc_object_id id_aes128_ecb = { { 2, 16, 840, 1, 101, 3, 4, 1, 1, -1 } };
|
|
|
|
static const struct sc_object_id id_aes128_cbc = { { 2, 16, 840, 1, 101, 3, 4, 1, 2, -1 } };
|
|
|
|
static const struct sc_object_id id_aes256_ecb = { { 2, 16, 840, 1, 101, 3, 4, 1, 41, -1 } };
|
|
|
|
static const struct sc_object_id id_aes256_cbc = { { 2, 16, 840, 1, 101, 3, 4, 1, 42, -1 } };
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_pkcs15_skey_info *skey_info = (struct sc_pkcs15_skey_info *) object->data;
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
switch (object->type) {
|
|
|
|
case SC_PKCS15_TYPE_SKEY_GENERIC:
|
|
|
|
switch (skey_info->key_type | (skey_info->value_len << 16)) {
|
|
|
|
case CKM_AES_ECB | (128 << 16):
|
|
|
|
_add_supported_algo(profile, p15card, object, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_ECB, &id_aes128_ecb);
|
|
|
|
_add_supported_algo(profile, p15card, object, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_CBC, &id_aes128_cbc);
|
|
|
|
break;
|
|
|
|
case CKM_AES_ECB | (256 << 16):
|
|
|
|
_add_supported_algo(profile, p15card, object, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_ECB, &id_aes256_ecb);
|
|
|
|
_add_supported_algo(profile, p15card, object, SC_PKCS15_ALGO_OP_DECIPHER|SC_PKCS15_ALGO_OP_ENCIPHER, CKM_AES_CBC, &id_aes256_cbc);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-02 09:44:46 +00:00
|
|
|
|
|
|
|
/*
|
2017-04-07 07:24:05 +00:00
|
|
|
* Create a private key file
|
2010-02-02 09:44:46 +00:00
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
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) {
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_card *card = p15card->card;
|
2017-04-14 07:42:30 +00:00
|
|
|
struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) object->data;
|
|
|
|
struct sc_pkcs15_skey_info *skey_info = (struct sc_pkcs15_skey_info *) object->data;
|
|
|
|
struct sc_pkcs15_id *id;
|
|
|
|
struct sc_path *path;
|
|
|
|
int *key_reference;
|
2010-02-02 09:44:46 +00:00
|
|
|
struct sc_file *file = NULL;
|
2017-04-07 07:24:05 +00:00
|
|
|
struct sc_pkcs15_object *pin_object = NULL;
|
|
|
|
struct sc_pkcs15_auth_info *pkcs15_auth_info = NULL;
|
|
|
|
unsigned char sec_attrs[] = {0xFF, 0xFF, 0xFF};
|
2017-04-17 11:23:44 +00:00
|
|
|
int r, ef_structure = 0, keybits = 0, pin_reference = -1;
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
2012-11-28 10:52:43 +00:00
|
|
|
|
|
|
|
switch (object->type) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
2017-04-14 07:42:30 +00:00
|
|
|
ef_structure = SC_CARDCTL_MYEID_KEY_RSA;
|
|
|
|
keybits = prkey_info->modulus_length;
|
2012-11-28 10:52:43 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_EC:
|
2017-04-14 07:42:30 +00:00
|
|
|
ef_structure = SC_CARDCTL_MYEID_KEY_EC;
|
|
|
|
keybits = prkey_info->field_length;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_SKEY_DES:
|
|
|
|
case SC_PKCS15_TYPE_SKEY_3DES:
|
|
|
|
ef_structure = SC_CARDCTL_MYEID_KEY_DES;
|
|
|
|
keybits = skey_info->value_len;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_SKEY_GENERIC:
|
|
|
|
keybits = skey_info->value_len;
|
2017-04-17 11:23:44 +00:00
|
|
|
switch (skey_info->key_type) {
|
|
|
|
case CKM_AES_ECB:
|
|
|
|
ef_structure = SC_CARDCTL_MYEID_KEY_AES;
|
|
|
|
break;
|
|
|
|
case CKM_DES_ECB:
|
|
|
|
ef_structure = SC_CARDCTL_MYEID_KEY_DES;
|
|
|
|
break;
|
|
|
|
}
|
2012-11-28 10:52:43 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-04-17 11:23:44 +00:00
|
|
|
if (!ef_structure) {
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS,
|
|
|
|
"Unsupported key type");
|
|
|
|
}
|
|
|
|
|
|
|
|
myeid_fixup_supported_algos(profile, p15card, object);
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2017-04-14 07:42:30 +00:00
|
|
|
if ((object->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) {
|
|
|
|
id = &prkey_info->id;
|
|
|
|
path = &prkey_info->path;
|
|
|
|
key_reference = &prkey_info->key_reference;
|
|
|
|
} else {
|
|
|
|
id = &skey_info->id;
|
|
|
|
path = &skey_info->path;
|
|
|
|
key_reference = &skey_info->key_reference;
|
|
|
|
}
|
|
|
|
|
|
|
|
sc_log(ctx, "create MyEID key ID:%s", sc_pkcs15_print_id(id));
|
2010-02-02 09:44:46 +00:00
|
|
|
|
|
|
|
/* Get the private key file */
|
2017-04-14 07:42:30 +00:00
|
|
|
r = myeid_new_file(profile, card, object->type, *key_reference, &file);
|
|
|
|
LOG_TEST_RET(ctx, r, "Cannot get new MyEID key file");
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2015-02-15 12:59:11 +00:00
|
|
|
if (!file || !file->path.len)
|
2017-04-14 07:42:30 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot determine key file");
|
2015-02-15 12:59:11 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
sc_log(ctx, "Key file size %d", keybits);
|
2010-09-04 20:46:07 +00:00
|
|
|
file->size = keybits;
|
2017-04-14 07:42:30 +00:00
|
|
|
file->ef_structure = ef_structure;
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2017-04-14 07:42:30 +00:00
|
|
|
memcpy(path->value, &file->path.value, file->path.len);
|
|
|
|
*key_reference = file->path.value[file->path.len - 1] & 0xFF;
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2017-04-14 07:42:30 +00:00
|
|
|
sc_log(ctx, "Path of MyEID key file to create %s",
|
2010-09-04 20:46:07 +00:00
|
|
|
sc_print_path(&file->path));
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2017-04-07 07:24:05 +00:00
|
|
|
if (object->auth_id.len >= 1) {
|
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &object->auth_id, &pin_object);
|
|
|
|
|
|
|
|
if (r != SC_SUCCESS)
|
|
|
|
sc_file_free(file);
|
|
|
|
LOG_TEST_RET(ctx, r, "Failed to get pin object by auth_id");
|
|
|
|
|
|
|
|
if (pin_object->type != SC_PKCS15_TYPE_AUTH_PIN) {
|
|
|
|
sc_file_free(file);
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, "Invalid object returned when locating pin object.");
|
|
|
|
}
|
|
|
|
|
|
|
|
pkcs15_auth_info = (struct sc_pkcs15_auth_info*) pin_object->data;
|
|
|
|
|
|
|
|
if (pkcs15_auth_info == NULL || pkcs15_auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) {
|
|
|
|
sc_file_free(file);
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, "NULL or invalid sc_pkcs15_auth_info in pin object");
|
|
|
|
}
|
|
|
|
|
|
|
|
pin_reference = pkcs15_auth_info->attrs.pin.reference;
|
|
|
|
|
|
|
|
if (pin_reference >= 1 && pin_reference < MYEID_MAX_PINS) {
|
|
|
|
sec_attrs[0] = (pin_reference << 4 | (pin_reference & 0x0F));
|
|
|
|
sec_attrs[1] = (pin_reference << 4 | (pin_reference & 0x0F));
|
|
|
|
sc_file_set_sec_attr(file, sec_attrs, sizeof(sec_attrs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sc_file_free(file);
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid AuthID value for a private key.");
|
|
|
|
}
|
|
|
|
|
2010-02-02 09:44:46 +00:00
|
|
|
/* Now create the key file */
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_create_file(profile, p15card, file);
|
2010-02-02 09:44:46 +00:00
|
|
|
sc_file_free(file);
|
2017-04-14 07:42:30 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot create MyEID key file");
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2010-02-02 09:44:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store a private key
|
|
|
|
*/
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
2012-04-02 21:40:05 +00:00
|
|
|
struct sc_pkcs15_object *object,
|
2012-11-28 10:52:43 +00:00
|
|
|
struct sc_pkcs15_prkey *prkey) {
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_card *card = p15card->card;
|
2010-02-02 09:44:46 +00:00
|
|
|
struct sc_cardctl_myeid_gen_store_key_info args;
|
|
|
|
struct sc_file *file = NULL;
|
2017-04-14 07:42:30 +00:00
|
|
|
struct sc_pkcs15_id *id;
|
|
|
|
struct sc_path *path;
|
|
|
|
int r;
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2017-04-14 07:42:30 +00:00
|
|
|
if ((object->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) {
|
|
|
|
struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) object->data;
|
|
|
|
id = &prkey_info->id;
|
|
|
|
path = &prkey_info->path;
|
|
|
|
} else {
|
|
|
|
struct sc_pkcs15_skey_info *skey_info = (struct sc_pkcs15_skey_info *) object->data;
|
|
|
|
id = &skey_info->id;
|
|
|
|
path = &skey_info->path;
|
2012-11-28 10:52:43 +00:00
|
|
|
}
|
2014-01-19 13:11:16 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
sc_log(ctx, "store MyEID key with ID:%s and path:%s",
|
2017-04-14 07:42:30 +00:00
|
|
|
sc_pkcs15_print_id(id), sc_print_path(path));
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2017-04-14 07:42:30 +00:00
|
|
|
r = sc_select_file(card, path, &file);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot store MyEID key: select key file failed");
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "No authorisation to store MyEID private key");
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2017-01-05 19:21:44 +00:00
|
|
|
sc_file_free(file);
|
2010-02-02 09:44:46 +00:00
|
|
|
|
|
|
|
/* Fill in data structure */
|
2012-11-28 10:52:43 +00:00
|
|
|
memset(&args, 0, sizeof (args));
|
|
|
|
|
|
|
|
args.op_type = OP_TYPE_STORE;
|
2017-04-14 07:42:30 +00:00
|
|
|
|
|
|
|
switch (object->type) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_RSA:
|
2012-11-28 10:52:43 +00:00
|
|
|
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;
|
2010-02-02 09:44:46 +00:00
|
|
|
|
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;
|
|
|
|
|
2017-04-14 07:42:30 +00:00
|
|
|
//args.key_len_bits = keybits;
|
2012-11-28 10:52:43 +00:00
|
|
|
args.key_len_bits = prkey->u.rsa.modulus.len;
|
|
|
|
args.mod = prkey->u.rsa.modulus.data;
|
2017-04-14 07:42:30 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PRKEY_EC:
|
2012-11-28 10:52:43 +00:00
|
|
|
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;
|
2017-04-14 07:42:30 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_SKEY_GENERIC:
|
|
|
|
case SC_PKCS15_TYPE_SKEY_DES:
|
|
|
|
case SC_PKCS15_TYPE_SKEY_2DES:
|
|
|
|
case SC_PKCS15_TYPE_SKEY_3DES:
|
|
|
|
switch (prkey->algorithm) {
|
|
|
|
case SC_ALGORITHM_AES:
|
|
|
|
args.key_type = SC_CARDCTL_MYEID_KEY_AES;
|
|
|
|
break;
|
|
|
|
case SC_ALGORITHM_DES:
|
|
|
|
args.key_type = SC_CARDCTL_MYEID_KEY_DES;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
args.d = prkey->u.secret.data;
|
|
|
|
args.d_len = prkey->u.secret.data_len;
|
|
|
|
break;
|
2012-11-28 10:52:43 +00:00
|
|
|
}
|
2010-02-02 09:44:46 +00:00
|
|
|
/* Store RSA key */
|
|
|
|
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed");
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2010-02-02 09:44:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
2012-04-02 21:40:05 +00:00
|
|
|
struct sc_pkcs15_object *object,
|
2012-11-28 10:52:43 +00:00
|
|
|
struct sc_pkcs15_pubkey *pubkey) {
|
2010-02-21 16:21:57 +00:00
|
|
|
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;
|
2010-02-02 09:44:46 +00:00
|
|
|
struct sc_cardctl_myeid_gen_store_key_info args;
|
|
|
|
struct sc_file *file = NULL;
|
2010-04-02 12:15:12 +00:00
|
|
|
int r;
|
2016-08-07 11:08:19 +00:00
|
|
|
unsigned int cla,tag;
|
|
|
|
size_t taglen;
|
2010-04-02 12:15:12 +00:00
|
|
|
size_t keybits = key_info->modulus_length;
|
2016-08-07 11:08:19 +00:00
|
|
|
u8 raw_pubkey[MYEID_MAX_RSA_KEY_LEN / 8];
|
|
|
|
u8* dataptr;
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
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");
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2010-09-04 20:46:07 +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:
|
2015-02-15 12:59:11 +00:00
|
|
|
/* EC is supported in MyEID v > 3.5. TODO: set correct return value if older MyEID version. */
|
|
|
|
/* Here the information about curve is not available, that's why supported algorithm is checked
|
2015-11-25 11:12:30 +00:00
|
|
|
without curve OID. */
|
|
|
|
|
2015-02-15 12:59:11 +00:00
|
|
|
if(key_info->field_length != 0)
|
|
|
|
keybits = key_info->field_length;
|
|
|
|
else
|
|
|
|
key_info->field_length = keybits;
|
2015-11-25 11:12:30 +00:00
|
|
|
|
|
|
|
if (sc_card_find_ec_alg(p15card->card, keybits, NULL) == NULL)
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size");
|
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported key type");
|
|
|
|
break;
|
|
|
|
}
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
sc_log(ctx, "Generate key with ID:%s and path:%s",
|
2010-09-04 20:46:07 +00:00
|
|
|
sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path));
|
2010-02-02 09:44:46 +00:00
|
|
|
|
|
|
|
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");
|
2012-04-02 21:40:05 +00:00
|
|
|
|
2010-09-04 20:46:07 +00:00
|
|
|
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");
|
2010-02-02 09:44:46 +00:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2016-08-07 11:08:19 +00:00
|
|
|
/* Generate the key */
|
2010-02-02 09:44:46 +00:00
|
|
|
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args);
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed");
|
2010-02-02 09:44:46 +00:00
|
|
|
|
|
|
|
/* Keypair generation -> collect public key info */
|
2012-11-28 10:52:43 +00:00
|
|
|
if (pubkey != NULL) {
|
2010-02-02 09:44:46 +00:00
|
|
|
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);
|
2014-01-19 13:11:16 +00:00
|
|
|
}
|
2012-11-28 10:52:43 +00:00
|
|
|
else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) {
|
2015-04-20 20:44:33 +00:00
|
|
|
struct sc_ec_parameters *ecparams = (struct sc_ec_parameters *)key_info->params.data;
|
2012-11-28 10:52:43 +00:00
|
|
|
|
2017-03-14 19:02:30 +00:00
|
|
|
sc_log(ctx,
|
|
|
|
"curve '%s', len %"SC_FORMAT_LEN_SIZE_T"u, oid '%s'",
|
|
|
|
ecparams->named_curve, ecparams->field_length,
|
|
|
|
sc_dump_oid(&(ecparams->id)));
|
2012-11-28 10:52:43 +00:00
|
|
|
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");
|
|
|
|
|
2016-08-07 11:08:19 +00:00
|
|
|
dataptr = data_obj.Data;
|
|
|
|
r = sc_asn1_read_tag((const u8 **)&dataptr, data_obj.DataLen, &cla, &tag, &taglen);
|
|
|
|
LOG_TEST_RET(ctx, r, "Invalid EC public key data. Cannot parse DER structure.");
|
|
|
|
|
|
|
|
if (taglen == 0)
|
|
|
|
LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
|
|
|
|
|
2015-02-15 12:59:11 +00:00
|
|
|
if (pubkey->u.ec.ecpointQ.value)
|
|
|
|
free(pubkey->u.ec.ecpointQ.value);
|
2016-08-07 11:08:19 +00:00
|
|
|
|
|
|
|
pubkey->u.ec.ecpointQ.value = malloc(taglen);
|
|
|
|
|
|
|
|
if (pubkey->u.ec.ecpointQ.value == NULL)
|
2015-02-15 12:59:11 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
|
2016-08-07 11:08:19 +00:00
|
|
|
|
|
|
|
memcpy(pubkey->u.ec.ecpointQ.value, dataptr, taglen);
|
|
|
|
pubkey->u.ec.ecpointQ.len = taglen;
|
2015-02-15 12:59:11 +00:00
|
|
|
|
|
|
|
if (pubkey->u.ec.params.named_curve)
|
|
|
|
free(pubkey->u.ec.params.named_curve);
|
|
|
|
pubkey->u.ec.params.named_curve = NULL;
|
|
|
|
if (pubkey->u.ec.params.der.value)
|
|
|
|
free(pubkey->u.ec.params.der.value);
|
|
|
|
pubkey->u.ec.params.der.value = NULL;
|
|
|
|
pubkey->u.ec.params.der.len = 0;
|
|
|
|
|
|
|
|
pubkey->u.ec.params.named_curve = strdup(ecparams->named_curve);
|
|
|
|
if (!pubkey->u.ec.params.named_curve)
|
|
|
|
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
|
|
|
|
r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params);
|
|
|
|
LOG_TEST_RET(ctx, r, "Cannot fix EC parameters");
|
2012-11-28 10:52:43 +00:00
|
|
|
}
|
2010-02-02 09:44:46 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 19:21:44 +00:00
|
|
|
sc_file_free(file);
|
2010-09-04 20:46:07 +00:00
|
|
|
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2010-02-02 09:44:46 +00:00
|
|
|
}
|
|
|
|
|
2010-09-04 20:46:07 +00:00
|
|
|
/* 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) {
|
2012-08-14 13:37:24 +00:00
|
|
|
LOG_FUNC_CALLED(card->ctx);
|
|
|
|
LOG_FUNC_RETURN(card->ctx, sc_card_ctl(card, SC_CARDCTL_MYEID_ACTIVATE_CARD, NULL));
|
2010-09-04 20:46:07 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 09:44:46 +00:00
|
|
|
|
2009-10-03 07:48:28 +00:00
|
|
|
/*
|
|
|
|
* 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 */
|
2009-10-03 07:48:28 +00:00
|
|
|
myeid_select_pin_reference,
|
|
|
|
myeid_create_pin,
|
2012-11-28 10:52:43 +00:00
|
|
|
NULL, /* select_key_reference */
|
2010-02-02 09:44:46 +00:00
|
|
|
myeid_create_key,
|
|
|
|
myeid_store_key,
|
|
|
|
myeid_generate_key,
|
2009-10-03 07:48:28 +00:00
|
|
|
myeid_encode_private_key,
|
|
|
|
myeid_encode_public_key,
|
2010-09-04 20:46:07 +00:00
|
|
|
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 */
|
2009-10-03 07:48:28 +00:00
|
|
|
};
|
|
|
|
|
2012-11-28 10:52:43 +00:00
|
|
|
struct sc_pkcs15init_operations *sc_pkcs15init_get_myeid_ops(void) {
|
2009-10-03 07:48:28 +00:00
|
|
|
return &sc_pkcs15init_myeid_operations;
|
|
|
|
}
|