diff --git a/doc/tools/pkcs15-init.1.xml b/doc/tools/pkcs15-init.1.xml
index 5ddaad56a3..9c5018297c 100644
--- a/doc/tools/pkcs15-init.1.xml
+++ b/doc/tools/pkcs15-init.1.xml
@@ -139,7 +139,13 @@
where keyspec describes the algorithm and the parameters
of the key to be created. For example, rsa:2048 generates a RSA key
with 2048-bit modulus. If you are generating an EC key, the curve designation must
- be specified, for example ec:prime256v1. For symmetric key,
+ be specified, for example ec:prime256v1.
+ The following curves do not need parameters:
+ Edwards 25519 curves use one of these equivalent names: Ed25519(preferred), ed25519 or edwards25519
+ and for the 448 curve use: Ed448.
+ For Montgomery 25519 curves use one of these equivalent names: X25519(preferred), cv25519 or curve25519
+ and for the 448 curve use: X448.
+ For symmetric key,
the length of key is specified in bytes, for example AES:32
or DES3:24.
diff --git a/doc/tools/tools.html b/doc/tools/tools.html
index 4294dc16fd..173469fdc2 100644
--- a/doc/tools/tools.html
+++ b/doc/tools/tools.html
@@ -1989,7 +1989,13 @@
where keyspec
describes the algorithm and the parameters
of the key to be created. For example, rsa:2048
generates a RSA key
with 2048-bit modulus. If you are generating an EC key, the curve designation must
- be specified, for example ec:prime256v1
. For symmetric key,
+ be specified, for example ec:prime256v1
.
+ The following curves do not need parameters:
+ Edwards 25519 curves use one of these equivalent names: Ed25519(preferred), ed25519 or edwards25519
+ and for the 448 curve use: Ed448.
+ For Montgomery 25519 curves use one of these equivalent names: X25519(preferred), cv25519 or curve25519
+ and for the 448 curve use: X448.
+ For symmetric key,
the length of key is specified in bytes, for example AES:32
or DES3:24
.
diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c
index 7df722cdb7..0b903ca124 100644
--- a/src/libopensc/card-openpgp.c
+++ b/src/libopensc/card-openpgp.c
@@ -86,34 +86,49 @@ static struct sc_card_driver pgp_drv = {
NULL, 0, NULL
};
-
-static pgp_ec_curves_t ec_curves_openpgp34[] = {
+// clang-format off
+static pgp_ec_curves_t ec_curves_openpgp34[] = {
/* OpenPGP 3.4+ Ed25519 and Curve25519 */
- {{{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, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* curve25519 for encryption => CKK_EC_MONTGOMERY */
+ {{{1, 3, 101, 110, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* RFC8410 OID equivalent to curve25519 */
+ {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 255, SC_ALGORITHM_EDDSA}, /* ed25519 for signatures => CKK_EC_EDWARDS */
+ {{{1, 3, 101, 112, -1}}, 255, SC_ALGORITHM_EDDSA}, /* RFC8410 OID equivalent to ed25519 */
+
/* v3.0+ supports: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */
- {{{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 */
- {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256}, /* brainpoolP256r1 */
- {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 11, -1}}, 384}, /* brainpoolP384r1 */
- {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 13, -1}}, 512}, /* brainpoolP512r1 */
- {{{-1}}, 0} /* This entry must not be touched. */
+ {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, SC_ALGORITHM_EC}, /* ansiX9p256r1 */
+ {{{1, 3, 132, 0, 34, -1}}, 384, SC_ALGORITHM_EC}, /* ansiX9p384r1 */
+ {{{1, 3, 132, 0, 35, -1}}, 521, SC_ALGORITHM_EC}, /* ansiX9p521r1 */
+ {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256, SC_ALGORITHM_EC}, /* brainpoolP256r1 */
+ {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 11, -1}}, 384, SC_ALGORITHM_EC}, /* brainpoolP384r1 */
+ {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 13, -1}}, 512, SC_ALGORITHM_EC}, /* brainpoolP512r1 */
+ {{{-1}}, 0, 0 } /* This entry must not be touched. */
};
-static pgp_ec_curves_t *ec_curves_openpgp = ec_curves_openpgp34 + 2;
+#ifdef ENABLE_OPENSSL
+static pgp_ec_curves_alt_t ec_curves_alt[] = {
+ {{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, {{1, 3, 101, 110, -1}}, 255}, /* curve25519 CKK_EC_MONTGOMERY X25519 */
+ {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, {{1, 3, 101, 112, -1}}, 255}, /* ed25519 CKK_EC_EDWARDS Ed25519 */
+ {{{-1}}, {{-1}}, 0 } /* This entry must not be touched. */
+};
+
+#endif /* ENABLE_OPENSSL */
+
+static pgp_ec_curves_t *ec_curves_openpgp = ec_curves_openpgp34 + 4;
struct sc_object_id curve25519_oid = {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}};
+struct sc_object_id X25519_oid = {{1, 3, 101, 110, -1}}; /* need to check for RFC8410 version? */
/* 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}, /* 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. */
+static pgp_ec_curves_t ec_curves_gnuk[] = {
+ {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, SC_ALGORITHM_EC}, /* ansiX9p256r1 */
+ {{{1, 3, 132, 0, 10, -1}}, 256, SC_ALGORITHM_EC}, /* secp256k1 */
+ {{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* curve25519 for encryption => CKK_EC_MONTGOMERY */
+ {{{1, 3, 101, 110, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* RFC8410 OID equivalent to curve25519 */
+ {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 255, SC_ALGORITHM_EDDSA}, /* ed25519 for signatures => CKK_EC_EDWARDS */
+ {{{1, 3, 101, 112, -1}}, 255, SC_ALGORITHM_EDDSA}, /* RFC8410 OID equivalent to ed25519 */
+ {{{-1}}, 0, 0} /* This entry must not be touched. */
};
-
+// clang-format on
/*
* The OpenPGP card doesn't have a file system, instead everything
@@ -516,9 +531,11 @@ pgp_init(sc_card_t *card)
/* if algorithm attributes can be changed,
* add supported algorithms based on specification for pkcs15-init */
- if ((priv->ext_caps & EXT_CAP_ALG_ATTR_CHANGEABLE) &&
- (strcmp(card->ctx->app_name, "pkcs15-init") == 0)) {
+ /* pkcs11 or other utilities may need all the algs registered */
+ if ((priv->ext_caps & EXT_CAP_ALG_ATTR_CHANGEABLE)
+ /* && (strcmp(card->ctx->app_name, "pkcs15-init") == 0) */) {
unsigned long flags_rsa, flags_ecc, ext_flags;
+ unsigned long flags_eddsa, flags_xeddsa;
/* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 / v3.x section 7.2.11 & 7.2.12 */
flags_rsa = SC_ALGORITHM_RSA_PAD_PKCS1|
@@ -530,6 +547,12 @@ pgp_init(sc_card_t *card)
SC_ALGORITHM_ONBOARD_KEY_GEN;
ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE;
+ flags_eddsa = SC_ALGORITHM_EDDSA_RAW |
+ SC_ALGORITHM_ONBOARD_KEY_GEN;
+ /* xeddsa may allow signing at some time */
+ flags_xeddsa = SC_ALGORITHM_ECDH_CDH_RAW |
+ SC_ALGORITHM_ONBOARD_KEY_GEN;
+
switch (card->type) {
case SC_CARD_TYPE_OPENPGP_V3:
/* RSA 1024 was removed for v3+ */
@@ -540,8 +563,15 @@ pgp_init(sc_card_t *card)
_sc_card_add_rsa_alg(card, 2048, flags_rsa, 0);
for (i=0; priv->ec_curves[i].oid.value[0] >= 0; i++)
{
- _sc_card_add_ec_alg(card, priv->ec_curves[i].size,
- flags_ecc, ext_flags, &priv->ec_curves[i].oid);
+ if (priv->ec_curves[i].key_type == SC_ALGORITHM_EC)
+ _sc_card_add_ec_alg(card, priv->ec_curves[i].size,
+ flags_ecc, ext_flags, &priv->ec_curves[i].oid);
+ else if (priv->ec_curves[i].key_type == SC_ALGORITHM_EDDSA)
+ _sc_card_add_eddsa_alg(card, priv->ec_curves[i].size,
+ flags_eddsa, ext_flags, &priv->ec_curves[i].oid);
+ else
+ _sc_card_add_xeddsa_alg(card, priv->ec_curves[i].size,
+ flags_xeddsa, ext_flags, &priv->ec_curves[i].oid);
}
break;
case SC_CARD_TYPE_OPENPGP_V2:
@@ -680,14 +710,15 @@ pgp_parse_algo_attr_blob(sc_card_t *card, const pgp_blob_t *blob,
int _pgp_handle_curve25519(sc_card_t *card,
sc_cardctl_openpgp_keygen_info_t key_info, unsigned int do_num)
{
- if (!sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid))
+ if (!sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid) &&
+ !sc_compare_oid(&key_info.u.ec.oid, &X25519_oid))
return 0;
/* CKM_XEDDSA supports both Sign and Derive, but
* OpenPGP card supports only derivation using these
* keys as far as I know */
_sc_card_add_xeddsa_alg(card, key_info.u.ec.key_length,
- SC_ALGORITHM_ECDH_CDH_RAW, 0, &key_info.u.ec.oid);
+ SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN, 0, &key_info.u.ec.oid);
sc_log(card->ctx, "DO %uX: Added XEDDSA algorithm (%d), mod_len = %zu",
do_num, SC_ALGORITHM_XEDDSA, key_info.u.ec.key_length);
return 1;
@@ -739,7 +770,7 @@ int _pgp_add_algo(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t key_info, un
if (_pgp_handle_curve25519(card, key_info, do_num))
break;
_sc_card_add_eddsa_alg(card, key_info.u.ec.key_length,
- SC_ALGORITHM_EDDSA_RAW, 0, &key_info.u.ec.oid);
+ SC_ALGORITHM_EDDSA_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN, 0, &key_info.u.ec.oid);
sc_log(card->ctx, "DO %uX: Added EDDSA algorithm (%d), mod_len = %zu" ,
do_num, key_info.algorithm, key_info.u.ec.key_length);
@@ -1709,8 +1740,8 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
/* 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;
+ p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data;
+ p15pubkey.u.ec.ecpointQ.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] */
@@ -1720,8 +1751,8 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
/* 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;
+ p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data;
+ p15pubkey.u.ec.ecpointQ.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] */
@@ -1762,14 +1793,12 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
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.algorithm == SC_ALGORITHM_EDDSA ||
+ p15pubkey.algorithm == SC_ALGORITHM_XEDDSA) {
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);
@@ -2502,7 +2531,7 @@ static int
pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
{
struct pgp_priv_data *priv = DRVDATA(card);
- pgp_blob_t *algo_blob;
+ pgp_blob_t *algo_blob = NULL;
const unsigned int tag = 0x00C0 | key_info->key_id;
u8 *data;
size_t data_len;
@@ -2519,16 +2548,42 @@ pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_
if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
|| key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA
|| key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA){
- data_len = key_info->u.ec.oid_len+1;
+ /* Note OpenPGP or current cards do not support 448 size keys yet */
+ unsigned char *aoid = NULL; /* ASN1 */
+ size_t aoid_len;
+ struct sc_object_id *scoid = NULL;
+
+ scoid = &key_info->u.ec.oid;
+ /*
+ * Current OpenPGP cards use pre RFC8410 OIDs for ECDH and EdDSA
+ * so convert to older versions of the OIDs.
+ */
+ for (i = 0; ec_curves_alt[i].size > 0; i++) {
+ if (sc_compare_oid(scoid, &ec_curves_alt[i].oid_alt)) {
+ scoid = &ec_curves_alt[i].oid;
+ break;
+ }
+ }
+
+ r = sc_encode_oid(card->ctx, scoid, &aoid, &aoid_len);
+ LOG_TEST_RET(card->ctx, r, "invalid ec oid");
+ if (aoid == NULL || aoid_len < 3 || aoid[1] > 127) {
+ free(aoid);
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+ }
+
+ data_len = aoid_len + 1 - 2; /* +1 for algorithm -2 drop 06 len */
data = malloc(data_len);
- if (!data)
+ if (!data) {
+ free(aoid);
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
+ }
data[0] = key_info->algorithm;
- /* oid.value is type int, therefore we need to loop over the values */
- for (i=0; i < key_info->u.ec.oid_len; i++){
- data[i+1] = key_info->u.ec.oid.value[i];
- }
+ for (i = 0; i < aoid_len - 2; i++)
+ data[i + 1] = aoid[i + 2];
+
+ free(aoid);
}
/* RSA */
@@ -2557,10 +2612,9 @@ pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
}
- pgp_set_blob(algo_blob, data, data_len);
+ r = pgp_put_data(card, tag, data, data_len);
+ /* Note: pgp_put_data calls pgp_set_blob */
free(data);
- r = pgp_put_data(card, tag, algo_blob->data, data_len);
- /* Note: Don't use pgp_set_blob to set data, because it won't touch the real DO */
LOG_TEST_RET(card->ctx, r, "Cannot set new algorithm attributes");
} else {
sc_cardctl_openpgp_keygen_info_t old_key_info;
@@ -2665,8 +2719,9 @@ 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) {
+ else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* also includes XEDDSA */
+ key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA ||
+ key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) {
if (key_info->u.ec.ecpoint == NULL || (key_info->u.ec.ecpoint_len) == 0) {
sc_log(card->ctx, "Error: ecpoint required!");
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
@@ -2674,12 +2729,12 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
/* https://tools.ietf.org/html/rfc4880 page 41, 72
* and https://tools.ietf.org/html/rfc6637 section 9 (page 8 and 9) */
- pk_packet_len = 1 /* version number */
- + 4 /* creation time */
- + 1 /* algorithm */
- + 1 /* oid len */
- + (key_info->u.ec.oid_len) /* oid */
- + (key_info->u.ec.ecpoint_len); /* ecpoint */
+ pk_packet_len = 1 /* version number */
+ + 4 /* creation time */
+ + 1 /* algorithm */
+ + 1 /* oid len */
+ + (key_info->u.ec.oid_len) /* oid */
+ + BYTES4BITS(key_info->u.ec.ecpoint_len); /* ecpoint */
/* KDF parameters for ECDH */
if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH) {
@@ -2689,8 +2744,7 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
+ 1 /* KDF algo */
+ 1; /* KEK algo */
}
- }
- else
+ } else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
sc_log(card->ctx, "pk_packet_len is %"SC_FORMAT_LEN_SIZE_T"u", pk_packet_len);
@@ -2729,9 +2783,9 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
memcpy(p, key_info->u.rsa.exponent, bytes_length);
}
/* ECC */
- else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
- || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA
- || key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) {
+ else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* includes XEDDSA */
+ 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;
@@ -2739,13 +2793,13 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
p += 1;
memcpy(p, key_info->u.ec.oid.value, key_info->u.ec.oid_len);
p += key_info->u.ec.oid_len;
- memcpy(p, key_info->u.ec.ecpoint, key_info->u.ec.ecpoint_len);
+ memcpy(p, key_info->u.ec.ecpoint, BYTES4BITS(key_info->u.ec.ecpoint_len));
/* KDF parameters for ECDH */
if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH) {
/* https://tools.ietf.org/html/rfc6637#section-8
* This is copied from GnuPG's ecdh_params() function in app-openpgp.c */
- p += key_info->u.ec.ecpoint_len;
+ p += BYTES4BITS(key_info->u.ec.ecpoint_len);
*p = 0x03; /* number of bytes following */
p += 1;
*p = 0x01; /* version of this format */
@@ -2763,8 +2817,7 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime,
*(p+1) = 0x09; /* KEK algo */
}
}
- }
- else
+ } else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
p = NULL;
@@ -2847,14 +2900,15 @@ pgp_update_pubkey_blob(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_in
p15pubkey.u.rsa.exponent.len = BYTES4BITS(key_info->u.rsa.exponent_len);
}
/* ECC */
- else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
- || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){
+ /* TODO FIXME? */
+ else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* includes XEDDSA */
+ key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA ||
+ key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) {
memset(&p15pubkey, 0, sizeof(p15pubkey));
- p15pubkey.algorithm = SC_ALGORITHM_EC;
+ p15pubkey.algorithm = key_info->key_type;
p15pubkey.u.ec.ecpointQ.value = key_info->u.ec.ecpoint;
p15pubkey.u.ec.ecpointQ.len = key_info->u.ec.ecpoint_len;
- }
- else
+ } else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
r = sc_pkcs15_encode_pubkey(card->ctx, &p15pubkey, &data, &len);
@@ -2882,7 +2936,8 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len,
/* store creation time */
r = pgp_store_creationtime(card, key_info->key_id, &ctime);
- LOG_TEST_RET(card->ctx, r, "Cannot store creation time");
+ /* TODO for now with GNUK at least, log but do not return error */
+ sc_log(card->ctx, "Cannot store creation time");
/* parse response. Ref: pgp_enumerate_blob() */
while (data_len > (size_t) (in - data)) {
@@ -2934,16 +2989,30 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len,
/* ECC public key */
else if (tag == 0x0086) {
/* set the output data */
- /* len is ecpoint length + format byte
- * see section 7.2.14 of 3.3.1 specs */
- if ((key_info->u.ec.ecpoint_len) != (len - 1)
- || key_info->u.ec.ecpoint == NULL) {
- free(key_info->u.ec.ecpoint);
- key_info->u.ec.ecpoint = malloc(len);
- if (key_info->u.ec.ecpoint == NULL)
- LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
+ /* EC is in 04||x||y format
+ * (field_length + 7)/8 * 2 + 1 in bytes
+ * len is ecpoint length + format byte
+ * see section 7.2.14 of 3.3.1 specs
+ * EDDSA and XEDDSA have no format byte and one number
+ * (field_length + 7)/8 in bytes
+ */
+ /* GNUK returns 04|x|y */
+
+ /* TODO check len is reasonable */
+ key_info->u.ec.ecpoint = malloc(len);
+ if (key_info->u.ec.ecpoint == NULL)
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
+
+ switch (key_info->key_type) {
+ case SC_ALGORITHM_EC:
+ case SC_ALGORITHM_EDDSA:
+ case SC_ALGORITHM_XEDDSA:
+ memcpy(key_info->u.ec.ecpoint, part, len);
+ key_info->u.ec.ecpoint_len = len;
+ break;
+ default:
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
}
- memcpy(key_info->u.ec.ecpoint, part + 1, len - 1);
}
/* go to next part to parse */
@@ -2958,6 +3027,7 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len,
/* update pubkey blobs (B601, B801, A401) */
sc_log(card->ctx, "Update blobs holding pubkey info.");
r = pgp_update_pubkey_blob(card, key_info);
+
LOG_FUNC_RETURN(card->ctx, r);
}
@@ -2975,8 +3045,9 @@ pgp_update_card_algorithms(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *ke
LOG_FUNC_CALLED(card->ctx);
/* protect incompatible cards against non-RSA */
- if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
- && priv->bcd_version < OPENPGP_CARD_3_0)
+ if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA &&
+ priv->bcd_version < OPENPGP_CARD_3_0 &&
+ card->type != SC_CARD_TYPE_OPENPGP_GNUK)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
if (id > card->algorithm_count) {
@@ -2993,12 +3064,13 @@ pgp_update_card_algorithms(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *ke
algo->algorithm = SC_ALGORITHM_RSA;
algo->key_length = (unsigned int)key_info->u.rsa.modulus_len;
}
- else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
- || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA) {
+ /* TODO FIXME */
+ else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* includes XEDDSA */
+ key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA ||
+ key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) {
algo->algorithm = SC_ALGORITHM_EC;
algo->key_length = (unsigned int)((key_info->u.ec.ecpoint_len));
- }
- else
+ } else
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
@@ -3023,11 +3095,9 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info)
LOG_FUNC_CALLED(card->ctx);
/* protect incompatible cards against non-RSA */
- if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
- && priv->bcd_version < OPENPGP_CARD_3_0)
- LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
- if (key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA
- && card->type != SC_CARD_TYPE_OPENPGP_GNUK)
+ if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA &&
+ priv->bcd_version < OPENPGP_CARD_3_0 &&
+ card->type != SC_CARD_TYPE_OPENPGP_GNUK)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* set Control Reference Template for key */
@@ -3243,12 +3313,12 @@ pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info
componenttags[3] = 0x97;
componentnames[3] = "modulus";
comp_to_add = 4;
- }
- /* validate */
- if (comp_to_add == 4 && (key_info->u.rsa.n == NULL || key_info->u.rsa.n_len == 0)){
- sc_log(ctx, "Error: Modulus required!");
- LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
+ /* validate */
+ if (comp_to_add == 4 && (key_info->u.rsa.n == NULL || key_info->u.rsa.n_len == 0)) {
+ sc_log(ctx, "Error: Modulus required!");
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
+ }
}
/* Cardholder private key template's data part */
@@ -3284,18 +3354,18 @@ pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info
comp_to_add = 1;
/* import public key as well */
- if (key_info->u.ec.keyformat == SC_OPENPGP_KEYFORMAT_EC_STDPUB){
+ if (key_info->u.ec.keyformat == SC_OPENPGP_KEYFORMAT_EC_STDPUB) {
components[1] = key_info->u.ec.ecpointQ;
componentlens[1] = key_info->u.ec.ecpointQ_len;
componenttags[1] = 0x99;
componentnames[1] = "public key";
comp_to_add = 2;
- }
- /* validate */
- if ((key_info->u.ec.ecpointQ == NULL || key_info->u.ec.ecpointQ_len == 0)){
- sc_log(ctx, "Error: ecpointQ required!");
- LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
+ /* validate */
+ if ((key_info->u.ec.ecpointQ == NULL || key_info->u.ec.ecpointQ_len == 0)) {
+ sc_log(ctx, "Error: ecpointQ required!");
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
+ }
}
/* Cardholder private key template's data part */
@@ -3383,14 +3453,25 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info)
sc_cardctl_openpgp_keygen_info_t pubkey;
u8 *data = NULL;
size_t len = 0;
- int r;
+ int r = 0;
+ int has_pubkey = 0, has_privkey = 0;
struct pgp_priv_data *priv = DRVDATA(card);
LOG_FUNC_CALLED(card->ctx);
+ /* PKCS11 loads privkey separately from pubkey as two diffrent operations
+ * So this routine will be called twice to create two different objects.
+ * pkcs15init only calls once, with both.
+ * OpenPGP 4.3.1 says modulus and ecpointQ are optional when
+ * creating the extended header.
+ * So we can tell the difference and only do appropriate parts of this
+ * routine.
+ */
+
/* protect incompatible cards against non-RSA */
- if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA
- && priv->bcd_version < OPENPGP_CARD_3_0)
+ if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA &&
+ priv->bcd_version < OPENPGP_CARD_3_0 &&
+ card->type != SC_CARD_TYPE_OPENPGP_GNUK)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
/* Validate */
@@ -3401,18 +3482,29 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info)
/* set algorithm attributes */
/* RSA */
if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA){
+ has_pubkey = (key_info->u.rsa.n && key_info->u.rsa.n_len &&
+ key_info->u.rsa.e && key_info->u.rsa.e_len);
+ has_privkey = (has_pubkey &&
+ key_info->u.rsa.p && key_info->u.rsa.p_len &&
+ key_info->u.rsa.q && key_info->u.rsa.q_len);
+
+ if (!has_pubkey && !has_privkey)
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+
/* we just support standard key format */
- switch (key_info->u.rsa.keyformat) {
- case SC_OPENPGP_KEYFORMAT_RSA_STD:
- case SC_OPENPGP_KEYFORMAT_RSA_STDN:
- break;
+ if (has_privkey) {
+ switch (key_info->u.rsa.keyformat) {
+ case SC_OPENPGP_KEYFORMAT_RSA_STD:
+ case SC_OPENPGP_KEYFORMAT_RSA_STDN:
+ break;
- case SC_OPENPGP_KEYFORMAT_RSA_CRT:
- case SC_OPENPGP_KEYFORMAT_RSA_CRTN:
- LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+ case SC_OPENPGP_KEYFORMAT_RSA_CRT:
+ case SC_OPENPGP_KEYFORMAT_RSA_CRTN:
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
- default:
- LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+ default:
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+ }
}
/* we only support exponent of maximum 32 bits */
@@ -3426,59 +3518,68 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info)
memset(&pubkey, 0, sizeof(pubkey));
pubkey.key_id = key_info->key_id;
pubkey.algorithm = key_info->algorithm;
- if (key_info->u.rsa.n && key_info->u.rsa.n_len
- && key_info->u.rsa.e && key_info->u.rsa.e_len) {
- pubkey.u.rsa.modulus = key_info->u.rsa.n;
- pubkey.u.rsa.modulus_len = key_info->u.rsa.n_len;
- pubkey.u.rsa.exponent = key_info->u.rsa.e;
- pubkey.u.rsa.exponent_len = key_info->u.rsa.e_len;
- }
- else
- LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS);
+ pubkey.u.rsa.modulus = key_info->u.rsa.n;
+ pubkey.u.rsa.modulus_len = key_info->u.rsa.n_len;
+ pubkey.u.rsa.exponent = key_info->u.rsa.e;
+ pubkey.u.rsa.exponent_len = key_info->u.rsa.e_len;
+
}
/* ECC */
- else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH
- || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){
+ else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA ||
+ key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* includes XEDDSA */
+ key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) {
+ has_pubkey = (key_info->u.ec.ecpointQ && key_info->u.ec.ecpointQ_len);
+ has_privkey = (key_info->u.ec.privateD && key_info->u.ec.privateD_len);
+
+ if (!has_pubkey && !has_privkey)
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+
memset(&pubkey, 0, sizeof(pubkey));
pubkey.key_id = key_info->key_id;
pubkey.algorithm = key_info->algorithm;
- if (key_info->u.ec.ecpointQ && key_info->u.ec.ecpointQ_len){
- pubkey.u.ec.ecpoint = key_info->u.ec.ecpointQ;
- pubkey.u.ec.ecpoint_len = key_info->u.ec.ecpointQ_len;
- pubkey.u.ec.oid = key_info->u.ec.oid;
- pubkey.u.ec.oid_len = key_info->u.ec.oid_len;
- }
- else
- LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS);
+ pubkey.u.ec.oid = key_info->u.ec.oid;
+ pubkey.u.ec.oid_len = key_info->u.ec.oid_len;
+ pubkey.u.ec.ecpoint = key_info->u.ec.ecpointQ;
+ pubkey.u.ec.ecpoint_len = key_info->u.ec.ecpointQ_len;
+ pubkey.u.ec.oid = key_info->u.ec.oid;
+ pubkey.u.ec.oid_len = key_info->u.ec.oid_len;
}
- else
- LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
- r = pgp_update_new_algo_attr(card, &pubkey);
- LOG_TEST_RET(card->ctx, r, "Failed to update new algorithm attributes");
+ /* TODO where is curve_name are */
+ if (has_pubkey) {
+ r = pgp_update_new_algo_attr(card, &pubkey);
+ LOG_TEST_RET(card->ctx, r, "Failed to update new algorithm attributes");
+ }
/* build Extended Header list */
- r = pgp_build_extended_header_list(card, key_info, &data, &len);
- LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to build Extended Header list");
+ if (has_privkey) {
+ r = pgp_build_extended_header_list(card, key_info, &data, &len);
+ LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to build Extended Header list");
+ }
/* write to DO */
- r = pgp_put_data(card, 0x4D, data, len);
- LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to write to DO 004D");
+ if (has_privkey) {
+ r = pgp_put_data(card, 0x4D, data, len);
+ LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to write to DO 004D");
- /* store creation time */
- r = pgp_store_creationtime(card, key_info->key_id, &key_info->creationtime);
- LOG_TEST_RET(card->ctx, r, "Cannot store creation time");
+ /* store creation time */
+ r = pgp_store_creationtime(card, key_info->key_id, &key_info->creationtime);
+ LOG_TEST_RET(card->ctx, r, "Cannot store creation time");
+ }
- /* calculate and store fingerprint */
- sc_log(card->ctx, "Calculate and store fingerprint");
- r = pgp_calculate_and_store_fingerprint(card, key_info->creationtime, &pubkey);
- LOG_TEST_RET(card->ctx, r, "Cannot store fingerprint");
- /* update pubkey blobs (B601,B801, A401) */
- sc_log(card->ctx, "Update blobs holding pubkey info.");
- r = pgp_update_pubkey_blob(card, &pubkey);
+ if (has_pubkey) {
+ /* calculate and store fingerprint */
+ sc_log(card->ctx, "Calculate and store fingerprint");
+ r = pgp_calculate_and_store_fingerprint(card, key_info->creationtime, &pubkey);
- sc_log(card->ctx, "Update card algorithms");
- pgp_update_card_algorithms(card, &pubkey);
+ LOG_TEST_RET(card->ctx, r, "Cannot store fingerprint");
+ /* update pubkey blobs (B601,B801, A401) */
+ sc_log(card->ctx, "Update blobs holding pubkey info.");
+ r = pgp_update_pubkey_blob(card, &pubkey);
+
+ sc_log(card->ctx, "Update card algorithms");
+ pgp_update_card_algorithms(card, &pubkey);
+ }
err:
free(data);
diff --git a/src/libopensc/card-openpgp.h b/src/libopensc/card-openpgp.h
index 36a84086bf..85fc14865a 100644
--- a/src/libopensc/card-openpgp.h
+++ b/src/libopensc/card-openpgp.h
@@ -163,8 +163,16 @@ typedef struct pgp_blob {
typedef struct _pgp_ec_curves {
struct sc_object_id oid;
size_t size;
+ unsigned int key_type;
} pgp_ec_curves_t;
+#ifdef ENABLE_OPENSSL
+typedef struct _pgp_ec_curves_alt {
+ struct sc_object_id oid;
+ struct sc_object_id oid_alt; /* RFC8410 OIDs to be mapped to oid */
+ size_t size;
+} pgp_ec_curves_alt_t;
+#endif /* ENABLE_OPENSSL */
#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data))
diff --git a/src/libopensc/card.c b/src/libopensc/card.c
index 7f4ef98f91..ea3e4cd2da 100644
--- a/src/libopensc/card.c
+++ b/src/libopensc/card.c
@@ -163,11 +163,10 @@ static void sc_card_free(sc_card_t *card)
int i;
for (i=0; ialgorithm_count; i++) {
struct sc_algorithm_info *info = (card->algorithms + i);
- if (info->algorithm == SC_ALGORITHM_EC) {
- struct sc_ec_parameters ep = info->u._ec.params;
-
- free(ep.named_curve);
- free(ep.der.value);
+ if (info->algorithm == SC_ALGORITHM_EC ||
+ info->algorithm == SC_ALGORITHM_EDDSA ||
+ info->algorithm == SC_ALGORITHM_XEDDSA) {
+ sc_clear_ec_params(&info->u._ec.params);
}
}
free(card->algorithms);
@@ -1167,6 +1166,7 @@ _sc_card_add_ec_alg_int(sc_card_t *card, size_t key_length,
int algorithm)
{
sc_algorithm_info_t info;
+ int r;
memset(&info, 0, sizeof(info));
sc_init_oid(&info.u._ec.params.id);
@@ -1176,10 +1176,19 @@ _sc_card_add_ec_alg_int(sc_card_t *card, size_t key_length,
info.flags = flags;
info.u._ec.ext_flags = ext_flags;
- if (curve_oid)
+ if (curve_oid) {
info.u._ec.params.id = *curve_oid;
+ r = sc_encode_oid(card->ctx, &info.u._ec.params.id, &info.u._ec.params.der.value, &info.u._ec.params.der.len);
+ LOG_TEST_GOTO_ERR(card->ctx, r, "sc_encode_oid failed");
+ r = sc_pkcs15_fix_ec_parameters(card->ctx, &info.u._ec.params);
+ LOG_TEST_GOTO_ERR(card->ctx, r, "sc_pkcs15_fix_ec_parameters failed");
+ }
- return _sc_card_add_algorithm(card, &info);
+ r = _sc_card_add_algorithm(card, &info);
+ return r;
+err:
+ sc_clear_ec_params(&info.u._ec.params);
+ return r;
}
int _sc_card_add_ec_alg(sc_card_t *card, size_t key_length,
@@ -1216,13 +1225,13 @@ sc_algorithm_info_t *sc_card_find_alg(sc_card_t *card,
for (i = 0; i < card->algorithm_count; i++) {
sc_algorithm_info_t *info = &card->algorithms[i];
- if (info->algorithm != algorithm)
- continue;
if (param && (info->algorithm == SC_ALGORITHM_EC ||
info->algorithm == SC_ALGORITHM_EDDSA ||
info->algorithm == SC_ALGORITHM_XEDDSA)) {
if (sc_compare_oid((struct sc_object_id *)param, &info->u._ec.params.id))
return info;
+ } else if (info->algorithm != algorithm) {
+ continue;
} else if (info->key_length == key_length)
return info;
}
@@ -1507,6 +1516,17 @@ void sc_print_cache(struct sc_card *card)
sc_print_path(&card->cache.current_df->path));
}
+void
+sc_clear_ec_params(struct sc_ec_parameters *ecp)
+{
+ if (ecp) {
+ free(ecp->named_curve);
+ free(ecp->der.value);
+ memset(ecp, 0, sizeof(struct sc_ec_parameters));
+ }
+ return;
+}
+
int sc_copy_ec_params(struct sc_ec_parameters *dst, struct sc_ec_parameters *src)
{
if (!dst || !src)
@@ -1528,8 +1548,9 @@ int sc_copy_ec_params(struct sc_ec_parameters *dst, struct sc_ec_parameters *src
memcpy(dst->der.value, src->der.value, src->der.len);
dst->der.len = src->der.len;
}
- src->type = dst->type;
- src->field_length = dst->field_length;
+ dst->type = src->type;
+ dst->field_length = src->field_length;
+ dst->key_type = src->key_type;
return SC_SUCCESS;
}
diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h
index 70115977a7..a9c90efe91 100644
--- a/src/libopensc/cardctl.h
+++ b/src/libopensc/cardctl.h
@@ -882,6 +882,7 @@ typedef struct sc_cardctl_piv_genkey_info_st {
typedef struct sc_cardctl_openpgp_keygen_info {
u8 key_id; /* SC_OPENPGP_KEY_... */
u8 algorithm; /* SC_OPENPGP_KEYALGO_... */
+ unsigned long key_type; /* SC_ALGORITHM_... */
union {
struct {
u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */
diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports
index b5f0b1cb27..fbc0ea96c4 100644
--- a/src/libopensc/libopensc.exports
+++ b/src/libopensc/libopensc.exports
@@ -64,6 +64,7 @@ sc_cancel
sc_card_ctl
sc_change_reference_data
sc_check_sw
+sc_clear_ec_params
sc_compare_oid
sc_compare_path
sc_compare_path_prefix
diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h
index cbcb3bebb3..36ba1722dc 100644
--- a/src/libopensc/opensc.h
+++ b/src/libopensc/opensc.h
@@ -280,14 +280,20 @@ struct sc_pbes2_params {
};
/*
+ * PKCS11 2.3 Elliptic Curve lists mechanisms that use CKA_ECPARMS
+ * which implies the type of key and size needed in the OID
* The ecParameters can be presented as
* - name of curve;
* - OID of named curve;
* - implicit parameters.
+ * - printable string for non standard OIDS - added in pkcs11 3.0
*
* type - type(choice) of 'EC domain parameters' as it present in CKA_EC_PARAMS (PKCS#11).
- Recommended value '1' -- namedCurve.
+ * Recommended value '1' -- namedCurve.
* field_length - EC key size in bits.
+ * key_type - 0 implies SC_ALGORITHM_EC, SC_ALGORITHM_EDDSA or SC_ALGORITHM_XEDDSA
+ * Not actually part of CKA_EC_PARAMS - used in OpenSC to differentiate key types that use ec_params
+ * will be set by, sc_pkcs15_fix_ec_parameters
*/
struct sc_ec_parameters {
char *named_curve;
@@ -296,6 +302,7 @@ struct sc_ec_parameters {
int type;
size_t field_length;
+ unsigned int key_type;
};
typedef struct sc_algorithm_info {
@@ -1646,6 +1653,11 @@ const u8 *sc_compacttlv_find_tag(const u8 *buf, size_t len, u8 tag, size_t *outl
*/
void sc_remote_data_init(struct sc_remote_data *rdata);
+/**
+ * Clear ec_params
+ * @ecp
+ */
+void sc_clear_ec_params(struct sc_ec_parameters *);
/**
* Copy and allocate if needed EC parameters data
diff --git a/src/libopensc/pkcs15-algo.c b/src/libopensc/pkcs15-algo.c
index 3b1b3ba031..d39ca853a9 100644
--- a/src/libopensc/pkcs15-algo.c
+++ b/src/libopensc/pkcs15-algo.c
@@ -347,116 +347,136 @@ asn1_free_ec_params(void *params)
}
}
-
static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = {
#ifdef SC_ALGORITHM_SHA1
/* hmacWithSHA1 */
- { SC_ALGORITHM_SHA1, {{ 1, 2, 840, 113549, 2, 7, -1}}, NULL, NULL, NULL },
- { SC_ALGORITHM_SHA1, {{ 1, 3, 6, 1, 5, 5, 8, 1, 2, -1}}, NULL, NULL, NULL },
- /* SHA1 */
- { SC_ALGORITHM_SHA1, {{ 1, 3, 14, 3, 2, 26, -1}}, NULL, NULL, NULL },
+ {SC_ALGORITHM_SHA1, {{1, 2, 840, 113549, 2, 7, -1}}, NULL, NULL, NULL},
+ {SC_ALGORITHM_SHA1, {{1, 3, 6, 1, 5, 5, 8, 1, 2, -1}}, NULL, NULL, NULL},
+ /* SHA1 */
+ {SC_ALGORITHM_SHA1, {{1, 3, 14, 3, 2, 26, -1}}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_MD5
- { SC_ALGORITHM_MD5, {{ 1, 2, 840, 113549, 2, 5, -1}}, NULL, NULL, NULL },
+ {SC_ALGORITHM_MD5, {{1, 2, 840, 113549, 2, 5, -1}}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_RSA /* really rsaEncryption */
- { SC_ALGORITHM_RSA, {{ 1, 2, 840, 113549, 1, 1, 1, -1}}, NULL, NULL, NULL },
+ {SC_ALGORITHM_RSA, {{1, 2, 840, 113549, 1, 1, 1, -1}}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_DH
- { SC_ALGORITHM_DH, {{ 1, 2, 840, 10046, 2, 1, -1}}, NULL, NULL, NULL },
+ {SC_ALGORITHM_DH, {{1, 2, 840, 10046, 2, 1, -1}}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_RC2_WRAP /* from CMS */
- { SC_ALGORITHM_RC2_WRAP, {{ 1, 2, 840, 113549, 1, 9, 16, 3, 7, -1}}, NULL, NULL, NULL },
+ {SC_ALGORITHM_RC2_WRAP, {{1, 2, 840, 113549, 1, 9, 16, 3, 7, -1}}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_RC2 /* CBC mode */
- { SC_ALGORITHM_RC2, {{ 1, 2, 840, 113549, 3, 2, -1}},
+ {SC_ALGORITHM_RC2, {{1, 2, 840, 113549, 3, 2, -1}},
asn1_decode_rc2_params,
- asn1_encode_rc2_params },
+ asn1_encode_rc2_params},
#endif
#ifdef SC_ALGORITHM_DES /* CBC mode */
- { SC_ALGORITHM_DES, {{ 1, 3, 14, 3, 2, 7, -1}},
+ {SC_ALGORITHM_DES, {{1, 3, 14, 3, 2, 7, -1}},
asn1_decode_des_params,
asn1_encode_des_params,
- free },
+ free},
#endif
#ifdef SC_ALGORITHM_3DES_WRAP /* from CMS */
- { SC_ALGORITHM_3DES_WRAP, {{ 1, 2, 840, 113549, 1, 9, 16, 3, 6, -1}}, NULL, NULL, NULL },
+ {SC_ALGORITHM_3DES_WRAP, {{1, 2, 840, 113549, 1, 9, 16, 3, 6, -1}}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_3DES /* EDE CBC mode */
- { SC_ALGORITHM_3DES, {{ 1, 2, 840, 113549, 3, 7, -1}},
+ {SC_ALGORITHM_3DES, {{1, 2, 840, 113549, 3, 7, -1}},
asn1_decode_des_params,
asn1_encode_des_params,
- free },
+ free},
#endif
#ifdef SC_ALGORITHM_GOST /* EDE CBC mode */
- { SC_ALGORITHM_GOST, {{ 1, 2, 4434, 66565, 3, 7, -1}}, NULL, NULL, NULL },
+ {SC_ALGORITHM_GOST, {{1, 2, 4434, 66565, 3, 7, -1}}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_GOSTR3410
- { SC_ALGORITHM_GOSTR3410, {{ 1, 2, 643, 2, 2, 19, -1}},
+ {SC_ALGORITHM_GOSTR3410, {{1, 2, 643, 2, 2, 19, -1}},
asn1_decode_gostr3410_params,
asn1_encode_gostr3410_params,
- NULL },
+ NULL},
#endif
/* We do not support PBES1 because the encryption is weak */
#ifdef SC_ALGORITHM_PBKDF2
- { SC_ALGORITHM_PBKDF2, {{ 1, 2, 840, 113549, 1, 5, 12, -1}},
+ {SC_ALGORITHM_PBKDF2, {{1, 2, 840, 113549, 1, 5, 12, -1}},
asn1_decode_pbkdf2_params,
asn1_encode_pbkdf2_params,
- free },
+ free},
#endif
#ifdef SC_ALGORITHM_PBES2
- { SC_ALGORITHM_PBES2, {{ 1, 2, 840, 113549, 1, 5, 13, -1}},
+ {SC_ALGORITHM_PBES2, {{1, 2, 840, 113549, 1, 5, 13, -1}},
asn1_decode_pbes2_params,
asn1_encode_pbes2_params,
- asn1_free_pbes2_params },
+ asn1_free_pbes2_params},
#endif
#ifdef SC_ALGORITHM_EC
- { SC_ALGORITHM_EC, {{ 1, 2, 840, 10045, 2, 1, -1}},
+ {SC_ALGORITHM_EC, {{1, 2, 840, 10045, 2, 1, -1}},
asn1_decode_ec_params,
asn1_encode_ec_params,
- asn1_free_ec_params },
+ asn1_free_ec_params},
#endif
-/* TODO: -DEE Not clear if we need the next five or not */
#ifdef SC_ALGORITHM_ECDSA_SHA1
/* Note RFC 3279 says no ecParameters */
- { SC_ALGORITHM_ECDSA_SHA1, {{ 1, 2, 840, 10045, 4, 1, -1}}, NULL, NULL, NULL},
+ {SC_ALGORITHM_ECDSA_SHA1, {{1, 2, 840, 10045, 4, 1, -1}}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_ECDSA_SHA224
-/* These next 4 are defined in RFC 5758 */
- { SC_ALGORITHM_ECDSA_SHA224, {{ 1, 2, 840, 10045, 4, 3, 1, -1}},
+ /* These next 4 are defined in RFC 5758 */
+ {SC_ALGORITHM_ECDSA_SHA224, {{1, 2, 840, 10045, 4, 3, 1, -1}},
asn1_decode_ec_params,
asn1_encode_ec_params,
- asn1_free_ec_params },
+ asn1_free_ec_params},
#endif
#ifdef SC_ALGORITHM_ECDSA_SHA256
- { SC_ALGORITHM_ECDSA_SHA256, {{ 1, 2, 840, 10045, 4, 3, 2, -1}},
+ {SC_ALGORITHM_ECDSA_SHA256, {{1, 2, 840, 10045, 4, 3, 2, -1}},
asn1_decode_ec_params,
asn1_encode_ec_params,
- asn1_free_ec_params },
+ asn1_free_ec_params},
#endif
#ifdef SC_ALGORITHM_ECDSA_SHA384
- { SC_ALGORITHM_ECDSA_SHA384, {{ 1, 2, 840, 10045, 4, 3, 3, -1}},
+ {SC_ALGORITHM_ECDSA_SHA384, {{1, 2, 840, 10045, 4, 3, 3, -1}},
asn1_decode_ec_params,
asn1_encode_ec_params,
- asn1_free_ec_params },
+ asn1_free_ec_params},
#endif
#ifdef SC_ALGORITHM_ECDSA_SHA512
- { SC_ALGORITHM_ECDSA_SHA512, {{ 1, 2, 840, 10045, 4, 3, 4, -1}},
+ {SC_ALGORITHM_ECDSA_SHA512, {{1, 2, 840, 10045, 4, 3, 4, -1}},
asn1_decode_ec_params,
asn1_encode_ec_params,
- asn1_free_ec_params },
+ asn1_free_ec_params},
#endif
#ifdef SC_ALGORITHM_EDDSA
/* aka Ed25519 */
- /* RFC 8410, needed to parse/create X509 certs/pubkeys */
- { SC_ALGORITHM_EDDSA, {{1, 3, 101, 112, -1}}, NULL, NULL, NULL },
+ /* RFC 8410, needed to parse/create X509 certs/pubkeys */
+ {SC_ALGORITHM_EDDSA, {{1, 3, 101, 112, -1}},
+ asn1_decode_ec_params,
+ asn1_encode_ec_params,
+ asn1_free_ec_params}, /* Ed25119 */
+ {SC_ALGORITHM_EDDSA, {{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}},
+ asn1_decode_ec_params,
+ asn1_encode_ec_params,
+ asn1_free_ec_params}, /* Ed25519 OID used by OpenPGP */
+ {SC_ALGORITHM_EDDSA, {{1, 3, 101, 113, -1}},
+ asn1_decode_ec_params,
+ asn1_encode_ec_params,
+ asn1_free_ec_params}, /* Ed448 */
#endif
#ifdef SC_ALGORITHM_XEDDSA
/* aka curve25519 */
- /* RFC 8410, needed to parse/create X509 certs/pubkeys */
- { SC_ALGORITHM_XEDDSA, {{1, 3, 101, 110, -1}}, NULL, NULL, NULL },
+ /* RFC 8410, needed to parse/create X509 certs/pubkeys ec_parms*/
+ {SC_ALGORITHM_XEDDSA, {{1, 3, 101, 110, -1}},
+ asn1_decode_ec_params,
+ asn1_encode_ec_params,
+ asn1_free_ec_params}, /* X25519 */
+ {SC_ALGORITHM_XEDDSA, {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1 - 1}},
+ asn1_decode_ec_params,
+ asn1_encode_ec_params,
+ asn1_free_ec_params}, /* X25519 OID used by OpenPGP */
+ {SC_ALGORITHM_XEDDSA, {{1, 3, 101, 111, -1}},
+ asn1_decode_ec_params,
+ asn1_encode_ec_params,
+ asn1_free_ec_params}, /* X448 */
#endif
- { -1, {{ -1 }}, NULL, NULL, NULL }
+ {-1, {{-1}}, NULL, NULL, NULL}
};
@@ -554,6 +574,7 @@ sc_asn1_encode_algorithm_id(struct sc_context *ctx, u8 **buf, size_t *len,
/* no parameters, write NULL tag */
/* If it's EDDSA/XEDDSA, according to RFC8410, params
* MUST be absent */
+ /* PKCS11 3.0 list them under ec_params */
if (id->algorithm != SC_ALGORITHM_EDDSA &&
id->algorithm != SC_ALGORITHM_XEDDSA &&
(!id->params || !alg_info->encode))
diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c
index 70834713a1..63e0566787 100644
--- a/src/libopensc/pkcs15-prkey.c
+++ b/src/libopensc/pkcs15-prkey.c
@@ -570,19 +570,13 @@ sc_pkcs15_erase_prkey(struct sc_pkcs15_prkey *key)
free(key->u.gostr3410.d.data);
break;
case SC_ALGORITHM_EC:
- free(key->u.ec.params.der.value);
- free(key->u.ec.params.named_curve);
+ case SC_ALGORITHM_EDDSA:
+ case SC_ALGORITHM_XEDDSA:
+ /* EC, Edwards and Montgomery use common ec params */
+ sc_clear_ec_params(&key->u.ec.params);
free(key->u.ec.privateD.data);
free(key->u.ec.ecpointQ.value);
break;
- case SC_ALGORITHM_EDDSA:
- free(key->u.eddsa.pubkey.value);
- key->u.eddsa.pubkey.value = NULL;
- key->u.eddsa.pubkey.len = 0;
- free(key->u.eddsa.value.value);
- key->u.eddsa.value.value = NULL;
- key->u.eddsa.value.len = 0;
- break;
}
sc_mem_clear(key, sizeof(*key));
}
diff --git a/src/libopensc/pkcs15-pubkey.c b/src/libopensc/pkcs15-pubkey.c
index 1f9c2c46d9..4b2c3b17b3 100644
--- a/src/libopensc/pkcs15-pubkey.c
+++ b/src/libopensc/pkcs15-pubkey.c
@@ -517,6 +517,7 @@ sc_pkcs15_encode_pukdf_entry(struct sc_context *ctx, const struct sc_pkcs15_obje
return r;
}
+// clang-format off
#define C_ASN1_PUBLIC_KEY_SIZE 2
static struct sc_asn1_entry c_asn1_public_key[C_ASN1_PUBLIC_KEY_SIZE] = {
{ "publicKeyCoefficients", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
@@ -536,18 +537,23 @@ static struct sc_asn1_entry c_asn1_gostr3410_pub_coefficients[C_ASN1_GOSTR3410_P
{ NULL, 0, 0, 0, NULL, NULL }
};
-#define C_ASN1_EC_POINTQ_SIZE 2
+/* older incorrect implementation may have encoded as OCTET STRING */
+/* accept either */
+#define C_ASN1_EC_POINTQ_SIZE 3
static struct sc_asn1_entry c_asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE] = {
- { "ecpointQ", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL },
+ { "ecpointQ", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL },
+ { "ecpointQ-OS", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
-#define C_ASN1_EDDSA_PUBKEY_SIZE 2
+/* See RFC8410 */
+#define C_ASN1_EDDSA_PUBKEY_SIZE 3
static struct sc_asn1_entry c_asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE] = {
- { "pubkey", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL },
+ { "ecpointQ", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL },
+ { "ecpointQ-OS", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
-
+// clang-format on
int
sc_pkcs15_decode_pubkey_rsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_rsa *key,
@@ -636,7 +642,8 @@ sc_pkcs15_encode_pubkey_gostr3410(sc_context_t *ctx,
}
/*
- * We are storing the ec_pointQ as u8 string. not as DER
+ * We are storing the ec_pointQ as u8 string not as DER
+ * Will accept either BIT STRING or OCTET STRING
*/
int
sc_pkcs15_decode_pubkey_ec(sc_context_t *ctx,
@@ -645,19 +652,20 @@ sc_pkcs15_decode_pubkey_ec(sc_context_t *ctx,
{
int r;
u8 * ecpoint_data = NULL;
- size_t ecpoint_len;
+ size_t ecpoint_len = 0;
struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE];
LOG_FUNC_CALLED(ctx);
sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ);
sc_format_asn1_entry(asn1_ec_pointQ + 0, &ecpoint_data, &ecpoint_len, 1);
- r = sc_asn1_decode(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL);
- if (r < 0) {
+ sc_format_asn1_entry(asn1_ec_pointQ + 1, &ecpoint_data, &ecpoint_len, 1);
+ r = sc_asn1_decode_choice(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL);
+ if (r < 0 || ecpoint_len == 0 || ecpoint_data == NULL) {
free(ecpoint_data);
- LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT);
}
- if (ecpoint_len == 0 || *ecpoint_data != 0x04) {
+ if (*ecpoint_data != 0x04) {
free(ecpoint_data);
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Supported only uncompressed EC pointQ value");
}
@@ -665,11 +673,6 @@ sc_pkcs15_decode_pubkey_ec(sc_context_t *ctx,
key->ecpointQ.len = ecpoint_len;
key->ecpointQ.value = ecpoint_data;
- /*
- * Only get here if raw point is stored in pkcs15 without curve name
- * spki has the curvename, so we can get the field_length
- * Following only true for curves that are multiple of 8
- */
key->params.field_length = (ecpoint_len - 1)/2 * 8;
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
@@ -680,57 +683,70 @@ sc_pkcs15_encode_pubkey_ec(sc_context_t *ctx, struct sc_pkcs15_pubkey_ec *key,
u8 **buf, size_t *buflen)
{
struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE];
+ size_t key_len;
+ volatile int gdb_test = 1; /* so can reset via gdb for testing new way */
LOG_FUNC_CALLED(ctx);
sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ);
- sc_format_asn1_entry(asn1_ec_pointQ + 0, key->ecpointQ.value, &key->ecpointQ.len, 1);
+
+ if (gdb_test == 1) {
+ key_len = key->ecpointQ.len * 8; /* encode in bit string */
+ sc_format_asn1_entry(asn1_ec_pointQ + 0, key->ecpointQ.value, &key_len, 1);
+ } else {
+ key_len = key->ecpointQ.len;
+ sc_format_asn1_entry(asn1_ec_pointQ + 1, key->ecpointQ.value, &key_len, 1);
+ }
LOG_FUNC_RETURN(ctx,
sc_asn1_encode(ctx, asn1_ec_pointQ, buf, buflen));
}
/*
- * EdDSA keys are just byte strings. For now only
- * for Ed25519 keys 32B length are supported
+ * all "ec" keys uses same pubkey format, keep this external entrypoint
+ * keys are just byte strings.
+ * will accept in either BIT STRING or OCTET STRING
*/
int
sc_pkcs15_decode_pubkey_eddsa(sc_context_t *ctx,
- struct sc_pkcs15_pubkey_eddsa *key,
+ struct sc_pkcs15_pubkey_ec *key,
const u8 *buf, size_t buflen)
{
int r;
- u8 * pubkey = NULL;
- size_t pubkey_len;
- struct sc_asn1_entry asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE];
+ u8 *ecpoint_data = NULL;
+ size_t ecpoint_len = 0;
+ struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE];
LOG_FUNC_CALLED(ctx);
- sc_copy_asn1_entry(c_asn1_eddsa_pubkey, asn1_eddsa_pubkey);
- sc_format_asn1_entry(asn1_eddsa_pubkey + 0, &pubkey, &pubkey_len, 1);
- r = sc_asn1_decode(ctx, asn1_eddsa_pubkey, buf, buflen, NULL, NULL);
- if (r < 0)
- LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
+ sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ);
+ sc_format_asn1_entry(asn1_ec_pointQ + 0, &ecpoint_data, &ecpoint_len, 1);
+ sc_format_asn1_entry(asn1_ec_pointQ + 1, &ecpoint_data, &ecpoint_len, 1);
+ r = sc_asn1_decode_choice(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL);
+ if (r < 0 || ecpoint_len == 0 || ecpoint_data == NULL) {
+ free(ecpoint_data);
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT);
+ }
- key->pubkey.len = pubkey_len;
- key->pubkey.value = pubkey;
+ key->ecpointQ.len = ecpoint_len;
+ key->ecpointQ.value = ecpoint_data;
+ key->params.field_length = ecpoint_len * 8;
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
int
-sc_pkcs15_encode_pubkey_eddsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_eddsa *key,
+sc_pkcs15_encode_pubkey_eddsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_ec *key,
u8 **buf, size_t *buflen)
{
struct sc_asn1_entry asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE];
LOG_FUNC_CALLED(ctx);
sc_copy_asn1_entry(c_asn1_eddsa_pubkey, asn1_eddsa_pubkey);
- sc_format_asn1_entry(asn1_eddsa_pubkey + 0, key->pubkey.value, &key->pubkey.len, 1);
+ sc_format_asn1_entry(asn1_eddsa_pubkey + 0, key->ecpointQ.value, &key->ecpointQ.len, 1);
LOG_FUNC_RETURN(ctx,
sc_asn1_encode(ctx, asn1_eddsa_pubkey, buf, buflen));
}
-
int
sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key,
u8 **buf, size_t *len)
@@ -741,9 +757,8 @@ sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key,
return sc_pkcs15_encode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len);
if (key->algorithm == SC_ALGORITHM_EC)
return sc_pkcs15_encode_pubkey_ec(ctx, &key->u.ec, buf, len);
- if (key->algorithm == SC_ALGORITHM_EDDSA ||
- key->algorithm == SC_ALGORITHM_XEDDSA) /* XXX encoding is the same here */
- return sc_pkcs15_encode_pubkey_eddsa(ctx, &key->u.eddsa, buf, len);
+ if (key->algorithm == SC_ALGORITHM_EDDSA || key->algorithm == SC_ALGORITHM_XEDDSA)
+ return sc_pkcs15_encode_pubkey_eddsa(ctx, &key->u.ec, buf, len);
sc_log(ctx, "Encoding of public key type %lu not supported", key->algorithm);
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
@@ -789,6 +804,8 @@ sc_pkcs15_encode_pubkey_as_spki(sc_context_t *ctx, struct sc_pkcs15_pubkey *pubk
switch (pubkey->algorithm) {
case SC_ALGORITHM_EC:
+ case SC_ALGORITHM_EDDSA:
+ case SC_ALGORITHM_XEDDSA:
/*
* most keys, but not EC have only one encoding.
* For a SPKI, the ecpoint is placed directly in the
@@ -826,14 +843,6 @@ sc_pkcs15_encode_pubkey_as_spki(sc_context_t *ctx, struct sc_pkcs15_pubkey *pubk
r = sc_pkcs15_encode_pubkey(ctx, pubkey, &pkey.value, &pkey.len);
key_len = pkey.len * 8;
break;
- case SC_ALGORITHM_EDDSA:
- case SC_ALGORITHM_XEDDSA:
- /* For a SPKI, the pubkey is placed directly in the BIT STRING */
- pkey.value = malloc(pubkey->u.eddsa.pubkey.len);
- memcpy(pkey.value, pubkey->u.eddsa.pubkey.value, pubkey->u.eddsa.pubkey.len);
- // Should be pkey.len = 0 there?
- key_len = pubkey->u.eddsa.pubkey.len * 8;
- break;
default:
r = sc_pkcs15_encode_pubkey(ctx, pubkey, &pkey.value, &pkey.len);
key_len = pkey.len * 8;
@@ -867,9 +876,8 @@ sc_pkcs15_decode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key,
return sc_pkcs15_decode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len);
if (key->algorithm == SC_ALGORITHM_EC)
return sc_pkcs15_decode_pubkey_ec(ctx, &key->u.ec, buf, len);
- if (key->algorithm == SC_ALGORITHM_EDDSA ||
- key->algorithm == SC_ALGORITHM_XEDDSA)
- return sc_pkcs15_decode_pubkey_eddsa(ctx, &key->u.eddsa, buf, len);
+ if (key->algorithm == SC_ALGORITHM_EDDSA || key->algorithm == SC_ALGORITHM_XEDDSA)
+ return sc_pkcs15_decode_pubkey_eddsa(ctx, &key->u.ec, buf, len);
sc_log(ctx, "Decoding of public key type %lu not supported", key->algorithm);
return SC_ERROR_NOT_SUPPORTED;
@@ -1030,29 +1038,20 @@ sc_pkcs15_pubkey_from_prvkey(struct sc_context *ctx, struct sc_pkcs15_prkey *prv
case SC_ALGORITHM_GOSTR3410:
break;
case SC_ALGORITHM_EC:
- pubkey->u.ec.ecpointQ.value = malloc(prvkey->u.ec.ecpointQ.len);
- if (!pubkey->u.ec.ecpointQ.value) {
- sc_pkcs15_free_pubkey(pubkey);
- LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
- }
- memcpy(pubkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.len);
- pubkey->u.ec.ecpointQ.len = prvkey->u.ec.ecpointQ.len;
- break;
case SC_ALGORITHM_EDDSA:
case SC_ALGORITHM_XEDDSA:
/* Copy pubkey */
- if (prvkey->u.eddsa.pubkey.value == NULL || prvkey->u.eddsa.pubkey.len <= 0) {
+ if (prvkey->u.ec.ecpointQ.value == NULL || prvkey->u.ec.ecpointQ.len <= 0) {
sc_pkcs15_free_pubkey(pubkey);
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
}
- pubkey->u.eddsa.pubkey.value = malloc(prvkey->u.eddsa.pubkey.len);
- if (!pubkey->u.eddsa.pubkey.value) {
+ pubkey->u.ec.ecpointQ.value = malloc(prvkey->u.ec.ecpointQ.len);
+ if (!pubkey->u.ec.ecpointQ.value) {
sc_pkcs15_free_pubkey(pubkey);
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
}
- memcpy(pubkey->u.eddsa.pubkey.value, prvkey->u.eddsa.pubkey.value, prvkey->u.eddsa.pubkey.len);
- pubkey->u.eddsa.pubkey.len = prvkey->u.eddsa.pubkey.len;
-
+ memcpy(pubkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.len);
+ pubkey->u.ec.ecpointQ.len = prvkey->u.ec.ecpointQ.len;
break;
default:
sc_log(ctx, "Unsupported private key algorithm");
@@ -1111,6 +1110,8 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc
case SC_ALGORITHM_GOSTR3410:
break;
case SC_ALGORITHM_EC:
+ case SC_ALGORITHM_EDDSA:
+ case SC_ALGORITHM_XEDDSA:
pubkey->u.ec.ecpointQ.value = malloc(key->u.ec.ecpointQ.len);
if (!pubkey->u.ec.ecpointQ.value) {
rv = SC_ERROR_OUT_OF_MEMORY;
@@ -1119,6 +1120,12 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc
memcpy(pubkey->u.ec.ecpointQ.value, key->u.ec.ecpointQ.value, key->u.ec.ecpointQ.len);
pubkey->u.ec.ecpointQ.len = key->u.ec.ecpointQ.len;
+ if (key->u.ec.params.named_curve) {
+ rv = sc_pkcs15_fix_ec_parameters(ctx, &key->u.ec.params);
+ if (rv)
+ break;
+ }
+
pubkey->u.ec.params.der.value = malloc(key->u.ec.params.der.len);
if (!pubkey->u.ec.params.der.value) {
rv = SC_ERROR_OUT_OF_MEMORY;
@@ -1127,27 +1134,17 @@ 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;
- 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;
- case SC_ALGORITHM_EDDSA:
- case SC_ALGORITHM_XEDDSA:
- /* Copy pubkey */
- pubkey->u.eddsa.pubkey.value = malloc(key->u.eddsa.pubkey.len);
- if (!pubkey->u.eddsa.pubkey.value) {
- rv = SC_ERROR_OUT_OF_MEMORY;
- break;
+ /* RFC4810 no named_curve */
+ if ((key->algorithm != SC_ALGORITHM_EDDSA) && (key->algorithm != SC_ALGORITHM_XEDDSA)) {
+ 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;
+ }
}
- memcpy(pubkey->u.eddsa.pubkey.value, key->u.eddsa.pubkey.value, key->u.eddsa.pubkey.len);
- pubkey->u.eddsa.pubkey.len = key->u.eddsa.pubkey.len;
break;
default:
@@ -1177,28 +1174,18 @@ sc_pkcs15_erase_pubkey(struct sc_pkcs15_pubkey *key)
}
switch (key->algorithm) {
case SC_ALGORITHM_RSA:
- if (key->u.rsa.modulus.data)
- free(key->u.rsa.modulus.data);
- if (key->u.rsa.exponent.data)
- free(key->u.rsa.exponent.data);
+ free(key->u.rsa.modulus.data);
+ free(key->u.rsa.exponent.data);
break;
case SC_ALGORITHM_GOSTR3410:
- if (key->u.gostr3410.xy.data)
- free(key->u.gostr3410.xy.data);
+ free(key->u.gostr3410.xy.data);
break;
case SC_ALGORITHM_EC:
- if (key->u.ec.params.der.value)
- free(key->u.ec.params.der.value);
- if (key->u.ec.params.named_curve)
- free(key->u.ec.params.named_curve);
- if (key->u.ec.ecpointQ.value)
- free(key->u.ec.ecpointQ.value);
- break;
case SC_ALGORITHM_EDDSA:
case SC_ALGORITHM_XEDDSA:
- free(key->u.eddsa.pubkey.value);
- key->u.eddsa.pubkey.value = NULL;
- key->u.eddsa.pubkey.len = 0;
+ free(key->u.ec.params.der.value);
+ free(key->u.ec.params.named_curve);
+ free(key->u.ec.ecpointQ.value);
break;
}
sc_mem_clear(key, sizeof(*key));
@@ -1402,9 +1389,9 @@ sc_pkcs15_pubkey_from_spki_fields(struct sc_context *ctx, struct sc_pkcs15_pubke
} else if (pk_alg.algorithm == SC_ALGORITHM_EDDSA ||
pk_alg.algorithm == SC_ALGORITHM_XEDDSA) {
/* EDDSA/XEDDSA public key is not encapsulated into BIT STRING -- it's a BIT STRING */
- pubkey->u.eddsa.pubkey.value = malloc(pk.len);
- memcpy(pubkey->u.eddsa.pubkey.value, pk.value, pk.len);
- pubkey->u.eddsa.pubkey.len = pk.len;
+ pubkey->u.ec.ecpointQ.value = malloc(pk.len);
+ memcpy(pubkey->u.ec.ecpointQ.value, pk.value, pk.len);
+ pubkey->u.ec.ecpointQ.len = pk.len;
} else {
/* Public key is expected to be encapsulated into BIT STRING */
r = sc_pkcs15_decode_pubkey(ctx, pubkey, pk.value, pk.len);
@@ -1471,82 +1458,134 @@ sc_pkcs15_pubkey_from_spki_file(struct sc_context *ctx, char * filename,
LOG_FUNC_RETURN(ctx, r);
}
-
+// clang-format off
static struct ec_curve_info {
const char *name;
const char *oid_str;
const char *oid_encoded;
size_t size;
-} ec_curve_infos[] = {
- {"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192},
- {"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192},
- {"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192},
- {"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192},
-
- {"secp224r1", "1.3.132.0.33", "06052b81040021", 224},
- {"nistp224", "1.3.132.0.33", "06052b81040021", 224},
-
- {"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
- {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
- {"nistp256", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
- {"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256},
-
- {"secp384r1", "1.3.132.0.34", "06052B81040022", 384},
- {"prime384v1", "1.3.132.0.34", "06052B81040022", 384},
- {"nistp384", "1.3.132.0.34", "06052B81040022", 384},
- {"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384},
-
- {"secp521r1", "1.3.132.0.35", "06052B81040023", 521},
- {"nistp521", "1.3.132.0.35", "06052B81040023", 521},
+ const unsigned int key_type;
- {"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192},
- {"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224},
- {"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256},
- {"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320},
- {"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384},
- {"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512},
-
- {"secp192k1", "1.3.132.0.31", "06052B8104001F", 192},
- {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256},
-
- {"ed25519", "1.3.6.1.4.1.11591.15.1", "06092B06010401DA470F01", 255},
- {"curve25519", "1.3.6.1.4.1.3029.1.5.1", "060A2B060104019755010501", 255},
-
- {NULL, NULL, NULL, 0}, /* Do not touch this */
+} ec_curve_infos[] = {
+ {"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, SC_ALGORITHM_EC},
+ {"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, SC_ALGORITHM_EC},
+ {"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, SC_ALGORITHM_EC},
+ {"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, SC_ALGORITHM_EC},
+
+ {"secp224r1", "1.3.132.0.33", "06052b81040021", 224, SC_ALGORITHM_EC},
+ {"nistp224", "1.3.132.0.33", "06052b81040021", 224, SC_ALGORITHM_EC},
+
+ {"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, SC_ALGORITHM_EC},
+ {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, SC_ALGORITHM_EC},
+ {"nistp256", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, SC_ALGORITHM_EC},
+ {"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, SC_ALGORITHM_EC},
+
+ {"secp384r1", "1.3.132.0.34", "06052B81040022", 384, SC_ALGORITHM_EC},
+ {"prime384v1", "1.3.132.0.34", "06052B81040022", 384, SC_ALGORITHM_EC},
+ {"nistp384", "1.3.132.0.34", "06052B81040022", 384, SC_ALGORITHM_EC},
+ {"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384, SC_ALGORITHM_EC},
+
+ {"secp521r1", "1.3.132.0.35", "06052B81040023", 521, SC_ALGORITHM_EC},
+ {"nistp521", "1.3.132.0.35", "06052B81040023", 521, SC_ALGORITHM_EC},
+
+ {"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192, SC_ALGORITHM_EC},
+ {"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224, SC_ALGORITHM_EC},
+ {"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256, SC_ALGORITHM_EC},
+ {"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320, SC_ALGORITHM_EC},
+ {"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384, SC_ALGORITHM_EC},
+ {"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512, SC_ALGORITHM_EC},
+
+ {"secp192k1", "1.3.132.0.31", "06052B8104001F", 192, SC_ALGORITHM_EC},
+ {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256, SC_ALGORITHM_EC},
+
+ /* OpenPGP extensions by Yubikey and GNUK are not defined in RFCs but we know the oid written to card */
+
+ {"edwards25519", "1.3.6.1.4.1.11591.15.1", "06092B06010401DA470F01", 255, SC_ALGORITHM_EDDSA},
+ {"curve25519", "1.3.6.1.4.1.3029.1.5.1", "060A2B060104019755010501", 255, SC_ALGORITHM_XEDDSA},
+
+ /* RFC 8410 defined curves */
+ {"X25519", "1.3.101.110", "06032b656e", 255, SC_ALGORITHM_XEDDSA},
+ {"X448", "1.3.101.111", "06032b656f", 448, SC_ALGORITHM_XEDDSA},
+ {"Ed25519", "1.3.101.112", "06032b6570", 255, SC_ALGORITHM_EDDSA},
+ {"Ed448", "1.3.101.113", "06032b6571", 448, SC_ALGORITHM_EDDSA},
+ /* GnuPG openpgp curves as used in gnupg-card are equivalent to RFC8410 OIDs */
+ {"cv25519", "1.3.101.110", "06032b656e", 255, SC_ALGORITHM_XEDDSA},
+ {"ed25519", "1.3.101.112", "06032b6570", 255, SC_ALGORITHM_EDDSA},
+
+ {NULL, NULL, NULL, 0, 0}, /* Do not touch this */
};
-
+// clang-format on
int
sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecparams)
{
int rv, ii;
+ int mapped_string = 0; /* der is printable string that can be replaced with der of OID */
LOG_FUNC_CALLED(ctx);
/* In PKCS#11 EC parameters arrives in DER encoded form */
- if (ecparams->der.value && ecparams->der.len) {
- for (ii=0; ec_curve_infos[ii].name; ii++) {
- struct sc_object_id id;
- unsigned char *buf = NULL;
- size_t len = 0;
-
- sc_format_oid(&id, ec_curve_infos[ii].oid_str);
- sc_encode_oid (ctx, &id, &buf, &len);
+ if (ecparams->der.value && ecparams->der.len && ecparams->der.len > 2) {
+
+ /* caller provided a der version of OID */
+ switch (ecparams->der.value[0]) {
+ case 0x06: /* der.value is an OID */
+ for (ii = 0; ec_curve_infos[ii].name; ii++) {
+ struct sc_object_id id;
+ unsigned char *buf = NULL;
+ size_t len = 0;
+
+ sc_format_oid(&id, ec_curve_infos[ii].oid_str);
+ sc_encode_oid(ctx, &id, &buf, &len);
+
+ if (ecparams->der.len == len && !memcmp(ecparams->der.value, buf, len)) {
+ free(buf);
+ break; /* found ec_curve_infos[ii] */
+ }
+ free(buf); /* ii points at {NULL, NULL, NULL, 0} entry */
+ }
+ break;
- if (ecparams->der.len == len && !memcmp(ecparams->der.value, buf, len)) {
- free(buf);
- break;
+ case 0x13:
+ /* printable string as per PKCS11 V 3.0 for experimental curves */
+ {
+ int r_tag;
+ const u8 *body = ecparams->der.value;
+ size_t len = ecparams->der.len;
+ unsigned int cla_out, tag_out;
+ size_t bodylen;
+
+ r_tag = sc_asn1_read_tag(&body, len, &cla_out, &tag_out, &bodylen);
+ if (r_tag != SC_SUCCESS || tag_out != 0x13) {
+ sc_log(ctx, "Invalid printable string");
+ LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
+ }
+ for (ii = 0; ec_curve_infos[ii].name; ii++) {
+ size_t len = strlen(ec_curve_infos[ii].name);
+ if (bodylen != len || memcmp(ec_curve_infos[ii].name, body, len) != 0)
+ continue;
+ /* found replacement of printable string to OID */
+ mapped_string = 1;
+ break;
+ }
}
+ break;
- free(buf);
+ default:
+ sc_log(ctx, "Unsupported ec params");
+ LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
}
- /* TODO: support of explicit EC parameters form */
if (!ec_curve_infos[ii].name)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported named curve");
sc_log(ctx, "Found known curve '%s'", ec_curve_infos[ii].name);
- if (!ecparams->named_curve) {
+ if (mapped_string) { /* free der of printable string replace below with OID */
+ free(ecparams->named_curve);
+ ecparams->named_curve = NULL;
+ }
+
+ if (!ecparams->named_curve) {
ecparams->named_curve = strdup(ec_curve_infos[ii].name);
if (!ecparams->named_curve)
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
@@ -1554,21 +1593,34 @@ sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecp
sc_log(ctx, "Curve name: '%s'", ecparams->named_curve);
}
- if (!sc_valid_oid(&ecparams->id))
+ if (!sc_valid_oid(&ecparams->id) || mapped_string)
sc_format_oid(&ecparams->id, ec_curve_infos[ii].oid_str);
ecparams->field_length = ec_curve_infos[ii].size;
- sc_log(ctx, "Curve length %"SC_FORMAT_LEN_SIZE_T"u",
- ecparams->field_length);
- }
- else if (ecparams->named_curve) { /* it can be name of curve or OID in ASCII form */
- for (ii=0; ec_curve_infos[ii].name; ii++) {
+ ecparams->key_type = ec_curve_infos[ii].key_type;
+ sc_log(ctx, "Curve length %" SC_FORMAT_LEN_SIZE_T "u key_type %d",
+ ecparams->field_length, ecparams->key_type);
+ if (mapped_string) {
+ /* replace the printable string version with the oid */
+ free(ecparams->der.value);
+ ecparams->der.len = strlen(ec_curve_infos[ii].oid_encoded) / 2;
+ ecparams->der.value = malloc(ecparams->der.len);
+ if (!ecparams->der.value)
+ LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
+ if (sc_hex_to_bin(ec_curve_infos[ii].oid_encoded, ecparams->der.value, &ecparams->der.len) < 0) {
+ free(ecparams->der.value);
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
+ }
+ }
+ } else if (ecparams->named_curve) { /* it can be name of curve or OID in ASCII form */
+ /* caller did not provide an OID, look for a name or oid_string */
+ for (ii = 0; ec_curve_infos[ii].name; ii++) {
if (!strcmp(ec_curve_infos[ii].name, ecparams->named_curve))
break;
if (!strcmp(ec_curve_infos[ii].oid_str, ecparams->named_curve))
break;
}
- if (!ec_curve_infos[ii].name) {
+ if (!ec_curve_infos[ii].name) {
sc_log(ctx, "Named curve '%s' not supported", ecparams->named_curve);
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
}
@@ -1577,13 +1629,18 @@ sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecp
LOG_TEST_RET(ctx, rv, "Invalid OID format");
ecparams->field_length = ec_curve_infos[ii].size;
+ ecparams->key_type = ec_curve_infos[ii].key_type;
+ sc_log(ctx, "Curve length %" SC_FORMAT_LEN_SIZE_T "u key_type %d",
+ ecparams->field_length, ecparams->key_type);
if (!ecparams->der.value || !ecparams->der.len) {
+ free(ecparams->der.value); /* just in case */
+ ecparams->der.value = NULL;
+ /* if caller did not provide der OID, fill in */
rv = sc_encode_oid (ctx, &ecparams->id, &ecparams->der.value, &ecparams->der.len);
LOG_TEST_RET(ctx, rv, "Cannot encode object ID");
}
- }
- else
+ } 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);
diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h
index ce107c02a0..e2832600cd 100644
--- a/src/libopensc/pkcs15.h
+++ b/src/libopensc/pkcs15.h
@@ -203,19 +203,10 @@ struct sc_pkcs15_pubkey_ec {
struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */
};
-struct sc_pkcs15_pubkey_eddsa {
- struct sc_pkcs15_u8 pubkey;
-};
-
struct sc_pkcs15_prkey_ec {
struct sc_ec_parameters params;
- sc_pkcs15_bignum_t privateD; /* note this is bignum */
- struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */
-};
-
-struct sc_pkcs15_prkey_eddsa {
- struct sc_pkcs15_u8 pubkey;
- struct sc_pkcs15_u8 value;
+ struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */
+ sc_pkcs15_bignum_t privateD; /* note this is bignum */
};
struct sc_pkcs15_pubkey_gostr3410 {
@@ -236,7 +227,6 @@ struct sc_pkcs15_pubkey {
union {
struct sc_pkcs15_pubkey_rsa rsa;
struct sc_pkcs15_pubkey_ec ec;
- struct sc_pkcs15_pubkey_eddsa eddsa;
struct sc_pkcs15_pubkey_gostr3410 gostr3410;
} u;
};
@@ -249,7 +239,6 @@ struct sc_pkcs15_prkey {
union {
struct sc_pkcs15_prkey_rsa rsa;
struct sc_pkcs15_prkey_ec ec;
- struct sc_pkcs15_prkey_eddsa eddsa;
struct sc_pkcs15_prkey_gostr3410 gostr3410;
struct sc_pkcs15_skey secret;
} u;
@@ -712,7 +701,7 @@ int sc_pkcs15_decode_pubkey_ec(struct sc_context *,
int sc_pkcs15_encode_pubkey_ec(struct sc_context *,
struct sc_pkcs15_pubkey_ec *, u8 **, size_t *);
int sc_pkcs15_encode_pubkey_eddsa(struct sc_context *,
- struct sc_pkcs15_pubkey_eddsa *, u8 **, size_t *);
+ struct sc_pkcs15_pubkey_ec *, u8 **, size_t *);
int sc_pkcs15_decode_pubkey(struct sc_context *,
struct sc_pkcs15_pubkey *, const u8 *, size_t);
int sc_pkcs15_encode_pubkey(struct sc_context *,
diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c
index 68b7a790dd..400f03cf73 100644
--- a/src/pkcs11/framework-pkcs15.c
+++ b/src/pkcs11/framework-pkcs15.c
@@ -163,6 +163,15 @@ const unsigned int gostr3410_paramset_B_oid[] = {1, 2, 643, 2, 2, 35, 2, (unsign
const CK_BYTE gostr3410_paramset_C_encoded_oid[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x03 };
const unsigned int gostr3410_paramset_C_oid[] = {1, 2, 643, 2, 2, 35, 3, (unsigned int)-1};
+#ifdef ENABLE_OPENSSL
+// clang-format off
+static const struct sc_object_id oid_ED25519 = { { 1, 3, 101, 112, -1 } };
+static const struct sc_object_id oid_ED448 = { { 1, 3, 101, 113, -1 } };
+static const struct sc_object_id oid_X25519 = { { 1, 3, 101, 110, -1 } };
+static const struct sc_object_id oid_X448 = { { 1, 3, 101, 111, -1 } };
+// clang-format on
+#endif /* ENABLE_OPENSSL */
+
static const struct {
const CK_BYTE *encoded_oid;
const unsigned int encoded_oid_size;
@@ -2339,12 +2348,12 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil
break;
case CKK_EC_EDWARDS:
args.key.algorithm = SC_ALGORITHM_EDDSA;
- /* TODO */
- return CKR_ATTRIBUTE_VALUE_INVALID;
+ ec = &args.key.u.ec;
+ break;
case CKK_EC_MONTGOMERY:
args.key.algorithm = SC_ALGORITHM_XEDDSA;
- /* TODO */
- return CKR_ATTRIBUTE_VALUE_INVALID;
+ ec = &args.key.u.ec;
+ break;
case CKK_EC:
args.key.algorithm = SC_ALGORITHM_EC;
ec = &args.key.u.ec;
@@ -2386,15 +2395,21 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil
case CKA_VALUE:
if (key_type == CKK_GOSTR3410)
bn = &gost->d;
- if (key_type == CKK_EC)
+ else if (key_type == CKK_EC ||
+ key_type == CKK_EC_EDWARDS ||
+ key_type == CKK_EC_MONTGOMERY) {
bn = &ec->privateD;
+ }
break;
case CKA_EC_PARAMS:
ec->params.der.value = calloc(1, attr->ulValueLen);
ec->params.der.len = attr->ulValueLen;
rv = attr_extract(attr, ec->params.der.value, &ec->params.der.len);
- if (rv != CKR_OK)
+ if (rv != CKR_OK) {
+ free(ec->params.der.value);
+ ec->params.der.value = NULL;
goto out;
+ }
if (sc_pkcs15_fix_ec_parameters(p11card->card->ctx, &ec->params) != SC_SUCCESS)
return CKR_ATTRIBUTE_VALUE_INVALID;
break;
@@ -2448,9 +2463,10 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil
rv = sc_to_cryptoki_error(rc, "C_CreateObject");
goto out;
}
- }
- else if (key_type == CKK_EC) {
- if (!ec->privateD.len || !ec->params.field_length) {
+ } else if (key_type == CKK_EC ||
+ key_type == CKK_EC_EDWARDS ||
+ key_type == CKK_EC_MONTGOMERY) {
+ if (!ec->privateD.len || !ec->params.field_length) {
sc_log(context, "Template to store the EC private key is incomplete");
return CKR_TEMPLATE_INCOMPLETE;
}
@@ -2458,11 +2474,11 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil
rc = sc_pkcs15init_store_private_key(fw_data->p15_card, profile, &args, &key_obj);
/* free args now */
- if (key_type == CKK_EC) {
+ if (key_type == CKK_EC ||
+ key_type == CKK_EC_EDWARDS ||
+ key_type == CKK_EC_MONTGOMERY) {
+ sc_clear_ec_params(&ec->params);
/* allocated above */
- free(ec->params.der.value);
- /* in sc_pkcs15_fix_ec_parameters() */
- free(ec->params.named_curve);
}
if (rc < 0) {
rv = sc_to_cryptoki_error(rc, "C_CreateObject");
@@ -2720,9 +2736,13 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile
ec = &args.key.u.ec;
break;
case CKK_EC_EDWARDS:
+ args.key.algorithm = SC_ALGORITHM_EDDSA;
+ ec = &args.key.u.ec;
+ break;
case CKK_EC_MONTGOMERY:
- /* TODO: -DEE Do not have real pkcs15 card with EC */
- /* fall through */
+ args.key.algorithm = SC_ALGORITHM_XEDDSA;
+ ec = &args.key.u.ec;
+ break;
default:
return CKR_ATTRIBUTE_VALUE_INVALID;
}
@@ -2764,17 +2784,39 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile
args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_WRAP);
break;
case CKA_EC_POINT:
- if (key_type == CKK_EC) {
+ switch (key_type) {
+ case CKK_EC:
if (sc_pkcs15_decode_pubkey_ec(p11card->card->ctx, ec, attr->pValue, attr->ulValueLen) < 0)
return CKR_ATTRIBUTE_VALUE_INVALID;
+ break;
+ case CKK_EC_EDWARDS:
+ case CKK_EC_MONTGOMERY:
+ /* Difference between 25519 and 448 versions set by ec->ecpointQ.len below */
+ ec->ecpointQ.value = calloc(1, attr->ulValueLen);
+ ec->ecpointQ.len = attr->ulValueLen;
+ rv = attr_extract(attr, ec->ecpointQ.value, &ec->ecpointQ.len);
+ if (rv != CKR_OK) {
+ free(ec->ecpointQ.value);
+ ec->ecpointQ.value = NULL;
+ ec->ecpointQ.len = 0;
+ sc_clear_ec_params(&ec->params);
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+ break;
+
+ default:
+ return CKR_ATTRIBUTE_VALUE_INVALID;
}
break;
case CKA_EC_PARAMS:
ec->params.der.value = calloc(1, attr->ulValueLen);
ec->params.der.len = attr->ulValueLen;
rv = attr_extract(attr, ec->params.der.value, &ec->params.der.len);
- if (rv != CKR_OK)
+ if (rv != CKR_OK) {
+ sc_clear_ec_params(&ec->params);
+ free(ec->params.der.value);
return CKR_ATTRIBUTE_VALUE_INVALID;
+ }
break;
default:
/* ignore unknown attrs, or flag error? */
@@ -2789,12 +2831,27 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile
}
}
+ if (key_type == CKK_EC_EDWARDS) {
+ if (ec->ecpointQ.len == 32)
+ ec->params.id = oid_ED25519;
+ else
+ ec->params.id = oid_ED448;
+ } else if (key_type == CKK_EC_MONTGOMERY) {
+ if (ec->ecpointQ.len == 32)
+ ec->params.id = oid_X25519;
+ else
+ ec->params.id = oid_X448;
+ }
+
if (key_type == CKK_RSA) {
if (!rsa->modulus.len || !rsa->exponent.len)
return CKR_TEMPLATE_INCOMPLETE;
- }
- else if (key_type == CKK_EC) {
- if (!ec->ecpointQ.len || !ec->params.der.value) {
+ } else if (key_type == CKK_EC ||
+ key_type == CKK_EC_EDWARDS ||
+ key_type == CKK_EC_MONTGOMERY) {
+ rc = sc_pkcs15_fix_ec_parameters(p11card->card->ctx, &ec->params);
+
+ if (rc || !ec->ecpointQ.len || !ec->params.der.value) {
sc_log(context, "Template to store the EC public key is incomplete");
return CKR_TEMPLATE_INCOMPLETE;
}
@@ -2802,13 +2859,10 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile
rc = sc_pkcs15init_store_public_key(fw_data->p15_card, profile, &args, &key_obj);
/* free args now */
- if (key_type == CKK_EC) {
- /* allocated above */
- free(ec->params.der.value);
- /* in sc_pkcs15_fix_ec_parameters() */
- free(ec->params.named_curve);
- /* in sc_pkcs15_decode_pubkey_ec() */
- free(ec->ecpointQ.value);
+ if (key_type == CKK_EC ||
+ key_type == CKK_EC_EDWARDS ||
+ key_type == CKK_EC_MONTGOMERY) {
+ sc_clear_ec_params(&ec->params);
}
if (rc < 0)
return sc_to_cryptoki_error(rc, "C_CreateObject");
@@ -3356,8 +3410,7 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism,
if (rv != CKR_OK)
keybits = 1024; /* Default key size */
/* TODO: check allowed values of keybits */
- }
- else if (keytype == CKK_EC) {
+ } else if (keytype == CKK_EC || keytype == CKK_EC_EDWARDS || keytype == CKK_EC_MONTGOMERY) {
struct sc_lv_data *der = &keygen_args.prkey_args.key.u.ec.params.der;
void *ptr = NULL;
@@ -3368,29 +3421,21 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism,
sc_unlock(p11card->card);
return rv;
}
+ }
+ if (keytype == CKK_EC) {
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_EC;
pub_args.key.algorithm = SC_ALGORITHM_EC;
- }
- else if (keytype == CKK_EC_EDWARDS) {
- /* TODO Validate EC_PARAMS contains curveName "edwards25519" or "edwards448" (from RFC 8032)
- * or id-Ed25519 or id-Ed448 (or equivalent OIDs in oId field) (from RFC 8410)
- * otherwise return CKR_CURVE_NOT_SUPPORTED
- */
+ } else if (keytype == CKK_EC_EDWARDS) {
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_EDDSA;
- pub_args.key.algorithm = SC_ALGORITHM_EDDSA;
- return CKR_CURVE_NOT_SUPPORTED;
- }
- else if (keytype == CKK_EC_MONTGOMERY) {
- /* TODO Validate EC_PARAMS contains curveName "curve25519" or "curve448" (from RFC 7748)
- * or id-X25519 or id-X448 (or equivalent OIDs in oId field) (from RFC 8410)
- * otherwise return CKR_CURVE_NOT_SUPPORTED
- */
+ keygen_args.prkey_args.usage |= SC_PKCS15_PRKEY_USAGE_SIGN;
+ pub_args.key.algorithm = SC_ALGORITHM_EDDSA;
+ } else if (keytype == CKK_EC_MONTGOMERY) {
keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_XEDDSA;
- pub_args.key.algorithm = SC_ALGORITHM_XEDDSA;
- return CKR_CURVE_NOT_SUPPORTED;
- }
- else {
+ /* Can not sign. To created a cert, see: openssl x509 -force_pubkey */
+ keygen_args.prkey_args.usage |= SC_PKCS15_PRKEY_USAGE_DERIVE;
+ pub_args.key.algorithm = SC_ALGORITHM_XEDDSA;
+ } else {
/* CKA_KEY_TYPE is set, but keytype isn't correct */
rv = CKR_ATTRIBUTE_VALUE_INVALID;
goto kpgen_done;
@@ -4909,6 +4954,7 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_
case CKA_MODULUS_BITS:
case CKA_VALUE:
case CKA_SPKI:
+ case CKA_PUBLIC_KEY_INFO:
case CKA_PUBLIC_EXPONENT:
case CKA_EC_PARAMS:
case CKA_EC_POINT:
@@ -5035,26 +5081,25 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_
*/
case CKA_VALUE:
case CKA_SPKI:
+ case CKA_PUBLIC_KEY_INFO:
- if (attr->type != CKA_SPKI && pubkey->pub_info && pubkey->pub_info->direct.raw.value && pubkey->pub_info->direct.raw.len) {
+ if (attr->type != CKA_SPKI && attr->type != CKA_PUBLIC_KEY_INFO && pubkey->pub_info && pubkey->pub_info->direct.raw.value && pubkey->pub_info->direct.raw.len) {
check_attribute_buffer(attr, pubkey->pub_info->direct.raw.len);
memcpy(attr->pValue, pubkey->pub_info->direct.raw.value, pubkey->pub_info->direct.raw.len);
- }
- else if (pubkey->pub_info && pubkey->pub_info->direct.spki.value && pubkey->pub_info->direct.spki.len) {
+ } else if (pubkey->pub_info && pubkey->pub_info->direct.spki.value && pubkey->pub_info->direct.spki.len) {
check_attribute_buffer(attr, pubkey->pub_info->direct.spki.len);
memcpy(attr->pValue, pubkey->pub_info->direct.spki.value, pubkey->pub_info->direct.spki.len);
- }
- else if (pubkey->pub_data) {
+ } else if (pubkey->pub_data) {
unsigned char *value = NULL;
size_t len;
- if (attr->type != CKA_SPKI) {
+ if (attr->type != CKA_SPKI && attr->type != CKA_PUBLIC_KEY_INFO) {
if (sc_pkcs15_encode_pubkey(context, pubkey->pub_data, &value, &len))
return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetAttributeValue");
- } else {
- if (sc_pkcs15_encode_pubkey_as_spki(context, pubkey->pub_data, &value, &len))
+ } else {
+ if (sc_pkcs15_encode_pubkey_as_spki(context, pubkey->pub_data, &value, &len))
return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetAttributeValue");
- }
+ }
if (attr->pValue == NULL_PTR) {
attr->ulValueLen = len;
@@ -5070,16 +5115,13 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_
memcpy(attr->pValue, value, len);
free(value);
- }
- else if (attr->type != CKA_SPKI && pubkey->base.p15_object && pubkey->base.p15_object->content.value && pubkey->base.p15_object->content.len) {
+ } else if (attr->type != CKA_SPKI && attr->type != CKA_PUBLIC_KEY_INFO && pubkey->base.p15_object && pubkey->base.p15_object->content.value && pubkey->base.p15_object->content.len) {
check_attribute_buffer(attr, pubkey->base.p15_object->content.len);
memcpy(attr->pValue, pubkey->base.p15_object->content.value, pubkey->base.p15_object->content.len);
- }
- else if (cert && cert->cert_data) {
+ } else if (cert && cert->cert_data) {
check_attribute_buffer(attr, cert->cert_data->data.len);
memcpy(attr->pValue, cert->cert_data->data.value, cert->cert_data->data.len);
- }
- else {
+ } else {
return CKR_ATTRIBUTE_TYPE_INVALID;
}
break;
@@ -5989,7 +6031,7 @@ get_ec_pubkey_point(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr)
switch (key->algorithm) {
case SC_ALGORITHM_EDDSA:
case SC_ALGORITHM_XEDDSA:
- rc = sc_pkcs15_encode_pubkey_eddsa(context, &key->u.eddsa, &value, &value_len);
+ rc = sc_pkcs15_encode_pubkey_eddsa(context, &key->u.ec, &value, &value_len);
if (rc != SC_SUCCESS)
return sc_to_cryptoki_error(rc, NULL);
diff --git a/src/pkcs15init/pkcs15-isoApplet.c b/src/pkcs15init/pkcs15-isoApplet.c
index 632989d142..64c73e46d9 100644
--- a/src/pkcs15init/pkcs15-isoApplet.c
+++ b/src/pkcs15init/pkcs15-isoApplet.c
@@ -571,17 +571,7 @@ isoApplet_generate_key_ec(const sc_pkcs15_prkey_info_t *key_info, sc_card_t *car
free(pubkey->alg_id);
pubkey->alg_id = NULL;
}
- if(pubkey->u.ec.params.der.value)
- {
- free(pubkey->u.ec.params.der.value);
- pubkey->u.ec.params.der.value = NULL;
- pubkey->u.ec.params.der.len = 0;
- }
- if(pubkey->u.ec.params.named_curve)
- {
- free(pubkey->u.ec.params.named_curve);
- pubkey->u.ec.params.named_curve = NULL;
- }
+ sc_clear_ec_params(&pubkey->u.ec.params);
if(pubkey->u.ec.ecpointQ.value)
{
free(pubkey->u.ec.ecpointQ.value);
diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c
index dbb5748b25..b74520c969 100644
--- a/src/pkcs15init/pkcs15-lib.c
+++ b/src/pkcs15init/pkcs15-lib.c
@@ -176,10 +176,7 @@ static void sc_pkcs15init_free_ec_params(void *ptr)
{
struct sc_ec_parameters *ecparams = (struct sc_ec_parameters *)ptr;
if (ecparams) {
- if (ecparams->der.value)
- free(ecparams->der.value);
- if (ecparams->named_curve)
- free(ecparams->named_curve);
+ sc_clear_ec_params(ecparams);
free(ecparams);
}
}
@@ -1303,10 +1300,12 @@ sc_pkcs15init_init_prkdf(struct sc_pkcs15_card *p15card, struct sc_profile *prof
keyinfo_gostparams->gostr3410 = keyargs->params.gost.gostr3410;
keyinfo_gostparams->gostr3411 = keyargs->params.gost.gostr3411;
keyinfo_gostparams->gost28147 = keyargs->params.gost.gost28147;
- }
- else if (key->algorithm == SC_ALGORITHM_EC) {
+ } else if (key->algorithm == SC_ALGORITHM_EC ||
+ key->algorithm == SC_ALGORITHM_EDDSA ||
+ key->algorithm == SC_ALGORITHM_XEDDSA) {
/* keyargs->key.u.ec.params.der.value is allocated in keyargs, which is on stack */
struct sc_ec_parameters *ecparams = &keyargs->key.u.ec.params;
+
new_ecparams = calloc(1, sizeof(struct sc_ec_parameters));
if (!new_ecparams) {
r = SC_ERROR_OUT_OF_MEMORY;
@@ -1603,9 +1602,9 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_profile *pr
pubkey_args.params.gost = keygen_args->prkey_args.params.gost;
r = sc_copy_gost_params(&(pubkey_args.key.u.gostr3410.params), &(keygen_args->prkey_args.key.u.gostr3410.params));
LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate GOST parameters");
- }
- else if (algorithm == SC_ALGORITHM_EC) {
- /* needs to be freed in case of failure when pubkey is not set yet */
+ } else if (algorithm == SC_ALGORITHM_EC ||
+ algorithm == SC_ALGORITHM_EDDSA ||
+ algorithm == SC_ALGORITHM_XEDDSA) {
r = sc_copy_ec_params(&pubkey_args.key.u.ec.params, &keygen_args->prkey_args.key.u.ec.params);
LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate EC parameters");
}
@@ -1630,7 +1629,6 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_profile *pr
if (iid.len)
key_info->id = iid;
}
-
pubkey = &pubkey_args.key;
if (!pubkey->alg_id) {
pubkey->alg_id = calloc(1, sizeof(struct sc_algorithm_id));
@@ -1673,11 +1671,6 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_profile *pr
err:
sc_pkcs15_free_object(object);
sc_pkcs15_erase_pubkey(&pubkey_args.key);
- if (algorithm == SC_ALGORITHM_EC) {
- /* allocated in check_keygen_params_consistency() */
- free(keygen_args->prkey_args.key.u.ec.params.der.value);
- keygen_args->prkey_args.key.u.ec.params.der.value = NULL;
- }
LOG_FUNC_RETURN(ctx, r);
}
@@ -1913,13 +1906,29 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, struct sc_profile
type = SC_PKCS15_TYPE_PUBKEY_GOSTR3410;
break;
case SC_ALGORITHM_EC:
- type = SC_PKCS15_TYPE_PUBKEY_EC;
+ case SC_ALGORITHM_EDDSA:
+ case SC_ALGORITHM_XEDDSA:
r = sc_copy_ec_params(&key.u.ec.params, &keyargs->key.u.ec.params);
LOG_TEST_GOTO_ERR(ctx, r, "Failed to copy EC public key parameters");
r = sc_pkcs15_fix_ec_parameters(ctx, &key.u.ec.params);
LOG_TEST_GOTO_ERR(ctx, r, "Failed to fix EC public key parameters");
+ if (keyargs->key.u.ec.ecpointQ.value) {
+ key.u.ec.ecpointQ.value = malloc(keyargs->key.u.ec.ecpointQ.len);
+ if (!key.u.ec.ecpointQ.value) {
+ r = SC_ERROR_OUT_OF_MEMORY;
+ LOG_TEST_GOTO_ERR(ctx, r, "Failed to copy EC... public key parameters");
+ }
+ }
+
+ if (key.algorithm == SC_ALGORITHM_EC)
+ type = SC_PKCS15_TYPE_PUBKEY_EC;
+ else if (key.algorithm == SC_ALGORITHM_EDDSA)
+ type = SC_PKCS15_TYPE_PUBKEY_EDDSA;
+ else if (key.algorithm == SC_ALGORITHM_XEDDSA)
+ type = SC_PKCS15_TYPE_PUBKEY_XEDDSA;
+
keybits = key.u.ec.params.field_length;
break;
default:
@@ -1960,8 +1969,10 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, struct sc_profile
keyinfo_gostparams->gostr3410 = keyargs->params.gost.gostr3410;
keyinfo_gostparams->gostr3411 = keyargs->params.gost.gostr3411;
keyinfo_gostparams->gost28147 = keyargs->params.gost.gost28147;
- }
- else if (key.algorithm == SC_ALGORITHM_EC) {
+ } else if (key.algorithm == SC_ALGORITHM_EC ||
+ key.algorithm == SC_ALGORITHM_EDDSA ||
+ key.algorithm == SC_ALGORITHM_XEDDSA) {
+ /* TODO if EC don't write the 0x04 byte to card */
key_info->field_length = keybits;
if (key.u.ec.params.der.value) {
key_info->params.data = malloc(key.u.ec.params.der.len);
@@ -2526,7 +2537,9 @@ check_keygen_params_consistency(struct sc_card *card,
struct sc_context *ctx = card->ctx;
int i, rv;
- if (alg == SC_ALGORITHM_EC && prkey) {
+ if (prkey && (alg == SC_ALGORITHM_EC ||
+ alg == SC_ALGORITHM_EDDSA ||
+ alg == SC_ALGORITHM_XEDDSA)) {
struct sc_ec_parameters *ecparams = &prkey->key.u.ec.params;
rv = sc_pkcs15_fix_ec_parameters(ctx, ecparams);
@@ -2549,14 +2562,17 @@ check_keygen_params_consistency(struct sc_card *card,
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
- if (alg == SC_ALGORITHM_EC && prkey)
+ if (prkey && (alg == SC_ALGORITHM_EC ||
+ alg == SC_ALGORITHM_EDDSA ||
+ alg == SC_ALGORITHM_XEDDSA)) {
/* allocated in sc_pkcs15_fix_ec_parameters */
free(prkey->key.u.ec.params.der.value);
+ prkey->key.u.ec.params.der.value = NULL;
+ }
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
}
-
/*
* Check whether the card has native crypto support for this key.
*/
@@ -2568,13 +2584,21 @@ check_key_compatibility(struct sc_pkcs15_card *p15card, unsigned long alg,
struct sc_context *ctx = p15card->card->ctx;
struct sc_algorithm_info *info;
unsigned int count;
+ unsigned long talg = alg;
LOG_FUNC_CALLED(ctx);
+
+ if (alg == SC_ALGORITHM_EDDSA || alg == SC_ALGORITHM_XEDDSA)
+ talg = SC_ALGORITHM_EC; /* really testing ecparams */
+
count = p15card->card->algorithm_count;
for (info = p15card->card->algorithms; count--; info++) {
/* don't check flags if none was specified */
- if (info->algorithm != alg || info->key_length != key_length)
- continue;
+
+ if (alg != SC_ALGORITHM_EDDSA && alg != SC_ALGORITHM_XEDDSA) {
+ if (info->algorithm != alg || info->key_length != key_length)
+ continue;
+ }
if (flags != 0 && ((info->flags & flags) != flags))
continue;
@@ -2593,8 +2617,7 @@ check_key_compatibility(struct sc_pkcs15_card *p15card, unsigned long alg,
if (info->u._rsa.exponent != exponent)
continue;
}
- }
- else if (alg == SC_ALGORITHM_EC) {
+ } else if (talg == SC_ALGORITHM_EC) { /* includes EDDSA and XEDDSA */
if (!sc_valid_oid(&prkey->u.ec.params.id))
if (sc_pkcs15_fix_ec_parameters(ctx, &prkey->u.ec.params))
LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_VALID);
@@ -2754,8 +2777,10 @@ prkey_bits(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *key)
}
return SC_PKCS15_GOSTR3410_KEYSIZE;
case SC_ALGORITHM_EC:
- sc_log(ctx, "Private EC key length %"SC_FORMAT_LEN_SIZE_T"u",
- key->u.ec.params.field_length);
+ case SC_ALGORITHM_EDDSA:
+ case SC_ALGORITHM_XEDDSA:
+ sc_log(ctx, "Private EC type key length %" SC_FORMAT_LEN_SIZE_T "u",
+ key->u.ec.params.field_length);
if (key->u.ec.params.field_length == 0) {
sc_log(ctx, "Invalid EC key length");
return SC_ERROR_OBJECT_NOT_VALID;
@@ -2779,6 +2804,10 @@ key_pkcs15_algo(struct sc_pkcs15_card *p15card, unsigned long algorithm)
return SC_PKCS15_TYPE_PRKEY_GOSTR3410;
case SC_ALGORITHM_EC:
return SC_PKCS15_TYPE_PRKEY_EC;
+ case SC_ALGORITHM_EDDSA:
+ return SC_PKCS15_TYPE_PRKEY_EDDSA;
+ case SC_ALGORITHM_XEDDSA:
+ return SC_PKCS15_TYPE_PRKEY_XEDDSA;
case SC_ALGORITHM_DES:
return SC_PKCS15_TYPE_SKEY_DES;
case SC_ALGORITHM_3DES:
diff --git a/src/pkcs15init/pkcs15-openpgp.c b/src/pkcs15init/pkcs15-openpgp.c
index 553c8acea8..5a767fd41c 100644
--- a/src/pkcs15init/pkcs15-openpgp.c
+++ b/src/pkcs15init/pkcs15-openpgp.c
@@ -117,9 +117,8 @@ 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;
- sc_cardctl_openpgp_keystore_info_t key_info;
+ sc_cardctl_openpgp_keystore_info_t key_info = {0};
int r;
- unsigned int i;
LOG_FUNC_CALLED(card->ctx);
@@ -140,7 +139,10 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
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) {
+ case SC_PKCS15_TYPE_PRKEY_EDDSA:
+ case SC_PKCS15_TYPE_PRKEY_XEDDSA:
+ if (card->type != SC_CARD_TYPE_OPENPGP_GNUK &&
+ 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);
}
@@ -151,35 +153,14 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
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.ecpointQ = key->u.ec.ecpointQ.value;
- key_info.u.ec.ecpointQ_len = key->u.ec.ecpointQ.len;
- /* extract oid the way we need to import it to OpenPGP Card */
- if (key->u.ec.params.der.len > 2)
- key_info.u.ec.oid_len = key->u.ec.params.der.value[1];
- else
- LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
-
- for (i=0; (i < key_info.u.ec.oid_len) && (i+2 < key->u.ec.params.der.len); i++){
- key_info.u.ec.oid.value[i] = key->u.ec.params.der.value[i+2];
+ if (key->u.ec.ecpointQ.len) {
+ key_info.u.ec.ecpointQ = malloc(key->u.ec.ecpointQ.len);
+ if (!key_info.u.ec.ecpointQ)
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+ memcpy(&key_info.u.ec.ecpointQ, key->u.ec.ecpointQ.value, key->u.ec.ecpointQ.len);
}
- 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;
+ key_info.u.ec.oid = key->u.ec.params.id;
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info);
break;
default:
@@ -286,9 +267,8 @@ static int openpgp_generate_key_ec(sc_card_t *card, sc_pkcs15_object_t *obj,
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;
+ struct sc_ec_parameters *info_ec =
+ (struct sc_ec_parameters *)required->params.data;
int r;
LOG_FUNC_CALLED(ctx);
@@ -310,29 +290,42 @@ static int openpgp_generate_key_ec(sc_card_t *card, sc_pkcs15_object_t *obj,
if (!key_info.key_id)
key_info.key_id = kid->value[0];
+ key_info.key_type = pubkey->algorithm;
+ /* set algorithm id based on key reference and key type */
+ switch (pubkey->algorithm) {
+ /* EC is in 04||x||y format
+ * (field_length + 7)/8 * 2 + 1 in bytes
+ * len is ecpoint length + format byte
+ * see section 7.2.14 of 3.3.1 specs
+ * EDDSA and XEDDSA have no format byte and one number
+ * (field_length + 7)/8 in bytes
+ */
+
+ case SC_ALGORITHM_EC:
+ 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 */
+ key_info.u.ec.ecpoint_len = 1 + 2 * BYTES4BITS(required->field_length);
+ break;
+ case SC_ALGORITHM_EDDSA:
+ key_info.algorithm = SC_OPENPGP_KEYALGO_EDDSA; /* only sign */
+ key_info.u.ec.ecpoint_len = BYTES4BITS(required->field_length);
+ break;
+ case SC_ALGORITHM_XEDDSA:
+ /* TODO may need to look at MSE, and how sign XEDDSA certificate */
+ key_info.algorithm = SC_OPENPGP_KEYALGO_ECDH; /* but could be used to sign too */
+ key_info.u.ec.ecpoint_len = BYTES4BITS(required->field_length);
+ break;
+ }
-
- /* 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 */
+ /* copying info_ec.id works for any EC ECDH EdDSA keys */
if (info_ec->der.len > 2)
- key_info.u.ec.oid_len = info_ec->der.value[1];
+ key_info.u.ec.oid = info_ec->id; /* copy sc_object_id */
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);
+ /* save expected length */
+ key_info.u.ec.ecpoint_len = BYTES4BITS(required->field_length);
/* generate key on card */
r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info);
@@ -340,11 +333,13 @@ static int openpgp_generate_key_ec(sc_card_t *card, sc_pkcs15_object_t *obj,
/* set pubkey according to response of card */
sc_log(ctx, "Set output ecpoint info");
- pubkey->algorithm = SC_ALGORITHM_EC;
+
+ pubkey->algorithm = key_info.key_type;
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;
+ LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
+
memcpy(pubkey->u.ec.ecpointQ.value, key_info.u.ec.ecpoint, key_info.u.ec.ecpoint_len);
err:
@@ -385,8 +380,9 @@ 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");
+ case SC_PKCS15_TYPE_PRKEY_XEDDSA:
+ if (card->type != SC_CARD_TYPE_OPENPGP_GNUK && card->type < SC_CARD_TYPE_OPENPGP_V3) {
+ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EdDSA or XEDDSA are not supported on this card");
return SC_ERROR_NOT_SUPPORTED;
}
r = openpgp_generate_key_ec(card, obj, pubkey);
diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c
index 46f8b735e5..91cfa45c1a 100644
--- a/src/tools/pkcs11-tool.c
+++ b/src/tools/pkcs11-tool.c
@@ -147,8 +147,23 @@ static struct ec_curve_info {
{"secp256k1", "1.3.132.0.10", "06052B8104000A", 256, 0},
{"secp521k1", "1.3.132.0.35", "06052B81040023", 521, 0},
- {"edwards25519","1.3.6.1.4.1159.15.1", "130c656477617264733235353139", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN},
- {"curve25519", "1.3.6.1.4.3029.1.5.1", "130b63757276653235353139", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN},
+ /* Some of the following may not yet be supported by the OpenSC module, but may be other modules */
+ /* OpenPGP extensions by Yubikey and GNUK are not defined in RFCs, so pass by printable string */
+ /* See PKCS#11 3.0 2.3.7 */
+ {"edwards25519", "1.3.6.1.4.1.11591.15.1", "130c656477617264733235353139", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN}, /* send by curve name */
+ {"curve25519", "1.3.6.1.4.1.3029.1.5.1", "130a63757276653235353139", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN}, /* send by curve name */
+
+ /* RFC8410, EDWARDS and MONTGOMERY curves are used by GnuPG and also by OpenSSL */
+
+ {"X25519", "1.3.101.110", "06032b656e", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN}, /* RFC 4810 send by OID */
+ {"X448", "1.3.101.111", "06032b656f", 448, CKM_EC_MONTGOMERY_KEY_PAIR_GEN}, /* RFC 4810 send by OID */
+ {"Ed25519", "1.3.101.112", "06032b6570", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN}, /* RFC 4810 send by OID */
+ {"Ed448", "1.3.101.113", "06032b6571", 448, CKM_EC_EDWARDS_KEY_PAIR_GEN}, /* RFC 4810 send by OID */
+
+ /* GnuPG openpgp curves as used in gnupg-card are equivalent to RFC8410 OIDs */
+ {"cv25519", "1.3.101.110", "06032b656e", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN},
+ {"ed25519", "1.3.101.112", "06032b6570", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN},
+ /* OpenSC card-openpgp.c will map these to what is need on the card */
{NULL, NULL, NULL, 0, 0},
};
@@ -2436,6 +2451,7 @@ static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
unsigned char rs_buffer[512];
bytes = getEC_POINT(session, key, &len);
free(bytes);
+ /* TODO DEE EDDSA and EC_POINT returned in BIT STRING needs some work */
/*
* (We only support uncompressed for now)
* Uncompressed EC_POINT is DER OCTET STRING of "04||x||y"
@@ -4232,12 +4248,24 @@ static CK_RV write_object(CK_SESSION_HANDLE session)
n_privkey_attr++;
}
#if !defined(OPENSSL_NO_EC)
-#ifdef EVP_PKEY_ED448
- else if ((pk_type == EVP_PKEY_EC) || (pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448)) {
-#else
- else if ((pk_type == EVP_PKEY_EC) || (pk_type == EVP_PKEY_ED25519)) {
+/* aappeas the precompiler */
+#ifndef EVP_PKEY_ED448
+#define EVP_PKEY_ED448 EVP_PKEY_ED25519
+#endif
+#ifndef EVP_PKEY_X448
+#define EVP_PKEY_X448 EVP_PKEY_X25519
#endif
- type = (pk_type == EVP_PKEY_EC) ? CKK_EC : CKK_EC_EDWARDS;
+
+ else if ((pk_type == EVP_PKEY_EC) ||
+ (pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448) ||
+ (pk_type == EVP_PKEY_X25519) || (pk_type == EVP_PKEY_X448)) {
+
+ if ((pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448))
+ type = CKK_EC_EDWARDS;
+ else if ((pk_type == EVP_PKEY_X25519) || (pk_type == EVP_PKEY_X448))
+ type = CKK_EC_MONTGOMERY;
+ else
+ type = CKK_EC;
FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
n_privkey_attr++;
@@ -4245,8 +4273,7 @@ static CK_RV write_object(CK_SESSION_HANDLE session)
n_privkey_attr++;
FILL_ATTR(privkey_templ[n_privkey_attr], CKA_VALUE, gost.private.value, gost.private.len);
n_privkey_attr++;
- }
- else if (pk_type == NID_id_GostR3410_2001) {
+ } else if (pk_type == NID_id_GostR3410_2001) {
type = CKK_GOSTR3410;
FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
@@ -4273,12 +4300,11 @@ static CK_RV write_object(CK_SESSION_HANDLE session)
#if !defined(OPENSSL_NO_EC)
else if (pk_type == EVP_PKEY_EC)
type = CKK_EC;
-#ifdef EVP_PKEY_ED448
else if ((pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448))
-#else
- else if (pk_type == EVP_PKEY_ED25519)
-#endif
type = CKK_EC_EDWARDS;
+ else if ((pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448))
+ type = CKK_EC_MONTGOMERY;
+
else if (pk_type == NID_id_GostR3410_2001)
type = CKK_GOSTR3410;
#endif
@@ -4342,12 +4368,16 @@ static CK_RV write_object(CK_SESSION_HANDLE session)
n_pubkey_attr++;
}
#if !defined(OPENSSL_NO_EC)
-#ifdef EVP_PKEY_ED448
- else if ((pk_type == EVP_PKEY_EC) || (pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448)) {
-#else
- else if ((pk_type == EVP_PKEY_EC) || (pk_type == EVP_PKEY_ED25519)) {
-#endif
- type = (pk_type == EVP_PKEY_EC) ? CKK_EC : CKK_EC_EDWARDS;
+ else if ((pk_type == EVP_PKEY_EC) ||
+ (pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448) ||
+ (pk_type == EVP_PKEY_X25519) || (pk_type == EVP_PKEY_X448)) {
+
+ if ((pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448))
+ type = CKK_EC_EDWARDS;
+ else if ((pk_type == EVP_PKEY_X25519) || (pk_type == EVP_PKEY_X448))
+ type = CKK_EC_MONTGOMERY;
+ else
+ type = CKK_EC;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
n_pubkey_attr++;
@@ -4355,8 +4385,7 @@ static CK_RV write_object(CK_SESSION_HANDLE session)
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_EC_POINT, gost.public.value, gost.public.len);
n_pubkey_attr++;
- }
- else if (pk_type == NID_id_GostR3410_2001) {
+ } else if (pk_type == NID_id_GostR3410_2001) {
type = CKK_GOSTR3410;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
@@ -4856,18 +4885,17 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
CK_BBOOL _true = TRUE;
CK_BBOOL _false = FALSE;
CK_OBJECT_HANDLE newkey = 0;
+
+ // clang-format off
CK_ATTRIBUTE newkey_template[20] = {
- {CKA_TOKEN, &_false, sizeof(_false)}, /* session only object */
- {CKA_CLASS, &newkey_class, sizeof(newkey_class)},
- {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)},
- {CKA_SENSITIVE, &_false, sizeof(_false)},
- {CKA_EXTRACTABLE, &_true, sizeof(_true)},
- {CKA_ENCRYPT, &_true, sizeof(_true)},
- {CKA_DECRYPT, &_true, sizeof(_true)},
- {CKA_WRAP, &_true, sizeof(_true)},
- {CKA_UNWRAP, &_true, sizeof(_true)}
- };
- int n_attrs = 9;
+ {CKA_TOKEN, &_false, sizeof(_false) }, /* session only object */
+ {CKA_CLASS, &newkey_class, sizeof(newkey_class)},
+ {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type) },
+ {CKA_SENSITIVE, &_false, sizeof(_false) },
+ {CKA_EXTRACTABLE, &_true, sizeof(_true) },
+ };
+ // clang-format on
+ int n_attrs = 5;
CK_ECDH1_DERIVE_PARAMS ecdh_parms;
CK_RV rv;
BIO *bio_in = NULL;
@@ -4879,6 +4907,7 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
unsigned char * derp = NULL;
size_t der_size = 0;
EVP_PKEY *pkey = NULL;
+ int key_id = 0; /* nid of peer key */
#if OPENSSL_VERSION_NUMBER < 0x30000000L
EC_KEY *eckey = NULL;
const EC_GROUP *ecgroup = NULL;
@@ -4889,7 +4918,7 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
int nid = 0;
#endif
- printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(mech_mech));
+ printf("Using derive algorithm 0x%8.8lx %s\n", mech_mech, p11_mechanism_to_name(mech_mech));
memset(&mech, 0, sizeof(mech));
mech.mechanism = mech_mech;
@@ -4905,26 +4934,31 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
#endif
if (!pkey)
- util_fatal("Cannot read EC key from %s", opt_input);
+ util_fatal("Cannot read peer EC key from %s", opt_input);
+
+ key_id = EVP_PKEY_id(pkey);
+
+ switch (key_id) {
+ case EVP_PKEY_EC: /* CKK_EC*/
#if OPENSSL_VERSION_NUMBER < 0x30000000L
- eckey = EVP_PKEY_get0_EC_KEY(pkey);
- ecpoint = EC_KEY_get0_public_key(eckey);
- ecgroup = EC_KEY_get0_group(eckey);
+ eckey = EVP_PKEY_get0_EC_KEY(pkey);
+ ecpoint = EC_KEY_get0_public_key(eckey);
+ ecgroup = EC_KEY_get0_group(eckey);
- if (!ecpoint || !ecgroup)
- util_fatal("Failed to parse other EC key from %s", opt_input);
+ if (!ecpoint || !ecgroup)
+ util_fatal("Failed to parse peer EC key from %s", opt_input);
#else
- if (EVP_PKEY_get_group_name(pkey, name, sizeof(name), &len) != 1
- || (nid = OBJ_txt2nid(name)) == NID_undef
- || (ecgroup = EC_GROUP_new_by_curve_name(nid)) == NULL)
- util_fatal("Failed to parse other EC key from %s", opt_input);
+ if (EVP_PKEY_get_group_name(pkey, name, sizeof(name), &len) != 1 || (nid = OBJ_txt2nid(name)) == NID_undef || (ecgroup = EC_GROUP_new_by_curve_name(nid)) == NULL)
+ util_fatal("Failed to parse peer EC key from %s", opt_input);
#endif
- /* both eckeys must be same curve */
- key_len = (EC_GROUP_get_degree(ecgroup) + 7) / 8;
- FILL_ATTR(newkey_template[n_attrs], CKA_VALUE_LEN, &key_len, sizeof(key_len));
- n_attrs++;
+ /* both eckeys must be same curve */
+ key_len = (EC_GROUP_get_degree(ecgroup) + 7) / 8;
+ FILL_ATTR(newkey_template[n_attrs], CKA_VALUE_LEN, &key_len, sizeof(key_len));
+ n_attrs++;
+ break;
+ }
if (opt_allowed_mechanisms_len > 0) {
FILL_ATTR(newkey_template[n_attrs],
@@ -4934,11 +4968,29 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
}
#if OPENSSL_VERSION_NUMBER < 0x30000000L
- buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
- buf = (unsigned char *)malloc(buf_size);
- if (buf == NULL)
- util_fatal("malloc() failure\n");
- buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, NULL);
+ switch (key_id) {
+ case EVP_PKEY_EC:
+ buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
+ buf = (unsigned char *)malloc(buf_size);
+ if (buf == NULL)
+ util_fatal("malloc() failure\n");
+ buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, NULL);
+ break;
+ case EVP_PKEY_X25519:
+#if defined(EVP_PKEY_X448)
+ case EVP_PKEY_X448:
+#endif
+ EVP_PKEY_get_raw_public_key(pkey, NULL, &buf_size);
+ if (buf_size == 0)
+ util_fatal("Unable to get of peer key\n");
+ buf = (unsigned char *)malloc(buf_size);
+ if (buf == NULL)
+ util_fatal("malloc() failure\n");
+ EVP_PKEY_get_raw_public_key(pkey, buf, &buf_size);
+ break;
+ default:
+ util_fatal("Unknown EVP_PKEY_id\n");
+ }
#else
EC_GROUP_free(ecgroup);
EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0, &buf_size);
@@ -4947,10 +4999,27 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE
if (EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, buf_size, NULL) != 1) {
free(buf);
- util_fatal("Failed to parse other EC key from %s", opt_input);
+ util_fatal("Failed to parse peer EC key from %s", opt_input);
}
#endif
+ switch (key_id) {
+ case EVP_PKEY_EC: /* CKK_EC*/
+ if (mech_mech != CKM_ECDH1_DERIVE && mech_mech != CKM_ECDH1_COFACTOR_DERIVE)
+ util_fatal("Peer key %s not usable with %s", "CKK_EC", p11_mechanism_to_name(mech_mech));
+ break;
+ case EVP_PKEY_X25519: /* "CKK_EC_MONTGOMERY */
+#if defined(EVP_PKEY_X448)
+ case EVP_PKEY_X448:
+#endif
+ if (mech_mech != CKM_ECDH1_DERIVE)
+ util_fatal("Peer key %s not usable with %s", "CKK_EC_MONTGOMERY", p11_mechanism_to_name(mech_mech));
+ break;
+ default:
+ util_fatal("Peer key not usable with derive or unknown %i", key_id);
+ break;
+ }
+
if (opt_derive_pass_der) {
octet = ASN1_OCTET_STRING_new();
if (octet == NULL)
@@ -5005,18 +5074,19 @@ derive_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key)
CK_OBJECT_HANDLE derived_key = 0;
int fd;
ssize_t sz;
+ CK_KEY_TYPE key_type = getKEY_TYPE(session, key);
if (!opt_mechanism_used)
if (!find_mechanism(slot, CKF_DERIVE|opt_allow_sw, NULL, 0, &opt_mechanism))
util_fatal("Derive mechanism not supported");
- switch(opt_mechanism) {
- case CKM_ECDH1_COFACTOR_DERIVE:
- case CKM_ECDH1_DERIVE:
- derived_key= derive_ec_key(session, key, opt_mechanism);
+ switch (key_type) {
+ case CKK_EC:
+ case CKK_EC_MONTGOMERY:
+ derived_key = derive_ec_key(session, key, opt_mechanism);
break;
default:
- util_fatal("mechanism not supported for derive");
+ util_fatal("Key type %lu does not support derive", key_type);
break;
}
@@ -5139,30 +5209,50 @@ show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
}
if (pub) {
unsigned char *bytes = NULL;
- unsigned long ksize;
+ unsigned long ksize = 0;
unsigned int n;
+ unsigned long body_len = 0;
+
+ bytes = getEC_POINT(sess, obj, &ksize);
+ /*
+ * simple parse of DER BIT STRING 0x03 or OCTET STRING 0x04
+ * good to 65K bytes
+ */
+ if (ksize > 3 && (bytes[0] == 0x03 || bytes[0] == 0x04)) {
+ if (bytes[1] <= 127 && ksize == (unsigned long)(bytes[1] + 2)) {
+ body_len = ksize - 2;
+ } else if (bytes[1] == 0x81 && size == ((unsigned long)bytes[2] + 3)) {
+ body_len = ksize - 3;
+ } else if (bytes[1] == 0x82 && size == ((unsigned long)(bytes[2] << 8) + (unsigned long)bytes[3] + 4)) {
+ body_len = ksize - 4;
+ }
+ }
+ /* With BIT STRING remove unused bits in last byte indicator */
+ if (body_len > 0 && bytes[0] == 0x03)
+ body_len--;
- bytes = getEC_POINT(sess, obj, &size);
- if (key_type == CKK_EC) {
+ if (key_type == CKK_EC && body_len > 0) {
/*
- * (We only support uncompressed for now)
- * Uncompressed EC_POINT is DER OCTET STRING of "04||x||y"
- * So a "256" bit key has x and y of 32 bytes each
- * something like: "04 41 04||x||y"
- * Do simple size calculation based on DER encoding
- */
- if ((size - 2) <= 127)
- ksize = (size - 3) * 4;
- else if ((size - 3) <= 255)
- ksize = (size - 4) * 4;
- else
- ksize = (size - 5) * 4;
- } else {
- /* This should be 255 for ed25519 and 448 for ed448 curves so roughly */
- ksize = size * 8;
+ * (We only support uncompressed for now)
+ * Uncompressed EC_POINT is DER OCTET STRING
+ * or DER BIT STRING "04||x||y"
+ * So a "256" bit key has x and y of 32 bytes each
+ * something like: "03 42 00 04|x|y" or "04 41 04||x||y"
+ * Do simple size calculation based on DER encoding
+ */
+ ksize = (body_len - 1) * 4;
+ } else if (body_len > 0) {
+ /*
+ * EDDSA and XEDDSA in PKCS11 and only one coordinate
+ */
+ ksize = (body_len) * 8;
}
- printf(" EC_POINT %lu bits\n", ksize);
+ if (ksize)
+ printf(" EC_POINT %lu bits\n", ksize);
+ else
+ printf(" EC_POINT size unknown");
+
if (bytes) {
if ((CK_LONG)size > 0) { /* Will print the point here */
printf(" EC_POINT: ");
@@ -5779,6 +5869,7 @@ static int read_object(CK_SESSION_HANDLE session)
value = getEC_POINT(session, obj, &len);
/* PKCS#11-compliant modules should return ASN1_OCTET_STRING */
+ /* TODO DEE Should be returned encoded in BIT STRING, Need to accept both */
a = value;
os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)len);
#if OPENSSL_VERSION_NUMBER < 0x30000000L
@@ -5885,8 +5976,13 @@ static int read_object(CK_SESSION_HANDLE session)
value = getEC_POINT(session, obj, &len);
/* PKCS#11-compliant modules should return ASN1_OCTET_STRING */
+ /* TODO DEE should be in BIT STRING accept both */
a = value;
os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)len);
+ if (!os) {
+ os = d2i_ASN1_BIT_STRING(NULL, &a, (long)&len);
+ len = (len + 7) / 8;
+ }
if (!os) {
util_fatal("cannot decode EC_POINT");
}
@@ -8110,6 +8206,7 @@ static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
return;
}
getEC_POINT(session, pub_key, &ec_point_len);
+ /* TODO only looking at length of encoded EC_POINT. May be in BIT STRING or OCTET STRING */
if (ec_point_len < 5 || ec_point_len > 10000) {
printf("ERR: GetAttribute(pubkey, CKA_EC_POINT) doesn't seem to work\n");
return;
diff --git a/src/tools/pkcs15-init.c b/src/tools/pkcs15-init.c
index 3759e252ee..7bf7b1dcde 100644
--- a/src/tools/pkcs15-init.c
+++ b/src/tools/pkcs15-init.c
@@ -720,21 +720,42 @@ static const struct alg_spec alg_types_sym[] = {
{ NULL, -1, 0 }
};
+// clang-format off
+/* RSA can have a number , default is 2048 */
+/* EC require a curve name */
+/* EDDSA and XEDDSA without a size require a size or curve name or OID */
+/* other EDDSA and XEDDSA can be used alone */
static const struct alg_spec alg_types_asym[] = {
- { "rsa", SC_ALGORITHM_RSA, 1024 },
+ { "rsa", SC_ALGORITHM_RSA, 2048 }, /* new default */
{ "gost2001", SC_ALGORITHM_GOSTR3410, SC_PKCS15_GOSTR3410_KEYSIZE },
{ "ec", SC_ALGORITHM_EC, 0 },
+ { "EdDSA", SC_ALGORITHM_EDDSA, 0 }, /* RFC 8410 section 8 */
+ { "xeddsa", SC_ALGORITHM_XEDDSA, 0 },
+ { "ECDH", SC_ALGORITHM_XEDDSA, 0 }, /* RFC 8410 section 8 */
+ /* RFC 8410 */
+ { "Ed25519", SC_ALGORITHM_EDDSA, 255 }, /* RFC 8410 and gunpg */
+ { "Ed448", SC_ALGORITHM_EDDSA, 448 },
+ { "X25519", SC_ALGORITHM_XEDDSA, 255 },
+ { "X448", SC_ALGORITHM_XEDDSA, 448 },
+ /* used by Yubikey and GNUK */
+ { "edwards25519", SC_ALGORITHM_EDDSA, 255 },
+ { "curve25519", SC_ALGORITHM_XEDDSA, 255 },
+ /* gnupg */
+ { "cv25519", SC_ALGORITHM_XEDDSA, 255 },
+
{ NULL, -1, 0 }
};
+// clang-format on
static int
parse_alg_spec(const struct alg_spec *types, const char *spec, unsigned int *keybits, struct sc_pkcs15_prkey *prkey)
{
- int i, algorithm = -1;
+ int i, types_idx = -1, algorithm = -1;
char *end;
for (i = 0; types[i].spec; i++) {
if (!strncasecmp(spec, types[i].spec, strlen(types[i].spec))) {
+ types_idx = i; /* save index of types array */
algorithm = types[i].algorithm;
*keybits = types[i].keybits;
spec += strlen(types[i].spec);
@@ -749,9 +770,18 @@ parse_alg_spec(const struct alg_spec *types, const char *spec, unsigned int *key
if (*spec == '/' || *spec == '-' || *spec == ':')
spec++;
+ /* if we have everything for EDDSA or XEDDSA */
+ if (*spec == 0x00 && *keybits && (algorithm == SC_ALGORITHM_EDDSA || algorithm == SC_ALGORITHM_XEDDSA) && prkey) {
+ prkey->u.ec.params.named_curve = strdup(types[types_idx].spec); /* correct case */
+ *keybits = types[types_idx].keybits;
+ return algorithm;
+ }
+
if (*spec) {
- if (isalpha((unsigned char)*spec) && algorithm == SC_ALGORITHM_EC && prkey) {
+ if (isalpha((unsigned char)*spec) && algorithm == SC_ALGORITHM_EC && prkey)
prkey->u.ec.params.named_curve = strdup(spec);
+ else if (isalpha((unsigned char)*spec) && (algorithm == SC_ALGORITHM_EDDSA || algorithm == SC_ALGORITHM_XEDDSA) && prkey) {
+ prkey->u.ec.params.named_curve = strdup(types[types_idx].spec); /* copy correct case */
} else {
*keybits = (unsigned)strtoul(spec, &end, 10);
if (*end) {
diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c
index 59551c97e5..fc5df6b5eb 100644
--- a/src/tools/pkcs15-tool.c
+++ b/src/tools/pkcs15-tool.c
@@ -1021,7 +1021,7 @@ static int read_ssh_key(void)
unsigned char buf[64];
size_t n, len;
- n = pubkey->u.eddsa.pubkey.len;
+ n = pubkey->u.ec.ecpointQ.len;
if (n != 32) {
fprintf(stderr, "Wrong public key length\n");
goto fail2;
@@ -1039,7 +1039,7 @@ static int read_ssh_key(void)
buf[len++] = 0;
buf[len++] = 0;
buf[len++] = n & 0xff;
- memcpy(buf + len, pubkey->u.eddsa.pubkey.value, n);
+ memcpy(buf + len, pubkey->u.ec.ecpointQ.value, n);
len += n;
print_ssh_key(outf, alg, obj, buf, len);