- 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:
parent
6faee57a95
commit
d2075b2c13
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue