OpenPGP Card v3 ECC support (#1506)
* pgp: initialize ecc keys for OPC3 * Add supported ECC algorithms by card version * Add tasks identified so far * pgp: Recognize ECC set on card * pgp: get_pubkey_pem read ECC pubkey from card * pgp: minor code changes for ECC compatibility * pgp: expand sc_cardctl_openpgp_keygen_info to hold ec info * Fix segfault problem in pkcs15-pubkey.c * pgp: enable key generation with pkcs15-init and ECC * pgp: adapt calculate_and_store_fingerprint to accept ECC * pgp: adapt rest of pgp_gen_key and subfunctions to accept ECC * pgp: add kdf parameters for ECDH fingerprint calculation * pgp: enable key import with pkcs15-init and ECC * pkcs15-pubkey: fix_ec_parameters onlz accpets explicit data or named_curve * Fix some mistakes during merge * More clean up for PR * Fix some ugly alignments * Improve code readability * Prevent unitialized variable by using FUNC_RETURN * OpenPGP: add length check * pgp: save exponent length in bits for sc_cardctl_openpgp_keystore_info_t * pgp: length checks and reallocations * pgp: oid init added * OpenPGP: slightly re-factor pgp_update_new_algo_attr() * replace loop copy with memcpy() * use ushort2bebytes() to set RSA modulus & exponent * use symbolic name SC_OPENPGP_KEYFORMAT_RSA_STD for the key import format * OpenPGP: slighly re-factor pgp_parse_and_set_pubkey_output() * check for RSA modulus & exponent lengths not being a multiple of 8 * make sure RSA modulus & exponent lengths are always set * remove a left-over RSA setting from the EC code * pgp: adding BYTES4BITS * pgp: initialization of values in pgp_build_extended_header_list based on key type * pgp: add BYTES4BITS and remove unnecessary tests * Fix broken pgp_update_new_algo_attr * pgp: fix the ecpoint_len variable
This commit is contained in:
parent
7a7ff50422
commit
09a594d0f0
File diff suppressed because it is too large
Load Diff
|
@ -944,38 +944,45 @@ typedef struct sc_cardctl_piv_genkey_info_st {
|
|||
#define SC_OPENPGP_KEY_AUTH 3
|
||||
|
||||
#define SC_OPENPGP_KEYALGO_RSA 0x01
|
||||
#define SC_OPENPGP_KEYALGO_ECDH 0x12
|
||||
#define SC_OPENPGP_KEYALGO_ECDSA 0x13
|
||||
|
||||
#define SC_OPENPGP_KEYFORMAT_RSA_STD 0 /* See 4.3.3.6 Algorithm Attributes */
|
||||
#define SC_OPENPGP_KEYFORMAT_RSA_STDN 1 /* OpenPGP card spec v2 */
|
||||
#define SC_OPENPGP_KEYFORMAT_RSA_CRT 2
|
||||
#define SC_OPENPGP_KEYFORMAT_RSA_CRTN 3
|
||||
|
||||
#define SC_OPENPGP_MAX_EXP_BITS 0x20 /* maximum exponent length supported in bits */
|
||||
|
||||
typedef struct sc_cardctl_openpgp_keygen_info {
|
||||
u8 key_id; /* SC_OPENPGP_KEY_... */
|
||||
u8 algorithm; /* SC_OPENPGP_KEYALGO_... */
|
||||
union { /* anonymous union */
|
||||
union {
|
||||
struct {
|
||||
u8 *modulus; /* New-generated pubkey info responded from the card */
|
||||
size_t modulus_len; /* Length of modulus in bit */
|
||||
u8 *exponent;
|
||||
size_t exponent_len;
|
||||
u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */
|
||||
size_t exponent_len; /* Length of exponent in bit */
|
||||
u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */
|
||||
} rsa;
|
||||
struct {
|
||||
u8 dummy; /* placeholder */
|
||||
// TODO: replace placeholder with real attributes
|
||||
u8 *ecpoint;
|
||||
size_t ecpoint_len;
|
||||
struct sc_object_id oid;
|
||||
u8 oid_len;
|
||||
unsigned int key_length;
|
||||
} ec;
|
||||
};
|
||||
} u;
|
||||
} sc_cardctl_openpgp_keygen_info_t;
|
||||
|
||||
typedef struct sc_cardctl_openpgp_keystore_info {
|
||||
u8 key_id; /* SC_OPENPGP_KEY_... */
|
||||
u8 algorithm; /* SC_OPENPGP_KEYALGO_... */
|
||||
union { /* anonymous union */
|
||||
union {
|
||||
struct {
|
||||
u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */
|
||||
u8 *e;
|
||||
size_t e_len;
|
||||
size_t e_len; /* Length of exponent in bit */
|
||||
u8 *p;
|
||||
size_t p_len;
|
||||
u8 *q;
|
||||
|
@ -984,10 +991,12 @@ typedef struct sc_cardctl_openpgp_keystore_info {
|
|||
size_t n_len;
|
||||
} rsa;
|
||||
struct {
|
||||
u8 dummy; /* placeholder */
|
||||
// TODO: replace placeholder with real attributes
|
||||
u8 *privateD;
|
||||
size_t privateD_len;
|
||||
u8 *ecpoint;
|
||||
size_t ecpoint_len;
|
||||
} ec;
|
||||
};
|
||||
} u;
|
||||
time_t creationtime;
|
||||
} sc_cardctl_openpgp_keystore_info_t;
|
||||
|
||||
|
|
|
@ -118,6 +118,8 @@ unsigned short bebytes2ushort(const u8 *buf);
|
|||
*/
|
||||
unsigned short lebytes2ushort(const u8 *buf);
|
||||
|
||||
#define BYTES4BITS(num) (((num) + 7) / 8) /* number of bytes necessary to hold 'num' bits */
|
||||
|
||||
/* Returns an scconf_block entry with matching ATR/ATRmask to the ATR specified,
|
||||
* NULL otherwise. Additionally, if card driver is not specified, search through
|
||||
* all card drivers user configured ATRs. */
|
||||
|
|
|
@ -268,20 +268,17 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
for (i = 0; i < 3; i++) {
|
||||
sc_pkcs15_prkey_info_t prkey_info;
|
||||
sc_pkcs15_object_t prkey_obj;
|
||||
u8 cxdata[10];
|
||||
u8 cxdata[12];
|
||||
char path_template[] = "006E:0073:00Cx";
|
||||
int j;
|
||||
|
||||
memset(&prkey_info, 0, sizeof(prkey_info));
|
||||
memset(&prkey_obj, 0, sizeof(prkey_obj));
|
||||
memset(&cxdata, 0, sizeof(cxdata));
|
||||
|
||||
path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */
|
||||
if ((r = read_file(card, path_template, cxdata, sizeof(cxdata))) < 0)
|
||||
goto failed;
|
||||
if (r != 6) {
|
||||
sc_log(ctx, "Key info bytes have unexpected length (expected 6, got %d)\n", r);
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
/* check validity using finger prints */
|
||||
for (j = 19; j >= 0; j--) {
|
||||
|
@ -296,14 +293,21 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
prkey_info.usage = key_cfg[i].prkey_usage;
|
||||
prkey_info.native = 1;
|
||||
prkey_info.key_reference = i;
|
||||
prkey_info.modulus_length = bebytes2ushort(cxdata + 1);
|
||||
|
||||
strlcpy(prkey_obj.label, key_cfg[i].label, sizeof(prkey_obj.label));
|
||||
prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE;
|
||||
prkey_obj.auth_id.len = 1;
|
||||
prkey_obj.auth_id.value[0] = key_cfg[i].prkey_pin;
|
||||
|
||||
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_RSA && r >= 3) {
|
||||
prkey_info.modulus_length = bebytes2ushort(cxdata + 1);
|
||||
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
}
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH
|
||||
|| cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA) {
|
||||
r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
|
@ -318,14 +322,11 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
|
||||
memset(&pubkey_info, 0, sizeof(pubkey_info));
|
||||
memset(&pubkey_obj, 0, sizeof(pubkey_obj));
|
||||
memset(&cxdata, 0, sizeof(cxdata));
|
||||
|
||||
path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */
|
||||
if ((r = read_file(card, path_template, cxdata, sizeof(cxdata))) < 0)
|
||||
goto failed;
|
||||
if (r != 6) {
|
||||
sc_log(ctx, "Key info bytes have unexpected length (expected 6, got %d)\n", r);
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
/* check validity using finger prints */
|
||||
for (j = 19; j >= 0; j--) {
|
||||
|
@ -337,14 +338,21 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
|||
if (j >= 0 && cxdata[0] != 0) {
|
||||
pubkey_info.id.len = 1;
|
||||
pubkey_info.id.value[0] = i + 1;
|
||||
pubkey_info.modulus_length = bebytes2ushort(cxdata + 1);
|
||||
pubkey_info.usage = key_cfg[i].pubkey_usage;
|
||||
sc_format_path(key_cfg[i].pubkey_path, &pubkey_info.path);
|
||||
|
||||
strlcpy(pubkey_obj.label, key_cfg[i].label, sizeof(pubkey_obj.label));
|
||||
pubkey_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
|
||||
|
||||
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_RSA && r >= 3) {
|
||||
pubkey_info.modulus_length = bebytes2ushort(cxdata + 1);
|
||||
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
}
|
||||
if (cxdata[0] == SC_OPENPGP_KEYALGO_ECDH
|
||||
|| cxdata[0] == SC_OPENPGP_KEYALGO_ECDSA) {
|
||||
r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return SC_ERROR_INTERNAL;
|
||||
}
|
||||
|
|
|
@ -1074,6 +1074,8 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc
|
|||
u8* alg;
|
||||
size_t alglen;
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
|
||||
if (!key || !out) {
|
||||
return SC_ERROR_INVALID_ARGUMENTS;
|
||||
}
|
||||
|
@ -1132,9 +1134,15 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc
|
|||
memcpy(pubkey->u.ec.params.der.value, key->u.ec.params.der.value, key->u.ec.params.der.len);
|
||||
pubkey->u.ec.params.der.len = key->u.ec.params.der.len;
|
||||
|
||||
pubkey->u.ec.params.named_curve = strdup(key->u.ec.params.named_curve);
|
||||
if (!pubkey->u.ec.params.named_curve)
|
||||
rv = SC_ERROR_OUT_OF_MEMORY;
|
||||
if (key->u.ec.params.named_curve){
|
||||
pubkey->u.ec.params.named_curve = strdup(key->u.ec.params.named_curve);
|
||||
if (!pubkey->u.ec.params.named_curve)
|
||||
rv = SC_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
sc_log(ctx, "named_curve parameter missing");
|
||||
rv = SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
|
@ -1557,9 +1565,8 @@ sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecp
|
|||
LOG_TEST_RET(ctx, rv, "Cannot encode object ID");
|
||||
}
|
||||
}
|
||||
else if (sc_valid_oid(&ecparams->id)) {
|
||||
else
|
||||
LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "EC parameters has to be presented as a named curve or explicit data");
|
||||
}
|
||||
|
||||
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "libopensc/opensc.h"
|
||||
#include "libopensc/cardctl.h"
|
||||
#include "libopensc/internal.h"
|
||||
#include "libopensc/log.h"
|
||||
#include "libopensc/cards.h"
|
||||
#include "libopensc/asn1.h"
|
||||
|
@ -104,7 +105,7 @@ static int openpgp_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
|||
}
|
||||
|
||||
/**
|
||||
* Stores an external (RSA) on the card.
|
||||
* Stores an external key on the card.
|
||||
* @param profile profile information for this card
|
||||
* @param card sc_card_t object to use
|
||||
* @param obj sc_pkcs15_object_t object with pkcs15 information
|
||||
|
@ -116,45 +117,61 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
|||
{
|
||||
sc_card_t *card = p15card->card;
|
||||
sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
|
||||
struct sc_pkcs15_prkey_rsa *rsa = &(key->u.rsa);
|
||||
sc_cardctl_openpgp_keystore_info_t key_info;
|
||||
int r;
|
||||
|
||||
LOG_FUNC_CALLED(card->ctx);
|
||||
|
||||
if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
|
||||
sc_log(card->ctx, "only RSA is currently supported");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
switch(obj->type)
|
||||
{
|
||||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
memset(&key_info, 0, sizeof(sc_cardctl_openpgp_keystore_info_t));
|
||||
key_info.algorithm = SC_OPENPGP_KEYALGO_RSA;
|
||||
key_info.key_id = kinfo->id.value[0];
|
||||
key_info.u.rsa.e = key->u.rsa.exponent.data;
|
||||
key_info.u.rsa.e_len = key->u.rsa.exponent.len * 8; /* use bits instead of bytes */
|
||||
key_info.u.rsa.p = key->u.rsa.p.data;
|
||||
key_info.u.rsa.p_len = key->u.rsa.p.len;
|
||||
key_info.u.rsa.q = key->u.rsa.q.data;
|
||||
key_info.u.rsa.q_len = key->u.rsa.q.len;
|
||||
key_info.u.rsa.n = key->u.rsa.modulus.data;
|
||||
key_info.u.rsa.n_len = key->u.rsa.modulus.len * 8; /* use bits instead of bytes */
|
||||
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info);
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
if (card->type < SC_CARD_TYPE_OPENPGP_V3) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "only RSA is supported on this card");
|
||||
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
memset(&key_info, 0, sizeof(sc_cardctl_openpgp_keystore_info_t));
|
||||
key_info.algorithm = (kinfo->id.value[0] == SC_OPENPGP_KEY_ENCR)
|
||||
? SC_OPENPGP_KEYALGO_ECDH /* ECDH for slot 2 only */
|
||||
: SC_OPENPGP_KEYALGO_ECDSA; /* ECDSA for slot 1 and 3 */
|
||||
key_info.key_id = kinfo->id.value[0];
|
||||
key_info.u.ec.privateD = key->u.ec.privateD.data;
|
||||
key_info.u.ec.privateD_len = key->u.ec.privateD.len;
|
||||
key_info.u.ec.ecpoint = key->u.ec.ecpointQ.value;
|
||||
key_info.u.ec.ecpoint_len = key->u.ec.ecpointQ.len;
|
||||
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info);
|
||||
break;
|
||||
default:
|
||||
r = SC_ERROR_NOT_SUPPORTED;
|
||||
sc_log(card->ctx, "%s: Key generation failed: Unknown/unsupported key type.", strerror(r));
|
||||
}
|
||||
|
||||
memset(&key_info, 0, sizeof(sc_cardctl_openpgp_keystore_info_t));
|
||||
key_info.key_id = kinfo->id.value[0];
|
||||
key_info.algorithm = SC_OPENPGP_KEYALGO_RSA;
|
||||
key_info.rsa.e = rsa->exponent.data;
|
||||
key_info.rsa.e_len = rsa->exponent.len;
|
||||
key_info.rsa.p = rsa->p.data;
|
||||
key_info.rsa.p_len = rsa->p.len;
|
||||
key_info.rsa.q = rsa->q.data;
|
||||
key_info.rsa.q_len = rsa->q.len;
|
||||
key_info.rsa.n = rsa->modulus.data;
|
||||
key_info.rsa.n_len = rsa->modulus.len;
|
||||
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info);
|
||||
|
||||
LOG_FUNC_RETURN(card->ctx, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new (RSA) key pair using an existing key file.
|
||||
* @param profile IN profile information for this card
|
||||
* Generates a new RSA key pair on card.
|
||||
* @param card IN sc_card_t object to use
|
||||
* @param obj IN sc_pkcs15_object_t object with pkcs15 information
|
||||
* @param pukkey OUT the newly created public key
|
||||
* @return SC_SUCCESS on success and an error code otherwise
|
||||
**/
|
||||
static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
||||
sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey)
|
||||
static int openpgp_generate_key_rsa(sc_card_t *card, sc_pkcs15_object_t *obj,
|
||||
sc_pkcs15_pubkey_t *pubkey)
|
||||
{
|
||||
sc_card_t *card = p15card->card;
|
||||
sc_context_t *ctx = card->ctx;
|
||||
sc_cardctl_openpgp_keygen_info_t key_info;
|
||||
sc_pkcs15_prkey_info_t *required = (sc_pkcs15_prkey_info_t *)obj->data;
|
||||
|
@ -185,46 +202,165 @@ static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card
|
|||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Prepare buffer */
|
||||
|
||||
key_info.algorithm = SC_OPENPGP_KEYALGO_RSA;
|
||||
key_info.rsa.modulus_len = required->modulus_length;
|
||||
key_info.rsa.modulus = calloc(required->modulus_length >> 3, 1);
|
||||
if (key_info.rsa.modulus == NULL)
|
||||
|
||||
/* Prepare buffer */
|
||||
key_info.u.rsa.modulus_len = required->modulus_length;
|
||||
key_info.u.rsa.modulus = calloc(required->modulus_length >> 3, 1);
|
||||
if (key_info.u.rsa.modulus == NULL)
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
||||
/* The OpenPGP supports only 32-bit exponent. */
|
||||
key_info.rsa.exponent_len = 32;
|
||||
key_info.rsa.exponent = calloc(key_info.rsa.exponent_len>>3, 1); /* 1/8 */
|
||||
if (key_info.rsa.exponent == NULL) {
|
||||
free(key_info.rsa.modulus);
|
||||
key_info.u.rsa.exponent_len = 32;
|
||||
key_info.u.rsa.exponent = calloc(BYTES4BITS(key_info.u.rsa.exponent_len), 1);
|
||||
if (key_info.u.rsa.exponent == NULL) {
|
||||
free(key_info.u.rsa.modulus);
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
|
||||
}
|
||||
|
||||
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
LOG_TEST_GOTO_ERR(card->ctx, r, "on-card EC key generation failed");
|
||||
|
||||
pubkey->algorithm = SC_ALGORITHM_RSA;
|
||||
|
||||
sc_log(ctx, "Set output modulus info");
|
||||
pubkey->u.rsa.modulus.len = key_info.rsa.modulus_len;
|
||||
pubkey->u.rsa.modulus.data = calloc(key_info.rsa.modulus_len, 1);
|
||||
pubkey->u.rsa.modulus.len = key_info.u.rsa.modulus_len;
|
||||
pubkey->u.rsa.modulus.data = calloc(key_info.u.rsa.modulus_len, 1);
|
||||
if (pubkey->u.rsa.modulus.data == NULL)
|
||||
goto out;
|
||||
memcpy(pubkey->u.rsa.modulus.data, key_info.rsa.modulus, key_info.rsa.modulus_len);
|
||||
goto err;
|
||||
memcpy(pubkey->u.rsa.modulus.data, key_info.u.rsa.modulus, key_info.u.rsa.modulus_len);
|
||||
|
||||
sc_log(ctx, "Set output exponent info");
|
||||
pubkey->u.rsa.exponent.len = key_info.rsa.exponent_len;
|
||||
pubkey->u.rsa.exponent.data = calloc(key_info.rsa.exponent_len>>3, 1); /* 1/8 */
|
||||
pubkey->u.rsa.exponent.len = key_info.u.rsa.exponent_len;
|
||||
pubkey->u.rsa.exponent.data = calloc(BYTES4BITS(key_info.u.rsa.exponent_len), 1);
|
||||
if (pubkey->u.rsa.exponent.data == NULL)
|
||||
goto out;
|
||||
memcpy(pubkey->u.rsa.exponent.data, key_info.rsa.exponent, key_info.rsa.exponent_len>>3); /* 1/8 */
|
||||
goto err;
|
||||
memcpy(pubkey->u.rsa.exponent.data, key_info.u.rsa.exponent, BYTES4BITS(key_info.u.rsa.exponent_len));
|
||||
|
||||
err:
|
||||
free(key_info.u.rsa.modulus);
|
||||
free(key_info.u.rsa.exponent);
|
||||
LOG_FUNC_RETURN(ctx, r);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a new ECC key pair on card.
|
||||
* @param card IN sc_card_t object to use
|
||||
* @param obj IN sc_pkcs15_object_t object with pkcs15 information
|
||||
* @param pukkey OUT the newly created public key
|
||||
* @return SC_SUCCESS on success and an error code otherwise
|
||||
**/
|
||||
static int openpgp_generate_key_ec(sc_card_t *card, sc_pkcs15_object_t *obj,
|
||||
sc_pkcs15_pubkey_t *pubkey)
|
||||
{
|
||||
sc_context_t *ctx = card->ctx;
|
||||
sc_cardctl_openpgp_keygen_info_t key_info;
|
||||
sc_pkcs15_prkey_info_t *required = (sc_pkcs15_prkey_info_t *)obj->data;
|
||||
sc_pkcs15_id_t *kid = &(required->id);
|
||||
const struct sc_ec_parameters *info_ec =
|
||||
(struct sc_ec_parameters *) required->params.data;
|
||||
unsigned int i;
|
||||
int r;
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
memset(&key_info, 0, sizeof(key_info));
|
||||
|
||||
sc_log(ctx, "Key ID to be generated: %s", sc_dump_hex(kid->value, kid->len));
|
||||
|
||||
/* Accept KeyID = 45, which is default value set by pkcs15init */
|
||||
if (kid->len == 1 && kid->value[0] == 0x45) {
|
||||
/* Default key is authentication key. We choose this because the common use
|
||||
* is to generate from PKCS#11 (Firefox/Thunderbird) */
|
||||
sc_log(ctx, "Authentication key is to be generated.");
|
||||
key_info.key_id = 3;
|
||||
}
|
||||
if (!key_info.key_id && (kid->len > 1 || kid->value[0] > 3)) {
|
||||
sc_log(ctx, "Key ID must be 1, 2 or 3!");
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
}
|
||||
|
||||
if (!key_info.key_id)
|
||||
key_info.key_id = kid->value[0];
|
||||
|
||||
|
||||
/* set algorithm id based on key reference */
|
||||
key_info.algorithm = (key_info.key_id == SC_OPENPGP_KEY_ENCR)
|
||||
? SC_OPENPGP_KEYALGO_ECDH /* ECDH for slot 2 only */
|
||||
: SC_OPENPGP_KEYALGO_ECDSA; /* ECDSA for slot 1 and 3 */
|
||||
|
||||
/* extract oid the way we need to import it to OpenPGP Card */
|
||||
if (info_ec->der.len > 2)
|
||||
key_info.u.ec.oid_len = info_ec->der.value[1];
|
||||
else
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
|
||||
|
||||
for (i=0; (i < key_info.u.ec.oid_len) && (i+2 < info_ec->der.len); i++){
|
||||
key_info.u.ec.oid.value[i] = info_ec->der.value[i+2];
|
||||
}
|
||||
key_info.u.ec.oid.value[key_info.u.ec.oid_len] = -1;
|
||||
|
||||
/* Prepare buffer */
|
||||
key_info.u.ec.ecpoint_len = required->field_length;
|
||||
key_info.u.ec.ecpoint = malloc(key_info.u.ec.ecpoint_len);
|
||||
if (key_info.u.ec.ecpoint == NULL)
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
|
||||
|
||||
/* generate key on card */
|
||||
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info);
|
||||
LOG_TEST_GOTO_ERR(card->ctx, r, "on-card EC key generation failed");
|
||||
|
||||
/* set pubkey according to response of card */
|
||||
sc_log(ctx, "Set output ecpoint info");
|
||||
pubkey->algorithm = SC_ALGORITHM_EC;
|
||||
pubkey->u.ec.ecpointQ.len = key_info.u.ec.ecpoint_len;
|
||||
pubkey->u.ec.ecpointQ.value = malloc(key_info.u.ec.ecpoint_len);
|
||||
if (pubkey->u.ec.ecpointQ.value == NULL)
|
||||
goto err;
|
||||
memcpy(pubkey->u.ec.ecpointQ.value, key_info.u.ec.ecpoint, key_info.u.ec.ecpoint_len);
|
||||
|
||||
err:
|
||||
if (key_info.u.ec.ecpoint)
|
||||
free(key_info.u.ec.ecpoint);
|
||||
|
||||
LOG_FUNC_RETURN(ctx, r);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a new key pair using an existing key file.
|
||||
* @param profile IN profile information for this card
|
||||
* @param card IN sc_card_t object to use
|
||||
* @param obj IN sc_pkcs15_object_t object with pkcs15 information
|
||||
* @param pukkey OUT the newly created public key
|
||||
* @return SC_SUCCESS on success and an error code otherwise
|
||||
**/
|
||||
static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
|
||||
sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey)
|
||||
{
|
||||
sc_card_t *card = p15card->card;
|
||||
sc_context_t *ctx = card->ctx;
|
||||
int r;
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
|
||||
switch(obj->type)
|
||||
{
|
||||
case SC_PKCS15_TYPE_PRKEY_RSA:
|
||||
r = openpgp_generate_key_rsa(card, obj, pubkey);
|
||||
break;
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
if (card->type < SC_CARD_TYPE_OPENPGP_V3) {
|
||||
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "only RSA is supported on this card");
|
||||
return SC_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
r = openpgp_generate_key_ec(card, obj, pubkey);
|
||||
break;
|
||||
default:
|
||||
r = SC_ERROR_NOT_SUPPORTED;
|
||||
sc_log(card->ctx, "%s: Key generation failed: Unknown/unsupported key type.", strerror(r));
|
||||
}
|
||||
|
||||
out:
|
||||
if (key_info.rsa.modulus)
|
||||
free(key_info.rsa.modulus);
|
||||
if (key_info.rsa.exponent)
|
||||
free(key_info.rsa.exponent);
|
||||
LOG_FUNC_RETURN(ctx, r);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "libopensc/opensc.h"
|
||||
#include "libopensc/asn1.h"
|
||||
#include "libopensc/cards.h"
|
||||
#include "libopensc/internal.h"
|
||||
#include "libopensc/cardctl.h"
|
||||
#include "libopensc/log.h"
|
||||
#include "libopensc/errors.h"
|
||||
|
@ -703,11 +704,11 @@ int do_genkey(sc_card_t *card, u8 in_key_id, const char *keytype)
|
|||
/* set key_info */
|
||||
key_info.key_id = in_key_id;
|
||||
key_info.algorithm = SC_OPENPGP_KEYALGO_RSA;
|
||||
key_info.rsa.modulus_len = keylen;
|
||||
key_info.rsa.modulus = malloc((keylen + 7) / 8);
|
||||
key_info.u.rsa.modulus_len = keylen;
|
||||
key_info.u.rsa.modulus = malloc(BYTES4BITS(keylen));
|
||||
|
||||
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info);
|
||||
free(key_info.rsa.modulus);
|
||||
free(key_info.u.rsa.modulus);
|
||||
if (r < 0) {
|
||||
util_error("failed to generate key: %s", sc_strerror(r));
|
||||
return EXIT_FAILURE;
|
||||
|
|
Loading…
Reference in New Issue