- 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;
|
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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue