openpgp: Initial support for (X)EdDSA keys

This commit is contained in:
Jakub Jelen 2020-02-24 18:17:45 +01:00
parent caae75758c
commit b351bf5ea4
4 changed files with 294 additions and 72 deletions

View File

@ -87,7 +87,8 @@ static struct sc_card_driver pgp_drv = {
};
static pgp_ec_curves_t ec_curves[] = {
/* v3.0+ supports: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */
static pgp_ec_curves_t ec_curves_openpgp[] = {
{{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* ansiX9p256r1 */
{{{1, 3, 132, 0, 34, -1}}, 384}, /* ansiX9p384r1 */
{{{1, 3, 132, 0, 35, -1}}, 521}, /* ansiX9p521r1 */
@ -97,11 +98,14 @@ static pgp_ec_curves_t ec_curves[] = {
{{{-1}}, 0} /* This entry must not be touched. */
};
struct sc_object_id curve25519_oid = {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}};
/* Gnuk supports NIST, SECG and Curve25519 since version 1.2 */
static pgp_ec_curves_t ec_curves_gnuk[] = {
{{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* ansiX9p256r1 */
{{{1, 3, 132, 0, 10, -1}}, 256}, /* secp256k1 */
/*{{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 256}, //cv25519
{{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 256}, // ed25519 */
{{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 256}, /* curve25519 for encryption => CKK_EC_MONTGOMERY */
{{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 256}, /* ed25519 for signatures => CKK_EC_EDWARDS */
{{{-1}}, 0} /* This entry must not be touched. */
};
@ -448,6 +452,13 @@ pgp_init(sc_card_t *card)
: (priv->bcd_version < OPENPGP_CARD_3_4) ? pgp33_objects
: pgp34_objects;
/* With gnuk, we use different curves */
if (card->type == SC_CARD_TYPE_OPENPGP_GNUK) {
priv->ec_curves = ec_curves_gnuk;
} else {
priv->ec_curves = ec_curves_openpgp;
}
/* change file path to MF for re-use in MF */
sc_format_path("3f00", &file->path);
@ -500,22 +511,15 @@ pgp_init(sc_card_t *card)
switch (card->type) {
case SC_CARD_TYPE_OPENPGP_V3:
/* RSA 1024 was removed for v3+ */
_sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
_sc_card_add_rsa_alg(card, 3072, flags_rsa, 0);
_sc_card_add_rsa_alg(card, 4096, flags_rsa, 0);
/* v3.0+ supports: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */
for (i=0; ec_curves[i].oid.value[0] >= 0; i++)
{
_sc_card_add_ec_alg(card, ec_curves[i].size, flags_ecc, ext_flags, &ec_curves[i].oid);
}
break;
_sc_card_add_rsa_alg(card, 3072, flags_rsa, 0);
/* fallthrough */
case SC_CARD_TYPE_OPENPGP_GNUK:
_sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
/* Gnuk supports NIST, SECG and Curve25519 since version 1.2 */
for (i=0; ec_curves_gnuk[i].oid.value[0] >= 0; i++)
for (i=0; priv->ec_curves[i].oid.value[0] >= 0; i++)
{
_sc_card_add_ec_alg(card, ec_curves_gnuk[i].size,
flags_ecc, ext_flags, &ec_curves_gnuk[i].oid);
_sc_card_add_ec_alg(card, priv->ec_curves[i].size,
flags_ecc, ext_flags, &priv->ec_curves[i].oid);
}
break;
case SC_CARD_TYPE_OPENPGP_V2:
@ -568,6 +572,7 @@ static int
pgp_parse_algo_attr_blob(sc_card_t *card, const pgp_blob_t *blob,
sc_cardctl_openpgp_keygen_info_t *key_info)
{
struct pgp_priv_data *priv = DRVDATA(card);
struct sc_object_id oid;
unsigned int j, r;
@ -596,8 +601,9 @@ pgp_parse_algo_attr_blob(sc_card_t *card, const pgp_blob_t *blob,
break;
case SC_OPENPGP_KEYALGO_ECDH:
case SC_OPENPGP_KEYALGO_ECDSA:
case SC_OPENPGP_KEYALGO_EDDSA:
/* SC_OPENPGP_KEYALGO_ECDH || SC_OPENPGP_KEYALGO_ECDSA */
/* SC_OPENPGP_KEYALGO_ECDH || SC_OPENPGP_KEYALGO_ECDSA || SC_OPENPGP_KEYALGO_EDDSA */
key_info->algorithm = blob->data[0];
/* last byte is only set if pubkey import is supported, empty otherwise*/
@ -623,16 +629,19 @@ pgp_parse_algo_attr_blob(sc_card_t *card, const pgp_blob_t *blob,
return r;
}
/* compare with list of supported ec_curves */
for (j = 0; ec_curves[j].oid.value[0] >= 0; j++) {
if (sc_compare_oid(&ec_curves[j].oid, &oid)) {
for (j = 0; priv->ec_curves[j].oid.value[0] >= 0; j++) {
if (sc_compare_oid(&priv->ec_curves[j].oid, &oid)) {
sc_log(card->ctx, "Matched EC oid %s (%d)",
sc_dump_oid(&oid), j);
key_info->u.ec.oid = ec_curves[j].oid;
key_info->u.ec.key_length = ec_curves[j].size;
key_info->u.ec.oid = priv->ec_curves[j].oid;
key_info->u.ec.key_length = priv->ec_curves[j].size;
break;
}
}
/* We did not match the OID */
if (priv->ec_curves[j].oid.value[0] < 0) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
}
break;
default:
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
@ -790,22 +799,39 @@ pgp_get_card_features(sc_card_t *card)
/* OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */
if ((pgp_get_blob(card, blob73, i, &blob) >= 0) &&
(pgp_parse_algo_attr_blob(card, blob, &key_info) >= 0)) {
unsigned long flags = 0, ext_flags = 0;
/* RSA [RFC 4880] */
if (key_info.algorithm == SC_OPENPGP_KEYALGO_RSA){
switch (key_info.algorithm) {
case SC_OPENPGP_KEYALGO_RSA:
/* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 /
* v3.x section 7.2.11 & 7.2.12 */
unsigned long flags = SC_ALGORITHM_RSA_PAD_PKCS1 |
SC_ALGORITHM_RSA_HASH_NONE |
SC_ALGORITHM_ONBOARD_KEY_GEN; /* key gen on card */
_sc_card_add_rsa_alg(card, key_info.u.rsa.modulus_len, flags, 0);
sc_log(card->ctx, "DO %zX: Added RSA algorithm, mod_len = %zu" , i, key_info.u.rsa.modulus_len);
}
/* v3.0+: ECC [RFC 4880 & 6637] */
else if (key_info.algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info.algorithm == SC_OPENPGP_KEYALGO_ECDSA) {
flags = SC_ALGORITHM_RSA_PAD_PKCS1 |
SC_ALGORITHM_RSA_HASH_NONE |
SC_ALGORITHM_ONBOARD_KEY_GEN; /* key gen on card */
unsigned long flags, ext_flags;
_sc_card_add_rsa_alg(card, key_info.u.rsa.modulus_len, flags, 0);
sc_log(card->ctx, "DO %zX: Added RSA algorithm, mod_len = %"
SC_FORMAT_LEN_SIZE_T"u",
i, key_info.u.rsa.modulus_len);
break;
case SC_OPENPGP_KEYALGO_ECDH:
/* The montgomery curve (curve25519) needs to go through
* different paths, otherwise we handle it as a normal EC key */
if (sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid)) {
_sc_card_add_xeddsa_alg(card, key_info.u.ec.key_length,
(SC_ALGORITHM_XEDDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW),
0, &key_info.u.ec.oid);
sc_log(card->ctx, "DO %zX: Added XEDDSA algorithm (%d), mod_len = %d" ,
i, key_info.algorithm, key_info.u.ec.key_length);
break;
}
/* fall through */
case SC_OPENPGP_KEYALGO_ECDSA:
/* v3.0+: ECC [RFC 4880 & 6637] */
/* EdDSA from draft-ietf-openpgp-rfc4880bis-08 */
flags = 0, ext_flags = 0;
if (key_info.algorithm == SC_OPENPGP_KEYALGO_ECDH)
flags = SC_ALGORITHM_ECDH_CDH_RAW;
@ -816,8 +842,21 @@ pgp_get_card_features(sc_card_t *card)
ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE;
_sc_card_add_ec_alg(card, key_info.u.ec.key_length, flags, ext_flags,
&key_info.u.ec.oid);
sc_log(card->ctx, "DO %zX: Added EC algorithm (%d), mod_len = %d" , i, key_info.algorithm, key_info.u.ec.key_length);
&key_info.u.ec.oid);
sc_log(card->ctx, "DO %zX: Added EC algorithm (%d), mod_len = %d" ,
i, key_info.algorithm, key_info.u.ec.key_length);
break;
case SC_OPENPGP_KEYALGO_EDDSA:
_sc_card_add_eddsa_alg(card, key_info.u.ec.key_length,
SC_ALGORITHM_EDDSA_RAW, 0, &key_info.u.ec.oid);
sc_log(card->ctx, "DO %zX: Added EDDSA algorithm (%d), mod_len = %d" ,
i, key_info.algorithm, key_info.u.ec.key_length);
break;
default:
sc_log(card->ctx, "DO %zX: Unknown algorithm ID (%d)" ,
i, key_info.algorithm);
break;
}
}
}
@ -1564,10 +1603,6 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
else if ((r = pgp_get_blob(card, blob, 0x0086, &pubkey_blob)) >= 0
&& (r = pgp_read_blob(card, pubkey_blob)) >= 0) {
p15pubkey.algorithm = SC_ALGORITHM_EC;
p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data;
p15pubkey.u.ec.ecpointQ.len = pubkey_blob->len;
switch(tag & 0xFFFE) {
case DO_SIGN: aa_tag = 0x00C1; break;
case DO_ENCR: aa_tag = 0x00C2; break;
@ -1581,14 +1616,51 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
((r = pgp_get_blob(card, blob6e, 0x0073, &blob73)) >= 0) &&
((r = pgp_get_blob(card, blob73, aa_tag, &aa_blob)) >= 0) &&
((r = pgp_parse_algo_attr_blob(card, aa_blob, &key_info)) >= 0)) {
switch (key_info.algorithm) {
case SC_OPENPGP_KEYALGO_EDDSA:
/* In EDDSA key case we do not have to care about OIDs
* as we support only one for now */
p15pubkey.algorithm = SC_ALGORITHM_EDDSA;
p15pubkey.u.eddsa.pubkey.value = pubkey_blob->data;
p15pubkey.u.eddsa.pubkey.len = pubkey_blob->len;
/* PKCS#11 3.0: 2.3.5 Edwards EC public keys only support the use
* of the curveName selection to specify a curve name as defined
* in [RFC 8032] */
if ((r = sc_encode_oid(card->ctx, &key_info.u.ec.oid,
&p15pubkey.u.ec.params.der.value,
&p15pubkey.u.ec.params.der.len)) == 0) {
p15pubkey.u.ec.params.type = 1;
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, &p15pubkey, &data, &len);
} else {
sc_log(card->ctx, "Unable to encode EC curve OID from algorithm info");
break;
case SC_OPENPGP_KEYALGO_ECDH:
/* This yields either EC(DSA) key or EC_MONTGOMERY (curve25519) key */
if (sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid)) {
p15pubkey.algorithm = SC_ALGORITHM_XEDDSA;
p15pubkey.u.eddsa.pubkey.value = pubkey_blob->data;
p15pubkey.u.eddsa.pubkey.len = pubkey_blob->len;
/* PKCS#11 3.0 2.3.7 Montgomery EC public keys only support
* the use of the curveName selection to specify a curve
* name as defined in [RFC7748] */
/* XXX only curve25519 supported now. Theoretically could be
* also curve448 or OIDs */
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, &p15pubkey, &data, &len);
break;
}
/* fall through */
case SC_OPENPGP_KEYALGO_ECDSA:
if ((r = sc_encode_oid(card->ctx, &key_info.u.ec.oid,
&p15pubkey.u.ec.params.der.value,
&p15pubkey.u.ec.params.der.len)) == 0) {
p15pubkey.algorithm = SC_ALGORITHM_EC;
p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data;
p15pubkey.u.ec.ecpointQ.len = pubkey_blob->len;
p15pubkey.u.ec.params.type = 1;
r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, &p15pubkey, &data, &len);
} else {
sc_log(card->ctx, "Unable to encode EC curve OID from algorithm info");
}
break;
default:
sc_log(card->ctx, "Unknown algorithm ID received (%d)", key_info.algorithm);
break;
}
} else {
sc_log(card->ctx, "Unable to find Algorithm Attribute for EC curve OID");
@ -1598,16 +1670,19 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
}
/* clean up anything we may have set in p15pubkey that can not be freed */
if (p15pubkey.algorithm == SC_ALGORITHM_RSA) {
if (p15pubkey.algorithm == SC_ALGORITHM_RSA) {
p15pubkey.u.rsa.modulus.data = NULL;
p15pubkey.u.rsa.modulus.len = 0;
p15pubkey.u.rsa.exponent.data = NULL;
p15pubkey.u.rsa.exponent.len = 0;
} else
if (p15pubkey.algorithm == SC_ALGORITHM_EC) {
} else if (p15pubkey.algorithm == SC_ALGORITHM_EC) {
p15pubkey.u.ec.ecpointQ.value = NULL;
p15pubkey.u.ec.ecpointQ.len = 0;
/* p15pubkey.u.ec.params.der and named_curve will be freed by sc_pkcs15_erase_pubkey */
} else if (p15pubkey.algorithm == SC_ALGORITHM_EDDSA
|| p15pubkey.algorithm == SC_ALGORITHM_XEDDSA) {
p15pubkey.u.eddsa.pubkey.value = NULL;
p15pubkey.u.eddsa.pubkey.len = 0;
}
sc_pkcs15_erase_pubkey(&p15pubkey);
@ -1980,6 +2055,7 @@ int pgp_logout(struct sc_card *card)
/**
* ABI: ISO 7816-8 SET SECURITY ENVIRONMENT.
* This is optional in the OpenPGP Card 3.4 specs
*/
static int
pgp_set_security_env(sc_card_t *card,
@ -2022,6 +2098,9 @@ pgp_set_security_env(sc_card_t *card,
"requested usage");
}
break;
case SC_SEC_OPERATION_DERIVE:
sc_log(card->ctx, "Operation: Derive: No particular action needed");
break;
default:
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
"invalid operation");
@ -2146,20 +2225,67 @@ pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
sc_apdu_t apdu;
u8 apdu_case = SC_APDU_CASE_4;
u8 *temp = NULL;
int r;
int r, extlen = 0;
LOG_FUNC_CALLED(card->ctx);
/* padding according to OpenPGP card spec 1.1 & 2.x section 7.2.9 / 3.x section 7.2.11 */
if (!(temp = malloc(inlen + 1)))
/* padding according to OpenPGP card spec 1.1 & 2.x section 7.2.9 / 3.x section 7.2.11
* The longest possible prefix is 10 bytes for ECDH */
if (!(temp = malloc(inlen + 10)))
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
/* padding byte: 0xa6 = ECC; 0x00 = RSA; 0x02 = AES */
(env->algorithm == SC_ALGORITHM_EC) ? (temp[0] = 0xa6) : (temp[0] = 0x00);
memcpy(temp + 1, in, inlen);
in = temp;
inlen += 1;
if (env->operation != SC_SEC_OPERATION_DECIPHER) {
/* padding byte: 0xa6 = ECC; 0x00 = RSA; 0x02 = AES */
switch (env->algorithm) {
case SC_ALGORITHM_RSA:
/* This is just PKCS#1.5 start byte and it should be already
* provided by the padding routines. But it lets put it here
* to make sure it does not conflict with following indicators */
temp[0] = 0x00;
extlen = 1;
break;
case SC_ALGORITHM_EC:
case SC_ALGORITHM_XEDDSA:
/* This is 0xA6 Cipher DO with associated length field */
temp[extlen++] = 0xa6;
if (inlen >= 128) {
temp[extlen++] = 0x81;
temp[extlen++] = inlen + 7;
} else {
temp[extlen++] = inlen + 5;
}
/* Public Key DO (0x7F49) with associated length field */
temp[extlen++] = 0x7f;
temp[extlen++] = 0x49;
if (inlen >= 128) {
temp[extlen++] = 0x81;
temp[extlen++] = inlen + 3;
} else {
temp[extlen++] = inlen + 2;
}
/* External Public Key (0x86) with associated length */
temp[extlen++] = 0x86;
if (inlen >= 128) {
temp[extlen++] = 0x81;
}
temp[extlen++] = inlen;
break;
case SC_ALGORITHM_AES:
/* not supported yet */
/*
temp[0] = 0x02;
extlen = 1;
*/
/* fall through */
default:
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
}
memcpy(temp + extlen, in, inlen);
in = temp;
inlen += extlen;
if (env->operation != SC_SEC_OPERATION_DECIPHER &&
env->operation != SC_SEC_OPERATION_DERIVE) {
free(temp);
LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
"invalid operation");
@ -2239,7 +2365,8 @@ pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_
if (priv->ext_caps & EXT_CAP_ALG_ATTR_CHANGEABLE) {
/* ECDSA and ECDH */
if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA
|| key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA){
data_len = key_info->u.ec.oid_len+1;
data = malloc(data_len);
if (!data)
@ -2443,7 +2570,8 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
}
/* ECC */
else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA) {
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA
|| key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) {
/* Algorithm ID, see https://tools.ietf.org/html/rfc6637#section-5 */
*p = key_info->algorithm + 6;
p += 1;
@ -2737,6 +2865,9 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
&& card->type < SC_CARD_TYPE_OPENPGP_V3
&& card->type != SC_CARD_TYPE_OPENPGP_GNUK)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
if (key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA
&& card->type != SC_CARD_TYPE_OPENPGP_GNUK)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* set Control Reference Template for key */
if (key_info->key_id == SC_OPENPGP_KEY_SIGN)

View File

@ -184,6 +184,8 @@ struct pgp_priv_data {
size_t max_cert_size;
size_t max_specialDO_size;
pgp_ec_curves_t *ec_curves;
sc_security_env_t sec_env;
};

View File

@ -70,6 +70,7 @@ static const pgp_pin_cfg_t pin_cfg_v2[3] = {
{ "Admin PIN", 0x03, PGP_ADMIN_PIN_FLAGS, 8, 2 }
};
struct sc_object_id curve25519_binary_oid = {{0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01, -1}};
#define PGP_SIG_PRKEY_USAGE (SC_PKCS15_PRKEY_USAGE_SIGN \
| SC_PKCS15_PRKEY_USAGE_SIGNRECOVER \
@ -269,6 +270,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
sc_pkcs15_prkey_info_t prkey_info;
sc_pkcs15_object_t prkey_obj;
u8 cxdata[12];
int cxdata_len = sizeof(cxdata);
char path_template[] = "006E:0073:00Cx";
int j;
@ -277,7 +279,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
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)
if ((cxdata_len = read_file(card, path_template, cxdata, sizeof(cxdata))) < 1)
goto failed;
/* check validity using finger prints */
@ -288,6 +290,9 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
/* only add valid keys, i.e. those with a legal algorithm identifier & finger print */
if (j >= 0 && cxdata[0] != 0) {
struct sc_object_id oid;
int k;
prkey_info.id.len = 1;
prkey_info.id.value[0] = i + 1;
prkey_info.usage = key_cfg[i].prkey_usage;
@ -299,13 +304,41 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
prkey_obj.auth_id.len = 1;
prkey_obj.auth_id.value[0] = key_cfg[i].prkey_pin;
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) {
switch (cxdata[0]) {
case SC_OPENPGP_KEYALGO_EDDSA:
/* TODO Store the OID from cxdata + 1 ?? */
/* assuming Ed25519 as it is the only supported now */
prkey_info.field_length = 255;
r = sc_pkcs15emu_add_eddsa_prkey(p15card, &prkey_obj, &prkey_info);
break;
case SC_OPENPGP_KEYALGO_ECDH:
/* This can result in either ECDSA key or EC_MONTGOMERY
* so we need to check OID */
sc_init_oid(&oid);
/* Create copy of oid */
for (k = 0; k < (cxdata_len-1) && k < SC_MAX_OBJECT_ID_OCTETS; k++) {
oid.value[k] = cxdata[k+1]; /* ignore first byte of blob (algo ID) */
}
if (sc_compare_oid(&oid, &curve25519_binary_oid)) {
prkey_info.field_length = 255;
r = sc_pkcs15emu_add_xeddsa_prkey(p15card, &prkey_obj, &prkey_info);
break;
}
/* fall through */
case SC_OPENPGP_KEYALGO_ECDSA:
/* TODO Store the OID from cxdata + 1 ?? */
r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
break;
case SC_OPENPGP_KEYALGO_RSA:
if (r >= 3) {
prkey_info.modulus_length = bebytes2ushort(cxdata + 1);
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
break;
}
/* Fallthrough */
default:
sc_log(ctx, "Invalid algorithm identifier %x (length = %d)",
cxdata[0], r);
}
if (r < 0)
@ -319,6 +352,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
sc_pkcs15_pubkey_info_t pubkey_info;
sc_pkcs15_object_t pubkey_obj;
u8 cxdata[10];
int cxdata_len = sizeof(cxdata);
char path_template[] = "006E:0073:00Cx";
int j;
@ -327,7 +361,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
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)
if ((cxdata_len = read_file(card, path_template, cxdata, sizeof(cxdata))) < 1)
goto failed;
/* check validity using finger prints */
@ -338,6 +372,9 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
/* only add valid keys, i.e. those with a legal algorithm identifier & finger print */
if (j >= 0 && cxdata[0] != 0) {
struct sc_object_id oid;
int k;
pubkey_info.id.len = 1;
pubkey_info.id.value[0] = i + 1;
pubkey_info.usage = key_cfg[i].pubkey_usage;
@ -346,13 +383,41 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
strlcpy(pubkey_obj.label, key_cfg[i].label, sizeof(pubkey_obj.label));
pubkey_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
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) {
switch (cxdata[0]) {
case SC_OPENPGP_KEYALGO_EDDSA:
/* TODO Store the OID from cxdata + 1 ?? */
/* assuming Ed25519 as it is the only supported now */
pubkey_info.field_length = 255;
r = sc_pkcs15emu_add_eddsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
break;
case SC_OPENPGP_KEYALGO_ECDH:
/* This can result in either ECDSA key or EC_MONTGOMERY
* so we need to check OID */
sc_init_oid(&oid);
/* Create copy of oid */
for (k = 0; k < (cxdata_len-1) && k < SC_MAX_OBJECT_ID_OCTETS; k++) {
oid.value[k] = cxdata[k+1]; /* ignore first byte of blob (algo ID) */
}
if (sc_compare_oid(&oid, &curve25519_binary_oid)) {
pubkey_info.field_length = 255;
r = sc_pkcs15emu_add_xeddsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
break;
}
/* fall through */
case SC_OPENPGP_KEYALGO_ECDSA:
/* TODO Store the OID from cxdata + 1 ?? */
r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
break;
case SC_OPENPGP_KEYALGO_RSA:
if (r >= 3) {
pubkey_info.modulus_length = bebytes2ushort(cxdata + 1);
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
break;
}
/* Fallthrough */
default:
sc_log(ctx, "Invalid algorithm identifier %x (length = %d)",
cxdata[0], r);
}
if (r < 0)

View File

@ -165,6 +165,23 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
key_info.u.ec.oid.value[key_info.u.ec.oid_len] = -1;
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info);
break;
case SC_PKCS15_TYPE_PRKEY_EDDSA:
if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EdDSA keys not 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_EDDSA; /* EdDSA for slot 1 and 3 */
key_info.key_id = kinfo->id.value[0];
/* TODO Test -- might not work */
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.ecpointQ = key->u.ec.ecpointQ.value;
key_info.u.ec.ecpointQ_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));
@ -367,6 +384,13 @@ static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card
}
r = openpgp_generate_key_ec(card, obj, pubkey);
break;
case SC_PKCS15_TYPE_PRKEY_EDDSA:
if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EdDSA is not 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));