openpgp: Initial support for (X)EdDSA keys
This commit is contained in:
parent
caae75758c
commit
b351bf5ea4
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue