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

View File

@ -100,7 +100,13 @@ struct sc_pkcs15init_prkeyargs {
unsigned long x509_usage;
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_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 **);
static int aodf_add_pin(struct sc_pkcs15_card *, struct sc_profile *,
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_dsa_key(struct sc_pkcs15_prkey_dsa *);
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)
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->id = keyargs->id;
key_info->usage = usage;
@ -444,23 +461,56 @@ sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card,
object->auth_id = keyargs->auth_id;
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 */
if ((r = set_so_pin_from_card(p15card, profile)) < 0)
return r;
r = profile->ops->new_key(profile, p15card->card,
&key, index, key_info);
if (r == SC_ERROR_NOT_SUPPORTED) {
/* XXX: handle extractable keys here.
* Store the private key, encrypted.
* So how does PKCS15 say this should be done? */
}
/* Get the number of private keys already on this card */
index = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY, NULL, 0);
if (!keyargs->extractable) {
r = profile->ops->new_key(profile, p15card->card,
&key, index, key_info);
if (r < 0)
return r;
} else {
sc_pkcs15_der_t encoded, wrapped, *der = &encoded;
struct sc_context *ctx = p15card->card->ctx;
if (r < 0)
return r;
key_info->native = 0;
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,
&p15card->df[SC_PKCS15_PRKDF], 0, object);
@ -715,6 +765,44 @@ sc_pkcs15init_keybits(sc_pkcs15_bignum_t *bn)
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
* 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 init_keyargs(struct sc_pkcs15init_prkeyargs *);
static int read_one_pin(struct sc_profile *, const char *,
const struct sc_pkcs15_pin_info *, int, char **);
static int get_pin_callback(struct sc_profile *profile,
@ -87,6 +88,8 @@ enum {
OPT_OPTIONS = 0x100,
OPT_PASSPHRASE,
OPT_PUBKEY,
OPT_EXTRACTABLE,
OPT_UNPROTECTED,
OPT_PIN1 = 0x10000, /* don't touch these values */
OPT_PUK1 = 0x10001,
@ -115,6 +118,9 @@ const struct option options[] = {
{ "passphrase", required_argument, 0, OPT_PASSPHRASE },
{ "store-certificate", required_argument, 0, 'X' },
{ "extractable", no_argument, 0, OPT_EXTRACTABLE },
{ "insecure", no_argument, 0, OPT_UNPROTECTED },
{ "profile", required_argument, 0, 'p' },
{ "options-file", required_argument, 0, OPT_OPTIONS },
{ "debug", no_argument, 0, 'd' },
@ -140,6 +146,9 @@ const char * option_help[] = {
"Specify passphrase for unlocking secret key",
"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",
"Read additional command line options from file",
"Enable debugging output",
@ -171,6 +180,7 @@ static int opt_debug = 0,
opt_quiet = 0,
opt_action = 0,
opt_erase = 0,
opt_extractable = 0,
opt_unprotected = 0;
static char * opt_profile = "pkcs15";
static char * opt_infile = 0;
@ -405,17 +415,8 @@ do_store_private_key(struct sc_profile *profile)
X509 *cert = NULL;
int r;
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 "
"specify a PIN using --auth-id");
return SC_ERROR_INVALID_ARGUMENTS;
}
args.label = opt_objectlabel;
if ((r = init_keyargs(&args)) < 0)
return r;
r = do_read_private_key(opt_infile, opt_format, &pkey, &cert);
if (r < 0)
@ -514,8 +515,10 @@ do_generate_key(struct sc_profile *profile, const char *spec)
unsigned int evp_algo, keybits = 1024;
int r;
if ((r = init_keyargs(&args)) < 0)
return r;
/* Parse the key spec given on the command line */
memset(&args, 0, sizeof(args));
if (!strncasecmp(spec, "rsa", 3)) {
args.key.algorithm = SC_ALGORITHM_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);
if (r < 0) {
EVP_PKEY *pkey;
@ -584,6 +576,37 @@ do_generate_key(struct sc_profile *profile, const char *spec)
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
@ -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->priv, src->priv_key);
DSA_free(src);
break;
}
default:
fatal("Unsupported key algorithm\n");
@ -1086,6 +1110,12 @@ handle_option(int c)
opt_action = ACTION_STORE_PUBKEY;
opt_infile = optarg;
break;
case OPT_UNPROTECTED:
opt_unprotected++;
break;
case OPT_EXTRACTABLE:
opt_extractable++;
break;
default:
print_usage_and_die("pkcs15-init");
}