- implemented split-key support for CardOS

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1038 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
okir 2003-04-17 12:38:08 +00:00
parent 6faee57a95
commit d2075b2c13
12 changed files with 301 additions and 102 deletions

View File

@ -121,6 +121,11 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
if (!prkey->native)
return SC_ERROR_EXTRACTABLE_KEY;
if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP))) {
error(ctx, "This key cannot be used for decryption\n");
return SC_ERROR_NOT_ALLOWED;
}
alg_info = _sc_card_find_rsa_alg(p15card->card, prkey->modulus_length);
if (alg_info == NULL) {
error(ctx, "Card does not support RSA with key length %d\n", prkey->modulus_length);
@ -281,6 +286,11 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
if (!prkey->native)
return SC_ERROR_EXTRACTABLE_KEY;
if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER))) {
error(ctx, "This key cannot be used for signing\n");
return SC_ERROR_NOT_ALLOWED;
}
alg_info = _sc_card_find_rsa_alg(p15card->card, prkey->modulus_length);
if (alg_info == NULL) {
error(ctx, "Card does not support RSA with key length %d\n", prkey->modulus_length);

View File

@ -28,6 +28,13 @@
#include <assert.h>
/* Search key when looking for objects */
struct sc_pkcs15_search_key {
const struct sc_pkcs15_id * id;
unsigned int usage_mask, usage_value;
unsigned int flags_mask, flags_value;
};
static int sc_pkcs15_bind_synthetic(struct sc_pkcs15_card *);
void sc_pkcs15_print_card(const struct sc_pkcs15_card *card)
@ -684,10 +691,9 @@ int sc_pkcs15_get_objects(struct sc_pkcs15_card *p15card, int type,
return sc_pkcs15_get_objects_cond(p15card, type, NULL, NULL, ret, ret_size);
}
static int compare_obj_id(struct sc_pkcs15_object *obj, void *arg)
static int compare_obj_id(struct sc_pkcs15_object *obj, const sc_pkcs15_id_t *id)
{
void *data = obj->data;
const struct sc_pkcs15_id *id = (const struct sc_pkcs15_id *) arg;
switch (obj->type) {
case SC_PKCS15_TYPE_CERT_X509:
@ -706,13 +712,61 @@ static int compare_obj_id(struct sc_pkcs15_object *obj, void *arg)
return 0;
}
static int find_by_id(struct sc_pkcs15_card *p15card,
int type, const struct sc_pkcs15_id *id,
struct sc_pkcs15_object **out)
static int compare_obj_usage(sc_pkcs15_object_t *obj, unsigned int mask, unsigned int value)
{
void *data = obj->data;
unsigned int usage;
switch (obj->type) {
case SC_PKCS15_TYPE_PRKEY_RSA:
case SC_PKCS15_TYPE_PRKEY_DSA:
usage = ((struct sc_pkcs15_prkey_info *) data)->usage;
break;
case SC_PKCS15_TYPE_PUBKEY_RSA:
case SC_PKCS15_TYPE_PUBKEY_DSA:
usage = ((struct sc_pkcs15_pubkey_info *) data)->usage;
break;
default:
return 0;
}
return !((usage ^ value) & mask);
}
static int compare_obj_flags(sc_pkcs15_object_t *obj, unsigned int mask, unsigned int value)
{
void *data = obj->data;
unsigned int flags;
switch (obj->type) {
case SC_PKCS15_TYPE_AUTH_PIN:
flags = ((struct sc_pkcs15_pin_info *) data)->flags;
break;
default:
return 0;
}
return !((flags ^ value) & mask);
}
static int compare_obj_key(struct sc_pkcs15_object *obj, void *arg)
{
struct sc_pkcs15_search_key *sk = (struct sc_pkcs15_search_key *) arg;
if (sk->id && !compare_obj_id(obj, sk->id))
return 0;
if (sk->usage_mask && !compare_obj_usage(obj, sk->usage_mask, sk->usage_value))
return 0;
if (sk->flags_mask && !compare_obj_flags(obj, sk->flags_mask, sk->flags_value))
return 0;
return 1;
}
static int find_by_key(struct sc_pkcs15_card *p15card,
int type, struct sc_pkcs15_search_key *sk,
struct sc_pkcs15_object **out)
{
int r;
r = sc_pkcs15_get_objects_cond(p15card, type, compare_obj_id, (void *) id, out, 1);
r = sc_pkcs15_get_objects_cond(p15card, type, compare_obj_key, sk, out, 1);
if (r < 0)
return r;
if (r == 0)
@ -720,6 +774,18 @@ static int find_by_id(struct sc_pkcs15_card *p15card,
return 0;
}
static int find_by_id(struct sc_pkcs15_card *p15card,
int type, const struct sc_pkcs15_id *id,
struct sc_pkcs15_object **out)
{
struct sc_pkcs15_search_key sk;
memset(&sk, 0, sizeof(sk));
sk.id = id;
return find_by_key(p15card, type, &sk, out);
}
int sc_pkcs15_find_cert_by_id(struct sc_pkcs15_card *p15card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_object **out)
@ -755,35 +821,29 @@ int sc_pkcs15_find_data_object_by_id(struct sc_pkcs15_card *p15card,
return find_by_id(p15card, SC_PKCS15_TYPE_DATA_OBJECT, id, out);
}
static int compare_flags(struct sc_pkcs15_object *obj, void *arg)
int sc_pkcs15_find_prkey_by_id_usage(struct sc_pkcs15_card *p15card,
const struct sc_pkcs15_id *id,
unsigned int usage,
struct sc_pkcs15_object **out)
{
struct sc_pkcs15_pin_info *pin;
unsigned int *match = (unsigned int *) arg;
struct sc_pkcs15_search_key sk;
assert (obj->type == SC_PKCS15_TYPE_AUTH_PIN);
pin = (struct sc_pkcs15_pin_info *) obj->data;
return (pin->flags & match[0]) == match[1];
memset(&sk, 0, sizeof(sk));
sk.usage_mask = sk.usage_value = usage;
sk.id = id;
return find_by_key(p15card, SC_PKCS15_TYPE_PRKEY, &sk, out);
}
int sc_pkcs15_find_so_pin(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_object **out)
{
unsigned int match[2];
int r;
/* The PIN flags are masked with the first word and
* compared to the second word. */
match[0] = SC_PKCS15_PIN_FLAG_SO_PIN;
match[1] = SC_PKCS15_PIN_FLAG_SO_PIN;
struct sc_pkcs15_search_key sk;
r = sc_pkcs15_get_objects_cond(p15card,
SC_PKCS15_TYPE_AUTH_PIN, compare_flags,
match, out, 1);
if (r < 0)
return r;
if (r == 0)
return SC_ERROR_OBJECT_NOT_FOUND;
return 0;
memset(&sk, 0, sizeof(sk));
sk.flags_mask = sk.flags_value = SC_PKCS15_PIN_FLAG_SO_PIN;
return find_by_key(p15card, SC_PKCS15_TYPE_AUTH_PIN, &sk, out);
}
int sc_pkcs15_add_object(struct sc_pkcs15_card *p15card,

View File

@ -443,6 +443,10 @@ int sc_pkcs15_create(struct sc_pkcs15_card *p15card, struct sc_card *card);
int sc_pkcs15_find_prkey_by_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_object **out);
int sc_pkcs15_find_prkey_by_id_usage(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
unsigned int usage,
struct sc_pkcs15_object **out);
int sc_pkcs15_find_pubkey_by_id(struct sc_pkcs15_card *card,
const struct sc_pkcs15_id *id,
struct sc_pkcs15_object **out);

View File

@ -63,6 +63,7 @@ struct pkcs15_any_object {
struct sc_pkcs15_object * p15_object;
struct pkcs15_pubkey_object * related_pubkey;
struct pkcs15_cert_object * related_cert;
struct pkcs15_prkey_object * related_privkey;
};
struct pkcs15_cert_object {
@ -85,6 +86,7 @@ struct pkcs15_prkey_object {
#define prv_p15obj base.p15_object
#define prv_pubkey base.related_pubkey
#define prv_cert base.related_cert
#define prv_next base.related_privkey
struct pkcs15_pubkey_object {
struct pkcs15_any_object base;
@ -320,6 +322,19 @@ __pkcs15_prkey_bind_related(struct pkcs15_fw_data *fw_data, struct pkcs15_prkey_
for (i = 0; i < fw_data->num_objects; i++) {
struct pkcs15_any_object *obj = fw_data->objects[i];
if (is_privkey(obj) && obj != (struct pkcs15_any_object *) pk) {
/* merge private keys with the same ID and
* different usage bits */
struct pkcs15_prkey_object *other, **pp;
other = (struct pkcs15_prkey_object *) obj;
if (sc_pkcs15_compare_id(&other->prv_info->id, id)) {
obj->base.flags |= SC_PKCS11_OBJECT_HIDDEN;
for (pp = &pk->prv_next; *pp; pp = &(*pp)->prv_next)
;
*pp = (struct pkcs15_prkey_object *) obj;
}
} else
if (is_cert(obj) && !pk->prv_cert) {
struct pkcs15_cert_object *cert;
@ -400,7 +415,8 @@ pkcs15_add_object(struct sc_pkcs11_slot *slot,
struct pkcs15_any_object *obj,
CK_OBJECT_HANDLE_PTR pHandle)
{
if (obj == NULL)
if (obj == NULL
|| (obj->base.flags & (SC_PKCS11_OBJECT_HIDDEN | SC_PKCS11_OBJECT_RECURS)))
return;
if (pool_is_present(&slot->object_pool, obj))
@ -414,6 +430,8 @@ pkcs15_add_object(struct sc_pkcs11_slot *slot,
* XXX prevent infinite recursion when a card specifies two certificates
* referring to each other.
*/
obj->base.flags |= SC_PKCS11_OBJECT_RECURS;
switch (__p15_type(obj)) {
case SC_PKCS15_TYPE_PRKEY_RSA:
case SC_PKCS15_TYPE_CERT_X509:
@ -421,6 +439,8 @@ pkcs15_add_object(struct sc_pkcs11_slot *slot,
pkcs15_add_object(slot, (struct pkcs15_any_object *) obj->related_cert, NULL);
break;
}
obj->base.flags &= ~SC_PKCS11_OBJECT_RECURS;
}
static void pkcs15_init_slot(struct sc_pkcs15_card *card,

View File

@ -118,6 +118,8 @@ struct sc_pkcs11_object {
};
#define SC_PKCS11_OBJECT_SEEN 0x0001
#define SC_PKCS11_OBJECT_HIDDEN 0x0002
#define SC_PKCS11_OBJECT_RECURS 0x8000
/*

View File

@ -118,15 +118,16 @@ struct sc_pkcs15init_prkeyargs {
const char * label;
unsigned long usage;
unsigned long x509_usage;
unsigned int flags;
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
#define SC_PKCS15INIT_SPLIT_KEY 0x0004
struct sc_pkcs15init_pubkeyargs {
struct sc_pkcs15_id id;
@ -220,6 +221,11 @@ extern int sc_pkcs15init_erase_card_recursively(struct sc_card *,
extern int sc_pkcs15init_rmdir(struct sc_card *, struct sc_profile *,
struct sc_file *df);
/* Helper function for CardOS */
extern int sc_pkcs15init_requires_restrictive_usage(
struct sc_pkcs15_card *,
struct sc_pkcs15init_prkeyargs *);
#ifdef __cplusplus
}
#endif

View File

@ -667,12 +667,12 @@ sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card,
keyargs->x509_usage, keybits, 0)) {
/* Make sure the caller explicitly tells us to store
* the key non-natively. */
if (!keyargs->extractable) {
if (!(keyargs->flags & SC_PKCS15INIT_EXTRACTABLE)) {
p15init_error("Card does not support this key.");
return SC_ERROR_INCOMPATIBLE_KEY;
}
if (!keyargs->passphrase
&& !(keyargs->extractable & SC_PKCS15INIT_NO_PASSPHRASE)) {
&& !(keyargs->flags & SC_PKCS15INIT_NO_PASSPHRASE)) {
p15init_error("No key encryption passphrase given.");
return SC_ERROR_PASSPHRASE_REQUIRED;
}
@ -689,6 +689,10 @@ sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card,
/* Select a Key ID if the user didn't specify one, otherwise
* make sure it's unique */
if (keyargs->id.len != 0
&& (keyargs->flags & SC_PKCS15INIT_SPLIT_KEY)) {
/* Split key; this ID exists already */
} else
if ((r = select_id(p15card, SC_PKCS15_TYPE_PRKEY, &keyargs->id)) < 0)
return r;
@ -700,7 +704,7 @@ sc_pkcs15init_store_private_key(struct sc_pkcs15_card *p15card,
/* 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) {
if (!(keyargs->flags & SC_PKCS15INIT_EXTRACTABLE)) {
r = profile->ops->new_key(profile, p15card->card,
&key, index, key_info);
if (r < 0)
@ -1079,11 +1083,11 @@ sc_pkcs15init_keybits(sc_pkcs15_bignum_t *bn)
* 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 x509_usage,
unsigned int key_length,
unsigned int flags)
__check_key_compatibility(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_prkey *key,
unsigned int x509_usage,
unsigned int key_length,
unsigned int flags)
{
struct sc_algorithm_info *info;
unsigned int count;
@ -1130,15 +1134,41 @@ check_key_compatibility(struct sc_pkcs15_card *p15card,
return 1;
}
if (bad_usage) {
return bad_usage? -1 : 0;
}
static int
check_key_compatibility(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_prkey *key,
unsigned int x509_usage,
unsigned int key_length,
unsigned int flags)
{
int res;
res = __check_key_compatibility(p15card, key,
x509_usage, key_length, flags);
if (res < 0) {
p15init_error("This device requires that keys have a "
"specific key usage.\n"
"Keys can be used for either signature or decryption, "
"but not both.\n"
"Please specify a key usage.\n");
return 0;
res = 0;
}
return 0;
return res;
}
int
sc_pkcs15init_requires_restrictive_usage(struct sc_pkcs15_card *p15card,
struct sc_pkcs15init_prkeyargs *keyargs)
{
int res;
res = __check_key_compatibility(p15card, &keyargs->key,
keyargs->x509_usage,
prkey_bits(&keyargs->key), 0);
return res < 0;
}
/*

View File

@ -163,9 +163,12 @@ int p15_eid_init(scam_context * sctx, int argc, const char **argv)
/* FIXME: Add support for selecting certificate by ID */
data->cinfo = (struct sc_pkcs15_cert_info *) data->objs[0]->data;
r = sc_pkcs15_find_prkey_by_id(data->p15card, &data->cinfo->id, &data->prkey);
r = sc_pkcs15_find_prkey_by_id_usage(data->p15card,
&data->cinfo->id,
SC_PKCS15_PRKEY_USAGE_SIGN,
&data->prkey);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_find_prkey_by_id: %s\n", sc_strerror(r));
scam_print_msg(sctx, "sc_pkcs15_find_prkey_by_id_usage: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
r = sc_pkcs15_find_pin_by_auth_id(data->p15card, &data->prkey->auth_id, &data->pin);

View File

@ -136,9 +136,12 @@ int p15_ldap_init(scam_context * sctx, int argc, const char **argv)
/* FIXME: Add support for selecting certificate by ID */
data->cinfo = (struct sc_pkcs15_cert_info *) data->objs[0]->data;
r = sc_pkcs15_find_prkey_by_id(data->p15card, &data->cinfo->id, &data->prkey);
r = sc_pkcs15_find_prkey_by_id_usage(data->p15card,
&data->cinfo->id,
SC_PKCS15_PRKEY_USAGE_SIGN,
&data->prkey);
if (r != SC_SUCCESS) {
scam_print_msg(sctx, "sc_pkcs15_find_prkey_by_id: %s\n", sc_strerror(r));
scam_print_msg(sctx, "sc_pkcs15_find_prkey_by_id_usage: %s\n", sc_strerror(r));
return SCAM_FAILED;
}
r = sc_pkcs15_find_pin_by_auth_id(data->p15card, &data->prkey->auth_id, &data->pin);

View File

@ -65,7 +65,10 @@ static int sc_private_decrypt(int flen, const unsigned char *from, unsigned char
goto err;
}
}
r = sc_pkcs15_find_prkey_by_id(priv->p15card, &priv->cert_id, &key);
r = sc_pkcs15_find_prkey_by_id_usage(priv->p15card,
&priv->cert_id,
SC_PKCS15_PRKEY_USAGE_DECRYPT
&key);
if (r) {
#if 0
error("Unable to find private key from SmartCard: %s", sc_strerror(r));
@ -131,7 +134,10 @@ sc_sign(int type, const unsigned char *m, unsigned int m_len,
goto err;
}
}
r = sc_pkcs15_find_prkey_by_id(priv->p15card, &priv->cert_id, &key);
r = sc_pkcs15_find_prkey_by_id_usage(priv->p15card,
&priv->cert_id,
SC_PKCS15_PRKEY_USAGE_SIGN,
&key);
if (r) {
DBG(printf("Unable to find private key from SmartCard: %s", sc_strerror(r)));
goto err;

View File

@ -392,15 +392,75 @@ int decipher(struct sc_pkcs15_object *obj)
return 0;
}
static int get_key(unsigned int usage, sc_pkcs15_object_t **result)
{
sc_pkcs15_object_t *key, *pin;
const char *usage_name;
sc_pkcs15_id_t id;
int r;
usage_name = (usage & SC_PKCS15_PRKEY_USAGE_SIGN)? "signature" : "decryption";
if (opt_key_id != NULL) {
sc_pkcs15_hex_string_to_id(opt_key_id, &id);
r = sc_pkcs15_find_prkey_by_id_usage(p15card, &id, usage, &key);
if (r < 0) {
fprintf(stderr, "Unable to find private %s key '%s': %s\n",
usage_name, opt_key_id, sc_strerror(r));
return 2;
}
} else {
r = sc_pkcs15_find_prkey_by_id_usage(p15card, NULL, usage, &key);
if (r < 0) {
fprintf(stderr, "Unable to find any private %s key: %s\n",
usage_name, sc_strerror(r));
return 2;
}
}
*result = key;
if (key->auth_id.len) {
static sc_pkcs15_object_t *prev_pin = NULL;
char *pincode;
r = sc_pkcs15_find_pin_by_auth_id(p15card, &key->auth_id, &pin);
if (r) {
fprintf(stderr, "Unable to find PIN code for private key: %s\n",
sc_strerror(r));
return 1;
}
/* Pin already verified previously */
if (pin == prev_pin)
return 0;
pincode = get_pin(pin);
if (pincode == NULL || *pincode == '\0')
return 5;
r = sc_pkcs15_verify_pin(p15card, (struct sc_pkcs15_pin_info *) pin->data,
(const u8 *) pincode, strlen(pincode));
if (r) {
fprintf(stderr, "PIN code verification failed: %s\n", sc_strerror(r));
return 5;
}
free(pincode);
if (!quiet)
fprintf(stderr, "PIN code correct.\n");
prev_pin = pin;
}
return 0;
}
int main(int argc, char * const argv[])
{
int err = 0, r, c, long_optind = 0;
int do_decipher = 0;
int do_sign = 0;
int action_count = 0;
struct sc_pkcs15_object *key, *pin, *objs[32];
struct sc_pkcs15_id id;
char *pincode;
struct sc_pkcs15_object *key;
while (1) {
c = getopt_long(argc, argv, "sck:r:i:o:qp:dw", options, &long_optind);
@ -487,55 +547,15 @@ int main(int argc, char * const argv[])
if (!quiet)
fprintf(stderr, "Found %s!\n", p15card->label);
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_PRKEY, objs, 32);
if (r <= 0) {
if (r == 0)
r = SC_ERROR_OBJECT_NOT_FOUND;
fprintf(stderr, "Private key enumeration failed: %s\n", sc_strerror(r));
err = 1;
goto end;
}
if (opt_key_id != NULL) {
sc_pkcs15_hex_string_to_id(opt_key_id, &id);
r = sc_pkcs15_find_prkey_by_id(p15card, &id, &key);
if (r < 0) {
fprintf(stderr, "Unable to find private key '%s': %s\n",
opt_key_id, sc_strerror(r));
err = 2;
goto end;
}
} else
key = objs[0];
if (key->auth_id.len) {
r = sc_pkcs15_find_pin_by_auth_id(p15card, &key->auth_id, &pin);
if (r) {
fprintf(stderr, "Unable to find PIN code for private key: %s\n",
sc_strerror(r));
err = 1;
goto end;
}
pincode = get_pin(pin);
if (pincode == NULL) {
err = 5;
goto end;
}
r = sc_pkcs15_verify_pin(p15card, (struct sc_pkcs15_pin_info *) pin->data, (const u8 *) pincode, strlen(pincode));
if (r) {
fprintf(stderr, "PIN code verification failed: %s\n", sc_strerror(r));
err = 5;
goto end;
}
free(pincode);
if (!quiet)
fprintf(stderr, "PIN code correct.\n");
}
if (do_decipher) {
if ((err = decipher(key)))
if ((err = get_key(SC_PKCS15_PRKEY_USAGE_DECRYPT, &key)) < 0
|| (err = decipher(key)))
goto end;
action_count--;
}
if (do_sign) {
if ((err = sign(key)))
if ((err = get_key(SC_PKCS15_PRKEY_USAGE_SIGN, &key)) < 0
|| (err = sign(key)))
goto end;
action_count--;
}

View File

@ -104,6 +104,7 @@ enum {
OPT_UNPROTECTED,
OPT_AUTHORITY,
OPT_SOFT_KEYGEN,
OPT_SPLIT_KEY,
OPT_PIN1 = 0x10000, /* don't touch these values */
OPT_PUK1 = 0x10001,
@ -136,6 +137,7 @@ const struct option options[] = {
{ "passphrase", required_argument, 0, OPT_PASSPHRASE },
{ "authority", no_argument, 0, OPT_AUTHORITY },
{ "key-usage", required_argument, 0, 'u' },
{ "split-key", no_argument, 0, OPT_SPLIT_KEY },
{ "extractable", no_argument, 0, OPT_EXTRACTABLE },
{ "insecure", no_argument, 0, OPT_UNPROTECTED },
@ -173,6 +175,7 @@ const char * option_help[] = {
"Specify passphrase for unlocking secret key",
"Mark certificate as a CA certificate",
"Specify X.509 key usage (use \"--key-usage help\" for more information)",
"Automatically create two keys with same ID and different usage (sign vs decipher)",
"Private key stored as an extractable key",
"Insecure mode: do not require PIN/passphrase for private key",
@ -224,6 +227,7 @@ static int opt_reader = -1,
opt_softkeygen = 0,
opt_noprompts = 0,
opt_use_defkeys = 0,
opt_split_key = 0,
opt_wait = 0;
static char * opt_profile = "pkcs15";
static char * opt_infile = 0;
@ -495,6 +499,12 @@ do_store_private_key(struct sc_profile *profile)
if ((r = do_convert_private_key(&args.key, pkey)) < 0)
return r;
if (ncerts) {
unsigned int usage = cert[0]->ex_kusage;
/* No certificate usage? Assume ordinary
* user cert */
usage = 0x1F;
/* If the user requested a specific key usage on the
* command line check if it includes _more_
* usage bits than the one specified by the cert,
@ -502,20 +512,42 @@ do_store_private_key(struct sc_profile *profile)
* If the usage specified on the command line
* is more restrictive, use that.
*/
if (~cert[0]->ex_kusage & opt_x509_usage) {
if (~usage & opt_x509_usage) {
fprintf(stderr,
"Warning: requested key usage incompatible with "
"key usage specified by X.509 certificate\n");
}
if (opt_x509_usage) {
args.x509_usage = opt_x509_usage;
} else {
args.x509_usage = cert[0]->ex_kusage;
}
args.x509_usage = opt_x509_usage? opt_x509_usage : usage;
}
if (sc_pkcs15init_requires_restrictive_usage(p15card, &args)) {
unsigned int usage = args.x509_usage;
if (!opt_split_key) {
fprintf(stderr, "\n"
"Error - this token requires a more restrictive key usage.\n"
"Keys stored on this token can be used either for signing or decipherment,\n"
"but not both. You can either specify a more restrictive usage through\n"
"the --key-usage command line argument, or allow me to transparently\n"
"create two key objects with separate usage by specifying --split-key\n");
exit(1);
}
/* keyEncipherment|dataEncipherment|keyAgreement */
args.x509_usage = usage & 0x1C;
r = sc_pkcs15init_store_private_key(p15card, profile, &args, NULL);
if (r >= 0) {
/* digitalSignature|nonRepudiation|certSign|cRLSign */
args.x509_usage = usage & 0x63;
/* Prevent pkcs15init from choking on duplicate ID */
args.flags |= SC_PKCS15INIT_SPLIT_KEY;
r = sc_pkcs15init_store_private_key(p15card, profile, &args, NULL);
}
} else {
r = sc_pkcs15init_store_private_key(p15card, profile, &args, NULL);
}
r = sc_pkcs15init_store_private_key(p15card, profile, &args, NULL);
if (r < 0)
return r;
@ -716,7 +748,7 @@ init_keyargs(struct sc_pkcs15init_prkeyargs *args)
return SC_ERROR_INVALID_ARGUMENTS;
}
if (opt_extractable) {
args->extractable |= SC_PKCS15INIT_EXTRACTABLE;
args->flags |= SC_PKCS15INIT_EXTRACTABLE;
if (opt_passphrase) {
args->passphrase = opt_passphrase;
} else {
@ -727,7 +759,7 @@ init_keyargs(struct sc_pkcs15init_prkeyargs *args)
"--passphrase");
return SC_ERROR_PASSPHRASE_REQUIRED;
}
args->extractable |= SC_PKCS15INIT_NO_PASSPHRASE;
args->flags |= SC_PKCS15INIT_NO_PASSPHRASE;
}
}
args->label = opt_label;
@ -1516,6 +1548,9 @@ handle_option(int c)
case 'T':
opt_use_defkeys = 1;
break;
case OPT_SPLIT_KEY:
opt_split_key = 1;
break;
default:
print_usage_and_die();
}