- 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:
parent
0877a5da74
commit
2a3e6e273d
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue