- starting to support extractable keys

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@557 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
okir 2002-04-17 20:47:18 +00:00
parent 0877a5da74
commit 2a3e6e273d
5 changed files with 181 additions and 40 deletions

View File

@ -57,6 +57,17 @@ filesystem {
WRITE=$PIN; WRITE=$PIN;
} }
# Extractable private keys are stored in transparent EFs.
# Encryption of the content is performed by libopensc.
EF template-extractable-key {
file-id = 7000;
structure = transparent;
ACL = *=NEVER,
READ=$PIN,
UPDATE=$PIN,
WRITE=$PIN;
}
EF template-public-key { EF template-public-key {
file-id = 8000; file-id = 8000;
structure = transparent; structure = transparent;

View File

@ -300,7 +300,7 @@ gpk_new_key(struct sc_profile *profile, struct sc_card *card,
struct sc_pkcs15_prkey *key, unsigned int index, struct sc_pkcs15_prkey *key, unsigned int index,
struct sc_pkcs15_prkey_info *info) struct sc_pkcs15_prkey_info *info)
{ {
struct sc_file *keyfile; struct sc_file *keyfile = NULL;
struct pkdata data; struct pkdata data;
int r; int r;
@ -333,8 +333,10 @@ gpk_new_key(struct sc_profile *profile, struct sc_card *card,
if (r >= 0) if (r >= 0)
r = gpk_store_pk(profile, card, keyfile, &data); r = gpk_store_pk(profile, card, keyfile, &data);
info->path = keyfile->path; if (keyfile) {
sc_file_free(keyfile); info->path = keyfile->path;
sc_file_free(keyfile);
}
return r; return r;
} }
@ -364,13 +366,17 @@ gpk_new_file(struct sc_profile *profile, struct sc_card *card,
#ifdef SC_PKCS15_TYPE_PRKEY_DSA #ifdef SC_PKCS15_TYPE_PRKEY_DSA
case SC_PKCS15_TYPE_PRKEY_DSA: case SC_PKCS15_TYPE_PRKEY_DSA:
desc = "DSA private key"; desc = "DSA private key";
tag = "data"; tag = "private-key";
break; break;
case SC_PKCS15_TYPE_PUBKEY_DSA: case SC_PKCS15_TYPE_PUBKEY_DSA:
desc = "DSA public key"; desc = "DSA public key";
tag = "data"; tag = "public-key";
break; break;
#endif #endif
case SC_PKCS15_TYPE_PRKEY:
desc = "extractable private key";
tag = "extractable-key";
break;
case SC_PKCS15_TYPE_CERT: case SC_PKCS15_TYPE_CERT:
desc = "certificate"; desc = "certificate";
tag = "certificate"; tag = "certificate";

View File

@ -100,7 +100,13 @@ struct sc_pkcs15init_prkeyargs {
unsigned long x509_usage; unsigned long x509_usage;
sc_pkcs15_prkey_t key; sc_pkcs15_prkey_t key;
/* support for non-native keys */
unsigned int extractable;
char * passphrase;
}; };
#define SC_PKCS15INIT_EXTRACTABLE 0x0001
#define SC_PKCS15INIT_NO_PASSPHRASE 0x0002
struct sc_pkcs15init_pubkeyargs { struct sc_pkcs15init_pubkeyargs {
struct sc_pkcs15_id id; struct sc_pkcs15_id id;

View File

@ -79,6 +79,8 @@ static int do_select_parent(struct sc_profile *, struct sc_card *,
struct sc_file *, struct sc_file **); struct sc_file *, struct sc_file **);
static int aodf_add_pin(struct sc_pkcs15_card *, struct sc_profile *, static int aodf_add_pin(struct sc_pkcs15_card *, struct sc_profile *,
const struct sc_pkcs15_pin_info *, const char *); const struct sc_pkcs15_pin_info *, const char *);
static int check_key_compatibility(struct sc_pkcs15_card *,
struct sc_pkcs15_prkey *, unsigned int);
static int fixup_rsa_key(struct sc_pkcs15_prkey_rsa *); static int fixup_rsa_key(struct sc_pkcs15_prkey_rsa *);
static int fixup_dsa_key(struct sc_pkcs15_prkey_dsa *); static int fixup_dsa_key(struct sc_pkcs15_prkey_dsa *);
static void default_error_handler(const char *fmt, ...); static void default_error_handler(const char *fmt, ...);
@ -429,6 +431,21 @@ sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card,
if ((label = keyargs->label) == NULL) if ((label = keyargs->label) == NULL)
label = "Private Key"; label = "Private Key";
/* Now check whether the card is able to handle this key */
if (!check_key_compatibility(p15card, &key, keybits)) {
/* Make sure the caller explicitly tells us to store
* the key non-natively. */
if (!keyargs->extractable) {
p15init_error("Card does not support this key.");
return SC_ERROR_INCOMPATIBLE_KEY;
}
if (!keyargs->passphrase
&& !(keyargs->extractable & SC_PKCS15INIT_NO_PASSPHRASE)) {
p15init_error("No key encryption passphrase given.");
return SC_ERROR_PASSPHRASE_REQUIRED;
}
}
key_info = calloc(1, sizeof(*key_info)); key_info = calloc(1, sizeof(*key_info));
key_info->id = keyargs->id; key_info->id = keyargs->id;
key_info->usage = usage; key_info->usage = usage;
@ -444,23 +461,56 @@ sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card,
object->auth_id = keyargs->auth_id; object->auth_id = keyargs->auth_id;
strncpy(object->label, label, sizeof(object->label)); strncpy(object->label, label, sizeof(object->label));
/* Get the number of private keys already on this card */
index = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY, NULL, 0);
/* Set the SO PIN reference from card */ /* Set the SO PIN reference from card */
if ((r = set_so_pin_from_card(p15card, profile)) < 0) if ((r = set_so_pin_from_card(p15card, profile)) < 0)
return r; return r;
r = profile->ops->new_key(profile, p15card->card, /* Get the number of private keys already on this card */
&key, index, key_info); index = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY, NULL, 0);
if (r == SC_ERROR_NOT_SUPPORTED) { if (!keyargs->extractable) {
/* XXX: handle extractable keys here. r = profile->ops->new_key(profile, p15card->card,
* Store the private key, encrypted. &key, index, key_info);
* So how does PKCS15 say this should be done? */ if (r < 0)
} return r;
} else {
sc_pkcs15_der_t encoded, wrapped, *der = &encoded;
struct sc_context *ctx = p15card->card->ctx;
if (r < 0) key_info->native = 0;
return r; object->flags |= SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
object->flags &= ~SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE;
/* DER encode the private key */
encoded.value = wrapped.value = NULL;
r = sc_pkcs15_encode_prkey(ctx, &key, &encoded.value, &encoded.len);
if (r < 0)
return r;
if (keyargs->passphrase) {
r = sc_pkcs15_wrap_data(ctx, keyargs->passphrase,
der->value, der->len,
&wrapped.value, &wrapped.len);
if (r < 0) {
free(der->value);
return r;
}
der = &wrapped;
}
r = sc_pkcs15init_store_data(p15card, profile,
SC_PKCS15_TYPE_PRKEY, der, &key_info->path);
/* 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);
if (r < 0)
return r;
}
r = sc_pkcs15_add_object(p15card, r = sc_pkcs15_add_object(p15card,
&p15card->df[SC_PKCS15_PRKDF], 0, object); &p15card->df[SC_PKCS15_PRKDF], 0, object);
@ -715,6 +765,44 @@ sc_pkcs15init_keybits(sc_pkcs15_bignum_t *bn)
return bits; return bits;
} }
/*
* Check whether the card has native crypto support for this key.
*/
static int
check_key_compatibility(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_prkey *key,
unsigned int key_length)
{
struct sc_algorithm_info *info;
unsigned int count;
count = p15card->card->algorithm_count;
info = p15card->card->algorithms;
while (count--) {
/* XXX: check for equality, or <= ? */
if (info->algorithm != key->algorithm
|| info->key_length != key_length)
continue;
if (key->algorithm == SC_ALGORITHM_RSA
&& info->u._rsa.exponent != 0) {
sc_pkcs15_bignum_t *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;
}
return 1;
}
return 0;
}
/* /*
* Check RSA key for consistency, and compute missing * Check RSA key for consistency, and compute missing
* CRT elements * CRT elements

View File

@ -67,6 +67,7 @@ static int do_convert_public_key(struct sc_pkcs15_pubkey *, EVP_PKEY *);
static int do_convert_cert(sc_pkcs15_der_t *, X509 *); static int do_convert_cert(sc_pkcs15_der_t *, X509 *);
static int init_keyargs(struct sc_pkcs15init_prkeyargs *);
static int read_one_pin(struct sc_profile *, const char *, static int read_one_pin(struct sc_profile *, const char *,
const struct sc_pkcs15_pin_info *, int, char **); const struct sc_pkcs15_pin_info *, int, char **);
static int get_pin_callback(struct sc_profile *profile, static int get_pin_callback(struct sc_profile *profile,
@ -87,6 +88,8 @@ enum {
OPT_OPTIONS = 0x100, OPT_OPTIONS = 0x100,
OPT_PASSPHRASE, OPT_PASSPHRASE,
OPT_PUBKEY, OPT_PUBKEY,
OPT_EXTRACTABLE,
OPT_UNPROTECTED,
OPT_PIN1 = 0x10000, /* don't touch these values */ OPT_PIN1 = 0x10000, /* don't touch these values */
OPT_PUK1 = 0x10001, OPT_PUK1 = 0x10001,
@ -115,6 +118,9 @@ const struct option options[] = {
{ "passphrase", required_argument, 0, OPT_PASSPHRASE }, { "passphrase", required_argument, 0, OPT_PASSPHRASE },
{ "store-certificate", required_argument, 0, 'X' }, { "store-certificate", required_argument, 0, 'X' },
{ "extractable", no_argument, 0, OPT_EXTRACTABLE },
{ "insecure", no_argument, 0, OPT_UNPROTECTED },
{ "profile", required_argument, 0, 'p' }, { "profile", required_argument, 0, 'p' },
{ "options-file", required_argument, 0, OPT_OPTIONS }, { "options-file", required_argument, 0, OPT_OPTIONS },
{ "debug", no_argument, 0, 'd' }, { "debug", no_argument, 0, 'd' },
@ -140,6 +146,9 @@ const char * option_help[] = {
"Specify passphrase for unlocking secret key", "Specify passphrase for unlocking secret key",
"Store an X.509 certificate", "Store an X.509 certificate",
"Private key stored as an extractable key",
"Insecure mode: do not require PIN/passphrase for private key",
"Specify the profile to use", "Specify the profile to use",
"Read additional command line options from file", "Read additional command line options from file",
"Enable debugging output", "Enable debugging output",
@ -171,6 +180,7 @@ static int opt_debug = 0,
opt_quiet = 0, opt_quiet = 0,
opt_action = 0, opt_action = 0,
opt_erase = 0, opt_erase = 0,
opt_extractable = 0,
opt_unprotected = 0; opt_unprotected = 0;
static char * opt_profile = "pkcs15"; static char * opt_profile = "pkcs15";
static char * opt_infile = 0; static char * opt_infile = 0;
@ -405,17 +415,8 @@ do_store_private_key(struct sc_profile *profile)
X509 *cert = NULL; X509 *cert = NULL;
int r; int r;
memset(&args, 0, sizeof(args)); if ((r = init_keyargs(&args)) < 0)
if (opt_objectid) return r;
sc_pkcs15_format_id(opt_objectid, &args.id);
if (opt_authid) {
sc_pkcs15_format_id(opt_authid, &args.auth_id);
} else if (!opt_unprotected) {
error("no PIN given for key - either use --unprotected or "
"specify a PIN using --auth-id");
return SC_ERROR_INVALID_ARGUMENTS;
}
args.label = opt_objectlabel;
r = do_read_private_key(opt_infile, opt_format, &pkey, &cert); r = do_read_private_key(opt_infile, opt_format, &pkey, &cert);
if (r < 0) if (r < 0)
@ -514,8 +515,10 @@ do_generate_key(struct sc_profile *profile, const char *spec)
unsigned int evp_algo, keybits = 1024; unsigned int evp_algo, keybits = 1024;
int r; int r;
if ((r = init_keyargs(&args)) < 0)
return r;
/* Parse the key spec given on the command line */ /* Parse the key spec given on the command line */
memset(&args, 0, sizeof(args));
if (!strncasecmp(spec, "rsa", 3)) { if (!strncasecmp(spec, "rsa", 3)) {
args.key.algorithm = SC_ALGORITHM_RSA; args.key.algorithm = SC_ALGORITHM_RSA;
evp_algo = EVP_PKEY_RSA; evp_algo = EVP_PKEY_RSA;
@ -541,17 +544,6 @@ do_generate_key(struct sc_profile *profile, const char *spec)
} }
} }
if (opt_objectid)
sc_pkcs15_format_id(opt_objectid, &args.id);
if (opt_authid)
sc_pkcs15_format_id(opt_authid, &args.auth_id);
else if (!opt_unprotected) {
error("no PIN given for key - either use --unprotected or "
"specify a PIN using --auth-id");
return SC_ERROR_INVALID_ARGUMENTS;
}
args.label = opt_objectlabel;
r = sc_pkcs15init_generate_key(p15card, profile, &args, keybits, NULL); r = sc_pkcs15init_generate_key(p15card, profile, &args, keybits, NULL);
if (r < 0) { if (r < 0) {
EVP_PKEY *pkey; EVP_PKEY *pkey;
@ -584,6 +576,37 @@ do_generate_key(struct sc_profile *profile, const char *spec)
return r; return r;
} }
int
init_keyargs(struct sc_pkcs15init_prkeyargs *args)
{
memset(args, 0, sizeof(*args));
if (opt_objectid)
sc_pkcs15_format_id(opt_objectid, &args->id);
if (opt_authid) {
sc_pkcs15_format_id(opt_authid, &args->auth_id);
} else if (!opt_unprotected) {
error("no PIN given for key - either use --unprotected or \n"
"specify a PIN using --auth-id");
return SC_ERROR_INVALID_ARGUMENTS;
}
if (opt_extractable) {
args->extractable |= SC_PKCS15INIT_EXTRACTABLE;
if (opt_passphrase) {
args->passphrase = opt_passphrase;
} else {
if (!opt_unprotected) {
error("no pass phrase given for key - "
"either use --unprotected or\n"
"specify a pass phrase using "
"--passphrase");
return SC_ERROR_PASSPHRASE_REQUIRED;
}
args->extractable |= SC_PKCS15INIT_NO_PASSPHRASE;
}
}
args->label = opt_objectlabel;
return 0;
}
/* /*
* Callbacks from the pkcs15init to retrieve PINs * Callbacks from the pkcs15init to retrieve PINs
@ -971,6 +994,7 @@ do_convert_private_key(struct sc_pkcs15_prkey *key, EVP_PKEY *pk)
do_convert_bignum(&dst->g, src->g); do_convert_bignum(&dst->g, src->g);
do_convert_bignum(&dst->priv, src->priv_key); do_convert_bignum(&dst->priv, src->priv_key);
DSA_free(src); DSA_free(src);
break;
} }
default: default:
fatal("Unsupported key algorithm\n"); fatal("Unsupported key algorithm\n");
@ -1086,6 +1110,12 @@ handle_option(int c)
opt_action = ACTION_STORE_PUBKEY; opt_action = ACTION_STORE_PUBKEY;
opt_infile = optarg; opt_infile = optarg;
break; break;
case OPT_UNPROTECTED:
opt_unprotected++;
break;
case OPT_EXTRACTABLE:
opt_extractable++;
break;
default: default:
print_usage_and_die("pkcs15-init"); print_usage_and_die("pkcs15-init");
} }