2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Initialize Cards according to PKCS#15.
|
|
|
|
*
|
|
|
|
* This is a fill in the blanks sort of exercise. You need a
|
|
|
|
* profile that describes characteristics of your card, and the
|
|
|
|
* application specific layout on the card. This program will
|
|
|
|
* set up the card according to this specification (including
|
|
|
|
* PIN initialization etc) and create the corresponding PKCS15
|
|
|
|
* structure.
|
|
|
|
*
|
|
|
|
* There are a very few tasks that are too card specific to have
|
|
|
|
* a generic implementation; that is how PINs and keys are stored
|
|
|
|
* on the card. These should be implemented in pkcs15-<cardname>.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002, Olaf Kirch <okir@lst.de>
|
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
#include <stdio.h>
|
2003-09-06 19:18:38 +00:00
|
|
|
#include <stdlib.h>
|
2002-04-02 13:26:42 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
2003-06-25 10:19:08 +00:00
|
|
|
#include <limits.h>
|
2005-08-05 19:07:24 +00:00
|
|
|
#include <time.h>
|
|
|
|
#ifdef HAVE_GETTIMEOFDAY
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
2002-10-19 14:04:52 +00:00
|
|
|
#ifdef HAVE_STRINGS_H
|
2002-05-20 09:19:41 +00:00
|
|
|
#include <strings.h>
|
2002-10-19 14:04:52 +00:00
|
|
|
#endif
|
2002-04-02 13:26:42 +00:00
|
|
|
#include <assert.h>
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2003-04-22 17:00:38 +00:00
|
|
|
#include <openssl/bn.h>
|
2002-04-02 13:26:42 +00:00
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/pem.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
#include <openssl/rsa.h>
|
|
|
|
#include <openssl/pkcs12.h>
|
2002-06-06 13:38:03 +00:00
|
|
|
#endif
|
2010-03-04 08:14:36 +00:00
|
|
|
|
|
|
|
#include "common/compat_strlcpy.h"
|
2011-02-17 13:35:25 +00:00
|
|
|
#include "common/libscdl.h"
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "libopensc/pkcs15.h"
|
|
|
|
#include "libopensc/cardctl.h"
|
|
|
|
#include "libopensc/log.h"
|
2002-04-02 13:26:42 +00:00
|
|
|
#include "profile.h"
|
|
|
|
#include "pkcs15-init.h"
|
|
|
|
|
2003-12-02 15:51:52 +00:00
|
|
|
#define OPENSC_INFO_FILEPATH "3F0050154946"
|
|
|
|
#define OPENSC_INFO_FILEID 0x4946
|
2003-11-19 20:37:02 +00:00
|
|
|
#define OPENSC_INFO_TAG_PROFILE 0x01
|
|
|
|
#define OPENSC_INFO_TAG_OPTION 0x02
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/* Default ID for new key/pin */
|
2003-10-13 16:13:12 +00:00
|
|
|
#define DEFAULT_ID 0x45
|
2003-10-16 14:32:42 +00:00
|
|
|
#define DEFAULT_PIN_FLAGS 0x03
|
2003-10-13 16:13:12 +00:00
|
|
|
#define DEFAULT_PRKEY_FLAGS 0x03
|
|
|
|
#define DEFAULT_PUBKEY_FLAGS 0x02
|
|
|
|
#define DEFAULT_CERT_FLAGS 0x02
|
2004-07-26 18:47:23 +00:00
|
|
|
#define DEFAULT_DATA_FLAGS 0x02
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-01-16 21:52:47 +00:00
|
|
|
#define TEMPLATE_INSTANTIATE_MIN_INDEX 0x0
|
|
|
|
#define TEMPLATE_INSTANTIATE_MAX_INDEX 0xFE
|
|
|
|
|
2011-04-27 14:45:23 +00:00
|
|
|
/* Maximal number of access conditions that can be defined for one card operation. */
|
|
|
|
#define SC_MAX_OP_ACS 16
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/* Handle encoding of PKCS15 on the card */
|
2010-03-04 13:05:03 +00:00
|
|
|
typedef int (*pkcs15_encoder)(struct sc_context *,
|
2002-04-02 13:26:42 +00:00
|
|
|
struct sc_pkcs15_card *, u8 **, size_t *);
|
|
|
|
|
|
|
|
static int sc_pkcs15init_store_data(struct sc_pkcs15_card *,
|
2010-03-04 13:05:03 +00:00
|
|
|
struct sc_profile *, struct sc_pkcs15_object *,
|
|
|
|
struct sc_pkcs15_der *, struct sc_path *);
|
|
|
|
static size_t sc_pkcs15init_keybits(struct sc_pkcs15_bignum *);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
static int sc_pkcs15init_update_dir(struct sc_pkcs15_card *,
|
|
|
|
struct sc_profile *profile,
|
2010-03-04 13:05:03 +00:00
|
|
|
struct sc_app_info *app);
|
2002-04-02 13:26:42 +00:00
|
|
|
static int sc_pkcs15init_update_tokeninfo(struct sc_pkcs15_card *,
|
|
|
|
struct sc_profile *profile);
|
|
|
|
static int sc_pkcs15init_update_odf(struct sc_pkcs15_card *,
|
|
|
|
struct sc_profile *profile);
|
2002-04-15 13:42:10 +00:00
|
|
|
static int sc_pkcs15init_map_usage(unsigned long, int);
|
2010-02-21 16:21:57 +00:00
|
|
|
static int do_select_parent(struct sc_profile *, struct sc_pkcs15_card *,
|
2010-03-04 16:14:30 +00:00
|
|
|
struct sc_file *, struct sc_file **);
|
|
|
|
static int sc_pkcs15init_create_pin(struct sc_pkcs15_card *, struct sc_profile *,
|
|
|
|
struct sc_pkcs15_object *, struct sc_pkcs15init_pinargs *);
|
2011-04-12 18:08:18 +00:00
|
|
|
static int check_keygen_params_consistency(struct sc_card *card, struct sc_pkcs15init_keygen_args *args,
|
|
|
|
unsigned int bits, unsigned int *out_bits);
|
2002-04-17 20:47:18 +00:00
|
|
|
static int check_key_compatibility(struct sc_pkcs15_card *,
|
2002-11-08 14:14:28 +00:00
|
|
|
struct sc_pkcs15_prkey *, unsigned int,
|
|
|
|
unsigned int, unsigned int);
|
2010-03-04 16:14:30 +00:00
|
|
|
static int prkey_fixup(struct sc_pkcs15_card *, struct sc_pkcs15_prkey *);
|
|
|
|
static int prkey_bits(struct sc_pkcs15_card *, struct sc_pkcs15_prkey *);
|
|
|
|
static int prkey_pkcs15_algo(struct sc_pkcs15_card *, struct sc_pkcs15_prkey *);
|
|
|
|
static int select_intrinsic_id(struct sc_pkcs15_card *, struct sc_profile *,
|
|
|
|
int, struct sc_pkcs15_id *, void *);
|
2010-01-10 20:33:32 +00:00
|
|
|
static int select_id(struct sc_pkcs15_card *, int, struct sc_pkcs15_id *);
|
2010-03-04 16:14:30 +00:00
|
|
|
static int select_object_path(struct sc_pkcs15_card *, struct sc_profile *,
|
2010-03-05 10:37:11 +00:00
|
|
|
struct sc_pkcs15_object *, struct sc_path *);
|
2010-03-04 16:14:30 +00:00
|
|
|
static int sc_pkcs15init_get_pin_path(struct sc_pkcs15_card *,
|
|
|
|
struct sc_pkcs15_id *, struct sc_path *);
|
|
|
|
static int sc_pkcs15init_qualify_pin(struct sc_card *, const char *,
|
|
|
|
unsigned int, struct sc_pkcs15_pin_info *);
|
2005-08-05 19:07:24 +00:00
|
|
|
static struct sc_pkcs15_df * find_df_by_type(struct sc_pkcs15_card *,
|
|
|
|
unsigned int);
|
2010-03-04 13:05:03 +00:00
|
|
|
static int sc_pkcs15init_read_info(struct sc_card *card, struct sc_profile *);
|
|
|
|
static int sc_pkcs15init_parse_info(struct sc_card *, const unsigned char *, size_t,
|
|
|
|
struct sc_profile *);
|
2010-02-21 18:24:41 +00:00
|
|
|
static int sc_pkcs15init_write_info(struct sc_pkcs15_card *, struct sc_profile *,
|
|
|
|
struct sc_pkcs15_object *);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2003-10-13 20:41:00 +00:00
|
|
|
static struct profile_operations {
|
2004-12-22 09:48:27 +00:00
|
|
|
const char *name;
|
2003-10-13 20:41:00 +00:00
|
|
|
void *func;
|
|
|
|
} profile_operations[] = {
|
2007-12-17 13:39:20 +00:00
|
|
|
{ "rutoken", (void *) sc_pkcs15init_get_rutoken_ops },
|
2003-10-13 20:41:00 +00:00
|
|
|
{ "gpk", (void *) sc_pkcs15init_get_gpk_ops },
|
|
|
|
{ "miocos", (void *) sc_pkcs15init_get_miocos_ops },
|
2003-12-08 11:43:21 +00:00
|
|
|
{ "flex", (void *) sc_pkcs15init_get_cryptoflex_ops },
|
|
|
|
{ "cyberflex", (void *) sc_pkcs15init_get_cyberflex_ops },
|
2006-01-23 21:48:08 +00:00
|
|
|
{ "cardos", (void *) sc_pkcs15init_get_cardos_ops },
|
|
|
|
{ "etoken", (void *) sc_pkcs15init_get_cardos_ops }, /* legacy */
|
2003-12-29 12:28:37 +00:00
|
|
|
{ "jcop", (void *) sc_pkcs15init_get_jcop_ops },
|
2004-04-17 09:23:26 +00:00
|
|
|
{ "starcos", (void *) sc_pkcs15init_get_starcos_ops },
|
2004-06-16 20:59:59 +00:00
|
|
|
{ "oberthur", (void *) sc_pkcs15init_get_oberthur_ops },
|
2005-04-04 09:30:54 +00:00
|
|
|
{ "setcos", (void *) sc_pkcs15init_get_setcos_ops },
|
2005-10-24 21:58:35 +00:00
|
|
|
{ "incrypto34", (void *) sc_pkcs15init_get_incrypto34_ops },
|
2006-06-07 08:33:37 +00:00
|
|
|
{ "muscle", (void*) sc_pkcs15init_get_muscle_ops },
|
2007-07-03 20:44:34 +00:00
|
|
|
{ "asepcos", (void*) sc_pkcs15init_get_asepcos_ops },
|
2008-08-20 05:41:20 +00:00
|
|
|
{ "entersafe",(void*) sc_pkcs15init_get_entersafe_ops },
|
2009-06-24 15:26:37 +00:00
|
|
|
{ "rutoken_ecp", (void *) sc_pkcs15init_get_rtecp_ops },
|
2009-09-12 11:46:00 +00:00
|
|
|
{ "westcos", (void *) sc_pkcs15init_get_westcos_ops },
|
2009-10-03 07:48:28 +00:00
|
|
|
{ "myeid", (void *) sc_pkcs15init_get_myeid_ops },
|
2010-12-31 08:54:07 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2010-12-30 14:40:28 +00:00
|
|
|
{ "authentic", (void *) sc_pkcs15init_get_authentic_ops },
|
2011-02-16 10:59:10 +00:00
|
|
|
{ "iasecc", (void *) sc_pkcs15init_get_iasecc_ops },
|
2010-12-31 08:54:07 +00:00
|
|
|
#endif
|
2003-10-13 20:41:00 +00:00
|
|
|
{ NULL, NULL },
|
|
|
|
};
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-04-12 18:08:18 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
static struct sc_pkcs15init_callbacks callbacks = {
|
2003-10-13 20:16:40 +00:00
|
|
|
NULL,
|
2003-10-13 20:41:00 +00:00
|
|
|
NULL,
|
2002-04-05 10:05:50 +00:00
|
|
|
};
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-05-22 10:00:12 +00:00
|
|
|
static void sc_pkcs15init_empty_callback(void *ptr)
|
2011-05-01 20:14:06 +00:00
|
|
|
{
|
|
|
|
}
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Set the application callbacks
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sc_pkcs15init_set_callbacks(struct sc_pkcs15init_callbacks *cb)
|
|
|
|
{
|
2003-10-13 16:13:12 +00:00
|
|
|
callbacks.get_pin = cb? cb->get_pin : NULL;
|
|
|
|
callbacks.get_key = cb? cb->get_key : NULL;
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2003-11-19 20:37:02 +00:00
|
|
|
/*
|
|
|
|
* Returns 1 if the a profile was found in the card's card_driver block
|
2003-10-13 16:13:12 +00:00
|
|
|
* in the config file, or 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int
|
2010-03-04 16:14:30 +00:00
|
|
|
get_profile_from_config(struct sc_card *card, char *buffer, size_t size)
|
2003-06-18 08:07:12 +00:00
|
|
|
{
|
2010-03-04 16:14:30 +00:00
|
|
|
struct sc_context *ctx = card->ctx;
|
2003-06-18 08:07:12 +00:00
|
|
|
const char *tmp;
|
|
|
|
scconf_block **blocks, *blk;
|
2003-06-25 10:19:08 +00:00
|
|
|
int i;
|
2003-06-18 08:07:12 +00:00
|
|
|
|
|
|
|
for (i = 0; ctx->conf_blocks[i]; i++) {
|
|
|
|
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i],
|
2003-10-13 16:13:12 +00:00
|
|
|
"card_driver",
|
|
|
|
card->driver->short_name);
|
2003-06-18 08:07:12 +00:00
|
|
|
blk = blocks[0];
|
|
|
|
free(blocks);
|
|
|
|
if (blk == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
tmp = scconf_get_str(blk, "profile", NULL);
|
|
|
|
if (tmp != NULL) {
|
2006-07-12 08:12:38 +00:00
|
|
|
strlcpy(buffer, tmp, size);
|
2003-06-18 08:07:12 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-10-25 10:43:50 +00:00
|
|
|
|
2010-02-02 17:18:06 +00:00
|
|
|
static const char *
|
2010-03-04 16:14:30 +00:00
|
|
|
find_library(struct sc_context *ctx, const char *name)
|
2004-10-25 10:43:50 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
const char *libname = NULL;
|
|
|
|
scconf_block *blk, **blocks;
|
|
|
|
|
|
|
|
for (i = 0; ctx->conf_blocks[i]; i++) {
|
2011-01-05 16:04:15 +00:00
|
|
|
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], "framework", "pkcs15");
|
2004-10-25 10:43:50 +00:00
|
|
|
blk = blocks[0];
|
|
|
|
free(blocks);
|
|
|
|
if (blk == NULL)
|
|
|
|
continue;
|
|
|
|
blocks = scconf_find_blocks(ctx->conf, blk, "pkcs15init", name);
|
|
|
|
blk = blocks[0];
|
|
|
|
free(blocks);
|
|
|
|
if (blk == NULL)
|
|
|
|
continue;
|
|
|
|
libname = scconf_get_str(blk, "module", NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!libname) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "unable to locate pkcs15init driver for '%s'", name);
|
2004-10-25 10:43:50 +00:00
|
|
|
}
|
|
|
|
return libname;
|
|
|
|
}
|
|
|
|
|
2010-02-02 17:18:06 +00:00
|
|
|
|
|
|
|
static void *
|
2010-03-04 16:14:30 +00:00
|
|
|
load_dynamic_driver(struct sc_context *ctx, void **dll,
|
2004-10-25 10:43:50 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
const char *version, *libname;
|
2011-02-16 19:02:11 +00:00
|
|
|
void *handle;
|
2004-10-25 10:43:50 +00:00
|
|
|
void *(*modinit)(const char *) = NULL;
|
|
|
|
const char *(*modversion)(void) = NULL;
|
|
|
|
|
|
|
|
libname = find_library(ctx, name);
|
|
|
|
if (!libname)
|
|
|
|
return NULL;
|
2011-02-16 19:02:11 +00:00
|
|
|
handle = sc_dlopen(libname);
|
2005-09-01 14:01:58 +00:00
|
|
|
if (handle == NULL) {
|
2011-02-16 19:02:11 +00:00
|
|
|
sc_log(ctx, "Module %s: cannot load '%s' library: %s", name, libname, sc_dlerror());
|
2004-10-25 10:43:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2004-12-15 13:53:36 +00:00
|
|
|
|
2004-10-25 10:43:50 +00:00
|
|
|
/* verify correctness of module */
|
2011-02-16 19:02:11 +00:00
|
|
|
modinit = (void *(*)(const char *)) sc_dlsym(handle, "sc_module_init");
|
|
|
|
modversion = (const char *(*)(void)) sc_dlsym(handle, "sc_driver_version");
|
2004-10-25 10:43:50 +00:00
|
|
|
if (modinit == NULL || modversion == NULL) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "dynamic library '%s' is not a OpenSC module",libname);
|
2011-02-16 19:02:11 +00:00
|
|
|
sc_dlclose(handle);
|
2004-10-25 10:43:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* verify module version */
|
|
|
|
version = modversion();
|
|
|
|
if (version == NULL || strncmp(version, "0.9.", strlen("0.9.")) > 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx,"dynamic library '%s': invalid module version",libname);
|
2011-02-16 19:02:11 +00:00
|
|
|
sc_dlclose(handle);
|
2004-10-25 10:43:50 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2005-09-01 14:01:58 +00:00
|
|
|
*dll = handle;
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "successfully loaded pkcs15init driver '%s'", name);
|
2004-10-25 10:43:50 +00:00
|
|
|
|
|
|
|
return modinit(name);
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Set up profile
|
|
|
|
*/
|
|
|
|
int
|
2010-03-04 16:14:30 +00:00
|
|
|
sc_pkcs15init_bind(struct sc_card *card, const char *name,
|
2003-10-13 16:13:12 +00:00
|
|
|
const char *profile_option,
|
|
|
|
struct sc_profile **result)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_context *ctx = card->ctx;
|
2002-04-05 10:05:50 +00:00
|
|
|
struct sc_profile *profile;
|
2003-10-13 20:41:00 +00:00
|
|
|
struct sc_pkcs15init_operations * (* func)(void) = NULL;
|
2002-04-02 13:26:42 +00:00
|
|
|
const char *driver = card->driver->short_name;
|
2003-11-19 20:37:02 +00:00
|
|
|
char card_profile[PATH_MAX];
|
2003-10-13 20:41:00 +00:00
|
|
|
int r, i;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2003-04-16 14:38:35 +00:00
|
|
|
/* Put the card into administrative mode */
|
|
|
|
r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
|
|
|
|
if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Set lifecycle error");
|
2003-04-16 14:38:35 +00:00
|
|
|
|
2002-04-05 10:05:50 +00:00
|
|
|
profile = sc_profile_new();
|
2003-10-14 09:57:29 +00:00
|
|
|
profile->card = card;
|
|
|
|
|
2003-10-13 20:41:00 +00:00
|
|
|
for (i = 0; profile_operations[i].name; i++) {
|
|
|
|
if (!strcasecmp(driver, profile_operations[i].name)) {
|
2004-12-15 13:53:36 +00:00
|
|
|
func = (struct sc_pkcs15init_operations *(*)(void)) profile_operations[i].func;
|
2003-10-13 20:41:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-10-25 10:43:50 +00:00
|
|
|
if (!func) {
|
|
|
|
/* no builtin support for this driver => look if there's a
|
|
|
|
* dynamic module for this card */
|
2004-12-15 13:53:36 +00:00
|
|
|
func = (struct sc_pkcs15init_operations *(*)(void)) load_dynamic_driver(card->ctx, &profile->dll, driver);
|
2004-10-25 10:43:50 +00:00
|
|
|
}
|
2003-10-13 20:41:00 +00:00
|
|
|
if (func) {
|
|
|
|
profile->ops = func();
|
|
|
|
} else {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Unsupported card driver %s", driver);
|
2002-04-05 10:05:50 +00:00
|
|
|
sc_profile_free(profile);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported card driver");
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2003-11-19 20:37:02 +00:00
|
|
|
/* Massage the main profile name to see if there are
|
|
|
|
* any options in there
|
2003-10-13 16:13:12 +00:00
|
|
|
*/
|
2003-11-19 20:37:02 +00:00
|
|
|
profile->name = strdup(name);
|
|
|
|
if (strchr(profile->name, '+') != NULL) {
|
|
|
|
char *s;
|
|
|
|
|
2004-12-22 09:48:27 +00:00
|
|
|
i = 0;
|
2003-11-19 20:37:02 +00:00
|
|
|
(void) strtok(profile->name, "+");
|
|
|
|
while ((s = strtok(NULL, "+")) != NULL) {
|
|
|
|
if (i < SC_PKCS15INIT_MAX_OPTIONS-1)
|
|
|
|
profile->options[i++] = strdup(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-18 10:15:51 +00:00
|
|
|
r = sc_pkcs15init_read_info(card, profile);
|
|
|
|
if (r < 0) {
|
2003-11-19 20:37:02 +00:00
|
|
|
sc_profile_free(profile);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Read info error");
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the config file for a profile name.
|
|
|
|
* If none is defined, use the default profile name.
|
2003-06-18 08:07:12 +00:00
|
|
|
*/
|
2003-10-13 16:13:12 +00:00
|
|
|
if (!get_profile_from_config(card, card_profile, sizeof(card_profile)))
|
|
|
|
strcpy(card_profile, driver);
|
2005-07-05 17:45:10 +00:00
|
|
|
if (profile_option != NULL) {
|
2006-07-12 08:12:38 +00:00
|
|
|
strlcpy(card_profile, profile_option, sizeof(card_profile));
|
2005-07-05 17:45:10 +00:00
|
|
|
}
|
2003-06-18 08:07:12 +00:00
|
|
|
|
2010-04-20 17:09:26 +00:00
|
|
|
do {
|
|
|
|
r = sc_profile_load(profile, profile->name);
|
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Failed to load profile '%s': %s", profile->name, sc_strerror(r));
|
2010-04-20 17:09:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_profile_load(profile, card_profile);
|
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Failed to load profile '%s': %s", card_profile, sc_strerror(r));
|
2010-04-20 17:09:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-01-17 14:51:10 +00:00
|
|
|
r = sc_profile_finish(profile, NULL);
|
2010-04-20 17:09:26 +00:00
|
|
|
if (r < 0)
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Failed to finalize profile: %s", sc_strerror(r));
|
2010-04-20 17:09:26 +00:00
|
|
|
} while (0);
|
|
|
|
|
|
|
|
if (r < 0) {
|
2002-04-05 10:05:50 +00:00
|
|
|
sc_profile_free(profile);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Load profile error");
|
2002-06-04 08:51:03 +00:00
|
|
|
}
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2003-12-19 09:29:56 +00:00
|
|
|
*result = profile;
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-05 10:05:50 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 17:18:06 +00:00
|
|
|
|
2002-04-08 15:49:39 +00:00
|
|
|
void
|
|
|
|
sc_pkcs15init_unbind(struct sc_profile *profile)
|
|
|
|
{
|
2005-08-05 19:07:24 +00:00
|
|
|
int r;
|
|
|
|
struct sc_context *ctx = profile->card->ctx;
|
|
|
|
|
2005-08-29 20:48:00 +00:00
|
|
|
if (profile->dirty != 0 && profile->p15_data != NULL && profile->pkcs15.do_last_update) {
|
2005-08-05 19:07:24 +00:00
|
|
|
r = sc_pkcs15init_update_tokeninfo(profile->p15_data, profile);
|
|
|
|
if (r < 0)
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Failed to update TokenInfo: %s", sc_strerror(r));
|
2005-08-05 19:07:24 +00:00
|
|
|
}
|
2004-10-25 10:43:50 +00:00
|
|
|
if (profile->dll)
|
2011-02-16 19:02:11 +00:00
|
|
|
sc_dlclose(profile->dll);
|
2002-04-08 15:49:39 +00:00
|
|
|
sc_profile_free(profile);
|
|
|
|
}
|
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2003-10-21 11:05:35 +00:00
|
|
|
void
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_pkcs15init_set_p15card(struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_card *p15card)
|
2003-10-21 11:05:35 +00:00
|
|
|
{
|
2010-03-04 13:05:03 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_pkcs15_object *p15objects[10];
|
|
|
|
int i, r, nn_objs;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-03-04 13:05:03 +00:00
|
|
|
|
|
|
|
/* Prepare pin-domain instantiation:
|
|
|
|
* for every present local User PIN, add to the profile EF list the named PIN path. */
|
|
|
|
nn_objs = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, p15objects, 10);
|
|
|
|
for (i = 0; i < nn_objs; i++) {
|
|
|
|
struct sc_pkcs15_pin_info *pininfo = (struct sc_pkcs15_pin_info *) p15objects[i]->data;
|
|
|
|
struct sc_file *file = NULL;
|
|
|
|
|
|
|
|
if (pininfo->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
|
|
|
|
continue;
|
|
|
|
if (pininfo->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)
|
|
|
|
continue;
|
|
|
|
if (!pininfo->path.len)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = sc_profile_get_file_by_path(profile, &pininfo->path, &file);
|
|
|
|
if (r == SC_ERROR_FILE_NOT_FOUND) {
|
|
|
|
if (!sc_select_file(p15card->card, &pininfo->path, &file)) {
|
|
|
|
char pin_name[16];
|
|
|
|
|
|
|
|
sprintf(pin_name, "pin-dir-%02X%02X",
|
|
|
|
file->path.value[file->path.len - 2],
|
|
|
|
file->path.value[file->path.len - 1]);
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "add '%s' to profile file list", pin_name);
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_profile_add_file(profile, pin_name, file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file)
|
|
|
|
sc_file_free(file);
|
|
|
|
}
|
|
|
|
|
2003-10-21 11:05:35 +00:00
|
|
|
profile->p15_data = p15card;
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "sc_pkcs15init_set_p15card() returns");
|
2003-10-21 11:05:35 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2003-04-16 14:38:35 +00:00
|
|
|
/*
|
|
|
|
* Set the card's lifecycle
|
|
|
|
*/
|
|
|
|
int
|
2010-03-04 16:14:30 +00:00
|
|
|
sc_pkcs15init_set_lifecycle(struct sc_card *card, int lcycle)
|
2003-04-16 14:38:35 +00:00
|
|
|
{
|
|
|
|
return sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &lcycle);
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-08 15:49:39 +00:00
|
|
|
/*
|
|
|
|
* Erase the card
|
|
|
|
*/
|
2002-04-05 10:05:50 +00:00
|
|
|
int
|
2011-01-11 16:50:30 +00:00
|
|
|
sc_pkcs15init_erase_card(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_aid *aid)
|
2002-04-05 10:05:50 +00:00
|
|
|
{
|
2011-01-11 16:50:30 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-02-21 18:24:41 +00:00
|
|
|
/* Needs the 'SOPIN' AUTH pkcs15 object.
|
|
|
|
* So that, SOPIN can be found by it's reference. */
|
2011-01-11 16:50:30 +00:00
|
|
|
if (sc_pkcs15_bind(p15card->card, aid, &p15card) >= 0)
|
2010-02-21 18:24:41 +00:00
|
|
|
profile->p15_data = p15card;
|
|
|
|
|
2002-04-08 15:49:39 +00:00
|
|
|
if (profile->ops->erase_card == NULL)
|
2011-01-11 16:50:30 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
|
|
|
|
|
|
|
|
rv = profile->ops->erase_card(profile, p15card);
|
|
|
|
|
|
|
|
LOG_FUNC_RETURN(ctx, rv);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2002-06-18 18:18:21 +00:00
|
|
|
int
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15init_erase_card_recursively(struct sc_pkcs15_card *p15card,
|
2010-03-05 10:37:11 +00:00
|
|
|
struct sc_profile *profile)
|
2002-06-18 18:18:21 +00:00
|
|
|
{
|
|
|
|
struct sc_file *df = profile->df_info->file, *dir;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Delete EF(DIR). This may not be very nice
|
|
|
|
* against other applications that use this file, but
|
|
|
|
* extremely useful for testing :)
|
2003-10-21 11:05:35 +00:00
|
|
|
* Note we need to delete it before the DF because we create
|
2002-06-18 18:18:21 +00:00
|
|
|
* it *after* the DF. Some cards (e.g. the cryptoflex) want
|
2003-10-21 11:05:35 +00:00
|
|
|
* us to delete files in reverse order of creation.
|
2002-06-18 18:18:21 +00:00
|
|
|
* */
|
|
|
|
if (sc_profile_get_file(profile, "DIR", &dir) >= 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_rmdir(p15card, profile, dir);
|
2002-06-18 18:18:21 +00:00
|
|
|
sc_file_free(dir);
|
2010-02-21 18:24:41 +00:00
|
|
|
if (r < 0 && r != SC_ERROR_FILE_NOT_FOUND) {
|
|
|
|
sc_free_apps(p15card->card);
|
|
|
|
return r;
|
|
|
|
}
|
2002-06-18 18:18:21 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_select_file(p15card->card, &df->path, &df);
|
2002-06-18 18:18:21 +00:00
|
|
|
if (r >= 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_rmdir(p15card, profile, df);
|
2002-06-18 18:18:21 +00:00
|
|
|
sc_file_free(df);
|
|
|
|
}
|
|
|
|
if (r == SC_ERROR_FILE_NOT_FOUND)
|
|
|
|
r = 0;
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_free_apps(p15card->card);
|
2002-06-18 18:18:21 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2010-02-02 17:18:06 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_delete_by_path(struct sc_profile *profile,
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_pkcs15_card *p15card, const struct sc_path *file_path)
|
2005-08-22 09:20:13 +00:00
|
|
|
{
|
2011-01-03 09:45:51 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_file *parent = NULL, *file = NULL;
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_path path;
|
2011-01-03 09:45:51 +00:00
|
|
|
int rv;
|
2005-08-22 09:20:13 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
sc_log(ctx, "trying to delete '%s'", sc_print_path(file_path));
|
2011-01-03 09:45:51 +00:00
|
|
|
|
|
|
|
/* For some cards, to delete file should be satisfied the 'DELETE' ACL of the file itself,
|
|
|
|
* for the others the 'DELETE' ACL of parent.
|
|
|
|
* Let's start from the file's 'DELETE' ACL.
|
|
|
|
*
|
|
|
|
* FIXME: will it be better to introduce the ACLs 'DELETE-CHILD' and 'DELETE-ITSELF',
|
|
|
|
* or dedicated card flag ?
|
|
|
|
*/
|
2005-08-22 09:20:13 +00:00
|
|
|
|
|
|
|
/* Select the file itself */
|
2011-01-03 09:45:51 +00:00
|
|
|
path = *file_path;
|
|
|
|
rv = sc_select_file(p15card->card, &path, &file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, rv, "cannot select file to delete");
|
2011-01-03 09:45:51 +00:00
|
|
|
|
|
|
|
rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_DELETE);
|
|
|
|
sc_file_free(file);
|
|
|
|
|
|
|
|
if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
|
|
|
|
if (file_path->len >= 2) {
|
|
|
|
/* Select the parent DF */
|
|
|
|
path.len -= 2;
|
|
|
|
rv = sc_select_file(p15card->card, &path, &parent);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, rv, "Cannot select parent");
|
2011-01-03 09:45:51 +00:00
|
|
|
|
|
|
|
rv = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_DELETE);
|
|
|
|
sc_file_free(parent);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, rv, "parent 'DELETE' authentication failed");
|
2011-01-03 09:45:51 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, rv, "'DELETE' authentication failed");
|
2005-08-22 09:20:13 +00:00
|
|
|
|
|
|
|
memset(&path, 0, sizeof(path));
|
|
|
|
path.type = SC_PATH_TYPE_FILE_ID;
|
|
|
|
path.value[0] = file_path->value[file_path->len - 2];
|
|
|
|
path.value[1] = file_path->value[file_path->len - 1];
|
|
|
|
path.len = 2;
|
|
|
|
|
2011-01-03 09:45:51 +00:00
|
|
|
rv = sc_delete_file(p15card->card, &path);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, rv);
|
2005-08-22 09:20:13 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2002-06-18 18:18:21 +00:00
|
|
|
/*
|
|
|
|
* Try to delete a file (and, in the DF case, its contents).
|
|
|
|
* Note that this will not work if a pkcs#15 file's ERASE AC
|
|
|
|
* references a pin other than the SO pin.
|
|
|
|
*/
|
|
|
|
int
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15init_rmdir(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_file *df)
|
2002-06-18 18:18:21 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
unsigned char buffer[1024];
|
2002-06-18 18:18:21 +00:00
|
|
|
struct sc_path path;
|
|
|
|
struct sc_file *file, *parent;
|
|
|
|
int r = 0, nfids;
|
|
|
|
|
2006-05-01 10:21:16 +00:00
|
|
|
if (df == NULL)
|
|
|
|
return SC_ERROR_INTERNAL;
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "sc_pkcs15init_rmdir(%s)", sc_print_path(&df->path));
|
2003-10-14 08:17:59 +00:00
|
|
|
|
2002-06-18 18:18:21 +00:00
|
|
|
if (df->type == SC_FILE_TYPE_DF) {
|
2010-02-21 18:24:41 +00:00
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, df, SC_AC_OP_LIST_FILES);
|
2002-06-18 18:18:21 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_list_files(p15card->card, buffer, sizeof(buffer));
|
2002-06-18 18:18:21 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
path = df->path;
|
|
|
|
path.len += 2;
|
|
|
|
|
|
|
|
nfids = r / 2;
|
|
|
|
while (r >= 0 && nfids--) {
|
|
|
|
path.value[path.len-2] = buffer[2*nfids];
|
|
|
|
path.value[path.len-1] = buffer[2*nfids+1];
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_select_file(p15card->card, &path, &file);
|
2002-06-18 18:18:21 +00:00
|
|
|
if (r < 0) {
|
|
|
|
if (r == SC_ERROR_FILE_NOT_FOUND)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
}
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_rmdir(p15card, profile, file);
|
2002-06-18 18:18:21 +00:00
|
|
|
sc_file_free(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Select the parent DF */
|
|
|
|
path = df->path;
|
|
|
|
path.len -= 2;
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_select_file(p15card->card, &path, &parent);
|
2002-06-18 18:18:21 +00:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, df, SC_AC_OP_DELETE);
|
2005-08-22 09:20:13 +00:00
|
|
|
if (r < 0) {
|
|
|
|
sc_file_free(parent);
|
|
|
|
return r;
|
|
|
|
}
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_DELETE);
|
2002-06-18 18:18:21 +00:00
|
|
|
sc_file_free(parent);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
memset(&path, 0, sizeof(path));
|
|
|
|
path.type = SC_PATH_TYPE_FILE_ID;
|
|
|
|
path.value[0] = df->id >> 8;
|
|
|
|
path.value[1] = df->id & 0xFF;
|
|
|
|
path.len = 2;
|
|
|
|
|
2005-12-17 20:54:29 +00:00
|
|
|
/* ensure that the card is in the correct lifecycle */
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_set_lifecycle(p15card->card, SC_CARDCTRL_LIFECYCLE_ADMIN);
|
2005-12-17 20:54:29 +00:00
|
|
|
if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
|
|
|
|
return r;
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_delete_file(p15card->card, &path);
|
2002-06-18 18:18:21 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2004-04-17 09:23:26 +00:00
|
|
|
int
|
2010-03-04 16:14:30 +00:00
|
|
|
sc_pkcs15init_finalize_card(struct sc_card *card, struct sc_profile *profile)
|
2004-04-17 09:23:26 +00:00
|
|
|
{
|
|
|
|
if (profile->ops->finalize_card == NULL)
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
return profile->ops->finalize_card(card);
|
|
|
|
}
|
2002-06-18 18:18:21 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2011-01-17 16:28:44 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_finalize_profile(struct sc_card *card, struct sc_profile *profile,
|
|
|
|
struct sc_aid *aid)
|
|
|
|
{
|
|
|
|
struct sc_context *ctx = card->ctx;
|
|
|
|
const struct sc_app_info *app = NULL;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
if (!aid || !aid->len)
|
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
|
|
|
|
|
|
|
if (card->app_count < 0)
|
|
|
|
sc_enum_apps(card);
|
|
|
|
|
|
|
|
sc_log(ctx, "finalize profile for AID %s", sc_dump_hex(aid->value, aid->len));
|
|
|
|
app = sc_find_app(card, aid);
|
|
|
|
if (!app) {
|
|
|
|
sc_log(ctx, "Cannot find oncard application");
|
|
|
|
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
|
|
|
}
|
|
|
|
|
|
|
|
sc_log(ctx, "Finalize profile with application '%s'", app->label);
|
|
|
|
rv = sc_profile_finish(profile, app);
|
|
|
|
|
|
|
|
sc_log(ctx, "sc_pkcs15init_finalize_profile() returns %i", rv);
|
|
|
|
LOG_FUNC_RETURN(ctx, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Initialize the PKCS#15 application
|
|
|
|
*/
|
|
|
|
int
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15init_add_app(struct sc_card *card, struct sc_profile *profile,
|
2002-04-02 14:45:55 +00:00
|
|
|
struct sc_pkcs15init_initargs *args)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = card->ctx;
|
|
|
|
struct sc_pkcs15_card *p15card = profile->p15_spec;
|
|
|
|
struct sc_pkcs15_pin_info pin_info, puk_info;
|
|
|
|
struct sc_pkcs15_object *pin_obj = NULL;
|
|
|
|
struct sc_app_info *app;
|
|
|
|
struct sc_file *df = profile->df_info->file;
|
2011-02-05 20:38:49 +00:00
|
|
|
int r;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-02-21 16:21:57 +00:00
|
|
|
p15card->card = card;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
/* FIXME:
|
|
|
|
* Some cards need pincache
|
|
|
|
* for ex. to create temporary CHV key with the value of default AUTH key.
|
|
|
|
*/
|
|
|
|
p15card->opts.use_pin_cache = 1;
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2010-01-16 21:52:47 +00:00
|
|
|
if (card->app_count >= SC_MAX_CARD_APPS)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_TOO_MANY_OBJECTS, "Too many applications on this card.");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2002-04-08 15:49:39 +00:00
|
|
|
/* If the profile requires an SO PIN, check min/max length */
|
2003-10-13 16:13:12 +00:00
|
|
|
if (args->so_pin_len) {
|
2003-10-16 14:32:42 +00:00
|
|
|
const char *pin_label;
|
|
|
|
|
|
|
|
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info);
|
|
|
|
r = sc_pkcs15init_qualify_pin(card, "SO PIN", args->so_pin_len, &pin_info);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to qualify SO PIN");
|
2003-10-16 14:32:42 +00:00
|
|
|
|
2010-01-27 17:03:04 +00:00
|
|
|
/* Path encoded only for local SO PIN */
|
|
|
|
if (pin_info.flags & SC_PKCS15_PIN_FLAG_LOCAL)
|
|
|
|
pin_info.path = df->path;
|
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
/* Select the PIN reference */
|
|
|
|
if (profile->ops->select_pin_reference) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->select_pin_reference(profile, p15card, &pin_info);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select card specific PIN reference");
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
2003-10-16 14:32:42 +00:00
|
|
|
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PUK, &puk_info);
|
|
|
|
r = sc_pkcs15init_qualify_pin(card, "SO PUK", args->so_puk_len, &puk_info);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to qulify SO PUK");
|
2003-10-16 14:32:42 +00:00
|
|
|
|
|
|
|
if (!(pin_label = args->so_pin_label)) {
|
|
|
|
if (pin_info.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
|
|
|
|
pin_label = "Security Officer PIN";
|
|
|
|
else
|
|
|
|
pin_label = "User PIN";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args->so_puk_len == 0)
|
|
|
|
pin_info.flags |= SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED;
|
|
|
|
|
|
|
|
pin_obj = sc_pkcs15init_new_object(SC_PKCS15_TYPE_AUTH_PIN,
|
2010-01-27 17:53:51 +00:00
|
|
|
pin_label, NULL, &pin_info);
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
if (pin_obj) {
|
|
|
|
/* When composing ACLs to create 'DIR' DF,
|
|
|
|
* the references of the not-yet-existing PINs can be requested.
|
|
|
|
* For this, create a 'virtual' AUTH object 'SO PIN', accessible by the card specific part,
|
|
|
|
* but not yet written into the on-card PKCS#15.
|
|
|
|
*/
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Add virtual SO_PIN('%s',flags:%X,reference:%i,path:'%s')",
|
2010-02-21 18:24:41 +00:00
|
|
|
pin_obj->label, pin_info.flags, pin_info.reference,
|
|
|
|
sc_print_path(&pin_info.path));
|
|
|
|
r = sc_pkcs15_add_object(p15card, pin_obj);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to add 'SOPIN' AUTH object");
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
2002-04-08 15:49:39 +00:00
|
|
|
}
|
|
|
|
|
2005-03-26 20:10:13 +00:00
|
|
|
/* Perform card-specific initialization */
|
2010-01-27 17:53:51 +00:00
|
|
|
if (profile->ops->init_card) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->init_card(profile, p15card);
|
2010-03-15 08:36:36 +00:00
|
|
|
if (r < 0 && pin_obj) {
|
|
|
|
sc_pkcs15_remove_object(p15card, pin_obj);
|
2005-12-05 21:57:07 +00:00
|
|
|
sc_pkcs15_free_object(pin_obj);
|
2010-03-15 08:36:36 +00:00
|
|
|
}
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific init failed");
|
2005-03-26 20:10:13 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 14:50:56 +00:00
|
|
|
/* Create the application directory */
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->create_dir(profile, p15card, df);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Create 'DIR' error");
|
2010-02-02 14:50:56 +00:00
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
/* Store SO PIN */
|
|
|
|
if (pin_obj)
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->create_pin(profile, p15card, df, pin_obj,
|
2003-10-13 16:13:12 +00:00
|
|
|
args->so_pin, args->so_pin_len,
|
|
|
|
args->so_puk, args->so_puk_len);
|
2010-02-21 18:24:41 +00:00
|
|
|
#if 0
|
|
|
|
if (r > 0 && profile->ops->finalize_dir)
|
|
|
|
r = profile->ops->finalize_dir(profile, p15card);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (pin_obj)
|
|
|
|
/* Remove 'virtual' AUTH object . */
|
|
|
|
sc_pkcs15_remove_object(p15card, pin_obj);
|
|
|
|
|
|
|
|
if (r < 0)
|
2010-01-27 17:53:51 +00:00
|
|
|
sc_pkcs15_free_object(pin_obj);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific create application DF failed");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
/* Store the PKCS15 information on the card
|
|
|
|
* We cannot use sc_pkcs15_create() because it makes
|
|
|
|
* all sorts of assumptions about DF and EF names, and
|
|
|
|
* doesn't work if secure messaging is required for the
|
|
|
|
* MF (which is the case with the GPK) */
|
2010-03-04 16:14:30 +00:00
|
|
|
app = (struct sc_app_info *)calloc(1, sizeof(*app));
|
2005-01-03 17:25:18 +00:00
|
|
|
if (app == NULL)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Failed to allocate application info");
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
app->path = p15card->file_app->path;
|
|
|
|
if (p15card->file_app->namelen <= SC_MAX_AID_SIZE) {
|
2011-01-05 15:42:36 +00:00
|
|
|
app->aid.len = p15card->file_app->namelen;
|
|
|
|
memcpy(app->aid.value, p15card->file_app->name, app->aid.len);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2004-07-19 16:58:27 +00:00
|
|
|
/* set serial number if explicitly specified */
|
2010-02-21 18:24:41 +00:00
|
|
|
if (args->serial) {
|
2002-04-07 13:15:31 +00:00
|
|
|
sc_pkcs15init_set_serial(profile, args->serial);
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
2004-07-19 16:58:27 +00:00
|
|
|
else {
|
|
|
|
/* otherwise try to get the serial number from the card */
|
2010-03-04 13:05:03 +00:00
|
|
|
struct sc_serial_number serialnr;
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2004-07-19 16:58:27 +00:00
|
|
|
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serialnr);
|
|
|
|
if (r == SC_SUCCESS) {
|
|
|
|
char hex_serial[SC_MAX_SERIALNR * 2 + 1];
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
sc_bin_to_hex(serialnr.value, serialnr.len, hex_serial, sizeof(hex_serial), 0);
|
2004-07-19 16:58:27 +00:00
|
|
|
sc_pkcs15init_set_serial(profile, hex_serial);
|
|
|
|
}
|
|
|
|
}
|
2002-12-04 14:56:17 +00:00
|
|
|
|
|
|
|
if (args->label) {
|
2010-10-05 15:44:58 +00:00
|
|
|
if (p15card->tokeninfo->label)
|
|
|
|
free(p15card->tokeninfo->label);
|
|
|
|
p15card->tokeninfo->label = strdup(args->label);
|
2002-12-04 14:56:17 +00:00
|
|
|
}
|
2010-10-05 15:44:58 +00:00
|
|
|
app->label = strdup(p15card->tokeninfo->label);
|
2002-12-04 14:56:17 +00:00
|
|
|
|
2002-04-08 09:29:37 +00:00
|
|
|
/* See if we've set an SO PIN */
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_AODF, pin_obj);
|
2006-05-01 10:22:25 +00:00
|
|
|
if (r >= 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_update_dir(p15card, profile, app);
|
2006-05-01 10:22:25 +00:00
|
|
|
if (r >= 0)
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_update_tokeninfo(p15card, profile);
|
2006-05-01 10:22:25 +00:00
|
|
|
/* FIXME: what to do if sc_pkcs15init_update_dir failed? */
|
|
|
|
} else {
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2006-05-01 10:22:25 +00:00
|
|
|
free(app); /* unused */
|
|
|
|
}
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15init_write_info(p15card, profile, pin_obj);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-01-27 17:53:51 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Store a PIN/PUK pair
|
|
|
|
*/
|
2010-03-28 09:45:54 +00:00
|
|
|
static int
|
2010-01-27 17:53:51 +00:00
|
|
|
sc_pkcs15init_store_puk(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15init_pinargs *args)
|
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_pkcs15_object *pin_obj;
|
|
|
|
struct sc_pkcs15_pin_info *pin_info;
|
2010-02-02 09:33:29 +00:00
|
|
|
int r;
|
2010-01-27 17:53:51 +00:00
|
|
|
char puk_label[0x30];
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-01-27 17:53:51 +00:00
|
|
|
if (!args->puk_id.len)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "PUK auth ID not supplied");
|
2010-01-27 17:53:51 +00:00
|
|
|
|
|
|
|
/* Make sure we don't get duplicate PIN IDs */
|
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &args->puk_id, NULL);
|
|
|
|
if (r != SC_ERROR_OBJECT_NOT_FOUND)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "There already is a PIN with this ID.");
|
2010-01-27 17:53:51 +00:00
|
|
|
|
|
|
|
if (!args->puk_label) {
|
|
|
|
if (args->label)
|
|
|
|
snprintf(puk_label, sizeof(puk_label), "%s (PUK)", args->label);
|
|
|
|
else
|
|
|
|
snprintf(puk_label, sizeof(puk_label), "User PUK");
|
|
|
|
|
|
|
|
args->puk_label = puk_label;
|
|
|
|
}
|
|
|
|
|
|
|
|
args->pin = args->puk;
|
|
|
|
args->pin_len = args->puk_len;
|
|
|
|
args->puk = NULL;
|
|
|
|
args->puk_len = 0;
|
|
|
|
|
|
|
|
pin_obj = sc_pkcs15init_new_object(SC_PKCS15_TYPE_AUTH_PIN, args->puk_label, NULL, NULL);
|
|
|
|
if (pin_obj == NULL)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate PIN object");
|
2010-01-27 17:53:51 +00:00
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
pin_info = (struct sc_pkcs15_pin_info *) pin_obj->data;
|
2010-01-27 17:53:51 +00:00
|
|
|
|
|
|
|
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, pin_info);
|
|
|
|
pin_info->auth_id = args->puk_id;
|
|
|
|
|
|
|
|
/* Now store the PINs */
|
|
|
|
if (profile->ops->create_pin)
|
|
|
|
r = sc_pkcs15init_create_pin(p15card, profile, pin_obj, args);
|
|
|
|
else
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "In Old API store PUK object is not supported");
|
2010-01-27 17:53:51 +00:00
|
|
|
|
|
|
|
if (r >= 0)
|
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_AODF, pin_obj);
|
|
|
|
else
|
|
|
|
sc_pkcs15_free_object(pin_obj);
|
|
|
|
|
|
|
|
profile->dirty = 1;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2010-01-27 17:53:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_store_pin(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15init_pinargs *args)
|
|
|
|
{
|
2010-01-27 17:53:51 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_pkcs15_object *pin_obj;
|
|
|
|
struct sc_pkcs15_pin_info *pin_info;
|
2010-02-21 16:21:57 +00:00
|
|
|
int r;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2002-04-08 15:49:39 +00:00
|
|
|
/* No auth_id given: select one */
|
|
|
|
if (args->auth_id.len == 0) {
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
args->auth_id.len = 1;
|
|
|
|
for (n = 1, r = 0; n < 256; n++) {
|
|
|
|
args->auth_id.value[0] = n;
|
2010-01-26 12:59:08 +00:00
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &args->auth_id, NULL);
|
2002-04-08 15:49:39 +00:00
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND)
|
|
|
|
break;
|
|
|
|
}
|
2010-01-27 17:53:51 +00:00
|
|
|
|
|
|
|
if (r != SC_ERROR_OBJECT_NOT_FOUND)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "No auth_id specified for new PIN");
|
2002-04-15 13:42:10 +00:00
|
|
|
} else {
|
|
|
|
/* Make sure we don't get duplicate PIN IDs */
|
2010-01-26 12:59:08 +00:00
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, &args->auth_id, NULL);
|
2010-01-27 17:53:51 +00:00
|
|
|
if (r != SC_ERROR_OBJECT_NOT_FOUND)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "There already is a PIN with this ID.");
|
2002-04-08 15:49:39 +00:00
|
|
|
}
|
|
|
|
|
2010-01-27 17:53:51 +00:00
|
|
|
pin_obj = sc_pkcs15init_new_object(SC_PKCS15_TYPE_AUTH_PIN, args->label, NULL, NULL);
|
2005-01-03 17:25:18 +00:00
|
|
|
if (pin_obj == NULL)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate PIN object");
|
2010-01-27 17:53:51 +00:00
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
pin_info = (struct sc_pkcs15_pin_info *) pin_obj->data;
|
2003-12-29 11:52:33 +00:00
|
|
|
|
|
|
|
sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, pin_info);
|
|
|
|
pin_info->auth_id = args->auth_id;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
/* Now store the PINs */
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Store PIN(%s,authID:%s)", pin_obj->label, sc_pkcs15_print_id(&pin_info->auth_id));
|
2010-02-02 14:50:56 +00:00
|
|
|
r = sc_pkcs15init_create_pin(p15card, profile, pin_obj, args);
|
2010-01-29 17:08:26 +00:00
|
|
|
if (r < 0)
|
2010-01-27 17:53:51 +00:00
|
|
|
sc_pkcs15_free_object(pin_obj);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific create PIN failed.");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-01-27 17:53:51 +00:00
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_AODF, pin_obj);
|
2010-01-29 17:12:53 +00:00
|
|
|
if (r < 0)
|
2005-12-05 21:57:07 +00:00
|
|
|
sc_pkcs15_free_object(pin_obj);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to add PIN object");
|
2010-01-27 17:53:51 +00:00
|
|
|
|
|
|
|
if (args->puk_id.len)
|
|
|
|
r = sc_pkcs15init_store_puk(p15card, profile, args);
|
2002-04-08 09:29:37 +00:00
|
|
|
|
2005-08-05 19:07:24 +00:00
|
|
|
profile->dirty = 1;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-08 09:29:37 +00:00
|
|
|
}
|
|
|
|
|
2010-01-27 17:53:51 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15init_create_pin(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_object *pin_obj,
|
2003-10-13 16:13:12 +00:00
|
|
|
struct sc_pkcs15init_pinargs *args)
|
|
|
|
{
|
2010-01-27 17:53:51 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2010-03-04 16:14:30 +00:00
|
|
|
struct sc_pkcs15_pin_info *pin_info = (struct sc_pkcs15_pin_info *) pin_obj->data;
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_file *df = profile->df_info->file;
|
2003-10-13 16:13:12 +00:00
|
|
|
int r, retry = 0;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2003-10-13 16:13:12 +00:00
|
|
|
/* Some cards need to keep all their PINs in separate directories.
|
|
|
|
* Create a subdirectory now, and put the pin into
|
|
|
|
* this subdirectory
|
|
|
|
*/
|
|
|
|
if (profile->pin_domains) {
|
2010-01-27 17:53:51 +00:00
|
|
|
if (!profile->ops->create_domain)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "PIN domains not supported.");
|
2010-01-27 17:53:51 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->create_domain(profile, p15card, &pin_info->auth_id, &df);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific create domain failed");
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
2010-01-27 17:03:04 +00:00
|
|
|
/* Path encoded only for local PINs */
|
2010-01-27 17:08:04 +00:00
|
|
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_LOCAL)
|
2010-01-27 17:03:04 +00:00
|
|
|
pin_info->path = df->path;
|
|
|
|
|
|
|
|
/* pin_info->reference = 0; */
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
/* Loop until we come up with an acceptable pin reference */
|
|
|
|
while (1) {
|
|
|
|
if (profile->ops->select_pin_reference) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->select_pin_reference(profile, p15card, pin_info);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific select PIN reference failed");
|
2010-01-27 17:53:51 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
retry = 1;
|
|
|
|
}
|
|
|
|
|
2010-01-27 17:53:51 +00:00
|
|
|
r = sc_pkcs15_find_pin_by_reference(p15card, &pin_info->path,
|
|
|
|
pin_info->reference, NULL);
|
2003-10-13 16:13:12 +00:00
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND)
|
|
|
|
break;
|
|
|
|
|
2010-01-27 17:53:51 +00:00
|
|
|
if (r != 0 || !retry)
|
2003-10-13 16:13:12 +00:00
|
|
|
/* Other error trying to retrieve pin obj */
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_TOO_MANY_OBJECTS, "Failed to allocate PIN reference.");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
pin_info->reference++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args->puk_len == 0)
|
|
|
|
pin_info->flags |= SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "create PIN with reference:%X, flags:%X, path:%s",
|
2010-01-27 17:53:51 +00:00
|
|
|
pin_info->reference, pin_info->flags, sc_print_path(&pin_info->path));
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->create_pin(profile, p15card,
|
2003-10-17 11:21:48 +00:00
|
|
|
df, pin_obj,
|
2003-10-13 16:13:12 +00:00
|
|
|
args->pin, args->pin_len,
|
|
|
|
args->puk, args->puk_len);
|
|
|
|
|
|
|
|
if (df != profile->df_info->file)
|
|
|
|
sc_file_free(df);
|
2010-01-27 17:53:51 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
/*
|
|
|
|
* Default function for creating a pin subdirectory
|
|
|
|
*/
|
|
|
|
int
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15_create_pin_domain(struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_card *p15card, const struct sc_pkcs15_id *id,
|
|
|
|
struct sc_file **ret)
|
2003-10-13 16:13:12 +00:00
|
|
|
{
|
2011-01-05 16:04:15 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_file *df = profile->df_info->file;
|
2003-10-13 16:13:12 +00:00
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "create PIN domain (path:%s,ID:%s)", sc_print_path(&df->path), sc_pkcs15_print_id(id));
|
2003-10-13 16:13:12 +00:00
|
|
|
/* Instantiate PIN directory just below the application DF */
|
2010-03-04 13:05:03 +00:00
|
|
|
r = sc_profile_instantiate_template(profile, "pin-domain", &df->path, "pin-dir", id, ret);
|
|
|
|
if (r >= 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "create PIN DF(path:%s)", sc_print_path(&(*ret)->path));
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->create_dir(profile, p15card, *ret);
|
2010-03-04 13:05:03 +00:00
|
|
|
}
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-05-22 11:42:53 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_encode_prvkey_content(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *prvkey,
|
|
|
|
struct sc_pkcs15_object *object)
|
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
|
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
if (prvkey->algorithm == SC_ALGORITHM_RSA) {
|
|
|
|
struct sc_pkcs15_pubkey pubkey;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
pubkey.algorithm = prvkey->algorithm;
|
|
|
|
pubkey.u.rsa.modulus = prvkey->u.rsa.modulus;
|
|
|
|
pubkey.u.rsa.exponent = prvkey->u.rsa.exponent;
|
|
|
|
|
|
|
|
rv = sc_pkcs15_encode_pubkey(ctx, &pubkey, &object->content.value, &object->content.len);
|
|
|
|
LOG_TEST_RET(ctx, rv, "Failed to encode public key");
|
|
|
|
}
|
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
|
|
|
}
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
/*
|
|
|
|
* Prepare private key download, and initialize a prkdf entry
|
|
|
|
*/
|
|
|
|
static int
|
2010-01-10 20:33:32 +00:00
|
|
|
sc_pkcs15init_init_prkdf(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
2003-10-13 16:13:12 +00:00
|
|
|
struct sc_pkcs15init_prkeyargs *keyargs,
|
2010-01-10 20:33:32 +00:00
|
|
|
struct sc_pkcs15_prkey *key, int keybits,
|
|
|
|
struct sc_pkcs15_object **res_obj)
|
2002-06-17 10:58:04 +00:00
|
|
|
{
|
2010-01-16 21:52:47 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-06-17 10:58:04 +00:00
|
|
|
struct sc_pkcs15_prkey_info *key_info;
|
2009-10-05 20:10:07 +00:00
|
|
|
struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams;
|
2002-06-17 10:58:04 +00:00
|
|
|
struct sc_pkcs15_object *object;
|
|
|
|
const char *label;
|
|
|
|
unsigned int usage;
|
2011-04-12 18:08:18 +00:00
|
|
|
int r = 0, key_type;
|
2002-06-17 10:58:04 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2005-12-05 21:57:07 +00:00
|
|
|
if (!res_obj || !keybits)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Initialize PrKDF entry failed");
|
2002-12-04 13:25:31 +00:00
|
|
|
|
2005-12-05 21:57:07 +00:00
|
|
|
*res_obj = NULL;
|
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
if ((usage = keyargs->usage) == 0) {
|
|
|
|
usage = SC_PKCS15_PRKEY_USAGE_SIGN;
|
|
|
|
if (keyargs->x509_usage)
|
|
|
|
usage = sc_pkcs15init_map_usage(keyargs->x509_usage, 1);
|
|
|
|
}
|
2003-06-12 21:23:01 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
if ((label = keyargs->label) == NULL)
|
|
|
|
label = "Private Key";
|
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
/* Create the prkey object now.
|
|
|
|
* If we find out below that we're better off reusing an
|
|
|
|
* existing object, we'll ditch this one */
|
2011-04-12 18:08:18 +00:00
|
|
|
key_type = prkey_pkcs15_algo(p15card, key);
|
|
|
|
LOG_TEST_RET(ctx, key_type, "Unsupported key type");
|
|
|
|
|
|
|
|
object = sc_pkcs15init_new_object(key_type, label, &keyargs->auth_id, NULL);
|
2005-01-03 17:25:18 +00:00
|
|
|
if (object == NULL)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate new PrKey object");
|
2003-10-16 14:32:42 +00:00
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
key_info = (struct sc_pkcs15_prkey_info *) object->data;
|
2002-06-17 10:58:04 +00:00
|
|
|
key_info->usage = usage;
|
|
|
|
key_info->native = 1;
|
|
|
|
key_info->key_reference = 0;
|
|
|
|
key_info->modulus_length = keybits;
|
2010-04-01 14:16:43 +00:00
|
|
|
key_info->access_flags = keyargs->access_flags;
|
2003-10-13 16:13:12 +00:00
|
|
|
/* Path is selected below */
|
2002-06-17 10:58:04 +00:00
|
|
|
|
2010-04-01 14:16:43 +00:00
|
|
|
if (keyargs->access_flags & SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE) {
|
2003-10-13 16:13:12 +00:00
|
|
|
key_info->access_flags &= ~SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE;
|
|
|
|
key_info->native = 0;
|
|
|
|
}
|
|
|
|
|
2011-01-02 13:55:03 +00:00
|
|
|
/* Select a Key ID if the user didn't specify one,
|
|
|
|
* otherwise make sure it's compatible with our intended use */
|
|
|
|
r = select_id(p15card, SC_PKCS15_TYPE_PRKEY, &keyargs->id);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot select ID for PrKey object");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
key_info->id = keyargs->id;
|
|
|
|
|
2009-10-05 20:10:07 +00:00
|
|
|
if (key->algorithm == SC_ALGORITHM_GOSTR3410) {
|
2011-05-01 19:18:14 +00:00
|
|
|
key_info->params.len = sizeof(*keyinfo_gostparams);
|
2009-10-05 20:10:07 +00:00
|
|
|
/* FIXME: malloc() call in pkcs15init, but free() call
|
|
|
|
* in libopensc (sc_pkcs15_free_prkey_info) */
|
2011-05-01 19:18:14 +00:00
|
|
|
key_info->params.data = malloc(key_info->params.len);
|
|
|
|
if (!key_info->params.data)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate memory for GOST parameters");
|
2011-05-01 19:18:14 +00:00
|
|
|
keyinfo_gostparams = key_info->params.data;
|
2011-04-12 11:36:40 +00:00
|
|
|
keyinfo_gostparams->gostr3410 = keyargs->params.gost.gostr3410;
|
|
|
|
keyinfo_gostparams->gostr3411 = keyargs->params.gost.gostr3411;
|
|
|
|
keyinfo_gostparams->gost28147 = keyargs->params.gost.gost28147;
|
2009-10-05 20:10:07 +00:00
|
|
|
}
|
2011-05-01 20:14:06 +00:00
|
|
|
else if (key->algorithm == SC_ALGORITHM_EC) {
|
|
|
|
struct sc_pkcs15_ec_parameters *ecparams = &keyargs->params.ec;
|
|
|
|
key_info->params.data = &keyargs->params.ec;
|
|
|
|
key_info->params.free_params = sc_pkcs15init_empty_callback;
|
|
|
|
key_info->field_length = ecparams->field_length;
|
|
|
|
}
|
2009-10-05 20:10:07 +00:00
|
|
|
|
2010-03-05 10:37:11 +00:00
|
|
|
r = select_object_path(p15card, profile, object, &key_info->path);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select private key object path");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
/* See if we need to select a key reference for this object */
|
|
|
|
if (profile->ops->select_key_reference) {
|
|
|
|
while (1) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->select_key_reference(profile, p15card, key_info);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select card specific key reference");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2011-04-12 18:08:18 +00:00
|
|
|
r = sc_pkcs15_find_prkey_by_reference(p15card, &key_info->path, key_info->key_reference, NULL);
|
2003-10-13 16:13:12 +00:00
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND)
|
|
|
|
break;
|
|
|
|
|
2010-01-16 21:52:47 +00:00
|
|
|
if (r != 0)
|
2003-10-13 16:13:12 +00:00
|
|
|
/* Other error trying to retrieve pin obj */
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_TOO_MANY_OBJECTS, "Failed to select key reference");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
key_info->key_reference++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
*res_obj = object;
|
2010-01-16 21:52:47 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2002-06-17 10:58:04 +00:00
|
|
|
}
|
|
|
|
|
2010-01-25 16:42:22 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Generate a new private key
|
|
|
|
*/
|
|
|
|
int
|
2011-04-12 18:08:18 +00:00
|
|
|
sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15init_keygen_args *keygen_args, unsigned int keybits,
|
2002-04-11 15:14:12 +00:00
|
|
|
struct sc_pkcs15_object **res_obj)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-01-25 16:42:22 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-06-06 09:18:53 +00:00
|
|
|
struct sc_pkcs15init_pubkeyargs pubkey_args;
|
2002-06-17 10:58:04 +00:00
|
|
|
struct sc_pkcs15_object *object;
|
|
|
|
struct sc_pkcs15_prkey_info *key_info;
|
2009-11-13 09:45:21 +00:00
|
|
|
int r, caller_supplied_id = 0;
|
2002-06-06 09:18:53 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2007-01-19 21:08:20 +00:00
|
|
|
/* check supported key size */
|
2011-04-12 18:08:18 +00:00
|
|
|
r = check_keygen_params_consistency(p15card->card, keygen_args, keybits, &keybits);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Invalid key size");
|
2007-01-19 21:08:20 +00:00
|
|
|
|
2011-04-12 18:08:18 +00:00
|
|
|
if (check_key_compatibility(p15card, &keygen_args->prkey_args.key, keygen_args->prkey_args.x509_usage,
|
2010-01-25 16:42:22 +00:00
|
|
|
keybits, SC_ALGORITHM_ONBOARD_KEY_GEN))
|
2011-04-12 18:08:18 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Cannot generate key with the given parameters");
|
2002-06-06 09:18:53 +00:00
|
|
|
|
2010-02-02 14:50:56 +00:00
|
|
|
if (profile->ops->generate_key == NULL)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key generation not supported");
|
2002-06-06 09:18:53 +00:00
|
|
|
|
2011-03-06 11:34:58 +00:00
|
|
|
if (keygen_args->prkey_args.id.len) {
|
|
|
|
caller_supplied_id = 1;
|
|
|
|
|
|
|
|
/* Make sure that private key's ID is the unique inside the PKCS#15 application */
|
|
|
|
r = sc_pkcs15_find_prkey_by_id(p15card, &keygen_args->prkey_args.id, NULL);
|
|
|
|
if (!r)
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NON_UNIQUE_ID, "Non unique ID of the private key object");
|
|
|
|
else if (r != SC_ERROR_OBJECT_NOT_FOUND)
|
|
|
|
LOG_TEST_RET(ctx, r, "Find private key error");
|
|
|
|
}
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
/* Set up the PrKDF object */
|
2003-12-08 12:02:28 +00:00
|
|
|
r = sc_pkcs15init_init_prkdf(p15card, profile, &keygen_args->prkey_args,
|
|
|
|
&keygen_args->prkey_args.key, keybits, &object);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Set up private key object error");
|
2010-01-25 16:42:22 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
key_info = (struct sc_pkcs15_prkey_info *) object->data;
|
|
|
|
|
|
|
|
/* Set up the PuKDF info. The public key will be filled in
|
2010-02-02 17:29:17 +00:00
|
|
|
* by the card driver's generate_key function called below.
|
|
|
|
* Auth.ID of the public key object is left empty. */
|
2002-06-06 09:18:53 +00:00
|
|
|
memset(&pubkey_args, 0, sizeof(pubkey_args));
|
2003-12-08 12:02:28 +00:00
|
|
|
pubkey_args.id = keygen_args->prkey_args.id;
|
2009-11-13 09:45:21 +00:00
|
|
|
pubkey_args.label = keygen_args->pubkey_label ? keygen_args->pubkey_label : object->label;
|
2003-12-08 12:02:28 +00:00
|
|
|
pubkey_args.usage = keygen_args->prkey_args.usage;
|
|
|
|
pubkey_args.x509_usage = keygen_args->prkey_args.x509_usage;
|
2011-04-12 11:36:40 +00:00
|
|
|
pubkey_args.params.gost = keygen_args->prkey_args.params.gost;
|
2002-06-06 09:18:53 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
/* Generate the private key on card */
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->create_key(profile, p15card, object);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot generate key: create key failed");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->generate_key(profile, p15card, object, &pubkey_args.key);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to generate key");
|
2002-06-06 09:18:53 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
/* update PrKDF entry */
|
2010-01-25 16:42:22 +00:00
|
|
|
if (!caller_supplied_id) {
|
|
|
|
struct sc_pkcs15_id iid;
|
|
|
|
|
|
|
|
/* Caller not supplied ID, so,
|
|
|
|
* if intrinsic ID can be calculated -- overwrite the native one */
|
|
|
|
memset(&iid, 0, sizeof(iid));
|
|
|
|
r = select_intrinsic_id(p15card, profile, SC_PKCS15_TYPE_PUBKEY, &iid, &pubkey_args.key);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Select intrinsic ID error");
|
2010-01-25 16:42:22 +00:00
|
|
|
|
2011-05-01 20:14:06 +00:00
|
|
|
if (iid.len)
|
2010-01-25 16:42:22 +00:00
|
|
|
key_info->id = iid;
|
2002-06-17 10:58:04 +00:00
|
|
|
}
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2011-05-01 20:14:06 +00:00
|
|
|
pubkey_args.id = key_info->id;
|
2010-05-10 14:35:43 +00:00
|
|
|
r = sc_pkcs15_encode_pubkey(ctx, &pubkey_args.key, &object->content.value, &object->content.len);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to encode public key");
|
2010-04-12 08:44:24 +00:00
|
|
|
|
2010-01-25 16:42:22 +00:00
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_PRKDF, object);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to add generated private key object");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2010-01-25 16:42:22 +00:00
|
|
|
r = sc_pkcs15init_store_public_key(p15card, profile, &pubkey_args, NULL);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to store public key");
|
2002-06-17 10:58:04 +00:00
|
|
|
|
2010-01-25 16:42:22 +00:00
|
|
|
if (res_obj)
|
2002-06-17 10:58:04 +00:00
|
|
|
*res_obj = object;
|
2005-01-21 18:31:05 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
sc_pkcs15_erase_pubkey(&pubkey_args.key);
|
|
|
|
|
2005-08-05 19:07:24 +00:00
|
|
|
profile->dirty = 1;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store private key
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
2002-04-15 13:42:10 +00:00
|
|
|
struct sc_pkcs15init_prkeyargs *keyargs,
|
2002-04-11 15:14:12 +00:00
|
|
|
struct sc_pkcs15_object **res_obj)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-01-16 21:52:47 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-04-02 13:26:42 +00:00
|
|
|
struct sc_pkcs15_object *object;
|
|
|
|
struct sc_pkcs15_prkey_info *key_info;
|
2010-01-10 20:33:32 +00:00
|
|
|
struct sc_pkcs15_prkey key;
|
|
|
|
int keybits, idx, r = 0;
|
2002-04-15 13:42:10 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2002-04-15 13:42:10 +00:00
|
|
|
/* Create a copy of the key first */
|
|
|
|
key = keyargs->key;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-01-16 21:52:47 +00:00
|
|
|
r = prkey_fixup(p15card, &key);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Private key data sanity check failed");
|
2010-01-16 21:52:47 +00:00
|
|
|
|
|
|
|
keybits = prkey_bits(p15card, &key);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, keybits, "Invalid private key size");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
/* Now check whether the card is able to handle this key */
|
2011-04-12 13:23:05 +00:00
|
|
|
if (check_key_compatibility(p15card, &key, keyargs->x509_usage, keybits, 0)) {
|
2002-04-17 20:47:18 +00:00
|
|
|
/* Make sure the caller explicitly tells us to store
|
2010-08-23 10:32:26 +00:00
|
|
|
* the key as extractable. */
|
2010-04-01 14:16:43 +00:00
|
|
|
if (!(keyargs->access_flags & SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE))
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INCOMPATIBLE_KEY, "Card does not support this key.");
|
2010-01-16 21:52:47 +00:00
|
|
|
|
2011-03-06 11:34:58 +00:00
|
|
|
if (!keyargs->passphrase && !(keyargs->flags & SC_PKCS15INIT_NO_PASSPHRASE))
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_PASSPHRASE_REQUIRED, "No key encryption passphrase given.");
|
2002-04-17 20:47:18 +00:00
|
|
|
}
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
/* Select a intrinsic Key ID if user didn't specify one */
|
|
|
|
r = select_intrinsic_id(p15card, profile, SC_PKCS15_TYPE_PRKEY, &keyargs->id, &keyargs->key);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Get intrinsic ID error");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2011-03-06 11:34:58 +00:00
|
|
|
/* Make sure that private key's ID is the unique inside the PKCS#15 application */
|
|
|
|
r = sc_pkcs15_find_prkey_by_id(p15card, &keyargs->id, NULL);
|
|
|
|
if (!r)
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NON_UNIQUE_ID, "Non unique ID of the private key object");
|
|
|
|
else if (r != SC_ERROR_OBJECT_NOT_FOUND)
|
|
|
|
LOG_TEST_RET(ctx, r, "Find private key error");
|
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
/* Set up the PrKDF object */
|
2003-10-13 16:13:12 +00:00
|
|
|
r = sc_pkcs15init_init_prkdf(p15card, profile, keyargs, &key, keybits, &object);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to initialize private key object");
|
2002-06-17 10:58:04 +00:00
|
|
|
key_info = (struct sc_pkcs15_prkey_info *) object->data;
|
|
|
|
|
2011-05-22 11:42:53 +00:00
|
|
|
r = sc_pkcs15init_encode_prvkey_content(p15card, &key, object);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to encode public key");
|
2010-03-18 10:15:51 +00:00
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
/* Get the number of private keys already on this card */
|
2004-12-22 09:48:27 +00:00
|
|
|
idx = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY, NULL, 0);
|
2010-04-01 14:16:43 +00:00
|
|
|
if (!(keyargs->access_flags & SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE)) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->create_key(profile, p15card, object);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific 'create key' failed");
|
2010-02-02 14:50:56 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = profile->ops->store_key(profile, p15card, object, &key);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific 'store key' failed");
|
2002-04-17 20:47:18 +00:00
|
|
|
} else {
|
2010-03-04 16:14:30 +00:00
|
|
|
struct sc_pkcs15_der encoded, wrapped, *der = &encoded;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
/* DER encode the private key */
|
|
|
|
encoded.value = wrapped.value = NULL;
|
|
|
|
r = sc_pkcs15_encode_prkey(ctx, &key, &encoded.value, &encoded.len);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to encode private key");
|
2002-04-17 20:47:18 +00:00
|
|
|
|
|
|
|
if (keyargs->passphrase) {
|
2011-01-05 16:04:15 +00:00
|
|
|
r = sc_pkcs15_wrap_data(ctx, keyargs->passphrase, der->value, der->len,
|
2002-04-17 20:47:18 +00:00
|
|
|
&wrapped.value, &wrapped.len);
|
|
|
|
if (r < 0) {
|
|
|
|
free(der->value);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to wrap private key data");
|
2002-04-17 20:47:18 +00:00
|
|
|
}
|
|
|
|
der = &wrapped;
|
|
|
|
}
|
|
|
|
|
2010-03-05 10:37:11 +00:00
|
|
|
r = sc_pkcs15init_store_data(p15card, profile, object, der, &key_info->path);
|
2002-04-17 20:47:18 +00:00
|
|
|
|
|
|
|
/* If the key is encrypted, flag the PrKDF entry as
|
|
|
|
* indirect-protected */
|
|
|
|
if (keyargs->passphrase)
|
|
|
|
key_info->path.type = SC_PATH_TYPE_PATH_PROT;
|
|
|
|
|
|
|
|
free(encoded.value);
|
|
|
|
free(wrapped.value);
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to store private key data");
|
2002-04-17 20:47:18 +00:00
|
|
|
}
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
/* Now update the PrKDF */
|
2010-03-18 10:15:51 +00:00
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_PRKDF, object);
|
2002-04-19 10:01:01 +00:00
|
|
|
|
2002-04-11 15:14:12 +00:00
|
|
|
if (r >= 0 && res_obj)
|
|
|
|
*res_obj = object;
|
|
|
|
|
2005-08-05 19:07:24 +00:00
|
|
|
profile->dirty = 1;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-01-16 21:52:47 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Store a public key
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
2002-04-15 13:42:10 +00:00
|
|
|
struct sc_pkcs15init_pubkeyargs *keyargs,
|
2002-04-11 15:14:12 +00:00
|
|
|
struct sc_pkcs15_object **res_obj)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-01-16 21:52:47 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-04-02 13:26:42 +00:00
|
|
|
struct sc_pkcs15_object *object;
|
|
|
|
struct sc_pkcs15_pubkey_info *key_info;
|
2009-10-05 20:10:07 +00:00
|
|
|
struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams;
|
2010-01-10 20:33:32 +00:00
|
|
|
struct sc_pkcs15_pubkey key;
|
|
|
|
struct sc_path *path;
|
2002-04-02 13:26:42 +00:00
|
|
|
const char *label;
|
2002-04-15 13:42:10 +00:00
|
|
|
unsigned int keybits, type, usage;
|
2002-04-02 13:26:42 +00:00
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-01-25 16:42:22 +00:00
|
|
|
if (!keyargs)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Store public key aborted");
|
2005-12-05 21:57:07 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
/* Create a copy of the key first */
|
|
|
|
key = keyargs->key;
|
|
|
|
|
|
|
|
switch (key.algorithm) {
|
2002-04-02 13:26:42 +00:00
|
|
|
case SC_ALGORITHM_RSA:
|
2002-04-15 13:42:10 +00:00
|
|
|
keybits = sc_pkcs15init_keybits(&key.u.rsa.modulus);
|
2011-04-15 16:50:04 +00:00
|
|
|
type = SC_PKCS15_TYPE_PUBKEY_RSA;
|
|
|
|
break;
|
2002-04-02 13:26:42 +00:00
|
|
|
#ifdef SC_PKCS15_TYPE_PUBKEY_DSA
|
|
|
|
case SC_ALGORITHM_DSA:
|
2002-04-15 13:42:10 +00:00
|
|
|
keybits = sc_pkcs15init_keybits(&key.u.dsa.q);
|
2011-04-15 16:50:04 +00:00
|
|
|
type = SC_PKCS15_TYPE_PUBKEY_DSA;
|
|
|
|
break;
|
2002-04-02 13:26:42 +00:00
|
|
|
#endif
|
2009-10-05 20:10:07 +00:00
|
|
|
case SC_ALGORITHM_GOSTR3410:
|
|
|
|
keybits = SC_PKCS15_GOSTR3410_KEYSIZE;
|
2011-04-15 16:50:04 +00:00
|
|
|
type = SC_PKCS15_TYPE_PUBKEY_GOSTR3410;
|
|
|
|
break;
|
|
|
|
case SC_ALGORITHM_EC:
|
2011-04-22 13:08:45 +00:00
|
|
|
keybits = key.u.ec.params.field_length;
|
2011-04-15 16:50:04 +00:00
|
|
|
type = SC_PKCS15_TYPE_PUBKEY_EC;
|
|
|
|
break;
|
2002-04-02 13:26:42 +00:00
|
|
|
default:
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported key algorithm.");
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((usage = keyargs->usage) == 0) {
|
2002-04-15 13:42:10 +00:00
|
|
|
usage = SC_PKCS15_PRKEY_USAGE_SIGN;
|
|
|
|
if (keyargs->x509_usage)
|
|
|
|
usage = sc_pkcs15init_map_usage(keyargs->x509_usage, 0);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
2010-03-18 10:15:51 +00:00
|
|
|
label = keyargs->label;
|
|
|
|
if (!label)
|
2002-04-02 13:26:42 +00:00
|
|
|
label = "Public Key";
|
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
/* Set up the pkcs15 object. */
|
2003-10-16 14:32:42 +00:00
|
|
|
object = sc_pkcs15init_new_object(type, label, &keyargs->auth_id, NULL);
|
2005-01-03 17:25:18 +00:00
|
|
|
if (object == NULL)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate new public key object");
|
2003-10-16 14:32:42 +00:00
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
key_info = (struct sc_pkcs15_pubkey_info *) object->data;
|
2002-04-02 13:26:42 +00:00
|
|
|
key_info->usage = usage;
|
2002-04-15 13:42:10 +00:00
|
|
|
key_info->modulus_length = keybits;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2009-10-05 20:10:07 +00:00
|
|
|
if (key.algorithm == SC_ALGORITHM_GOSTR3410) {
|
2011-05-01 19:18:14 +00:00
|
|
|
key_info->params.len = sizeof(*keyinfo_gostparams);
|
2009-10-05 20:10:07 +00:00
|
|
|
/* FIXME: malloc() call in pkcs15init, but free() call
|
|
|
|
* in libopensc (sc_pkcs15_free_prkey_info) */
|
2011-05-01 19:18:14 +00:00
|
|
|
key_info->params.data = malloc(key_info->params.len);
|
|
|
|
if (!key_info->params.data)
|
2009-10-05 20:10:07 +00:00
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2011-05-01 19:18:14 +00:00
|
|
|
keyinfo_gostparams = key_info->params.data;
|
2011-04-12 11:36:40 +00:00
|
|
|
keyinfo_gostparams->gostr3410 = keyargs->params.gost.gostr3410;
|
|
|
|
keyinfo_gostparams->gostr3411 = keyargs->params.gost.gostr3411;
|
|
|
|
keyinfo_gostparams->gost28147 = keyargs->params.gost.gost28147;
|
2009-10-05 20:10:07 +00:00
|
|
|
}
|
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
/* Select a intrinsic Key ID if the user didn't specify one */
|
|
|
|
r = select_intrinsic_id(p15card, profile, SC_PKCS15_TYPE_PUBKEY, &keyargs->id, &key);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Get intrinsic ID error");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
/* Select a Key ID if the user didn't specify one and there is no intrinsic ID,
|
|
|
|
* otherwise make sure it's unique */
|
2010-01-10 20:33:32 +00:00
|
|
|
r = select_id(p15card, SC_PKCS15_TYPE_PUBKEY, &keyargs->id);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select public key object ID");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2011-05-08 15:53:39 +00:00
|
|
|
/* Make sure that private key's ID is the unique inside the PKCS#15 application */
|
|
|
|
r = sc_pkcs15_find_pubkey_by_id(p15card, &keyargs->id, NULL);
|
|
|
|
if (!r)
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NON_UNIQUE_ID, "Non unique ID of the public key object");
|
|
|
|
else if (r != SC_ERROR_OBJECT_NOT_FOUND)
|
|
|
|
LOG_TEST_RET(ctx, r, "Find public key error");
|
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
key_info->id = keyargs->id;
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
/* DER encode public key components */
|
2010-03-18 10:15:51 +00:00
|
|
|
r = sc_pkcs15_encode_pubkey(p15card->card->ctx, &key, &object->content.value, &object->content.len);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Encode public key error");
|
2002-04-15 13:42:10 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/* Now create key file and store key */
|
2010-03-18 10:15:51 +00:00
|
|
|
r = sc_pkcs15init_store_data(p15card, profile, object, &object->content, &key_info->path);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
path = &key_info->path;
|
2003-06-03 13:57:52 +00:00
|
|
|
if (path->count == 0) {
|
|
|
|
path->index = 0;
|
|
|
|
path->count = -1;
|
|
|
|
}
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/* Update the PuKDF */
|
2002-06-17 10:58:04 +00:00
|
|
|
if (r >= 0)
|
2010-03-18 10:15:51 +00:00
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_PUKDF, object);
|
2002-04-19 10:01:01 +00:00
|
|
|
|
2002-04-11 15:14:12 +00:00
|
|
|
if (r >= 0 && res_obj)
|
|
|
|
*res_obj = object;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2005-08-05 19:07:24 +00:00
|
|
|
profile->dirty = 1;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Store a certificate
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
sc_pkcs15init_store_certificate(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
2002-04-11 15:14:12 +00:00
|
|
|
struct sc_pkcs15init_certargs *args,
|
|
|
|
struct sc_pkcs15_object **res_obj)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-01-25 16:42:22 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-04-02 13:26:42 +00:00
|
|
|
struct sc_pkcs15_cert_info *cert_info;
|
|
|
|
struct sc_pkcs15_object *object;
|
|
|
|
const char *label;
|
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-03-18 10:15:51 +00:00
|
|
|
|
|
|
|
label = args->label;
|
|
|
|
if (!label)
|
2002-04-02 13:26:42 +00:00
|
|
|
label = "Certificate";
|
2010-03-18 10:15:51 +00:00
|
|
|
|
2009-11-13 09:45:21 +00:00
|
|
|
r = select_intrinsic_id(p15card, profile, SC_PKCS15_TYPE_CERT_X509, &args->id, &args->der_encoded);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Get certificate 'intrinsic ID' error");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
2002-12-04 13:25:31 +00:00
|
|
|
/* Select an ID if the user didn't specify one, otherwise
|
|
|
|
* make sure it's unique */
|
2010-01-25 16:42:22 +00:00
|
|
|
r = select_id(p15card, SC_PKCS15_TYPE_CERT, &args->id);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Select certificate ID error");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2003-10-16 14:32:42 +00:00
|
|
|
object = sc_pkcs15init_new_object(SC_PKCS15_TYPE_CERT_X509, label, NULL, NULL);
|
2005-01-03 17:25:18 +00:00
|
|
|
if (object == NULL)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Failed to allocate certificate object");
|
2010-03-04 16:14:30 +00:00
|
|
|
cert_info = (struct sc_pkcs15_cert_info *) object->data;
|
2002-04-02 13:26:42 +00:00
|
|
|
cert_info->id = args->id;
|
2002-04-22 18:37:57 +00:00
|
|
|
cert_info->authority = args->authority;
|
2010-03-18 10:15:51 +00:00
|
|
|
sc_der_copy(&object->content, &args->der_encoded);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Store cert(%s,ID:%s,der(%p,%i))", object->label,
|
2010-03-18 10:15:51 +00:00
|
|
|
sc_pkcs15_print_id(&cert_info->id), args->der_encoded.value, args->der_encoded.len);
|
2010-03-04 13:05:03 +00:00
|
|
|
if (profile->pkcs15.direct_certificates)
|
2003-11-19 20:37:02 +00:00
|
|
|
sc_der_copy(&cert_info->value, &args->der_encoded);
|
2010-03-04 13:05:03 +00:00
|
|
|
else
|
2010-03-05 10:37:11 +00:00
|
|
|
r = sc_pkcs15init_store_data(p15card, profile, object, &args->der_encoded, &cert_info->path);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
/* Now update the CDF */
|
2010-05-10 09:18:49 +00:00
|
|
|
if (r >= 0) {
|
2010-01-10 20:33:32 +00:00
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_CDF, object);
|
2010-05-10 09:18:49 +00:00
|
|
|
/* TODO: update private key PKCS#15 object with the certificate's attributes */
|
|
|
|
}
|
2010-03-18 10:25:50 +00:00
|
|
|
|
|
|
|
if (r < 0)
|
2005-12-05 21:57:07 +00:00
|
|
|
sc_pkcs15_free_object(object);
|
2002-04-19 10:01:01 +00:00
|
|
|
|
2002-04-11 15:14:12 +00:00
|
|
|
if (r >= 0 && res_obj)
|
|
|
|
*res_obj = object;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2005-08-05 19:07:24 +00:00
|
|
|
profile->dirty = 1;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2002-12-18 10:17:01 +00:00
|
|
|
/*
|
|
|
|
* Store a data object
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
sc_pkcs15init_store_data_object(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15init_dataargs *args,
|
|
|
|
struct sc_pkcs15_object **res_obj)
|
|
|
|
{
|
2010-03-22 14:17:27 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-12-18 10:17:01 +00:00
|
|
|
struct sc_pkcs15_data_info *data_object_info;
|
|
|
|
struct sc_pkcs15_object *object;
|
2004-08-14 13:43:17 +00:00
|
|
|
struct sc_pkcs15_object *objs[32];
|
2002-12-18 10:17:01 +00:00
|
|
|
const char *label;
|
2004-08-14 13:43:17 +00:00
|
|
|
int r, i;
|
|
|
|
unsigned int tid = 0x01;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2007-06-21 09:37:18 +00:00
|
|
|
label = args->label;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
2004-08-14 13:43:17 +00:00
|
|
|
if (!args->id.len) {
|
|
|
|
/* Select an ID if the user didn't specify one, otherwise
|
|
|
|
* make sure it's unique (even though data objects doesn't
|
|
|
|
* have a pkcs15 id we need one here to create a unique
|
|
|
|
* file id from the data file template */
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_DATA_OBJECT, objs, 32);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Get 'DATA' objects error");
|
2010-03-22 14:17:27 +00:00
|
|
|
|
2004-08-14 13:43:17 +00:00
|
|
|
for (i = 0; i < r; i++) {
|
2010-03-22 14:17:27 +00:00
|
|
|
unsigned char cid;
|
|
|
|
struct sc_pkcs15_data_info *cinfo = (struct sc_pkcs15_data_info *) objs[i]->data;
|
2004-08-14 13:43:17 +00:00
|
|
|
if (!cinfo->path.len)
|
|
|
|
continue;
|
|
|
|
cid = cinfo->path.value[cinfo->path.len - 1];
|
|
|
|
if (cid >= tid)
|
|
|
|
tid = cid + 1;
|
|
|
|
}
|
|
|
|
if (tid > 0xff)
|
|
|
|
/* too many data objects ... */
|
|
|
|
return SC_ERROR_TOO_MANY_OBJECTS;
|
|
|
|
args->id.len = 1;
|
|
|
|
args->id.value[0] = tid;
|
|
|
|
} else {
|
|
|
|
/* in case the user specifies an id it should be at most
|
|
|
|
* one byte long */
|
|
|
|
if (args->id.len > 1)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2003-10-16 14:32:42 +00:00
|
|
|
object = sc_pkcs15init_new_object(SC_PKCS15_TYPE_DATA_OBJECT, label, &args->auth_id, NULL);
|
2005-01-03 17:25:18 +00:00
|
|
|
if (object == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
2010-03-04 16:14:30 +00:00
|
|
|
data_object_info = (struct sc_pkcs15_data_info *) object->data;
|
2007-06-21 09:37:18 +00:00
|
|
|
if (args->app_label != NULL) {
|
|
|
|
strlcpy(data_object_info->app_label, args->app_label,
|
|
|
|
sizeof(data_object_info->app_label));
|
|
|
|
} else if (label != NULL) {
|
2006-07-12 08:12:38 +00:00
|
|
|
strlcpy(data_object_info->app_label, label,
|
|
|
|
sizeof(data_object_info->app_label));
|
2003-10-16 14:32:42 +00:00
|
|
|
}
|
2003-08-20 14:15:02 +00:00
|
|
|
data_object_info->app_oid = args->app_oid;
|
2002-12-18 10:17:01 +00:00
|
|
|
|
2010-03-22 14:17:27 +00:00
|
|
|
r = sc_pkcs15init_store_data(p15card, profile, object, &args->der_encoded, &data_object_info->path);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Store 'DATA' object error");
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
|
|
/* Now update the DDF */
|
2010-03-22 14:17:27 +00:00
|
|
|
r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_DODF, object);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "'DODF' update error");
|
2002-12-18 10:17:01 +00:00
|
|
|
|
|
|
|
if (r >= 0 && res_obj)
|
|
|
|
*res_obj = object;
|
|
|
|
|
2005-08-05 19:07:24 +00:00
|
|
|
profile->dirty = 1;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-12-18 10:17:01 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
sc_pkcs15init_get_pin_reference(struct sc_pkcs15_card *p15card,
|
2010-03-05 10:37:11 +00:00
|
|
|
struct sc_profile *profile, unsigned auth_method, int reference)
|
2010-02-21 18:24:41 +00:00
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_pkcs15_pin_info pinfo;
|
|
|
|
struct sc_pkcs15_object *auth_objs[0x10];
|
|
|
|
int r, ii, nn_objs;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
/* 1. Look for the corresponding pkcs15 PIN object. */
|
|
|
|
|
|
|
|
/* Get all existing pkcs15 AUTH objects */
|
|
|
|
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, auth_objs, 0x10);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Get PKCS#15 AUTH objects error");
|
2010-02-21 18:24:41 +00:00
|
|
|
nn_objs = r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "found %i auth objects; looking for AUTH object(auth_method:%i,reference:%i)",
|
2010-02-21 18:24:41 +00:00
|
|
|
nn_objs, auth_method, reference);
|
|
|
|
for (ii=0; ii<nn_objs; ii++) {
|
|
|
|
struct sc_pkcs15_pin_info *pin_info = (struct sc_pkcs15_pin_info *)auth_objs[ii]->data;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "check PIN(%s,auth_method:%i,type:%i,reference:%i,flags:%X)",
|
2010-02-21 18:24:41 +00:00
|
|
|
auth_objs[ii]->label, pin_info->auth_method, pin_info->type,
|
|
|
|
pin_info->reference, pin_info->flags);
|
|
|
|
/* Find out if there is AUTH pkcs15 object with given 'type' and 'reference' */
|
|
|
|
if (pin_info->auth_method == auth_method && pin_info->reference == reference)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, pin_info->reference);
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
if (auth_method != SC_AC_SYMBOLIC)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Translate 'SYMBOLIC' PIN reference into the pkcs#15 pinAttributes.flags
|
|
|
|
* and check for the existing pkcs15 PIN object with these flags. */
|
|
|
|
switch (reference) {
|
|
|
|
case SC_PKCS15INIT_USER_PIN:
|
|
|
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
|
|
|
|
continue;
|
|
|
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15INIT_SO_PIN:
|
|
|
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)
|
|
|
|
continue;
|
|
|
|
if (!(pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN))
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15INIT_USER_PUK:
|
|
|
|
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
|
|
|
|
continue;
|
|
|
|
if (!(pin_info->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN))
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15INIT_SO_PUK:
|
|
|
|
if (!(pin_info->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN))
|
|
|
|
continue;
|
|
|
|
if (!(pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN))
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
default:
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid Symbolic PIN reference");
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, pin_info->reference);
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 2. No existing pkcs15 PIN object
|
|
|
|
* -- check if profile defines some PIN with 'reference' as PIN reference. */
|
|
|
|
r = sc_profile_get_pin_id_by_reference(profile, auth_method, reference, &pinfo);
|
|
|
|
if (r < 0)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "PIN template not found");
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, pinfo.reference);
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
static int
|
2010-03-05 10:37:11 +00:00
|
|
|
sc_pkcs15init_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_object *object, struct sc_pkcs15_der *data,
|
2010-01-25 16:42:22 +00:00
|
|
|
struct sc_path *path)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-01-16 21:52:47 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-04-02 13:26:42 +00:00
|
|
|
struct sc_file *file = NULL;
|
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2002-04-08 15:49:39 +00:00
|
|
|
|
2010-12-30 12:50:35 +00:00
|
|
|
if (profile->ops->emu_store_data) {
|
|
|
|
r = profile->ops->emu_store_data(p15card, profile, object, data, path);
|
|
|
|
if (r == SC_SUCCESS || r != SC_ERROR_NOT_IMPLEMENTED)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2010-12-30 12:50:35 +00:00
|
|
|
}
|
|
|
|
|
2010-03-05 10:37:11 +00:00
|
|
|
r = select_object_path(p15card, profile, object, path);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select object path");
|
2010-02-02 14:50:56 +00:00
|
|
|
|
|
|
|
r = sc_profile_get_file_by_path(profile, path, &file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to get file by path");
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2003-06-03 13:57:52 +00:00
|
|
|
if (file->path.count == 0) {
|
|
|
|
file->path.index = 0;
|
|
|
|
file->path.count = -1;
|
|
|
|
}
|
2010-05-26 14:33:01 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15init_delete_by_path(profile, p15card, &file->path);
|
|
|
|
if (r && r != SC_ERROR_FILE_NOT_FOUND)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot delete file");
|
2010-05-26 14:33:01 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15init_update_file(profile, p15card, file, data->value, data->len);
|
2004-06-16 20:59:59 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
*path = file->path;
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
if (file)
|
2002-04-02 13:26:42 +00:00
|
|
|
sc_file_free(file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Map X509 keyUsage extension bits to PKCS#15 keyUsage bits
|
|
|
|
*/
|
2005-09-07 09:32:52 +00:00
|
|
|
typedef struct {
|
|
|
|
unsigned long x509_usage;
|
|
|
|
unsigned int p15_usage;
|
|
|
|
} sc_usage_map;
|
|
|
|
|
|
|
|
static sc_usage_map x509_to_pkcs15_private_key_usage[16] = {
|
|
|
|
{ SC_PKCS15INIT_X509_DIGITAL_SIGNATURE,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER },
|
|
|
|
{ SC_PKCS15INIT_X509_NON_REPUDIATION, SC_PKCS15_PRKEY_USAGE_NONREPUDIATION },
|
|
|
|
{ SC_PKCS15INIT_X509_KEY_ENCIPHERMENT, SC_PKCS15_PRKEY_USAGE_UNWRAP },
|
|
|
|
{ SC_PKCS15INIT_X509_DATA_ENCIPHERMENT, SC_PKCS15_PRKEY_USAGE_DECRYPT },
|
|
|
|
{ SC_PKCS15INIT_X509_KEY_AGREEMENT, SC_PKCS15_PRKEY_USAGE_DERIVE },
|
|
|
|
{ SC_PKCS15INIT_X509_KEY_CERT_SIGN,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER },
|
|
|
|
{ SC_PKCS15INIT_X509_CRL_SIGN,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER }
|
2002-04-02 13:26:42 +00:00
|
|
|
};
|
|
|
|
|
2005-09-07 09:32:52 +00:00
|
|
|
static sc_usage_map x509_to_pkcs15_public_key_usage[16] = {
|
|
|
|
{ SC_PKCS15INIT_X509_DIGITAL_SIGNATURE,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER },
|
|
|
|
{ SC_PKCS15INIT_X509_NON_REPUDIATION, SC_PKCS15_PRKEY_USAGE_NONREPUDIATION },
|
|
|
|
{ SC_PKCS15INIT_X509_KEY_ENCIPHERMENT, SC_PKCS15_PRKEY_USAGE_WRAP },
|
|
|
|
{ SC_PKCS15INIT_X509_DATA_ENCIPHERMENT, SC_PKCS15_PRKEY_USAGE_ENCRYPT },
|
|
|
|
{ SC_PKCS15INIT_X509_KEY_AGREEMENT, SC_PKCS15_PRKEY_USAGE_DERIVE },
|
|
|
|
{ SC_PKCS15INIT_X509_KEY_CERT_SIGN,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER },
|
|
|
|
{ SC_PKCS15INIT_X509_CRL_SIGN,
|
|
|
|
SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER }
|
2002-04-02 13:26:42 +00:00
|
|
|
};
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
static int
|
2002-04-19 14:23:31 +00:00
|
|
|
sc_pkcs15init_map_usage(unsigned long x509_usage, int _private)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2005-09-07 09:32:52 +00:00
|
|
|
unsigned int p15_usage = 0, n;
|
|
|
|
sc_usage_map *map;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2005-09-07 09:32:52 +00:00
|
|
|
map = _private ? x509_to_pkcs15_private_key_usage
|
2002-04-02 13:26:42 +00:00
|
|
|
: x509_to_pkcs15_public_key_usage;
|
2005-09-07 09:32:52 +00:00
|
|
|
for (n = 0; n < 16; n++) {
|
|
|
|
if (x509_usage & map[n].x509_usage)
|
|
|
|
p15_usage |= map[n].p15_usage;
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
return p15_usage;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
/*
|
|
|
|
* Compute modulus length
|
|
|
|
*/
|
2010-01-10 20:33:32 +00:00
|
|
|
static size_t
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_pkcs15init_keybits(struct sc_pkcs15_bignum *bn)
|
2002-04-15 13:42:10 +00:00
|
|
|
{
|
|
|
|
unsigned int mask, bits;
|
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
if (!bn || !bn->len)
|
|
|
|
return 0;
|
2002-04-15 13:42:10 +00:00
|
|
|
bits = bn->len << 3;
|
2009-11-13 09:45:21 +00:00
|
|
|
for (mask = 0x80; mask && !(bn->data[0] & mask); mask >>= 1)
|
2002-04-15 13:42:10 +00:00
|
|
|
bits--;
|
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2007-01-19 21:08:20 +00:00
|
|
|
/*
|
2011-04-12 18:08:18 +00:00
|
|
|
* Check consistency of the key parameters.
|
2007-01-19 21:08:20 +00:00
|
|
|
*/
|
2010-01-10 20:33:32 +00:00
|
|
|
static int
|
2011-04-12 18:08:18 +00:00
|
|
|
check_keygen_params_consistency(struct sc_card *card, struct sc_pkcs15init_keygen_args *params,
|
|
|
|
unsigned int keybits, unsigned int *out_keybits)
|
2007-01-19 21:08:20 +00:00
|
|
|
{
|
2011-04-22 13:50:01 +00:00
|
|
|
struct sc_context *ctx = card->ctx;
|
2011-04-12 18:08:18 +00:00
|
|
|
unsigned int alg = params->prkey_args.key.algorithm;
|
2011-04-22 13:50:01 +00:00
|
|
|
int i, rv;
|
2007-01-19 21:08:20 +00:00
|
|
|
|
2011-04-22 13:50:01 +00:00
|
|
|
if (alg == SC_ALGORITHM_EC) {
|
|
|
|
struct sc_pkcs15_ec_parameters *ecparams = ¶ms->prkey_args.params.ec;
|
|
|
|
|
|
|
|
rv = sc_pkcs15_fix_ec_parameters(ctx, ecparams);
|
|
|
|
LOG_TEST_RET(ctx, rv, "Cannot fix EC parameters");
|
|
|
|
|
|
|
|
sc_log(ctx, "EC parameters: %s", sc_dump_hex(ecparams->der.value, ecparams->der.len));
|
|
|
|
if (keybits)
|
|
|
|
keybits = ecparams->field_length;
|
|
|
|
}
|
2011-04-12 18:08:18 +00:00
|
|
|
|
|
|
|
if (out_keybits)
|
|
|
|
*out_keybits = keybits;
|
|
|
|
|
2007-01-19 21:08:20 +00:00
|
|
|
for (i = 0; i < card->algorithm_count; i++) {
|
2010-03-04 16:14:30 +00:00
|
|
|
struct sc_algorithm_info *info = &card->algorithms[i];
|
2007-01-19 21:08:20 +00:00
|
|
|
|
|
|
|
if (info->algorithm != alg)
|
|
|
|
continue;
|
2011-04-12 18:08:18 +00:00
|
|
|
|
|
|
|
if (info->key_length != keybits)
|
2007-01-19 21:08:20 +00:00
|
|
|
continue;
|
2011-04-12 18:08:18 +00:00
|
|
|
|
2011-05-01 20:14:06 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2007-01-19 21:08:20 +00:00
|
|
|
}
|
2011-04-12 18:08:18 +00:00
|
|
|
|
2011-04-22 13:50:01 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
|
2007-01-19 21:08:20 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-17 20:47:18 +00:00
|
|
|
/*
|
|
|
|
* Check whether the card has native crypto support for this key.
|
|
|
|
*/
|
|
|
|
static int
|
2011-04-12 13:23:05 +00:00
|
|
|
check_key_compatibility(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *key,
|
|
|
|
unsigned int x509_usage, unsigned int key_length, unsigned int flags)
|
2002-04-17 20:47:18 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_algorithm_info *info;
|
2002-04-17 20:47:18 +00:00
|
|
|
unsigned int count;
|
|
|
|
|
|
|
|
count = p15card->card->algorithm_count;
|
2002-04-18 09:12:26 +00:00
|
|
|
for (info = p15card->card->algorithms; count--; info++) {
|
2011-04-12 13:23:05 +00:00
|
|
|
if (info->algorithm != key->algorithm || info->key_length != key_length || (info->flags & flags) != flags)
|
2002-04-17 20:47:18 +00:00
|
|
|
continue;
|
|
|
|
|
2011-04-12 18:08:18 +00:00
|
|
|
if (key->algorithm == SC_ALGORITHM_RSA) {
|
|
|
|
if (info->u._rsa.exponent != 0 && key->u.rsa.exponent.len != 0) {
|
|
|
|
struct sc_pkcs15_bignum *e = &key->u.rsa.exponent;
|
|
|
|
unsigned long exponent = 0;
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
if (e->len > 4)
|
|
|
|
continue;
|
|
|
|
for (n = 0; n < e->len; n++) {
|
|
|
|
exponent <<= 8;
|
|
|
|
exponent |= e->data[n];
|
|
|
|
}
|
|
|
|
if (info->u._rsa.exponent != exponent)
|
|
|
|
continue;
|
2002-04-17 20:47:18 +00:00
|
|
|
}
|
2011-04-12 18:08:18 +00:00
|
|
|
}
|
|
|
|
else if (key->algorithm == SC_ALGORITHM_EC) {
|
2002-04-17 20:47:18 +00:00
|
|
|
}
|
2002-11-08 14:14:28 +00:00
|
|
|
|
2011-04-12 13:23:05 +00:00
|
|
|
return SC_SUCCESS;
|
2002-04-17 20:47:18 +00:00
|
|
|
}
|
2002-11-08 14:14:28 +00:00
|
|
|
|
2011-04-12 13:23:05 +00:00
|
|
|
return SC_ERROR_OBJECT_NOT_VALID;
|
2003-04-17 12:38:08 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
/*
|
|
|
|
* Check RSA key for consistency, and compute missing
|
|
|
|
* CRT elements
|
|
|
|
*/
|
2004-12-22 09:48:27 +00:00
|
|
|
static int
|
2010-03-04 16:14:30 +00:00
|
|
|
prkey_fixup_rsa(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey_rsa *key)
|
2002-04-15 13:42:10 +00:00
|
|
|
{
|
2011-01-05 16:04:15 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
|
|
|
|
if (!key->modulus.len || !key->exponent.len || !key->d.len || !key->p.len || !key->q.len) {
|
|
|
|
sc_log(ctx, "Missing private RSA coefficient");
|
2002-04-15 13:42:10 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2002-04-15 13:42:10 +00:00
|
|
|
#define GETBN(dst, src, mem) \
|
|
|
|
do { dst.len = BN_num_bytes(src); \
|
|
|
|
assert(dst.len <= sizeof(mem)); \
|
|
|
|
BN_bn2bin(src, dst.data = mem); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* Generate additional parameters.
|
|
|
|
* At least the GPK seems to need the full set of CRT
|
|
|
|
* parameters; storing just the private exponent produces
|
|
|
|
* invalid signatures.
|
|
|
|
* The cryptoflex does not seem to be able to do any sort
|
|
|
|
* of RSA without the full set of CRT coefficients either
|
|
|
|
*/
|
|
|
|
if (!key->dmp1.len || !key->dmq1.len || !key->iqmp.len) {
|
|
|
|
static u8 dmp1[256], dmq1[256], iqmp[256];
|
|
|
|
RSA *rsa;
|
2011-02-05 20:29:52 +00:00
|
|
|
BIGNUM *aux;
|
2011-03-23 15:16:52 +00:00
|
|
|
BN_CTX *bn_ctx;
|
2002-04-15 13:42:10 +00:00
|
|
|
|
|
|
|
rsa = RSA_new();
|
2007-06-21 11:07:00 +00:00
|
|
|
rsa->n = BN_bin2bn(key->modulus.data, key->modulus.len, NULL);
|
|
|
|
rsa->e = BN_bin2bn(key->exponent.data, key->exponent.len, NULL);
|
|
|
|
rsa->d = BN_bin2bn(key->d.data, key->d.len, NULL);
|
|
|
|
rsa->p = BN_bin2bn(key->p.data, key->p.len, NULL);
|
|
|
|
rsa->q = BN_bin2bn(key->q.data, key->q.len, NULL);
|
2002-04-15 13:42:10 +00:00
|
|
|
if (!rsa->dmp1)
|
|
|
|
rsa->dmp1 = BN_new();
|
|
|
|
if (!rsa->dmq1)
|
|
|
|
rsa->dmq1 = BN_new();
|
|
|
|
if (!rsa->iqmp)
|
|
|
|
rsa->iqmp = BN_new();
|
|
|
|
|
|
|
|
aux = BN_new();
|
2011-03-23 15:16:52 +00:00
|
|
|
bn_ctx = BN_CTX_new();
|
2002-04-15 13:42:10 +00:00
|
|
|
|
|
|
|
BN_sub(aux, rsa->q, BN_value_one());
|
2011-03-23 15:16:52 +00:00
|
|
|
BN_mod(rsa->dmq1, rsa->d, aux, bn_ctx);
|
2002-04-15 13:42:10 +00:00
|
|
|
|
|
|
|
BN_sub(aux, rsa->p, BN_value_one());
|
2011-03-23 15:16:52 +00:00
|
|
|
BN_mod(rsa->dmp1, rsa->d, aux, bn_ctx);
|
2002-04-15 13:42:10 +00:00
|
|
|
|
2011-03-23 15:16:52 +00:00
|
|
|
BN_mod_inverse(rsa->iqmp, rsa->q, rsa->p, bn_ctx);
|
2002-04-15 13:42:10 +00:00
|
|
|
|
|
|
|
BN_clear_free(aux);
|
2011-03-23 15:16:52 +00:00
|
|
|
BN_CTX_free(bn_ctx);
|
2002-04-15 13:42:10 +00:00
|
|
|
|
|
|
|
/* Not thread safe, but much better than a memory leak */
|
|
|
|
GETBN(key->dmp1, rsa->dmp1, dmp1);
|
|
|
|
GETBN(key->dmq1, rsa->dmq1, dmq1);
|
|
|
|
GETBN(key->iqmp, rsa->iqmp, iqmp);
|
|
|
|
RSA_free(rsa);
|
|
|
|
}
|
|
|
|
#undef GETBN
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
static int
|
2010-03-04 16:14:30 +00:00
|
|
|
prkey_fixup(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *key)
|
2002-04-15 13:42:10 +00:00
|
|
|
{
|
2002-06-17 10:58:04 +00:00
|
|
|
switch (key->algorithm) {
|
|
|
|
case SC_ALGORITHM_RSA:
|
2003-10-14 09:57:29 +00:00
|
|
|
return prkey_fixup_rsa(p15card, &key->u.rsa);
|
2002-06-17 10:58:04 +00:00
|
|
|
case SC_ALGORITHM_DSA:
|
2009-10-05 20:10:07 +00:00
|
|
|
case SC_ALGORITHM_GOSTR3410:
|
2002-06-17 10:58:04 +00:00
|
|
|
/* for now */
|
|
|
|
return 0;
|
|
|
|
}
|
2002-04-15 13:42:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
static int
|
2010-03-04 16:14:30 +00:00
|
|
|
prkey_bits(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *key)
|
2002-06-17 10:58:04 +00:00
|
|
|
{
|
2011-01-05 16:04:15 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
switch (key->algorithm) {
|
|
|
|
case SC_ALGORITHM_RSA:
|
|
|
|
return sc_pkcs15init_keybits(&key->u.rsa.modulus);
|
|
|
|
case SC_ALGORITHM_DSA:
|
|
|
|
return sc_pkcs15init_keybits(&key->u.dsa.q);
|
2009-10-05 20:10:07 +00:00
|
|
|
case SC_ALGORITHM_GOSTR3410:
|
2011-01-05 16:04:15 +00:00
|
|
|
if (sc_pkcs15init_keybits(&key->u.gostr3410.d) > SC_PKCS15_GOSTR3410_KEYSIZE) {
|
|
|
|
sc_log(ctx, "Unsupported key (keybits %u)", sc_pkcs15init_keybits(&key->u.gostr3410.d));
|
2009-10-05 20:10:07 +00:00
|
|
|
return SC_ERROR_OBJECT_NOT_VALID;
|
|
|
|
}
|
|
|
|
return SC_PKCS15_GOSTR3410_KEYSIZE;
|
2002-06-17 10:58:04 +00:00
|
|
|
}
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Unsupported key algorithm.");
|
2002-06-17 10:58:04 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
static int
|
2010-03-04 16:14:30 +00:00
|
|
|
prkey_pkcs15_algo(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *key)
|
2002-06-17 10:58:04 +00:00
|
|
|
{
|
2011-01-05 16:04:15 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
|
2002-06-17 10:58:04 +00:00
|
|
|
switch (key->algorithm) {
|
|
|
|
case SC_ALGORITHM_RSA:
|
|
|
|
return SC_PKCS15_TYPE_PRKEY_RSA;
|
|
|
|
case SC_ALGORITHM_DSA:
|
|
|
|
return SC_PKCS15_TYPE_PRKEY_DSA;
|
2009-10-05 20:10:07 +00:00
|
|
|
case SC_ALGORITHM_GOSTR3410:
|
|
|
|
return SC_PKCS15_TYPE_PRKEY_GOSTR3410;
|
2011-04-12 18:08:18 +00:00
|
|
|
case SC_ALGORITHM_EC:
|
|
|
|
return SC_PKCS15_TYPE_PRKEY_EC;
|
2002-06-17 10:58:04 +00:00
|
|
|
}
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Unsupported key algorithm.");
|
2002-06-17 10:58:04 +00:00
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-19 09:22:44 +00:00
|
|
|
static struct sc_pkcs15_df *
|
2005-08-05 19:07:24 +00:00
|
|
|
find_df_by_type(struct sc_pkcs15_card *p15card, unsigned int type)
|
2002-04-19 09:22:44 +00:00
|
|
|
{
|
|
|
|
struct sc_pkcs15_df *df = p15card->df_list;
|
|
|
|
|
|
|
|
while (df != NULL && df->type != type)
|
|
|
|
df = df->next;
|
|
|
|
return df;
|
|
|
|
}
|
|
|
|
|
2010-02-02 17:18:06 +00:00
|
|
|
|
|
|
|
static int
|
2010-03-04 16:14:30 +00:00
|
|
|
select_intrinsic_id(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
int type, struct sc_pkcs15_id *id, void *data)
|
2009-11-13 09:45:21 +00:00
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_pkcs15_pubkey *pubkey = NULL;
|
|
|
|
unsigned id_style = profile->id_style;
|
|
|
|
int rv, allocated = 0;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2009-11-13 09:45:21 +00:00
|
|
|
#ifndef ENABLE_OPENSSL
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2009-11-13 09:45:21 +00:00
|
|
|
#else
|
|
|
|
/* ID already exists */
|
|
|
|
if (id->len)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
/* Native ID style is not an intrisic one */
|
|
|
|
if (profile->id_style == SC_PKCS15INIT_ID_STYLE_NATIVE)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
/* Get PKCS15 public key */
|
|
|
|
switch(type) {
|
|
|
|
case SC_PKCS15_TYPE_CERT_X509:
|
|
|
|
rv = sc_pkcs15_pubkey_from_cert(ctx, (struct sc_pkcs15_der *)data, &pubkey);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, rv, "X509 parse error");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
allocated = 1;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
rv = sc_pkcs15_pubkey_from_prvkey(ctx, (struct sc_pkcs15_prkey *)data, &pubkey);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, rv, "Cannot get public key");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
allocated = 1;
|
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
pubkey = (struct sc_pkcs15_pubkey *)data;
|
|
|
|
|
|
|
|
allocated = 0;
|
|
|
|
break;
|
|
|
|
default:
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Intrinsic ID is not implemented for the object type 0x%X", type);
|
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2009-11-13 09:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip silently if key is not inintialized. */
|
|
|
|
if (pubkey->algorithm == SC_ALGORITHM_RSA && !pubkey->u.rsa.modulus.len)
|
|
|
|
goto done;
|
|
|
|
else if (pubkey->algorithm == SC_ALGORITHM_DSA && !pubkey->u.dsa.pub.data)
|
|
|
|
goto done;
|
2009-11-19 15:41:03 +00:00
|
|
|
else if (pubkey->algorithm == SC_ALGORITHM_GOSTR3410 &&
|
|
|
|
!pubkey->u.gostr3410.xy.data)
|
2009-11-13 09:45:21 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* In Mozilla 'GOST R 34.10' is not yet supported.
|
|
|
|
* So, switch to the ID recommended by RFC2459 */
|
|
|
|
if (pubkey->algorithm == SC_ALGORITHM_GOSTR3410 && id_style == SC_PKCS15INIT_ID_STYLE_MOZILLA)
|
|
|
|
id_style = SC_PKCS15INIT_ID_STYLE_RFC2459;
|
|
|
|
|
|
|
|
if (id_style == SC_PKCS15INIT_ID_STYLE_MOZILLA) {
|
|
|
|
if (pubkey->algorithm == SC_ALGORITHM_RSA)
|
|
|
|
SHA1(pubkey->u.rsa.modulus.data, pubkey->u.rsa.modulus.len, id->value);
|
|
|
|
else if (pubkey->algorithm == SC_ALGORITHM_DSA)
|
|
|
|
SHA1(pubkey->u.dsa.pub.data, pubkey->u.dsa.pub.len, id->value);
|
2011-04-22 13:50:01 +00:00
|
|
|
else if (pubkey->algorithm == SC_ALGORITHM_EC)
|
|
|
|
SHA1(pubkey->u.ec.ecpointQ.value, pubkey->u.ec.ecpointQ.len, id->value);
|
2009-11-13 09:45:21 +00:00
|
|
|
else
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
id->len = SHA_DIGEST_LENGTH;
|
|
|
|
}
|
|
|
|
else if (id_style == SC_PKCS15INIT_ID_STYLE_RFC2459) {
|
|
|
|
unsigned char *id_data = NULL;
|
|
|
|
size_t id_data_len = 0;
|
|
|
|
|
|
|
|
rv = sc_pkcs15_encode_pubkey(ctx, pubkey, &id_data, &id_data_len);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, rv, "Encoding public key error");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
if (!id_data || !id_data_len)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "Encoding public key error");
|
2009-11-13 09:45:21 +00:00
|
|
|
|
|
|
|
SHA1(id_data, id_data_len, id->value);
|
|
|
|
id->len = SHA_DIGEST_LENGTH;
|
|
|
|
|
|
|
|
free(id_data);
|
|
|
|
}
|
|
|
|
else {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Unsupported ID style: %i", profile->id_style);
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Non supported ID style");
|
2009-11-13 09:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (allocated)
|
|
|
|
sc_pkcs15_free_pubkey(pubkey);
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, id->len);
|
2009-11-13 09:45:21 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-02-02 17:18:06 +00:00
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
static int
|
|
|
|
select_id(struct sc_pkcs15_card *p15card, int type, struct sc_pkcs15_id *id)
|
2002-12-04 13:25:31 +00:00
|
|
|
{
|
2011-01-02 13:55:03 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2010-01-10 20:33:32 +00:00
|
|
|
struct sc_pkcs15_id unused_id;
|
2003-10-13 16:13:12 +00:00
|
|
|
struct sc_pkcs15_object *obj;
|
2010-01-10 20:33:32 +00:00
|
|
|
unsigned int nid = DEFAULT_ID;
|
2003-10-13 16:13:12 +00:00
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2003-10-13 16:13:12 +00:00
|
|
|
/* If the user provided an ID, make sure we can use it */
|
|
|
|
if (id->len != 0) {
|
2003-10-30 11:13:11 +00:00
|
|
|
r = sc_pkcs15_find_object_by_id(p15card, type, id, &obj);
|
2011-01-02 13:55:03 +00:00
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND)
|
|
|
|
r = 0;
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&unused_id, 0, sizeof(unused_id));
|
|
|
|
while (nid < 255) {
|
|
|
|
id->value[0] = nid++;
|
|
|
|
id->len = 1;
|
|
|
|
|
2003-10-30 11:13:11 +00:00
|
|
|
r = sc_pkcs15_find_object_by_id(p15card, type, id, &obj);
|
2003-10-13 16:13:12 +00:00
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
|
2003-10-30 11:13:11 +00:00
|
|
|
/* We don't have an object of that type yet.
|
|
|
|
* If we're allocating a PRKEY object, make
|
|
|
|
* sure there's no conflicting pubkey or cert
|
|
|
|
* object either. */
|
|
|
|
if (type == SC_PKCS15_TYPE_PRKEY) {
|
2010-03-04 16:14:30 +00:00
|
|
|
struct sc_pkcs15_search_key search_key;
|
2003-10-30 11:13:11 +00:00
|
|
|
|
|
|
|
memset(&search_key, 0, sizeof(search_key));
|
2011-01-02 13:55:03 +00:00
|
|
|
search_key.class_mask = SC_PKCS15_SEARCH_CLASS_PUBKEY | SC_PKCS15_SEARCH_CLASS_CERT;
|
2003-10-30 11:13:11 +00:00
|
|
|
search_key.id = id;
|
|
|
|
|
2011-01-02 13:55:03 +00:00
|
|
|
r = sc_pkcs15_search_objects(p15card, &search_key, NULL, 0);
|
2003-10-30 11:13:11 +00:00
|
|
|
/* If there is a pubkey or cert with
|
|
|
|
* this ID, skip it. */
|
|
|
|
if (r > 0)
|
|
|
|
continue;
|
|
|
|
}
|
2003-10-13 16:13:12 +00:00
|
|
|
if (!unused_id.len)
|
|
|
|
unused_id = *id;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unused_id.len) {
|
|
|
|
*id = unused_id;
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, 0);
|
2002-12-04 13:25:31 +00:00
|
|
|
}
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_ERROR_TOO_MANY_OBJECTS);
|
2002-12-04 13:25:31 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
/*
|
|
|
|
* Select a path for a new object
|
|
|
|
* 1. If the object is to be protected by a PIN, use the path
|
|
|
|
* given in the PIN auth object
|
|
|
|
* 2. Otherwise, use the path of the application DF
|
|
|
|
* 3. If the profile defines a key-dir template, the new object
|
|
|
|
* should go into a subdirectory of the selected DF:
|
|
|
|
* Instantiate the template, using the ID of the new object
|
|
|
|
* to uniquify the path. Inside the instantiated template,
|
|
|
|
* look for a file corresponding to the type of object we
|
|
|
|
* wish to create ("private-key", "public-key" etc).
|
|
|
|
*/
|
2010-04-02 11:55:13 +00:00
|
|
|
static const char *
|
2010-03-05 10:37:11 +00:00
|
|
|
get_template_name_from_object (struct sc_pkcs15_object *obj)
|
2010-01-16 21:52:47 +00:00
|
|
|
{
|
|
|
|
switch (obj->type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
return "private-key";
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
return "public-key";
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
return "certificate";
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
if (obj->flags & SC_PKCS15_CO_FLAG_PRIVATE)
|
|
|
|
return "privdata";
|
|
|
|
else
|
|
|
|
return "data";
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2010-01-16 21:52:47 +00:00
|
|
|
static int
|
2010-03-05 10:37:11 +00:00
|
|
|
get_object_path_from_object (struct sc_pkcs15_object *obj,
|
2010-01-16 21:52:47 +00:00
|
|
|
struct sc_path *ret_path)
|
|
|
|
{
|
|
|
|
if (!ret_path)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
|
|
|
memset(ret_path, 0, sizeof(struct sc_path));
|
|
|
|
|
|
|
|
switch(obj->type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
2010-03-04 13:05:03 +00:00
|
|
|
*ret_path = ((struct sc_pkcs15_prkey_info *)obj->data)->path;
|
2010-01-16 21:52:47 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
2010-03-04 13:05:03 +00:00
|
|
|
*ret_path = ((struct sc_pkcs15_pubkey_info *)obj->data)->path;
|
2010-01-16 21:52:47 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
2010-03-04 13:05:03 +00:00
|
|
|
*ret_path = ((struct sc_pkcs15_cert_info *)obj->data)->path;
|
2010-01-16 21:52:47 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
2010-03-04 13:05:03 +00:00
|
|
|
*ret_path = ((struct sc_pkcs15_data_info *)obj->data)->path;
|
2010-01-16 21:52:47 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
case SC_PKCS15_TYPE_AUTH:
|
2010-03-04 13:05:03 +00:00
|
|
|
*ret_path = ((struct sc_pkcs15_pin_info *)obj->data)->path;
|
2010-01-16 21:52:47 +00:00
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
static int
|
2010-03-04 13:05:03 +00:00
|
|
|
select_object_path(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
2010-03-05 10:37:11 +00:00
|
|
|
struct sc_pkcs15_object *obj, struct sc_path *path)
|
2003-10-13 16:13:12 +00:00
|
|
|
{
|
2010-01-16 21:52:47 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_file *file;
|
|
|
|
struct sc_pkcs15_object *objs[32];
|
|
|
|
struct sc_pkcs15_id indx_id;
|
|
|
|
struct sc_path obj_path;
|
|
|
|
int ii, r, nn_objs, indx;
|
2003-10-13 16:13:12 +00:00
|
|
|
const char *name;
|
2010-01-16 21:52:47 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
fix:
CK_MECHANISM rsa_mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 };
C_GenerateKeyPair(..., &rsa_mech, ..., ..., ..., ..., ..., ...); -> ... -> sc_pkcs15init_store_public_key -> sc_pkcs15init_store_data -> select_object_path -> sc_pkcs15_get_objects: return 0 -> CKR_OK
($ pkcs15-tool --list-public-keys:
Public RSA Key [Public Key]
...
Path : 3f0050000200
)
CK_MECHANISM gost_mech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL, 0 };
C_GenerateKeyPair(..., &gost_mech, ..., ..., ..., ..., ..., ...); -> ... -> sc_pkcs15init_store_public_key -> sc_pkcs15init_store_data -> select_object_path -> sc_pkcs15_get_objects: return 0 -> CKR_OK
($ pkcs15-tool --list-public-keys:
Public RSA Key [Public Key]
...
Path : 3f0050000200
Public GOSTR3410 Key [Public Key]
...
Path : 3f0050000200
)
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3923 c6295689-39f2-0310-b995-f0e70906c6a9
2010-01-22 12:01:17 +00:00
|
|
|
r = sc_pkcs15_get_objects(p15card, obj->type & SC_PKCS15_TYPE_CLASS_MASK,
|
|
|
|
objs, sizeof(objs)/sizeof(objs[0]));
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Get PKCS#15 objects error");
|
2010-01-16 21:52:47 +00:00
|
|
|
nn_objs = r;
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
/* For cards with a pin-domain profile, we need
|
2010-01-16 21:52:47 +00:00
|
|
|
* to put the key below the DF of the specified PIN
|
|
|
|
*/
|
2003-10-13 16:13:12 +00:00
|
|
|
memset(path, 0, sizeof(*path));
|
2007-01-19 21:08:20 +00:00
|
|
|
if (obj->auth_id.len && profile->pin_domains != 0) {
|
2003-10-13 16:13:12 +00:00
|
|
|
r = sc_pkcs15init_get_pin_path(p15card, &obj->auth_id, path);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot get PIN path");
|
2010-01-16 21:52:47 +00:00
|
|
|
}
|
|
|
|
else {
|
2003-10-13 16:13:12 +00:00
|
|
|
*path = profile->df_info->file->path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the profile specifies a key directory template,
|
|
|
|
* instantiate it now and create the DF
|
|
|
|
*/
|
2010-03-05 10:37:11 +00:00
|
|
|
name = get_template_name_from_object (obj);
|
2010-01-16 21:52:47 +00:00
|
|
|
if (!name)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2003-10-13 16:13:12 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "key-domain.%s @%s (auth_id.len=%d)", name, sc_print_path(path), obj->auth_id.len);
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2010-01-16 21:52:47 +00:00
|
|
|
indx_id.len = 1;
|
|
|
|
for (indx = TEMPLATE_INSTANTIATE_MIN_INDEX; indx <= TEMPLATE_INSTANTIATE_MAX_INDEX; indx++) {
|
|
|
|
indx_id.value[0] = indx;
|
|
|
|
r = sc_profile_instantiate_template(profile, "key-domain", path, name, &indx_id, &file);
|
2010-01-25 16:42:22 +00:00
|
|
|
if (r == SC_ERROR_TEMPLATE_NOT_FOUND) {
|
2010-02-21 18:24:41 +00:00
|
|
|
/* No template in 'key-domain' -- try to instantiate the template-'object name'
|
2010-01-25 16:42:22 +00:00
|
|
|
* outside of the 'key-domain' scope. */
|
|
|
|
char t_name[0x40];
|
|
|
|
|
|
|
|
snprintf(t_name, sizeof(t_name), "template-%s", name);
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "get instance %i of '%s'", indx, t_name);
|
2010-01-25 16:42:22 +00:00
|
|
|
r = sc_profile_get_file_instance(profile, t_name, indx, &file);
|
|
|
|
}
|
2003-10-13 16:13:12 +00:00
|
|
|
if (r == SC_ERROR_TEMPLATE_NOT_FOUND)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
|
|
|
LOG_TEST_RET(ctx, r, "Template instantiation error");
|
2010-01-16 21:52:47 +00:00
|
|
|
|
2010-01-21 09:41:40 +00:00
|
|
|
if (file->type == SC_FILE_TYPE_BSO)
|
|
|
|
break;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "instantiated template path %s", sc_print_path(&file->path));
|
2010-01-16 21:52:47 +00:00
|
|
|
for (ii=0; ii<nn_objs; ii++) {
|
2010-03-05 10:37:11 +00:00
|
|
|
r = get_object_path_from_object(objs[ii], &obj_path);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to get object path from pkcs15 object");
|
2010-01-16 21:52:47 +00:00
|
|
|
|
|
|
|
if (obj_path.len != file->path.len)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!memcmp(obj_path.value, file->path.value, obj_path.len))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ii==nn_objs)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (obj_path.len != file->path.len)
|
|
|
|
break;
|
|
|
|
|
|
|
|
sc_file_free(file);
|
|
|
|
|
|
|
|
indx_id.value[0] += 1;
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
2010-01-16 21:52:47 +00:00
|
|
|
if (indx > TEMPLATE_INSTANTIATE_MAX_INDEX)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_TOO_MANY_OBJECTS, "Template instantiation error");
|
2010-01-16 21:52:47 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
*path = file->path;
|
|
|
|
sc_file_free(file);
|
2010-01-16 21:52:47 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "returns object path '%s'", sc_print_path(path));
|
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
2002-04-15 13:42:10 +00:00
|
|
|
/*
|
|
|
|
* Update EF(DIR)
|
|
|
|
*/
|
2002-04-02 13:26:42 +00:00
|
|
|
static int
|
|
|
|
sc_pkcs15init_update_dir(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
2010-02-02 18:15:53 +00:00
|
|
|
struct sc_app_info *app)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_card *card = p15card->card;
|
2010-02-02 18:15:53 +00:00
|
|
|
int r, retry = 1;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-03-18 09:10:51 +00:00
|
|
|
if (profile->ops->emu_update_dir) {
|
2010-07-02 13:46:13 +00:00
|
|
|
r = profile->ops->emu_update_dir(profile, p15card, app);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2010-03-18 09:10:51 +00:00
|
|
|
}
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
do {
|
|
|
|
struct sc_file *dir_file;
|
|
|
|
struct sc_path path;
|
|
|
|
|
|
|
|
r = sc_enum_apps(card);
|
|
|
|
if (r != SC_ERROR_FILE_NOT_FOUND)
|
|
|
|
break;
|
2010-02-02 18:15:53 +00:00
|
|
|
/* DIR file is not yet created. */
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
sc_format_path("3F002F00", &path);
|
2010-02-02 18:15:53 +00:00
|
|
|
r = sc_profile_get_file_by_path(profile, &path, &dir_file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "DIR file not defined in profile");
|
2010-02-02 18:15:53 +00:00
|
|
|
|
|
|
|
/* Create DIR file */
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_update_file(profile, p15card, dir_file, NULL, 0);
|
2002-04-02 13:26:42 +00:00
|
|
|
sc_file_free(dir_file);
|
|
|
|
} while (retry--);
|
|
|
|
|
|
|
|
if (r >= 0) {
|
|
|
|
card->app[card->app_count++] = app;
|
|
|
|
r = sc_update_dir(card, NULL);
|
|
|
|
}
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
static char *
|
2010-03-04 16:14:30 +00:00
|
|
|
get_generalized_time(struct sc_context *ctx)
|
2005-08-05 19:07:24 +00:00
|
|
|
{
|
|
|
|
#ifdef HAVE_GETTIMEOFDAY
|
|
|
|
struct timeval tv;
|
|
|
|
#endif
|
|
|
|
struct tm *tm_time;
|
|
|
|
time_t t;
|
|
|
|
char* ret;
|
|
|
|
size_t r;
|
|
|
|
|
|
|
|
#ifdef HAVE_GETTIMEOFDAY
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
t = tv.tv_sec;
|
|
|
|
#else
|
|
|
|
t = time(NULL);
|
|
|
|
#endif
|
|
|
|
tm_time = gmtime(&t);
|
|
|
|
if (tm_time == NULL) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "error: gmtime failed");
|
2005-08-05 19:07:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = calloc(1, 16);
|
|
|
|
if (ret == NULL) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "error: calloc failed");
|
2005-08-05 19:07:24 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* print time in generalized time format */
|
|
|
|
r = strftime(ret, 16, "%Y%m%d%H%M%SZ", tm_time);
|
|
|
|
if (r == 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "error: strftime failed");
|
2005-08-05 19:07:24 +00:00
|
|
|
free(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
static int
|
|
|
|
sc_pkcs15init_update_tokeninfo(struct sc_pkcs15_card *p15card,
|
2002-04-02 13:26:42 +00:00
|
|
|
struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
struct sc_card *card = p15card->card;
|
2010-03-04 16:14:30 +00:00
|
|
|
struct sc_pkcs15_tokeninfo tokeninfo;
|
|
|
|
unsigned char *buf = NULL;
|
2002-04-02 13:26:42 +00:00
|
|
|
size_t size;
|
|
|
|
int r;
|
|
|
|
|
2005-08-05 19:07:24 +00:00
|
|
|
/* set lastUpdate field */
|
2010-10-05 15:44:58 +00:00
|
|
|
if (p15card->tokeninfo->last_update != NULL)
|
|
|
|
free(p15card->tokeninfo->last_update);
|
|
|
|
p15card->tokeninfo->last_update = get_generalized_time(card->ctx);
|
|
|
|
if (p15card->tokeninfo->last_update == NULL)
|
2005-08-05 19:07:24 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
|
2010-10-05 15:44:58 +00:00
|
|
|
tokeninfo = *(p15card->tokeninfo);
|
2006-03-07 07:22:58 +00:00
|
|
|
|
2010-03-18 09:20:33 +00:00
|
|
|
if (profile->ops->emu_update_tokeninfo)
|
2010-07-02 13:46:13 +00:00
|
|
|
return profile->ops->emu_update_tokeninfo(profile, p15card, &tokeninfo);
|
2010-03-18 09:20:33 +00:00
|
|
|
|
2006-03-07 07:22:58 +00:00
|
|
|
r = sc_pkcs15_encode_tokeninfo(card->ctx, &tokeninfo, &buf, &size);
|
2002-04-02 13:26:42 +00:00
|
|
|
if (r >= 0)
|
2010-03-18 10:15:51 +00:00
|
|
|
r = sc_pkcs15init_update_file(profile, p15card, p15card->file_tokeninfo, buf, size);
|
2002-04-02 13:26:42 +00:00
|
|
|
if (buf)
|
|
|
|
free(buf);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15init_update_odf(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile)
|
|
|
|
{
|
2010-01-27 17:53:51 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
unsigned char *buf = NULL;
|
2002-04-02 13:26:42 +00:00
|
|
|
size_t size;
|
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-01-27 17:53:51 +00:00
|
|
|
r = sc_pkcs15_encode_odf(ctx, p15card, &buf, &size);
|
2002-04-02 13:26:42 +00:00
|
|
|
if (r >= 0)
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_update_file(profile, p15card,
|
2002-04-02 13:26:42 +00:00
|
|
|
p15card->file_odf, buf, size);
|
|
|
|
if (buf)
|
|
|
|
free(buf);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2004-01-06 14:30:24 +00:00
|
|
|
/*
|
|
|
|
* Update any PKCS15 DF file (except ODF and DIR)
|
|
|
|
*/
|
2006-01-03 16:24:54 +00:00
|
|
|
int
|
2010-02-02 17:18:06 +00:00
|
|
|
sc_pkcs15init_update_any_df(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_df *df,
|
2004-01-06 14:30:24 +00:00
|
|
|
int is_new)
|
|
|
|
{
|
2010-02-02 17:18:06 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2004-01-06 14:30:24 +00:00
|
|
|
struct sc_card *card = p15card->card;
|
2011-04-10 04:09:33 +00:00
|
|
|
struct sc_file *file = NULL;
|
2010-02-02 17:18:06 +00:00
|
|
|
unsigned char *buf = NULL;
|
2004-01-06 14:30:24 +00:00
|
|
|
size_t bufsize;
|
|
|
|
int update_odf = is_new, r = 0;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2011-04-10 04:09:33 +00:00
|
|
|
sc_profile_get_file_by_path(profile, &df->path, &file);
|
|
|
|
if (file == NULL)
|
|
|
|
sc_select_file(card, &df->path, &file);
|
2004-01-06 14:30:24 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15_encode_df(card->ctx, p15card, df, &buf, &bufsize);
|
|
|
|
if (r >= 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_update_file(profile, p15card, file, buf, bufsize);
|
2004-01-06 14:30:24 +00:00
|
|
|
|
|
|
|
/* For better performance and robustness, we want
|
|
|
|
* to note which portion of the file actually
|
|
|
|
* contains valid data.
|
|
|
|
*
|
|
|
|
* This is particularly useful if we store certificates
|
|
|
|
* directly in the CDF - we may want to make the CDF
|
|
|
|
* fairly big, without having to read the entire file
|
|
|
|
* every time we parse the CDF.
|
|
|
|
*/
|
|
|
|
if (profile->pkcs15.encode_df_length) {
|
|
|
|
df->path.count = bufsize;
|
|
|
|
df->path.index = 0;
|
|
|
|
update_odf = 1;
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
}
|
2011-04-10 04:09:33 +00:00
|
|
|
if (file)
|
|
|
|
sc_file_free(file);
|
2004-01-06 14:30:24 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to encode or update xDF");
|
2010-02-02 17:18:06 +00:00
|
|
|
|
2004-01-06 14:30:24 +00:00
|
|
|
/* Now update the ODF if we have to */
|
2010-02-02 17:18:06 +00:00
|
|
|
if (update_odf)
|
2004-01-06 14:30:24 +00:00
|
|
|
r = sc_pkcs15init_update_odf(p15card, profile);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to encode or update ODF");
|
2004-01-06 14:30:24 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2004-01-06 14:30:24 +00:00
|
|
|
}
|
|
|
|
|
2003-11-19 20:37:02 +00:00
|
|
|
/*
|
|
|
|
* Add an object to one of the pkcs15 directory files.
|
|
|
|
*/
|
2011-04-15 17:11:38 +00:00
|
|
|
int
|
2011-05-01 20:14:06 +00:00
|
|
|
sc_pkcs15init_add_object(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
unsigned int df_type, struct sc_pkcs15_object *object)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-01-27 17:53:51 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-04-19 10:01:01 +00:00
|
|
|
struct sc_pkcs15_df *df;
|
2010-03-01 15:29:39 +00:00
|
|
|
int is_new = 0, r = 0, object_added = 0;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
sc_log(ctx, "add object %p to DF of type %u", object, df_type);
|
2003-11-19 20:37:02 +00:00
|
|
|
|
2002-04-19 10:01:01 +00:00
|
|
|
df = find_df_by_type(p15card, df_type);
|
2011-02-05 20:38:49 +00:00
|
|
|
if (df == NULL) {
|
|
|
|
struct sc_file *file;
|
2002-04-02 13:26:42 +00:00
|
|
|
file = profile->df[df_type];
|
|
|
|
if (file == NULL) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Profile doesn't define a DF file %u", df_type);
|
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "DF not found in profile");
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
2011-04-10 04:09:33 +00:00
|
|
|
sc_pkcs15_add_df(p15card, df_type, &file->path);
|
2002-04-19 09:22:44 +00:00
|
|
|
df = find_df_by_type(p15card, df_type);
|
|
|
|
assert(df != NULL);
|
2004-01-06 14:30:24 +00:00
|
|
|
is_new = 1;
|
2003-10-13 16:13:12 +00:00
|
|
|
|
|
|
|
/* Mark the df as enumerated, so libopensc doesn't try
|
|
|
|
* to load the file at a most inconvenient moment */
|
|
|
|
df->enumerated = 1;
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
if (object == NULL) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Add nothing; just instantiate this directory file");
|
2003-10-13 16:13:12 +00:00
|
|
|
} else if (object->df == NULL) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Append object");
|
2002-04-19 10:01:01 +00:00
|
|
|
object->df = df;
|
2010-03-01 15:29:39 +00:00
|
|
|
r = sc_pkcs15_add_object(p15card, object);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to add pkcs15 object");
|
2010-03-01 15:29:39 +00:00
|
|
|
object_added = 1;
|
2003-10-13 16:13:12 +00:00
|
|
|
} else {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Reuse existing object");
|
2003-10-13 16:13:12 +00:00
|
|
|
assert(object->df == df);
|
2002-04-19 10:01:01 +00:00
|
|
|
}
|
|
|
|
|
2010-03-18 09:10:51 +00:00
|
|
|
if (profile->ops->emu_update_any_df)
|
2010-07-02 13:46:13 +00:00
|
|
|
r = profile->ops->emu_update_any_df(profile, p15card, SC_AC_OP_CREATE, object);
|
2010-03-18 09:10:51 +00:00
|
|
|
else
|
|
|
|
r = sc_pkcs15init_update_any_df(p15card, profile, df, is_new);
|
|
|
|
|
2010-03-01 15:29:39 +00:00
|
|
|
if (r < 0 && object_added)
|
|
|
|
sc_pkcs15_remove_object(p15card, object);
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2004-01-06 14:30:24 +00:00
|
|
|
}
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_pkcs15_object *
|
2011-04-12 18:08:18 +00:00
|
|
|
sc_pkcs15init_new_object(int type, const char *label, struct sc_pkcs15_id *auth_id, void *data)
|
2003-10-16 14:32:42 +00:00
|
|
|
{
|
2010-02-02 16:45:47 +00:00
|
|
|
struct sc_pkcs15_object *object;
|
2010-03-04 16:14:30 +00:00
|
|
|
unsigned int data_size = 0;
|
2003-10-16 14:32:42 +00:00
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
object = calloc(1, sizeof(*object));
|
2005-01-03 17:25:18 +00:00
|
|
|
if (object == NULL)
|
|
|
|
return NULL;
|
2003-10-16 14:32:42 +00:00
|
|
|
object->type = type;
|
|
|
|
|
|
|
|
switch (type & SC_PKCS15_TYPE_CLASS_MASK) {
|
|
|
|
case SC_PKCS15_TYPE_AUTH:
|
|
|
|
object->flags = DEFAULT_PIN_FLAGS;
|
2010-03-04 16:14:30 +00:00
|
|
|
data_size = sizeof(struct sc_pkcs15_pin_info);
|
2003-10-16 14:32:42 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
|
|
|
object->flags = DEFAULT_PRKEY_FLAGS;
|
2010-03-04 16:14:30 +00:00
|
|
|
data_size = sizeof(struct sc_pkcs15_prkey_info);
|
2003-10-16 14:32:42 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
|
|
|
object->flags = DEFAULT_PUBKEY_FLAGS;
|
2010-03-04 16:14:30 +00:00
|
|
|
data_size = sizeof(struct sc_pkcs15_pubkey_info);
|
2003-10-16 14:32:42 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
|
|
|
object->flags = DEFAULT_CERT_FLAGS;
|
2010-03-04 16:14:30 +00:00
|
|
|
data_size = sizeof(struct sc_pkcs15_cert_info);
|
2003-10-16 14:32:42 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
|
|
|
object->flags = DEFAULT_DATA_FLAGS;
|
2007-06-21 09:37:18 +00:00
|
|
|
if (auth_id->len != 0)
|
|
|
|
object->flags |= SC_PKCS15_CO_FLAG_PRIVATE;
|
2010-03-04 16:14:30 +00:00
|
|
|
data_size = sizeof(struct sc_pkcs15_data_info);
|
2003-10-16 14:32:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data_size) {
|
|
|
|
object->data = calloc(1, data_size);
|
|
|
|
if (data)
|
|
|
|
memcpy(object->data, data, data_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (label)
|
2006-07-12 08:12:38 +00:00
|
|
|
strlcpy(object->label, label, sizeof(object->label));
|
2003-10-16 14:32:42 +00:00
|
|
|
if (auth_id)
|
|
|
|
object->auth_id = *auth_id;
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
|
2003-06-27 11:59:37 +00:00
|
|
|
int
|
2011-05-01 20:14:06 +00:00
|
|
|
sc_pkcs15init_change_attrib(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_pkcs15_object *object,
|
|
|
|
int new_attrib_type, void *new_value, int new_len)
|
2003-06-27 11:59:37 +00:00
|
|
|
{
|
2011-05-01 20:14:06 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2003-06-27 11:59:37 +00:00
|
|
|
struct sc_card *card = p15card->card;
|
2010-03-04 16:14:30 +00:00
|
|
|
unsigned char *buf = NULL;
|
2003-06-27 11:59:37 +00:00
|
|
|
size_t bufsize;
|
|
|
|
int df_type, r = 0;
|
|
|
|
struct sc_pkcs15_df *df;
|
2010-03-04 16:14:30 +00:00
|
|
|
struct sc_pkcs15_id new_id = *((struct sc_pkcs15_id *) new_value);
|
2003-06-27 11:59:37 +00:00
|
|
|
|
|
|
|
if (object == NULL || object->df == NULL)
|
2011-05-01 20:21:31 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot change attribute");
|
2003-06-27 11:59:37 +00:00
|
|
|
df_type = object->df->type;
|
|
|
|
|
|
|
|
df = find_df_by_type(p15card, df_type);
|
|
|
|
if (df == NULL)
|
2011-05-01 20:21:31 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "Cannot change attribute");
|
2003-06-27 11:59:37 +00:00
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
switch(new_attrib_type) {
|
2003-06-27 11:59:37 +00:00
|
|
|
case P15_ATTR_TYPE_LABEL:
|
|
|
|
if (new_len >= SC_PKCS15_MAX_LABEL_SIZE)
|
2011-05-01 20:21:31 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "New label too long");
|
2003-06-27 11:59:37 +00:00
|
|
|
memcpy(object->label, new_value, new_len);
|
|
|
|
object->label[new_len] = '\0';
|
|
|
|
break;
|
|
|
|
case P15_ATTR_TYPE_ID:
|
|
|
|
switch(df_type) {
|
|
|
|
case SC_PKCS15_PRKDF:
|
2010-03-04 16:14:30 +00:00
|
|
|
((struct sc_pkcs15_prkey_info *) object->data)->id = new_id;
|
2003-06-27 11:59:37 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_PUKDF:
|
|
|
|
case SC_PKCS15_PUKDF_TRUSTED:
|
2010-03-04 16:14:30 +00:00
|
|
|
((struct sc_pkcs15_pubkey_info *) object->data)->id = new_id;
|
2003-06-27 11:59:37 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_CDF:
|
|
|
|
case SC_PKCS15_CDF_TRUSTED:
|
|
|
|
case SC_PKCS15_CDF_USEFUL:
|
2010-03-04 16:14:30 +00:00
|
|
|
((struct sc_pkcs15_cert_info *) object->data)->id = new_id;
|
2003-06-27 11:59:37 +00:00
|
|
|
break;
|
|
|
|
default:
|
2011-05-01 20:14:06 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Cannot change ID attribute");
|
2003-06-27 11:59:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2011-05-01 20:14:06 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Only 'LABEL' or 'ID' attributes can be changed");
|
2003-06-27 11:59:37 +00:00
|
|
|
}
|
|
|
|
|
2011-04-22 14:00:47 +00:00
|
|
|
if (profile->ops->emu_update_any_df) {
|
|
|
|
r = profile->ops->emu_update_any_df(profile, p15card, SC_AC_OP_CREATE, object);
|
2011-05-01 20:14:06 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific DF update failed");
|
2011-04-22 14:00:47 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
r = sc_pkcs15_encode_df(card->ctx, p15card, df, &buf, &bufsize);
|
|
|
|
if (r >= 0) {
|
|
|
|
struct sc_file *file = NULL;
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2011-04-22 14:00:47 +00:00
|
|
|
r = sc_profile_get_file_by_path(profile, &df->path, &file);
|
2011-05-01 20:14:06 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot instantiate file by path");
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2011-04-22 14:00:47 +00:00
|
|
|
r = sc_pkcs15init_update_file(profile, p15card, file, buf, bufsize);
|
|
|
|
free(buf);
|
|
|
|
sc_file_free(file);
|
|
|
|
}
|
2003-06-27 11:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return r < 0 ? r : 0;
|
|
|
|
}
|
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
sc_pkcs15init_delete_object(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_object *obj)
|
2005-08-22 09:20:13 +00:00
|
|
|
{
|
2010-02-02 17:20:09 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2010-01-10 20:33:32 +00:00
|
|
|
struct sc_file *file = NULL;
|
|
|
|
struct sc_path path;
|
2005-08-22 09:20:13 +00:00
|
|
|
struct sc_pkcs15_df *df;
|
2011-04-12 17:59:59 +00:00
|
|
|
int r = 0, stored_in_ef = 0;
|
2005-08-22 09:20:13 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-01-10 20:33:32 +00:00
|
|
|
switch(obj->type & SC_PKCS15_TYPE_CLASS_MASK) {
|
2005-08-22 09:20:13 +00:00
|
|
|
case SC_PKCS15_TYPE_PUBKEY:
|
2010-03-04 16:14:30 +00:00
|
|
|
path = ((struct sc_pkcs15_pubkey_info *)obj->data)->path;
|
2005-08-22 09:20:13 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_PRKEY:
|
2010-03-04 16:14:30 +00:00
|
|
|
path = ((struct sc_pkcs15_prkey_info *)obj->data)->path;
|
2005-08-22 09:20:13 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_CERT:
|
2010-03-04 16:14:30 +00:00
|
|
|
path = ((struct sc_pkcs15_cert_info *)obj->data)->path;
|
2005-08-22 09:20:13 +00:00
|
|
|
break;
|
|
|
|
case SC_PKCS15_TYPE_DATA_OBJECT:
|
2010-03-04 16:14:30 +00:00
|
|
|
path = ((struct sc_pkcs15_data_info *)obj->data)->path;
|
2005-08-22 09:20:13 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2011-01-18 10:39:08 +00:00
|
|
|
sc_log(ctx, "delete object(type:%X) with path(type:%X,%s)", obj->type, path.type, sc_print_path(&path));
|
2011-04-12 17:59:59 +00:00
|
|
|
if (path.len || path.aid.len) {
|
|
|
|
r = sc_select_file(p15card->card, &path, &file);
|
|
|
|
if (r != SC_ERROR_FILE_NOT_FOUND)
|
|
|
|
LOG_TEST_RET(ctx, r, "select object path failed");
|
2010-01-10 20:33:32 +00:00
|
|
|
|
2011-04-12 17:59:59 +00:00
|
|
|
stored_in_ef = (file->type != SC_FILE_TYPE_DF);
|
|
|
|
sc_file_free(file);
|
|
|
|
}
|
2010-01-10 20:33:32 +00:00
|
|
|
|
2011-01-18 10:39:08 +00:00
|
|
|
if (!r) {
|
|
|
|
/* If the object is stored in a normal EF, try to delete the EF. */
|
|
|
|
if (stored_in_ef) {
|
|
|
|
r = sc_pkcs15init_delete_by_path(profile, p15card, &path);
|
|
|
|
LOG_TEST_RET(ctx, r, "Failed to delete object by path");
|
|
|
|
}
|
|
|
|
else if (profile->ops->delete_object != NULL) {
|
|
|
|
/* If there's a card-specific way to delete objects, use it. */
|
2011-04-15 16:50:04 +00:00
|
|
|
r = profile->ops->delete_object(profile, p15card, obj, &path);
|
2011-01-18 10:39:08 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Card specific delete object failed");
|
|
|
|
}
|
|
|
|
}
|
2010-01-10 20:33:32 +00:00
|
|
|
|
2010-03-18 09:10:51 +00:00
|
|
|
if (profile->ops->emu_update_any_df) {
|
2010-07-02 13:46:13 +00:00
|
|
|
r = profile->ops->emu_update_any_df(profile, p15card, SC_AC_OP_ERASE, obj);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "'ERASE' update DF failed");
|
2010-03-18 09:10:51 +00:00
|
|
|
}
|
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
/* Get the DF we're part of. If there's no DF, fine, we haven't been added yet. */
|
|
|
|
df = obj->df;
|
2010-02-09 14:05:54 +00:00
|
|
|
if (df) {
|
2010-01-10 20:33:32 +00:00
|
|
|
/* Unlink the object and update the DF */
|
|
|
|
sc_pkcs15_remove_object(p15card, obj);
|
2010-02-09 14:05:54 +00:00
|
|
|
sc_pkcs15_free_object(obj);
|
|
|
|
}
|
2005-08-22 09:20:13 +00:00
|
|
|
|
2010-03-18 09:10:51 +00:00
|
|
|
if (!profile->ops->emu_update_any_df)
|
|
|
|
r = sc_pkcs15init_update_any_df(p15card, profile, df, 0);
|
2005-08-22 09:20:13 +00:00
|
|
|
|
2005-08-22 09:37:54 +00:00
|
|
|
/* mark card as dirty */
|
|
|
|
profile->dirty = 1;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2005-08-22 09:20:13 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 17:18:06 +00:00
|
|
|
|
2005-09-15 19:40:20 +00:00
|
|
|
int
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15init_update_certificate(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile, struct sc_pkcs15_object *obj,
|
2006-01-11 23:41:17 +00:00
|
|
|
const unsigned char *rawcert, size_t certlen)
|
2005-09-15 19:40:20 +00:00
|
|
|
{
|
2010-04-24 17:37:02 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_file *file = NULL;
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_path *path = &((struct sc_pkcs15_cert_info *)obj->data)->path;
|
2005-09-15 19:40:20 +00:00
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2005-09-15 19:40:20 +00:00
|
|
|
r = sc_select_file(p15card->card, path, &file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select cert file");
|
2005-09-15 19:40:20 +00:00
|
|
|
|
|
|
|
/* If the new cert doesn't fit in the EF, delete it and make the same, but bigger EF */
|
2010-05-26 14:33:01 +00:00
|
|
|
if (file->size != certlen) {
|
2010-04-24 17:37:02 +00:00
|
|
|
struct sc_file *parent = NULL;
|
|
|
|
|
|
|
|
r = sc_pkcs15init_delete_by_path(profile, p15card, path);
|
|
|
|
if (r < 0)
|
2005-09-15 19:40:20 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
file->size = certlen;
|
|
|
|
|
2010-04-24 17:37:02 +00:00
|
|
|
r = do_select_parent(profile, p15card, file, &parent);
|
|
|
|
if (r < 0)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_CREATE);
|
|
|
|
sc_file_free(parent);
|
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "'CREATE' authentication failed");
|
2010-04-24 17:37:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2005-12-17 20:54:29 +00:00
|
|
|
/* ensure we are in the correct lifecycle */
|
|
|
|
r = sc_pkcs15init_set_lifecycle(p15card->card, SC_CARDCTRL_LIFECYCLE_ADMIN);
|
|
|
|
if (r < 0 && r != SC_ERROR_NOT_SUPPORTED)
|
2005-09-15 19:40:20 +00:00
|
|
|
goto done;
|
2010-04-24 17:37:02 +00:00
|
|
|
|
|
|
|
r = sc_create_file(p15card->card, file);
|
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Cannot create cert file");
|
2010-04-24 17:37:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sc_file_get_acl_entry(file, SC_AC_OP_UPDATE)) {
|
|
|
|
struct sc_path tmp_path;
|
|
|
|
|
|
|
|
/* FCI of selected cert file do not contains ACLs.
|
|
|
|
* For the 'UPDATE' authentication use instead sc_file
|
|
|
|
* instantiated from card profile with default ACLs. */
|
|
|
|
sc_file_free(file);
|
|
|
|
|
|
|
|
r = select_object_path(p15card, profile, obj, &tmp_path);
|
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Select object path error");
|
2010-04-24 17:37:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_profile_get_file_by_path(profile, path, &file);
|
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Cannot instantiate cert file");
|
2010-04-24 17:37:02 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2005-09-15 19:40:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Write the new cert */
|
2010-04-24 17:37:02 +00:00
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
|
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "'UPDATE' authentication failed");
|
2005-09-15 19:40:20 +00:00
|
|
|
goto done;
|
2010-04-24 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
r = sc_select_file(p15card->card, path, NULL);
|
|
|
|
if (r < 0)
|
2005-09-15 19:40:20 +00:00
|
|
|
goto done;
|
2010-04-24 17:37:02 +00:00
|
|
|
|
|
|
|
r = sc_update_binary(p15card->card, 0, rawcert, certlen, 0);
|
|
|
|
if (r < 0)
|
2005-09-15 19:40:20 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
/* Fill the remaining space in the EF (if any) with zeros */
|
|
|
|
if (certlen < file->size) {
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
unsigned char *tmp = calloc(file->size - certlen, 1);
|
2005-09-15 19:40:20 +00:00
|
|
|
if (tmp == NULL) {
|
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
r = sc_update_binary(p15card->card, certlen, tmp, file->size - certlen, 0);
|
|
|
|
free(tmp);
|
2010-04-24 17:37:02 +00:00
|
|
|
if (r < 0)
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Update cert file error");
|
2005-09-15 19:40:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (r >= 0) {
|
|
|
|
/* Update the CDF entry */
|
2010-03-04 16:14:30 +00:00
|
|
|
path = &((struct sc_pkcs15_cert_info *)obj->data)->path;
|
2005-09-15 19:40:20 +00:00
|
|
|
if (file->size != certlen) {
|
|
|
|
path->index = 0;
|
|
|
|
path->count = certlen;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
path->count = -1;
|
|
|
|
r = sc_pkcs15init_update_any_df(p15card, profile, obj->df, 0);
|
2010-04-24 17:37:02 +00:00
|
|
|
if (r < 0)
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Failed to update CDF");
|
2005-09-15 19:40:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* mark card as dirty */
|
|
|
|
profile->dirty = 1;
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (file)
|
|
|
|
sc_file_free(file);
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2005-09-15 19:40:20 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2010-04-02 11:55:13 +00:00
|
|
|
static const char *
|
2010-02-21 18:24:41 +00:00
|
|
|
get_pin_ident_name(int type, int reference)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case SC_AC_CHV:
|
|
|
|
return "PIN";
|
|
|
|
case SC_AC_PRO:
|
|
|
|
return "secure messaging key";
|
|
|
|
case SC_AC_AUT:
|
|
|
|
return "authentication key";
|
2011-01-11 16:40:49 +00:00
|
|
|
case SC_AC_SEN:
|
|
|
|
return "security environment";
|
|
|
|
case SC_AC_IDA:
|
|
|
|
return "PKCS#15 reference";
|
|
|
|
case SC_AC_SCB:
|
|
|
|
return "SCB byte in IAS/ECC";
|
2010-02-21 18:24:41 +00:00
|
|
|
case SC_AC_SYMBOLIC:
|
|
|
|
switch (reference) {
|
|
|
|
case SC_PKCS15INIT_USER_PIN:
|
|
|
|
return "user PIN";
|
|
|
|
case SC_PKCS15INIT_SO_PIN:
|
|
|
|
return "SO PIN";
|
|
|
|
case SC_PKCS15INIT_USER_PUK:
|
|
|
|
return "user PUK";
|
|
|
|
case SC_PKCS15INIT_SO_PUK:
|
|
|
|
return "SO PUK";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "authentication data";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
sc_pkcs15init_get_transport_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
int type, int reference, unsigned char *pinbuf, size_t *pinsize)
|
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
struct sc_pkcs15_object *pin_obj = NULL;
|
|
|
|
struct sc_pkcs15_pin_info pin_info;
|
|
|
|
struct sc_cardctl_default_key data;
|
|
|
|
size_t defsize = 0;
|
|
|
|
unsigned char defbuf[0x100];
|
|
|
|
int rv;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
data.method = type;
|
|
|
|
data.key_ref = reference;
|
|
|
|
data.len = sizeof(defbuf);
|
|
|
|
data.key_data = defbuf;
|
|
|
|
rv = sc_card_ctl(p15card->card, SC_CARDCTL_GET_DEFAULT_KEY, &data);
|
|
|
|
if (rv >= 0)
|
|
|
|
defsize = data.len;
|
|
|
|
|
|
|
|
if (callbacks.get_key) {
|
|
|
|
rv = callbacks.get_key(profile, type, reference, defbuf, defsize, pinbuf, pinsize);
|
|
|
|
}
|
|
|
|
else if (rv >= 0) {
|
|
|
|
if (*pinsize < defsize)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Get transport key error");
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
memcpy(pinbuf, data.key_data, data.len);
|
|
|
|
*pinsize = data.len;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&pin_info, 0, sizeof(pin_info));
|
|
|
|
pin_info.auth_method = type;
|
|
|
|
pin_info.reference = reference;
|
|
|
|
pin_info.stored_length = *pinsize;
|
|
|
|
pin_info.max_length = *pinsize;
|
|
|
|
pin_info.min_length = *pinsize;
|
|
|
|
pin_info.magic = SC_PKCS15_PIN_MAGIC;
|
|
|
|
|
|
|
|
pin_obj = sc_pkcs15init_new_object(SC_PKCS15_TYPE_AUTH_PIN, "Default transport key", NULL, &pin_info);
|
|
|
|
if (!pin_obj)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate AUTH object");
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
rv = sc_pkcs15_add_object(p15card, pin_obj);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, rv, "Cannot add PKCS#15 AUTH object");
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2010-03-10 09:23:01 +00:00
|
|
|
sc_pkcs15_pincache_add(p15card, pin_obj, pinbuf, *pinsize);
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, rv);
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-11 15:14:12 +00:00
|
|
|
/*
|
|
|
|
* PIN verification
|
|
|
|
*/
|
2010-03-17 16:26:07 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_verify_secret(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_file *file, unsigned int type, int reference)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_pkcs15_object *pin_obj = NULL;
|
|
|
|
struct sc_pkcs15_pin_info pin_info;
|
|
|
|
struct sc_path *path;
|
|
|
|
int r, use_pinpad = 0, pin_id = -1;
|
|
|
|
const char *ident, *label = NULL;
|
2010-03-17 16:26:07 +00:00
|
|
|
unsigned char pinbuf[0x100];
|
|
|
|
size_t pinsize = sizeof(pinbuf);
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2003-10-13 16:13:12 +00:00
|
|
|
path = file? &file->path : NULL;
|
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
ident = get_pin_ident_name(type, reference);
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "get and verify PIN('%s',type:0x%X,reference:0x%X)", ident, type, reference);
|
2002-12-04 13:25:31 +00:00
|
|
|
|
2011-01-11 16:40:49 +00:00
|
|
|
if (type == SC_AC_SEN) {
|
|
|
|
r = sc_card_ctl(p15card->card, SC_CARDCTL_GET_CHV_REFERENCE_IN_SE, (void *)(&reference));
|
|
|
|
sc_log(ctx, "Card CTL(GET_CHV_REFERENCE_IN_SE) returned %i", r);
|
|
|
|
if (r > 0) {
|
|
|
|
sc_log(ctx, "CHV(ref:%i) found in SE(ref:%i)", r, reference);
|
|
|
|
type = SC_AC_CHV;
|
|
|
|
reference = r;
|
|
|
|
}
|
|
|
|
else if (r != SC_ERROR_NOT_SUPPORTED)
|
|
|
|
LOG_TEST_RET(ctx, r, "Card CTL error: cannot get CHV reference");
|
|
|
|
}
|
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
memset(&pin_info, 0, sizeof(pin_info));
|
|
|
|
pin_info.auth_method = type;
|
|
|
|
pin_info.reference = reference;
|
|
|
|
|
2010-03-05 10:37:11 +00:00
|
|
|
pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, type, reference);
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "found PIN reference %i", pin_id);
|
2010-02-21 18:24:41 +00:00
|
|
|
if (type == SC_AC_SYMBOLIC) {
|
|
|
|
if (pin_id == -1)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2010-02-21 18:24:41 +00:00
|
|
|
reference = pin_id;
|
|
|
|
type = SC_AC_CHV;
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "Symbolic PIN resolved to PIN(type:CHV,reference:%i)", type, reference);
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (p15card) {
|
|
|
|
if (path && path->len) {
|
|
|
|
struct sc_path tmp_path = *path;
|
|
|
|
int iter;
|
|
|
|
|
|
|
|
r = SC_ERROR_OBJECT_NOT_FOUND;
|
|
|
|
for (iter = tmp_path.len/2; iter >= 0 && r == SC_ERROR_OBJECT_NOT_FOUND; iter--, tmp_path.len -= 2)
|
|
|
|
r = sc_pkcs15_find_pin_by_type_and_reference(p15card,
|
|
|
|
tmp_path.len ? &tmp_path : NULL,
|
|
|
|
type, reference, &pin_obj);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
r = sc_pkcs15_find_pin_by_type_and_reference(p15card, NULL, type, reference, &pin_obj);
|
2003-10-13 16:13:12 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
if (!r && pin_obj) {
|
|
|
|
memcpy(&pin_info, pin_obj->data, sizeof(pin_info));
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "found PIN object '%s'", pin_obj->label);
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
if (pin_obj) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "PIN object '%s'; pin_obj->content.len:%i", pin_obj->label, pin_obj->content.len);
|
2010-02-21 18:24:41 +00:00
|
|
|
if (pin_obj->content.value && pin_obj->content.len) {
|
2010-03-17 16:26:07 +00:00
|
|
|
if (pin_obj->content.len > pinsize)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "PIN buffer is too small");
|
2010-03-17 16:26:07 +00:00
|
|
|
memcpy(pinbuf, pin_obj->content.value, pin_obj->content.len);
|
|
|
|
pinsize = pin_obj->content.len;
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "'ve got '%s' value from cache", ident);
|
2010-02-21 18:24:41 +00:00
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
2002-12-04 11:56:34 +00:00
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
if (pin_obj && pin_obj->label[0])
|
2003-10-21 11:05:35 +00:00
|
|
|
label = pin_obj->label;
|
2002-12-04 13:25:31 +00:00
|
|
|
|
2003-10-13 16:13:12 +00:00
|
|
|
switch (type) {
|
|
|
|
case SC_AC_CHV:
|
2010-02-21 18:24:41 +00:00
|
|
|
if (callbacks.get_pin) {
|
2010-03-17 16:26:07 +00:00
|
|
|
r = callbacks.get_pin(profile, pin_id, &pin_info, label, pinbuf, &pinsize);
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "'get_pin' callback returned %i; pinsize:%i", r, pinsize);
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
2003-10-13 16:13:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
2010-03-17 16:26:07 +00:00
|
|
|
r = sc_pkcs15init_get_transport_key(profile, p15card, type, reference, pinbuf, &pinsize);
|
2003-10-13 16:13:12 +00:00
|
|
|
break;
|
2002-12-04 11:56:34 +00:00
|
|
|
}
|
|
|
|
|
2010-01-17 21:08:13 +00:00
|
|
|
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
|
2010-02-21 18:24:41 +00:00
|
|
|
if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD)
|
|
|
|
r = 0, use_pinpad = 1;
|
|
|
|
else
|
2010-01-17 21:08:13 +00:00
|
|
|
r = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
|
|
|
|
}
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to get secret");
|
2002-04-05 14:00:27 +00:00
|
|
|
|
2010-03-17 16:26:07 +00:00
|
|
|
found:
|
|
|
|
if (pin_obj) {
|
2010-05-19 08:26:01 +00:00
|
|
|
r = sc_pkcs15_verify_pin(p15card, pin_obj, pinsize ? pinbuf : NULL, pinsize);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot validate pkcs15 PIN");
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
2010-02-01 10:14:04 +00:00
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
if (file) {
|
|
|
|
r = sc_select_file(p15card->card, &file->path, NULL);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select PIN path");
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
|
2010-03-17 16:26:07 +00:00
|
|
|
if (!pin_obj) {
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_pin_cmd_data pin_cmd;
|
2010-01-17 21:08:13 +00:00
|
|
|
|
2010-02-01 10:14:04 +00:00
|
|
|
memset(&pin_cmd, 0, sizeof(pin_cmd));
|
|
|
|
pin_cmd.cmd = SC_PIN_CMD_VERIFY;
|
|
|
|
pin_cmd.pin_type = type;
|
|
|
|
pin_cmd.pin_reference = reference;
|
|
|
|
pin_cmd.pin1.data = use_pinpad ? NULL : pinbuf;
|
2010-03-17 16:26:07 +00:00
|
|
|
pin_cmd.pin1.len = use_pinpad ? 0: pinsize;
|
2010-02-01 10:14:04 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pin_cmd(p15card->card, &pin_cmd, NULL);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "'VERIFY' pin cmd failed");
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-12-04 13:25:31 +00:00
|
|
|
}
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/*
|
|
|
|
* Present any authentication info as required by the file.
|
|
|
|
*
|
2005-03-30 18:25:50 +00:00
|
|
|
* Depending on the SC_CARD_CAP_USE_FCI_AC caps file in sc_card_t,
|
|
|
|
* we read the ACs of the file on the card, or rely on the ACL
|
|
|
|
* info for that file in the profile file.
|
2003-10-13 16:13:12 +00:00
|
|
|
*
|
2005-03-30 18:25:50 +00:00
|
|
|
* In the latter case, there's a problem here if e.g. the SO PIN
|
|
|
|
* defined by the profile is optional, and hasn't been set.
|
|
|
|
* On the orther hands, some cards do not return access conditions
|
|
|
|
* in their response to SELECT FILE), so the latter case has been
|
|
|
|
* used in most cards while the first case was added much later.
|
2002-04-02 13:26:42 +00:00
|
|
|
*/
|
|
|
|
int
|
2010-02-21 18:24:41 +00:00
|
|
|
sc_pkcs15init_authenticate(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_file *file, int op)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2011-01-06 14:39:19 +00:00
|
|
|
const struct sc_acl_entry *acl = NULL;
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_file *file_tmp = NULL;
|
2006-01-11 23:41:17 +00:00
|
|
|
int r = 0;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2011-01-06 14:39:19 +00:00
|
|
|
sc_log(ctx, "path '%s', op=%u", sc_print_path(&file->path), op);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
if (p15card->card->caps & SC_CARD_CAP_USE_FCI_AC) {
|
2010-02-21 18:24:41 +00:00
|
|
|
r = sc_select_file(p15card->card, &file->path, &file_tmp);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Authentication failed: cannot select file.");
|
2011-01-06 14:39:19 +00:00
|
|
|
|
2005-03-30 18:25:50 +00:00
|
|
|
acl = sc_file_get_acl_entry(file_tmp, op);
|
|
|
|
}
|
2010-02-21 18:24:41 +00:00
|
|
|
else {
|
2005-03-30 18:25:50 +00:00
|
|
|
acl = sc_file_get_acl_entry(file, op);
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
2011-01-06 14:39:19 +00:00
|
|
|
sc_log(ctx, "acl %p",acl);
|
2008-08-20 05:41:20 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
for (; r == 0 && acl; acl = acl->next) {
|
2010-02-21 18:24:41 +00:00
|
|
|
if (acl->method == SC_AC_NEVER) {
|
2011-01-06 14:39:19 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Authentication failed: never allowed");
|
2008-08-20 05:41:20 +00:00
|
|
|
}
|
2010-02-21 18:24:41 +00:00
|
|
|
else if (acl->method == SC_AC_NONE) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "always allowed");
|
2002-04-02 13:26:42 +00:00
|
|
|
break;
|
2008-08-20 05:41:20 +00:00
|
|
|
}
|
2010-02-21 18:24:41 +00:00
|
|
|
else if (acl->method == SC_AC_UNKNOWN) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "unknown acl method");
|
2005-01-14 23:14:34 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "verify acl(method:%i,reference:%i)", acl->method, acl->key_ref);
|
2010-03-17 16:26:07 +00:00
|
|
|
r = sc_pkcs15init_verify_secret(profile, p15card, file_tmp ? file_tmp : file, acl->method, acl->key_ref);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
2005-03-30 18:25:50 +00:00
|
|
|
|
|
|
|
if (file_tmp)
|
|
|
|
sc_file_free(file_tmp);
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-03-17 16:26:07 +00:00
|
|
|
|
2010-02-02 17:18:06 +00:00
|
|
|
static int
|
2010-02-21 16:21:57 +00:00
|
|
|
do_select_parent(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_file *file, struct sc_file **parent)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-04-02 13:26:42 +00:00
|
|
|
struct sc_path path;
|
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2002-04-02 13:26:42 +00:00
|
|
|
/* Get the parent's path */
|
|
|
|
path = file->path;
|
|
|
|
if (path.len >= 2)
|
|
|
|
path.len -= 2;
|
2011-01-17 16:28:44 +00:00
|
|
|
if (!path.len && !path.aid.len)
|
2002-04-02 13:26:42 +00:00
|
|
|
sc_format_path("3F00", &path);
|
|
|
|
|
2002-04-22 08:00:52 +00:00
|
|
|
/* Select the parent DF. */
|
2002-04-02 13:26:42 +00:00
|
|
|
*parent = NULL;
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_select_file(p15card->card, &path, parent);
|
2002-04-02 13:26:42 +00:00
|
|
|
/* If DF doesn't exist, create it (unless it's the MF,
|
|
|
|
* but then something's badly broken anyway :-) */
|
|
|
|
if (r == SC_ERROR_FILE_NOT_FOUND && path.len != 2) {
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_profile_get_file_by_path(profile, &path, parent);
|
2002-04-22 08:00:52 +00:00
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "no profile template for DF %s", sc_print_path(&path));
|
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
r = sc_pkcs15init_create_file(profile, p15card, *parent);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot create parent DF");
|
2006-01-11 23:41:17 +00:00
|
|
|
|
2010-02-21 18:24:41 +00:00
|
|
|
r = sc_select_file(p15card->card, &path, NULL);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot select parent DF");
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
else if (r == SC_SUCCESS && !strcmp(p15card->card->name, "STARCOS SPK 2.3")) {
|
2004-08-21 10:54:28 +00:00
|
|
|
/* in case of starcos spk 2.3 SELECT FILE does not
|
|
|
|
* give us the ACLs => ask the profile */
|
|
|
|
sc_file_free(*parent);
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_profile_get_file_by_path(profile, &path, parent);
|
2004-08-21 10:54:28 +00:00
|
|
|
if (r < 0) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "in StarCOS profile there is no template for DF %s", sc_print_path(&path));
|
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2004-08-21 10:54:28 +00:00
|
|
|
}
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
int
|
2010-02-21 16:21:57 +00:00
|
|
|
sc_pkcs15init_create_file(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_file *file)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2002-04-02 13:26:42 +00:00
|
|
|
struct sc_file *parent = NULL;
|
|
|
|
int r;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
sc_log(ctx, "create file '%s'", sc_print_path(&file->path));
|
2002-04-02 13:26:42 +00:00
|
|
|
/* Select parent DF and verify PINs/key as necessary */
|
2010-02-21 18:24:41 +00:00
|
|
|
r = do_select_parent(profile, p15card, file, &parent);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot create file: select parent error");
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_CREATE);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot create file: 'CREATE' authentication failed");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
/* Fix up the file's ACLs */
|
2010-02-21 18:24:41 +00:00
|
|
|
r = sc_pkcs15init_fixup_file(profile, p15card, file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot create file: file fixup failed");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2005-12-17 20:54:29 +00:00
|
|
|
/* ensure we are in the correct lifecycle */
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_set_lifecycle(p15card->card, SC_CARDCTRL_LIFECYCLE_ADMIN);
|
2010-02-21 18:24:41 +00:00
|
|
|
if (r != SC_ERROR_NOT_SUPPORTED)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Cannot create file: failed to set lifecycle 'ADMIN'");
|
2005-12-17 20:54:29 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_create_file(p15card->card, file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Create file failed");
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
if (parent)
|
2002-04-02 13:26:42 +00:00
|
|
|
sc_file_free(parent);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
|
|
|
|
2010-02-02 18:15:53 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
int
|
2010-02-21 18:24:41 +00:00
|
|
|
sc_pkcs15init_update_file(struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_card *p15card, struct sc_file *file,
|
|
|
|
void *data, unsigned int datalen)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2010-03-04 13:05:03 +00:00
|
|
|
struct sc_file *selected_file = NULL;
|
2004-01-07 10:10:34 +00:00
|
|
|
void *copy = NULL;
|
2010-05-27 08:12:20 +00:00
|
|
|
int r, need_to_zap = 0;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
|
|
|
sc_log(ctx, "path:%s; datalen:%i", sc_print_path(&file->path), datalen);
|
2003-10-22 05:43:57 +00:00
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
r = sc_select_file(p15card->card, &file->path, &selected_file);
|
2010-01-29 17:40:03 +00:00
|
|
|
if (!r) {
|
|
|
|
need_to_zap = 1;
|
|
|
|
}
|
|
|
|
else if (r == SC_ERROR_FILE_NOT_FOUND) {
|
2002-04-02 13:26:42 +00:00
|
|
|
/* Create file if it doesn't exist */
|
|
|
|
if (file->size < datalen)
|
|
|
|
file->size = datalen;
|
2010-01-29 17:40:03 +00:00
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_create_file(profile, p15card, file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to create file");
|
2010-01-29 17:40:03 +00:00
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
r = sc_select_file(p15card->card, &file->path, &selected_file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select newly created file");
|
2010-04-28 09:20:17 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, r, "Failed to select file");
|
2010-04-28 09:20:17 +00:00
|
|
|
}
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2010-03-04 13:05:03 +00:00
|
|
|
if (selected_file->size < datalen) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "File %s too small (require %u, have %u)",
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_print_path(&file->path), datalen, selected_file->size);
|
|
|
|
sc_file_free(selected_file);
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_TEST_RET(ctx, SC_ERROR_FILE_TOO_SMALL, "Update file failed");
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
2010-03-04 13:05:03 +00:00
|
|
|
else if (selected_file->size > datalen && need_to_zap) {
|
2004-01-07 10:10:34 +00:00
|
|
|
/* zero out the rest of the file - we may have shrunk
|
|
|
|
* the file contents */
|
2010-03-04 13:05:03 +00:00
|
|
|
copy = calloc(1, selected_file->size);
|
2005-01-03 17:25:18 +00:00
|
|
|
if (copy == NULL) {
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_file_free(selected_file);
|
2005-01-03 17:25:18 +00:00
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2004-01-07 10:10:34 +00:00
|
|
|
memcpy(copy, data, datalen);
|
2010-03-04 13:05:03 +00:00
|
|
|
datalen = selected_file->size;
|
2004-01-07 10:10:34 +00:00
|
|
|
data = copy;
|
2003-07-31 21:16:15 +00:00
|
|
|
}
|
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
/* Present authentication info needed */
|
2010-03-13 23:35:08 +00:00
|
|
|
r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
|
2002-04-02 13:26:42 +00:00
|
|
|
if (r >= 0 && datalen)
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_update_binary(p15card->card, 0, (const unsigned char *) data, datalen, 0);
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2004-01-07 10:10:34 +00:00
|
|
|
if (copy)
|
|
|
|
free(copy);
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_file_free(selected_file);
|
2002-04-02 13:26:42 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fix up a file's ACLs by replacing all occurrences of a symbolic
|
|
|
|
* PIN name with the real reference.
|
|
|
|
*/
|
2010-02-21 18:24:41 +00:00
|
|
|
static int
|
2010-03-05 10:37:11 +00:00
|
|
|
sc_pkcs15init_fixup_acls(struct sc_pkcs15_card *p15card, struct sc_file *file,
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_acl_entry *so_acl, struct sc_acl_entry *user_acl)
|
2002-04-02 13:26:42 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
2010-03-05 10:37:11 +00:00
|
|
|
unsigned int op;
|
|
|
|
int r = 0;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2002-04-02 13:26:42 +00:00
|
|
|
for (op = 0; r == 0 && op < SC_MAX_AC_OPS; op++) {
|
2011-04-27 14:45:23 +00:00
|
|
|
struct sc_acl_entry acls[SC_MAX_OP_ACS];
|
2010-02-21 18:24:41 +00:00
|
|
|
const struct sc_acl_entry *acl;
|
2002-04-02 13:26:42 +00:00
|
|
|
const char *what;
|
2010-03-05 10:37:11 +00:00
|
|
|
int added = 0, num, ii;
|
2002-04-02 13:26:42 +00:00
|
|
|
|
|
|
|
/* First, get original ACLs */
|
|
|
|
acl = sc_file_get_acl_entry(file, op);
|
2011-04-27 14:45:23 +00:00
|
|
|
for (num = 0; num < SC_MAX_OP_ACS && acl; num++, acl = acl->next)
|
2002-04-02 13:26:42 +00:00
|
|
|
acls[num] = *acl;
|
|
|
|
|
|
|
|
sc_file_clear_acl_entries(file, op);
|
2010-02-21 18:24:41 +00:00
|
|
|
for (ii = 0; ii < num; ii++) {
|
|
|
|
acl = acls + ii;
|
2002-04-02 13:26:42 +00:00
|
|
|
if (acl->method != SC_AC_SYMBOLIC)
|
|
|
|
goto next;
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2002-04-02 13:26:42 +00:00
|
|
|
if (acl->key_ref == SC_PKCS15INIT_SO_PIN) {
|
|
|
|
acl = so_acl;
|
|
|
|
what = "SO PIN";
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
else if (acl->key_ref == SC_PKCS15INIT_USER_PIN) {
|
2002-04-02 13:26:42 +00:00
|
|
|
acl = user_acl;
|
|
|
|
what = "user PIN";
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "ACL references unknown symbolic PIN %d", acl->key_ref);
|
2002-04-02 13:26:42 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we weren't given a replacement ACL,
|
|
|
|
* leave the original ACL untouched */
|
2010-02-21 18:24:41 +00:00
|
|
|
if (acl->key_ref == (unsigned int)-1) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "ACL references %s, which is not defined", what);
|
2002-04-02 13:26:42 +00:00
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (acl->method == SC_AC_NONE)
|
|
|
|
continue;
|
2010-02-21 18:24:41 +00:00
|
|
|
next:
|
|
|
|
sc_file_add_acl_entry(file, op, acl->method, acl->key_ref);
|
2002-04-02 13:26:42 +00:00
|
|
|
added++;
|
|
|
|
}
|
|
|
|
if (!added)
|
|
|
|
sc_file_add_acl_entry(file, op, SC_AC_NONE, 0);
|
|
|
|
}
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, r);
|
2002-04-02 13:26:42 +00:00
|
|
|
}
|
2010-02-21 18:24:41 +00:00
|
|
|
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
/*
|
|
|
|
* Fix up all file ACLs
|
|
|
|
*/
|
|
|
|
int
|
2010-02-21 18:24:41 +00:00
|
|
|
sc_pkcs15init_fixup_file(struct sc_profile *profile,
|
|
|
|
struct sc_pkcs15_card *p15card, struct sc_file *file)
|
2010-02-21 16:21:57 +00:00
|
|
|
{
|
|
|
|
struct sc_context *ctx = profile->card->ctx;
|
|
|
|
struct sc_acl_entry so_acl, user_acl;
|
|
|
|
unsigned int op, needfix = 0;
|
2010-02-21 18:24:41 +00:00
|
|
|
int rv, pin_ref;
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-02-21 16:21:57 +00:00
|
|
|
/* First, loop over all ACLs to find out whether there
|
|
|
|
* are still any symbolic references.
|
|
|
|
*/
|
|
|
|
for (op = 0; op < SC_MAX_AC_OPS; op++) {
|
2010-03-04 13:05:03 +00:00
|
|
|
const struct sc_acl_entry *acl;
|
2010-02-21 16:21:57 +00:00
|
|
|
|
|
|
|
acl = sc_file_get_acl_entry(file, op);
|
2010-02-21 18:24:41 +00:00
|
|
|
for (; acl; acl = acl->next)
|
2010-02-21 16:21:57 +00:00
|
|
|
if (acl->method == SC_AC_SYMBOLIC)
|
|
|
|
needfix++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!needfix)
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2010-03-05 10:37:11 +00:00
|
|
|
pin_ref = sc_pkcs15init_get_pin_reference(p15card, profile, SC_AC_SYMBOLIC, SC_PKCS15INIT_SO_PIN);
|
2010-02-21 18:24:41 +00:00
|
|
|
if (pin_ref < 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
so_acl.method = SC_AC_NONE;
|
|
|
|
so_acl.key_ref = 0;
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-02-21 16:21:57 +00:00
|
|
|
so_acl.method = SC_AC_CHV;
|
2010-02-21 18:24:41 +00:00
|
|
|
so_acl.key_ref = pin_ref;
|
2010-02-21 16:21:57 +00:00
|
|
|
}
|
|
|
|
|
2010-03-05 10:37:11 +00:00
|
|
|
pin_ref = sc_pkcs15init_get_pin_reference(p15card, profile, SC_AC_SYMBOLIC, SC_PKCS15INIT_USER_PIN);
|
2010-02-21 18:24:41 +00:00
|
|
|
if (pin_ref < 0) {
|
2010-02-21 16:21:57 +00:00
|
|
|
user_acl.method = SC_AC_NONE;
|
|
|
|
user_acl.key_ref = 0;
|
2010-02-21 18:24:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-02-21 16:21:57 +00:00
|
|
|
user_acl.method = SC_AC_CHV;
|
2010-02-21 18:24:41 +00:00
|
|
|
user_acl.key_ref = pin_ref;
|
2010-02-21 16:21:57 +00:00
|
|
|
}
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(ctx, "so_acl(method:%X,ref:%X), user_acl(method:%X,ref:%X)",
|
2010-02-21 18:24:41 +00:00
|
|
|
so_acl.method, so_acl.key_ref, user_acl.method, user_acl.key_ref);
|
|
|
|
|
2010-03-05 10:37:11 +00:00
|
|
|
rv = sc_pkcs15init_fixup_acls(p15card, file, &so_acl, &user_acl);
|
2010-02-21 18:24:41 +00:00
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, rv);
|
2010-02-21 16:21:57 +00:00
|
|
|
}
|
|
|
|
|
2002-04-05 10:05:50 +00:00
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
static int
|
2010-02-21 18:24:41 +00:00
|
|
|
sc_pkcs15init_get_pin_path(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_pkcs15_id *auth_id, struct sc_path *path)
|
2003-10-13 16:13:12 +00:00
|
|
|
{
|
2010-02-21 18:24:41 +00:00
|
|
|
struct sc_pkcs15_object *obj;
|
2003-10-13 16:13:12 +00:00
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sc_pkcs15_find_pin_by_auth_id(p15card, auth_id, &obj);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-02-21 18:24:41 +00:00
|
|
|
*path = ((struct sc_pkcs15_pin_info *) obj->data)->path;
|
2003-10-13 16:13:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-05 10:05:50 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_get_pin_info(struct sc_profile *profile,
|
2010-03-05 10:37:11 +00:00
|
|
|
int id, struct sc_pkcs15_pin_info *pin)
|
2002-04-05 10:05:50 +00:00
|
|
|
{
|
|
|
|
sc_profile_get_pin_info(profile, id, pin);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-05 14:56:21 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_get_manufacturer(struct sc_profile *profile, const char **res)
|
|
|
|
{
|
2010-10-05 15:44:58 +00:00
|
|
|
*res = profile->p15_spec->tokeninfo->manufacturer_id;
|
2002-04-05 14:56:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
sc_pkcs15init_get_serial(struct sc_profile *profile, const char **res)
|
|
|
|
{
|
2010-10-05 15:44:58 +00:00
|
|
|
*res = profile->p15_spec->tokeninfo->serial_number;
|
2002-04-05 14:56:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-07 13:15:31 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_set_serial(struct sc_profile *profile, const char *serial)
|
|
|
|
{
|
2010-10-05 15:44:58 +00:00
|
|
|
if (profile->p15_spec->tokeninfo->serial_number)
|
|
|
|
free(profile->p15_spec->tokeninfo->serial_number);
|
|
|
|
profile->p15_spec->tokeninfo->serial_number = strdup(serial);
|
2002-04-07 13:15:31 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2002-04-05 14:56:21 +00:00
|
|
|
int
|
|
|
|
sc_pkcs15init_get_label(struct sc_profile *profile, const char **res)
|
|
|
|
{
|
2010-10-05 15:44:58 +00:00
|
|
|
*res = profile->p15_spec->tokeninfo->label;
|
2002-04-05 14:56:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2003-10-16 14:32:42 +00:00
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2010-07-02 14:26:29 +00:00
|
|
|
/*
|
|
|
|
* Card specific sanity check procedure.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
sc_pkcs15init_sanity_check(struct sc_pkcs15_card *p15card, struct sc_profile *profile)
|
|
|
|
{
|
|
|
|
struct sc_context *ctx = p15card->card->ctx;
|
|
|
|
int rv = SC_ERROR_NOT_SUPPORTED;
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_CALLED(ctx);
|
2010-07-02 14:26:29 +00:00
|
|
|
if (profile->ops->sanity_check)
|
|
|
|
rv = profile->ops->sanity_check(profile, p15card);
|
|
|
|
|
2011-01-05 16:04:15 +00:00
|
|
|
LOG_FUNC_RETURN(ctx, rv);
|
2010-07-02 14:26:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
static int
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_pkcs15init_qualify_pin(struct sc_card *card, const char *pin_name,
|
|
|
|
unsigned int pin_len, struct sc_pkcs15_pin_info *pin_info)
|
2003-10-16 14:32:42 +00:00
|
|
|
{
|
|
|
|
if (pin_len == 0)
|
|
|
|
return 0;
|
|
|
|
if (pin_len < pin_info->min_length) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(card->ctx, "%s too short (min length %u)", pin_name, pin_info->min_length);
|
2003-10-16 14:32:42 +00:00
|
|
|
return SC_ERROR_WRONG_LENGTH;
|
|
|
|
}
|
|
|
|
if (pin_len > pin_info->max_length) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(card->ctx, "%s too long (max length %u)", pin_name, pin_info->max_length);
|
2003-10-16 14:32:42 +00:00
|
|
|
return SC_ERROR_WRONG_LENGTH;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2003-11-19 20:37:02 +00:00
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2003-11-19 20:37:02 +00:00
|
|
|
/*
|
|
|
|
* Get the list of options from the card, if it specifies them
|
|
|
|
*/
|
|
|
|
static int
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_pkcs15init_read_info(struct sc_card *card, struct sc_profile *profile)
|
2003-11-19 20:37:02 +00:00
|
|
|
{
|
2010-03-04 13:05:03 +00:00
|
|
|
struct sc_path path;
|
|
|
|
struct sc_file *file = NULL;
|
|
|
|
unsigned char *mem = NULL;
|
2003-11-19 20:37:02 +00:00
|
|
|
size_t len = 0;
|
|
|
|
int r;
|
|
|
|
|
2003-12-08 10:52:15 +00:00
|
|
|
sc_format_path(OPENSC_INFO_FILEPATH, &path);
|
2010-11-02 08:02:13 +00:00
|
|
|
r = sc_select_file(card, &path, &file);
|
|
|
|
if (r >= 0) {
|
2003-11-19 20:37:02 +00:00
|
|
|
len = file->size;
|
|
|
|
sc_file_free(file);
|
2010-11-02 08:02:13 +00:00
|
|
|
mem = malloc(len);
|
|
|
|
if (mem != NULL) {
|
2003-11-19 20:37:02 +00:00
|
|
|
r = sc_read_binary(card, 0, mem, len, 0);
|
2010-11-02 08:02:13 +00:00
|
|
|
} else {
|
|
|
|
r = SC_ERROR_OUT_OF_MEMORY;
|
2003-11-19 20:37:02 +00:00
|
|
|
}
|
2010-11-06 13:03:46 +00:00
|
|
|
} else
|
|
|
|
r = 0;
|
2003-11-19 20:37:02 +00:00
|
|
|
|
|
|
|
if (r >= 0)
|
|
|
|
r = sc_pkcs15init_parse_info(card, mem, len, profile);
|
|
|
|
if (mem)
|
|
|
|
free(mem);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2010-03-04 16:14:30 +00:00
|
|
|
|
2003-11-19 20:37:02 +00:00
|
|
|
static int
|
|
|
|
set_info_string(char **strp, const u8 *p, size_t len)
|
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
if (!(s = malloc(len+1)))
|
2003-11-19 20:37:02 +00:00
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
memcpy(s, p, len);
|
|
|
|
s[len] = '\0';
|
|
|
|
if (*strp)
|
|
|
|
free(*strp);
|
|
|
|
*strp = s;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse OpenSC Info file. We rudely clobber any information
|
|
|
|
* given on the command line.
|
2009-03-05 18:37:55 +00:00
|
|
|
*
|
|
|
|
* passed is a pointer (p) to (len) bytes. Those bytes contain
|
|
|
|
* one or several tag-length-value constructs, where tag and
|
|
|
|
* length are both single bytes. a final 0x00 or 0xff byte
|
|
|
|
* (with or without len byte) is ok.
|
2003-11-19 20:37:02 +00:00
|
|
|
*/
|
|
|
|
static int
|
2010-03-04 13:05:03 +00:00
|
|
|
sc_pkcs15init_parse_info(struct sc_card *card,
|
|
|
|
const unsigned char *p, size_t len,
|
|
|
|
struct sc_profile *profile)
|
2003-11-19 20:37:02 +00:00
|
|
|
{
|
2010-03-04 13:05:03 +00:00
|
|
|
unsigned char tag;
|
|
|
|
const unsigned char *end;
|
2003-11-19 20:37:02 +00:00
|
|
|
unsigned int nopts = 0;
|
|
|
|
size_t n;
|
|
|
|
|
2009-03-06 09:30:54 +00:00
|
|
|
if ((p == NULL) || (len == 0))
|
|
|
|
return 0;
|
|
|
|
|
2009-03-05 18:37:55 +00:00
|
|
|
end = p + (len - 1);
|
2009-03-06 09:26:41 +00:00
|
|
|
while (p < end) { /* more bytes to look at */
|
2003-11-19 20:37:02 +00:00
|
|
|
int r = 0;
|
|
|
|
|
2009-03-05 18:37:55 +00:00
|
|
|
tag = *p; p++;
|
|
|
|
if ((tag == 0) || (tag == 0xff) || (p >= end))
|
|
|
|
break;
|
|
|
|
|
|
|
|
n = *p;
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (p >= end || p + n > end) /* invalid length byte n */
|
2003-11-19 20:37:02 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
switch (tag) {
|
|
|
|
case OPENSC_INFO_TAG_PROFILE:
|
|
|
|
r = set_info_string(&profile->name, p, n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
break;
|
|
|
|
case OPENSC_INFO_TAG_OPTION:
|
|
|
|
if (nopts >= SC_PKCS15INIT_MAX_OPTIONS - 1) {
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(card->ctx, "Too many options in OpenSC Info file");
|
2003-11-19 20:37:02 +00:00
|
|
|
return SC_ERROR_PKCS15INIT;
|
|
|
|
}
|
|
|
|
r = set_info_string(&profile->options[nopts], p, n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
profile->options[++nopts] = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Unknown options ignored */ ;
|
|
|
|
}
|
|
|
|
p += n;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2011-01-05 16:04:15 +00:00
|
|
|
sc_log(card->ctx, "OpenSC info file corrupted");
|
2003-11-19 20:37:02 +00:00
|
|
|
return SC_ERROR_PKCS15INIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-03-04 13:05:03 +00:00
|
|
|
do_encode_string(unsigned char **memp, unsigned char *end,
|
|
|
|
unsigned char tag, const char *s)
|
2003-11-19 20:37:02 +00:00
|
|
|
{
|
2010-03-04 13:05:03 +00:00
|
|
|
unsigned char *p = *memp;
|
2003-11-19 20:37:02 +00:00
|
|
|
int n;
|
|
|
|
|
|
|
|
n = s? strlen(s) : 0;
|
|
|
|
if (n > 255)
|
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
if (p + 2 + n > end)
|
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
|
|
|
*p++ = tag;
|
|
|
|
*p++ = n;
|
|
|
|
memcpy(p, s, n);
|
|
|
|
*memp = p + n;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-21 16:21:57 +00:00
|
|
|
|
2010-01-10 20:33:32 +00:00
|
|
|
static int
|
2010-02-21 18:24:41 +00:00
|
|
|
sc_pkcs15init_write_info(struct sc_pkcs15_card *p15card,
|
|
|
|
struct sc_profile *profile,
|
2010-02-21 16:21:57 +00:00
|
|
|
struct sc_pkcs15_object *pin_obj)
|
2003-11-19 20:37:02 +00:00
|
|
|
{
|
2010-03-04 13:05:03 +00:00
|
|
|
struct sc_file *file = NULL, *df = profile->df_info->file;
|
2010-02-20 20:09:22 +00:00
|
|
|
unsigned char buffer[128], *p, *end;
|
2003-12-02 15:51:52 +00:00
|
|
|
unsigned int method;
|
|
|
|
unsigned long key_ref;
|
2003-11-19 20:37:02 +00:00
|
|
|
int n, r;
|
|
|
|
|
2010-03-18 09:10:51 +00:00
|
|
|
if (profile->ops->emu_write_info)
|
2010-07-02 13:46:13 +00:00
|
|
|
return profile->ops->emu_write_info(profile, p15card, pin_obj);
|
2010-03-18 09:10:51 +00:00
|
|
|
|
2010-02-20 20:09:22 +00:00
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
|
2003-11-19 20:37:02 +00:00
|
|
|
file = sc_file_new();
|
2003-12-02 15:51:52 +00:00
|
|
|
file->path.type = SC_PATH_TYPE_PATH;
|
|
|
|
memcpy(file->path.value, df->path.value, df->path.len);
|
|
|
|
file->path.len = df->path.len;
|
|
|
|
sc_append_file_id(&file->path, OPENSC_INFO_FILEID);
|
2003-11-19 20:37:02 +00:00
|
|
|
file->type = SC_FILE_TYPE_WORKING_EF;
|
|
|
|
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
|
|
|
file->id = OPENSC_INFO_FILEID;
|
2010-02-20 20:09:22 +00:00
|
|
|
file->size = sizeof(buffer);
|
2003-11-19 20:37:02 +00:00
|
|
|
|
2003-12-02 15:51:52 +00:00
|
|
|
if (pin_obj != NULL) {
|
|
|
|
method = SC_AC_CHV;
|
2010-03-04 13:05:03 +00:00
|
|
|
key_ref = ((struct sc_pkcs15_pin_info *) pin_obj->data)->reference;
|
2003-12-02 15:51:52 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
method = SC_AC_NONE; /* Unprotected */
|
|
|
|
key_ref = 0;
|
|
|
|
}
|
|
|
|
for (n = 0; n < SC_MAX_AC_OPS; n++) {
|
|
|
|
if (n == SC_AC_OP_READ)
|
|
|
|
sc_file_add_acl_entry(file, n, SC_AC_NONE, 0);
|
|
|
|
else
|
|
|
|
sc_file_add_acl_entry(file, n, method, key_ref);
|
|
|
|
}
|
2003-11-24 10:21:36 +00:00
|
|
|
|
2003-11-19 20:37:02 +00:00
|
|
|
p = buffer;
|
|
|
|
end = buffer + sizeof(buffer);
|
|
|
|
|
|
|
|
r = do_encode_string(&p, end, OPENSC_INFO_TAG_PROFILE, profile->name);
|
|
|
|
for (n = 0; r >= 0 && profile->options[n]; n++)
|
|
|
|
r = do_encode_string(&p, end, OPENSC_INFO_TAG_OPTION, profile->options[n]);
|
|
|
|
|
2010-02-20 20:09:22 +00:00
|
|
|
if (r >= 0)
|
2010-02-21 16:21:57 +00:00
|
|
|
r = sc_pkcs15init_update_file(profile, p15card, file, buffer, file->size);
|
2003-11-19 20:37:02 +00:00
|
|
|
|
|
|
|
sc_file_free(file);
|
|
|
|
return r;
|
|
|
|
}
|