summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-04-27 12:12:06 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-04-27 16:14:16 +0200
commitd95d4a4f3abbc54c7d03872d7bf0987be61c1051 (patch)
tree97161051903b1b3039876335c5a2f30cd1f81da4
parentcacb61d6885eef58f09da7fd958496a11e2000c5 (diff)
downloadgnutls-eddsa2.tar.gz
Added support for generating and reading EdDSA/Ed25519 keyseddsa2
This adds support for draft-ietf-curdle-pkix-00
-rw-r--r--doc/credentials/x509/Makefile.am3
-rw-r--r--doc/credentials/x509/cert-eddsa.pem9
-rw-r--r--lib/algorithms.h23
-rw-r--r--lib/algorithms/ecc.c21
-rw-r--r--lib/algorithms/publickey.c1
-rw-r--r--lib/algorithms/sign.c3
-rw-r--r--lib/auth/ecdhe.c5
-rw-r--r--lib/gnutls.asn2
-rw-r--r--lib/gnutls_asn1_tab.c5
-rw-r--r--lib/includes/gnutls/abstract.h8
-rw-r--r--lib/includes/gnutls/gnutls.h.in12
-rw-r--r--lib/nettle/pk.c159
-rw-r--r--lib/pk.c31
-rw-r--r--lib/pkcs11_privkey.c6
-rw-r--r--lib/privkey.c17
-rw-r--r--lib/privkey_raw.c3
-rw-r--r--lib/pubkey.c76
-rw-r--r--lib/x509/common.h2
-rw-r--r--lib/x509/key_decode.c65
-rw-r--r--lib/x509/key_encode.c156
-rw-r--r--lib/x509/output.c2
-rw-r--r--lib/x509/privkey.c127
-rw-r--r--lib/x509/privkey_pkcs8.c3
-rw-r--r--lib/x509/x509_int.h13
-rw-r--r--src/certtool-args.def6
-rw-r--r--src/certtool-common.c18
-rw-r--r--src/certtool.c10
-rw-r--r--tests/cert-tests/Makefile.am5
-rwxr-xr-xtests/cert-tests/ed2551982
-rw-r--r--tests/cert-tests/pkcs7-detached.eddsa.sig14
30 files changed, 760 insertions, 127 deletions
diff --git a/doc/credentials/x509/Makefile.am b/doc/credentials/x509/Makefile.am
index b40a52ed52..80529f5588 100644
--- a/doc/credentials/x509/Makefile.am
+++ b/doc/credentials/x509/Makefile.am
@@ -1,2 +1,3 @@
EXTRA_DIST = ca-key.pem ca.pem cert-rsa.pem key-rsa.pem clikey.pem clicert.pem \
- clicert-dsa.pem clikey-dsa.pem cert-dsa.pem key-dsa.pem cert-ecc.pem key-ecc.pem
+ clicert-dsa.pem clikey-dsa.pem cert-dsa.pem key-dsa.pem cert-ecc.pem key-ecc.pem \
+ key-eddsa.pem cert-eddsa.pem
diff --git a/doc/credentials/x509/cert-eddsa.pem b/doc/credentials/x509/cert-eddsa.pem
new file mode 100644
index 0000000000..eb87d12491
--- /dev/null
+++ b/doc/credentials/x509/cert-eddsa.pem
@@ -0,0 +1,9 @@
+-----BEGIN CERTIFICATE-----
+MIIBOTCB7KADAgECAghXIMh0GpYGCDAFBgMrZWQwFTETMBEGA1UEAxMKVGVzdCBF
+ZERTQTAgFw0xNjA0MjcxNDExMDFaGA85OTk5MTIzMTIzNTk1OVowFTETMBEGA1UE
+AxMKVGVzdCBFZERTQTAtMAgGAytlZAoBAgMhAKTkfrObKJtnttNIzxQBgFiFKb/7
+82TkhQ1x3zPKDlumo1UwUzAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUF
+BwMBMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFOBkJtX8yjpbIXnFik3dAC10
+o5a/MAUGAytlZANBANDF032xvnU+5xjOEruQe0MBLdIv9Sy34oQLpDC7D8Pez6bN
+f0/CMwlyEeE22wCWYvDRNw7sE35hFe+j27StTw8=
+-----END CERTIFICATE-----
diff --git a/lib/algorithms.h b/lib/algorithms.h
index 5ab350b098..aa9f52c35f 100644
--- a/lib/algorithms.h
+++ b/lib/algorithms.h
@@ -34,7 +34,7 @@
/* would allow for 256 ciphersuites */
#define MAX_CIPHERSUITE_SIZE 512
-#define IS_EC(x) (((x)==GNUTLS_PK_ECDSA)||((x)==GNUTLS_PK_ECDHX))
+#define IS_EC(x) (((x)==GNUTLS_PK_ECDSA)||((x)==GNUTLS_PK_ECDHX)||((x)==GNUTLS_PK_EDDSA))
/* Functions for version handling. */
const version_entry_st *version_to_entry(gnutls_protocol_t c);
@@ -323,7 +323,8 @@ struct gnutls_ecc_curve_entry_st {
gnutls_ecc_curve_t id;
gnutls_pk_algorithm_t pk;
int tls_id; /* The RFC4492 namedCurve ID */
- int size; /* the size in bytes */
+ unsigned size; /* the size of curve in bytes */
+ unsigned sig_size; /* the size of curve signatures in bytes (EdDSA) */
};
typedef struct gnutls_ecc_curve_entry_st gnutls_ecc_curve_entry_st;
@@ -332,9 +333,25 @@ const gnutls_ecc_curve_entry_st
gnutls_ecc_curve_t gnutls_ecc_curve_get_id(const char *name);
int _gnutls_tls_id_to_ecc_curve(int num);
int _gnutls_ecc_curve_get_tls_id(gnutls_ecc_curve_t supported_ecc);
-gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(int bits);
+gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(gnutls_pk_algorithm_t pk, int bits);
#define MAX_ECC_CURVE_SIZE 66
+inline static int _curve_is_eddsa(const gnutls_ecc_curve_entry_st * e)
+{
+ size_t ret = 0;
+ if (unlikely(e == NULL))
+ return ret;
+ if (e->pk == GNUTLS_PK_EDDSA)
+ return 1;
+ return 0;
+}
+
+inline static int curve_is_eddsa(gnutls_ecc_curve_t id)
+{
+ const gnutls_ecc_curve_entry_st *e = _gnutls_ecc_curve_get_params(id);
+ return _curve_is_eddsa(e);
+}
+
static inline int _gnutls_kx_is_ecc(gnutls_kx_algorithm_t kx)
{
if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA ||
diff --git a/lib/algorithms/ecc.c b/lib/algorithms/ecc.c
index 9d0c584b0a..bac5466c99 100644
--- a/lib/algorithms/ecc.c
+++ b/lib/algorithms/ecc.c
@@ -77,6 +77,14 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.pk = GNUTLS_PK_ECDHX,
.size = 32,
},
+ {
+ .name = "Ed25519ph",
+ .oid = "1.3.101.112",
+ .id = GNUTLS_ECC_CURVE_ED25519PH,
+ .pk = GNUTLS_PK_EDDSA,
+ .size = 32,
+ .sig_size = 64
+ },
{0, 0, 0}
};
@@ -159,7 +167,7 @@ gnutls_ecc_curve_t gnutls_oid_to_ecc_curve(const char *oid)
gnutls_ecc_curve_t ret = GNUTLS_ECC_CURVE_INVALID;
GNUTLS_ECC_CURVE_LOOP(
- if (strcasecmp(p->oid, oid) == 0 && _gnutls_pk_curve_exists(p->id)) {
+ if (p->oid != NULL && strcasecmp(p->oid, oid) == 0 && _gnutls_pk_curve_exists(p->id)) {
ret = p->id;
break;
}
@@ -200,12 +208,17 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get_id(const char *name)
* Returns: return a #gnutls_ecc_curve_t value corresponding to
* the specified bit length, or %GNUTLS_ECC_CURVE_INVALID on error.
-*/
-gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(int bits)
+gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(gnutls_pk_algorithm_t pk, int bits)
{
- gnutls_ecc_curve_t ret = GNUTLS_ECC_CURVE_SECP256R1;
+ gnutls_ecc_curve_t ret;
+
+ if (pk == GNUTLS_PK_ECDSA)
+ ret = GNUTLS_ECC_CURVE_SECP256R1;
+ else
+ ret = GNUTLS_ECC_CURVE_ED25519PH;
GNUTLS_ECC_CURVE_LOOP(
- if (8 * p->size >= bits && _gnutls_pk_curve_exists(p->id)) {
+ if (pk == p->pk && 8 * p->size >= (unsigned)bits && _gnutls_pk_curve_exists(p->id)) {
ret = p->id;
break;
}
diff --git a/lib/algorithms/publickey.c b/lib/algorithms/publickey.c
index c70187736f..2f0bc6b501 100644
--- a/lib/algorithms/publickey.c
+++ b/lib/algorithms/publickey.c
@@ -97,6 +97,7 @@ static const gnutls_pk_entry pk_algorithms[] = {
{"GOST R 34.10-2001", PK_GOST_R3410_2001_OID, GNUTLS_PK_UNKNOWN},
{"GOST R 34.10-94", PK_GOST_R3410_94_OID, GNUTLS_PK_UNKNOWN},
{"EC/ECDSA", "1.2.840.10045.2.1", GNUTLS_PK_ECDSA},
+ {"EdDSA", "1.3.101.100", GNUTLS_PK_EDDSA},
{"DH", NULL, GNUTLS_PK_DH},
{"ECDHX", NULL, GNUTLS_PK_ECDHX},
{0, 0, 0}
diff --git a/lib/algorithms/sign.c b/lib/algorithms/sign.c
index 6107c44435..5d62ab643b 100644
--- a/lib/algorithms/sign.c
+++ b/lib/algorithms/sign.c
@@ -106,6 +106,9 @@ static const gnutls_sign_entry sign_algorithms[] = {
{"ECDSA-SHA3-512", SIG_ECDSA_SHA3_512_OID, GNUTLS_SIGN_ECDSA_SHA3_512,
GNUTLS_PK_EC, GNUTLS_DIG_SHA3_512, TLS_SIGN_AID_UNKNOWN},
+ {"EdDSA-SHA2-512", SIG_EDDSA_SHA512_OID, GNUTLS_SIGN_EDDSA_SHA512,
+ GNUTLS_PK_EDDSA, GNUTLS_DIG_SHA512, TLS_SIGN_AID_UNKNOWN},
+
{"RSA-SHA3-224", SIG_RSA_SHA3_224_OID, GNUTLS_SIGN_RSA_SHA3_224,
GNUTLS_PK_RSA, GNUTLS_DIG_SHA3_224, TLS_SIGN_AID_UNKNOWN},
{"RSA-SHA3-256", SIG_RSA_SHA3_256_OID, GNUTLS_SIGN_RSA_SHA3_256,
diff --git a/lib/auth/ecdhe.c b/lib/auth/ecdhe.c
index e445c2f0fe..b86d259bd1 100644
--- a/lib/auth/ecdhe.c
+++ b/lib/auth/ecdhe.c
@@ -141,7 +141,7 @@ int _gnutls_proc_ecdh_common_client_kx(gnutls_session_t session,
{
ssize_t data_size = _data_size;
int ret, i = 0;
- int point_size;
+ unsigned point_size;
const gnutls_ecc_curve_entry_st *ecurve = _gnutls_ecc_curve_get_params(curve);
if (curve == GNUTLS_ECC_CURVE_INVALID || ecurve == NULL)
@@ -315,7 +315,8 @@ int
_gnutls_proc_ecdh_common_server_kx(gnutls_session_t session,
uint8_t * data, size_t _data_size)
{
- int i, ret, point_size;
+ int i, ret;
+ unsigned point_size;
gnutls_ecc_curve_t curve;
ssize_t data_size = _data_size;
const gnutls_ecc_curve_entry_st *ecurve;
diff --git a/lib/gnutls.asn b/lib/gnutls.asn
index 76bad6fbb6..1205c61eb0 100644
--- a/lib/gnutls.asn
+++ b/lib/gnutls.asn
@@ -122,4 +122,6 @@ KRB5PrincipalName ::= SEQUENCE {
principalName [1] PrincipalName
}
+EdDSAParameters ::= ENUMERATED { ed25519 (1), ed25519p (2) }
+
END
diff --git a/lib/gnutls_asn1_tab.c b/lib/gnutls_asn1_tab.c
index bc0e85ef5d..bcc0b67d2a 100644
--- a/lib/gnutls_asn1_tab.c
+++ b/lib/gnutls_asn1_tab.c
@@ -81,10 +81,13 @@ const asn1_static_node gnutls_asn1_tab[] = {
{ "name-string", 536879115, NULL },
{ NULL, 1073743880, "1"},
{ NULL, 27, NULL },
- { "KRB5PrincipalName", 536870917, NULL },
+ { "KRB5PrincipalName", 1610612741, NULL },
{ "realm", 1610620955, NULL },
{ NULL, 2056, "0"},
{ "principalName", 536879106, "PrincipalName"},
{ NULL, 2056, "1"},
+ { "EdDSAParameters", 537133077, NULL },
+ { "ed25519", 1073741825, "1"},
+ { "ed25519p", 1, "2"},
{ NULL, 0, NULL }
};
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index 772bd36255..71cba0c59a 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -134,6 +134,9 @@ int gnutls_pubkey_get_preferred_hash_algorithm(gnutls_pubkey_t key,
gnutls_digest_algorithm_t
* hash, unsigned int *mand);
+int gnutls_pubkey_export_eddsa_raw(gnutls_pubkey_t key, gnutls_ecc_curve_t * curve,
+ gnutls_datum_t * pub);
+
#define gnutls_pubkey_get_pk_rsa_raw gnutls_pubkey_export_rsa_raw
int gnutls_pubkey_export_rsa_raw(gnutls_pubkey_t key,
gnutls_datum_t * m, gnutls_datum_t * e);
@@ -415,6 +418,11 @@ int gnutls_privkey_decrypt_data(gnutls_privkey_t key,
const gnutls_datum_t * ciphertext,
gnutls_datum_t * plaintext);
+int gnutls_privkey_export_eddsa_raw(gnutls_privkey_t key,
+ gnutls_ecc_curve_t * curve,
+ gnutls_datum_t *pub,
+ gnutls_datum_t *priv);
+
int
gnutls_privkey_export_rsa_raw(gnutls_privkey_t key,
gnutls_datum_t * m, gnutls_datum_t * e,
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index aecf7ebc7c..cc6e146e12 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -676,6 +676,7 @@ typedef enum gnutls_certificate_print_formats {
* @GNUTLS_PK_DH: Diffie-Hellman algorithm. Used to generate parameters.
* @GNUTLS_PK_ECDSA: Elliptic curve algorithm. These parameters are compatible with the ECDSA and ECDH algorithm.
* @GNUTLS_PK_ECDHX: Elliptic curve algorithm, restricted to ECDH as per rfc7748.
+ * @GNUTLS_PK_EDDSA: Edwards curve Digital signature algorithm.
*
* Enumeration of different public-key algorithms.
*/
@@ -685,7 +686,8 @@ typedef enum {
GNUTLS_PK_DSA = 2,
GNUTLS_PK_DH = 3,
GNUTLS_PK_ECDSA = 4,
- GNUTLS_PK_ECDHX = 5
+ GNUTLS_PK_ECDHX = 5,
+ GNUTLS_PK_EDDSA = 6
} gnutls_pk_algorithm_t;
@@ -726,6 +728,7 @@ const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm);
* @GNUTLS_SIGN_RSA_SHA3_256: Digital signature algorithm RSA with SHA3-256.
* @GNUTLS_SIGN_RSA_SHA3_384: Digital signature algorithm RSA with SHA3-384.
* @GNUTLS_SIGN_RSA_SHA3_512: Digital signature algorithm RSA with SHA3-512.
+ * @GNUTLS_SIGN_EDDSA_SHA512: Digital signature algorithm EdDSA with SHA-512.
*
* Enumeration of different digital signature algorithms.
*/
@@ -763,7 +766,8 @@ typedef enum {
GNUTLS_SIGN_RSA_SHA3_224 = 28,
GNUTLS_SIGN_RSA_SHA3_256 = 29,
GNUTLS_SIGN_RSA_SHA3_384 = 30,
- GNUTLS_SIGN_RSA_SHA3_512 = 31
+ GNUTLS_SIGN_RSA_SHA3_512 = 31,
+ GNUTLS_SIGN_EDDSA_SHA512 = 32
} gnutls_sign_algorithm_t;
/**
@@ -775,6 +779,7 @@ typedef enum {
* @GNUTLS_ECC_CURVE_SECP384R1: the SECP384R1 curve
* @GNUTLS_ECC_CURVE_SECP521R1: the SECP521R1 curve
* @GNUTLS_ECC_CURVE_X25519: the X25519 curve (ECDH only)
+ * @GNUTLS_ECC_CURVE_ED25519PH: the Ed25519 curve (in prehash mode)
*
* Enumeration of ECC curves.
*/
@@ -785,7 +790,8 @@ typedef enum {
GNUTLS_ECC_CURVE_SECP384R1,
GNUTLS_ECC_CURVE_SECP521R1,
GNUTLS_ECC_CURVE_SECP192R1,
- GNUTLS_ECC_CURVE_X25519
+ GNUTLS_ECC_CURVE_X25519,
+ GNUTLS_ECC_CURVE_ED25519PH
} gnutls_ecc_curve_t;
/* macros to allow specifying a specific curve in gnutls_privkey_generate()
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index 55ed70666c..0e76add3dd 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -47,6 +47,7 @@
#include <nettle/ecdsa.h>
#include <nettle/ecc-curve.h>
#include <nettle/curve25519.h>
+#include <nettle/eddsa.h>
#include <gnettle.h>
#include <fips.h>
@@ -238,7 +239,7 @@ dh_cleanup:
break;
}
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
{
struct ecc_scalar ecc_priv;
struct ecc_point ecc_pub;
@@ -467,8 +468,42 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
unsigned int hash_len;
const mac_entry_st *me;
+ if (IS_EC(algo)) {
+ /* check if the curve relates to the algorithm used */
+ if (gnutls_ecc_curve_get_pk(pk_params->flags) != algo)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+ }
+
switch (algo) {
- case GNUTLS_PK_EC: /* we do ECDSA */
+ case GNUTLS_PK_EDDSA: /* we do EdDSA */
+ {
+ const gnutls_ecc_curve_entry_st *e;
+
+ if (pk_params->flags != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ e = _gnutls_ecc_curve_get_params(pk_params->flags);
+ if (e == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ signature->data = gnutls_malloc(e->sig_size);
+ if (signature->data == NULL) {
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto cleanup;
+ }
+
+ signature->size = e->sig_size;
+
+ if (pk_params->raw_pub.size != e->size || pk_params->raw_priv.size != e->size)
+ return gnutls_assert_val(GNUTLS_E_PK_SIGN_FAILED);
+
+ ed25519_sha512_sign(pk_params->raw_pub.data,
+ pk_params->raw_priv.data,
+ vdata->size, vdata->data, signature->data);
+
+ break;
+ }
+ case GNUTLS_PK_ECDSA: /* we do ECDSA */
{
struct ecc_scalar priv;
struct dsa_signature sig;
@@ -621,8 +656,40 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
unsigned int hash_len;
bigint_t tmp[2] = { NULL, NULL };
+ if (IS_EC(algo)) {
+ /* check if the curve relates to the algorithm used */
+ if (gnutls_ecc_curve_get_pk(pk_params->flags) != algo)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+ }
+
switch (algo) {
- case GNUTLS_PK_EC: /* ECDSA */
+ case GNUTLS_PK_EDDSA: /* we do EdDSA */
+ {
+ const gnutls_ecc_curve_entry_st *e;
+
+ if (pk_params->flags != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ e = _gnutls_ecc_curve_get_params(pk_params->flags);
+ if (e == NULL)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ if (signature->size != e->sig_size)
+ return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+
+ if (pk_params->raw_pub.size != e->size)
+ return gnutls_assert_val(GNUTLS_E_PK_SIGN_FAILED);
+
+ ret = ed25519_sha512_verify(pk_params->raw_pub.data, vdata->size, vdata->data, signature->data);
+ if (ret == 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ } else {
+ ret = 0;
+ }
+ break;
+ }
+ case GNUTLS_PK_ECDSA: /* ECDSA */
{
struct ecc_point pub;
struct dsa_signature sig;
@@ -770,6 +837,7 @@ static inline const struct ecc_curve *get_supported_nist_curve(int curve)
static int _wrap_nettle_pk_curve_exists(gnutls_ecc_curve_t curve)
{
switch (curve) {
+ case GNUTLS_ECC_CURVE_ED25519PH:
case GNUTLS_ECC_CURVE_X25519:
return 1;
default:
@@ -780,7 +848,7 @@ static int _wrap_nettle_pk_curve_exists(gnutls_ecc_curve_t curve)
/* Generates algorithm's parameters. That is:
* For DSA: p, q, and g are generated.
* For RSA: nothing
- * For ECDSA: just checks the curve is ok
+ * For ECDSA/EDDSA: nothing
*/
static int
wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
@@ -896,7 +964,8 @@ wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
break;
}
case GNUTLS_PK_RSA:
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
+ case GNUTLS_PK_EDDSA:
ret = 0;
break;
default:
@@ -1041,13 +1110,13 @@ int _gnutls_ecdh_generate_key(gnutls_ecc_curve_t curve,
gnutls_pk_params_init(&params);
params.flags = curve;
- params.algo = GNUTLS_PK_EC;
+ params.algo = GNUTLS_PK_ECDSA;
x->data = NULL;
y->data = NULL;
k->data = NULL;
- ret = _gnutls_pk_generate_keys(GNUTLS_PK_EC, curve, &params);
+ ret = _gnutls_pk_generate_keys(GNUTLS_PK_ECDSA, curve, &params);
if (ret < 0) {
return gnutls_assert_val(ret);
}
@@ -1096,7 +1165,7 @@ int _gnutls_ecdh_compute_key(gnutls_ecc_curve_t curve,
gnutls_pk_params_init(&pub);
gnutls_pk_params_init(&priv);
- pub.algo = GNUTLS_PK_EC;
+ pub.algo = GNUTLS_PK_ECDSA;
pub.flags = curve;
if (_gnutls_mpi_init_scan_nz
@@ -1143,12 +1212,12 @@ int _gnutls_ecdh_compute_key(gnutls_ecc_curve_t curve,
priv.params_nr = 3;
- priv.algo = GNUTLS_PK_EC;
+ priv.algo = GNUTLS_PK_ECDSA;
priv.flags = curve;
Z->data = NULL;
- ret = _gnutls_pk_derive(GNUTLS_PK_EC, Z, &priv, &pub);
+ ret = _gnutls_pk_derive(GNUTLS_PK_ECDSA, Z, &priv, &pub);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -1174,6 +1243,12 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
int ret;
unsigned int i;
+ if (IS_EC(algo)) {
+ /* check if the curve relates to the algorithm used */
+ if (gnutls_ecc_curve_get_pk(level) != algo)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+ }
+
switch (algo) {
case GNUTLS_PK_DSA:
#ifdef ENABLE_FIPS140
@@ -1365,7 +1440,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
break;
}
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
if (params->flags & GNUTLS_PK_FLAG_PROVABLE)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
@@ -1410,6 +1485,44 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
break;
}
+ case GNUTLS_PK_EDDSA:
+ {
+ unsigned size = gnutls_ecc_curve_get_size(level);
+
+ if (params->flags & GNUTLS_PK_FLAG_PROVABLE)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (level != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ if (size == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ params->flags = level;
+
+ params->raw_priv.data = gnutls_malloc(size);
+ if (params->raw_priv.data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ params->raw_pub.data = gnutls_malloc(size);
+ if (params->raw_pub.data == NULL) {
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto fail;
+ }
+
+ ret = _gnutls_rnd(GNUTLS_RND_RANDOM, params->raw_priv.data, size);
+ if (ret < 0) {
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto fail;
+ }
+ params->raw_pub.size = size;
+ params->raw_priv.size = size;
+
+ ed25519_sha512_public_key(params->raw_pub.data, params->raw_priv.data);
+ params->params_nr = 2;
+
+ break;
+ }
case GNUTLS_PK_ECDHX:
{
unsigned size = gnutls_ecc_curve_get_size(level);
@@ -1445,6 +1558,8 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
return GNUTLS_E_INVALID_REQUEST;
}
+ params->algo = algo;
+
FAIL_IF_LIB_ERROR;
return 0;
@@ -1588,7 +1703,7 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
}
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
{
struct ecc_point r, pub;
struct ecc_scalar priv;
@@ -1661,6 +1776,9 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
mpz_clear(y2);
}
break;
+ case GNUTLS_PK_EDDSA:
+ ret = 0;
+ break;
default:
ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
}
@@ -1678,7 +1796,7 @@ wrap_nettle_pk_verify_pub_params(gnutls_pk_algorithm_t algo,
case GNUTLS_PK_RSA:
case GNUTLS_PK_DSA:
return 0;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
{
/* just verify that x and y lie on the curve */
struct ecc_point r, pub;
@@ -1803,6 +1921,21 @@ wrap_nettle_pk_fixup(gnutls_pk_algorithm_t algo,
params->params_nr = RSA_PRIVATE_PARAMS;
}
+ if (direction == GNUTLS_IMPORT && algo == GNUTLS_PK_EDDSA) {
+ if (params->flags != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ if (params->raw_pub.data == NULL) {
+ params->raw_pub.data = gnutls_malloc(params->raw_priv.size);
+ }
+
+ if (params->raw_pub.data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ ed25519_sha512_public_key(params->raw_pub.data, params->raw_priv.data);
+ params->raw_pub.size = params->raw_priv.size;
+ }
+
return 0;
}
diff --git a/lib/pk.c b/lib/pk.c
index 182cdcb15f..0996b71492 100644
--- a/lib/pk.c
+++ b/lib/pk.c
@@ -170,7 +170,7 @@ int _gnutls_pk_params_copy(gnutls_pk_params_st * dst,
unsigned int i, j;
dst->params_nr = 0;
- if (src == NULL || src->params_nr == 0) {
+ if (src == NULL || (src->params_nr == 0 && src->raw_pub.size == 0)) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
@@ -668,6 +668,32 @@ int _gnutls_params_get_ecc_raw(const gnutls_pk_params_st* params,
if (curve)
*curve = params->flags;
+ if (curve_is_eddsa(params->flags)) {
+ if (x) {
+ ret = _gnutls_set_datum(x, params->raw_pub.data, params->raw_pub.size);
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
+ }
+ }
+
+ if (y) {
+ y->data = NULL;
+ y->size = 0;
+ }
+
+ if (k) {
+ ret = _gnutls_set_datum(k, params->raw_priv.data, params->raw_priv.size);
+ if (ret < 0) {
+ _gnutls_free_datum(x);
+ return gnutls_assert_val(ret);
+ }
+ }
+
+ return 0;
+ }
+
+ /* ECDSA */
+
/* X */
if (x) {
ret = _gnutls_mpi_dprint_lz(params->params[ECC_X], x);
@@ -761,7 +787,8 @@ pk_prepare_hash(gnutls_pk_algorithm_t pk,
_gnutls_free_datum(&old_digest);
break;
case GNUTLS_PK_DSA:
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
+ case GNUTLS_PK_EDDSA:
break;
default:
gnutls_assert();
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
index 531f646f5a..5f0f1a2372 100644
--- a/lib/pkcs11_privkey.c
+++ b/lib/pkcs11_privkey.c
@@ -302,7 +302,7 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
}
- if (key->pk_algorithm == GNUTLS_PK_EC
+ if (key->pk_algorithm == GNUTLS_PK_ECDSA
|| key->pk_algorithm == GNUTLS_PK_DSA) {
unsigned int hlen = siglen / 2;
gnutls_datum_t r, s;
@@ -891,7 +891,7 @@ gnutls_pkcs11_privkey_generate3(const char *url, gnutls_pk_algorithm_t pk,
}
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
p[p_val].type = CKA_SIGN;
if (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE) {
p[p_val].value = (void *) &tval;
@@ -910,7 +910,7 @@ gnutls_pkcs11_privkey_generate3(const char *url, gnutls_pk_algorithm_t pk,
if (GNUTLS_BITS_ARE_CURVE(bits)) {
bits = GNUTLS_BITS_TO_CURVE(bits);
} else {
- bits = _gnutls_ecc_bits_to_curve(bits);
+ bits = _gnutls_ecc_bits_to_curve(pk, bits);
}
ret = _gnutls_x509_write_ecc_params(bits, &der);
diff --git a/lib/privkey.c b/lib/privkey.c
index 0f63649ec2..9274a036f3 100644
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -134,10 +134,10 @@ int gnutls_privkey_get_pk_algorithm(gnutls_privkey_t key, unsigned int *bits)
bits);
#endif
case GNUTLS_PRIVKEY_X509:
- if (bits)
- *bits =
- _gnutls_mpi_get_nbits(key->key.x509->
- params.params[0]);
+ if (bits) {
+ *bits = pubkey_to_bits(key->key.x509->pk_algorithm, &key->key.x509->params);
+ }
+
return gnutls_x509_privkey_get_pk_algorithm(key->key.x509);
case GNUTLS_PRIVKEY_EXT:
if (bits)
@@ -189,7 +189,7 @@ privkey_to_pubkey(gnutls_pk_algorithm_t pk,
}
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
pub->params[ECC_X] = _gnutls_mpi_copy(priv->params[ECC_X]);
pub->params[ECC_Y] = _gnutls_mpi_copy(priv->params[ECC_Y]);
@@ -202,6 +202,13 @@ privkey_to_pubkey(gnutls_pk_algorithm_t pk,
}
break;
+ case GNUTLS_PK_EDDSA:
+ ret = _gnutls_set_datum(&pub->raw_pub, priv->raw_pub.data, priv->raw_pub.size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ break;
+
default:
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
diff --git a/lib/privkey_raw.c b/lib/privkey_raw.c
index 47754831ee..2e17556b2e 100644
--- a/lib/privkey_raw.c
+++ b/lib/privkey_raw.c
@@ -138,7 +138,8 @@ int ret;
*
* This function will export the ECC private key's parameters found
* in the given structure. The new parameters will be allocated using
- * gnutls_malloc() and will be stored in the appropriate datum.
+ * gnutls_malloc() and will be stored in the appropriate datum. For
+ * EdDSA keys, the @y value should be %NULL.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
diff --git a/lib/pubkey.c b/lib/pubkey.c
index 8ff248e2cd..4d14c73547 100644
--- a/lib/pubkey.c
+++ b/lib/pubkey.c
@@ -50,7 +50,8 @@ int pubkey_to_bits(gnutls_pk_algorithm_t pk, gnutls_pk_params_st * params)
return _gnutls_mpi_get_nbits(params->params[RSA_MODULUS]);
case GNUTLS_PK_DSA:
return _gnutls_mpi_get_nbits(params->params[DSA_P]);
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
+ case GNUTLS_PK_EDDSA:
return gnutls_ecc_curve_get_size(params->flags) * 8;
default:
return 0;
@@ -289,7 +290,7 @@ gnutls_pubkey_get_preferred_hash_algorithm(gnutls_pubkey_t key,
if (mand)
*mand = 1;
/* fallthrough */
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
me = _gnutls_dsa_q_to_hash(key->pk_algorithm, &key->params, NULL);
if (hash)
@@ -297,6 +298,12 @@ gnutls_pubkey_get_preferred_hash_algorithm(gnutls_pubkey_t key,
ret = 0;
break;
+ case GNUTLS_PK_EDDSA:
+ if (hash)
+ *hash = GNUTLS_DIG_SHA512;
+
+ ret = 0;
+ break;
case GNUTLS_PK_RSA:
if (hash)
*hash = GNUTLS_DIG_SHA256;
@@ -954,6 +961,7 @@ gnutls_pubkey_export_dsa_raw(gnutls_pubkey_t key,
* This function will export the ECC public key's parameters found in
* the given key. The new parameters will be allocated using
* gnutls_malloc() and will be stored in the appropriate datum.
+ * For EdDSA public keys, @y will be set to %NULL.
*
* This function allows for %NULL parameters since 3.4.1.
*
@@ -973,7 +981,7 @@ gnutls_pubkey_export_ecc_raw(gnutls_pubkey_t key,
return GNUTLS_E_INVALID_REQUEST;
}
- if (key->pk_algorithm != GNUTLS_PK_EC) {
+ if (!IS_EC(key->pk_algorithm)) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
@@ -981,6 +989,17 @@ gnutls_pubkey_export_ecc_raw(gnutls_pubkey_t key,
if (curve)
*curve = key->params.flags;
+ if (key->pk_algorithm == GNUTLS_PK_EDDSA) {
+ if (x) {
+ ret = _gnutls_set_datum(x, key->params.raw_pub.data, key->params.raw_pub.size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+ return 0;
+ }
+
+ /* ECDSA */
+
/* X */
if (x) {
ret = _gnutls_mpi_dprint_lz(key->params.params[ECC_X], x);
@@ -1395,7 +1414,8 @@ gnutls_pubkey_import_rsa_raw(gnutls_pubkey_t key,
* @y: holds the y
*
* This function will convert the given elliptic curve parameters to a
- * #gnutls_pubkey_t. The output will be stored in @key.
+ * #gnutls_pubkey_t. The output will be stored in @key. For EdDSA
+ * keys the @y parameter should be %NULL.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
@@ -1420,6 +1440,19 @@ gnutls_pubkey_import_ecc_raw(gnutls_pubkey_t key,
key->params.flags = curve;
+ if (curve_is_eddsa(curve)) {
+ key->pk_algorithm = GNUTLS_PK_EDDSA;
+
+ ret = _gnutls_set_datum(&key->params.raw_pub, x->data, x->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+ }
+
+ /* ECDSA */
+ key->pk_algorithm = GNUTLS_PK_ECDSA;
+
if (_gnutls_mpi_init_scan_nz
(&key->params.params[ECC_X], x->data, x->size)) {
gnutls_assert();
@@ -1435,7 +1468,6 @@ gnutls_pubkey_import_ecc_raw(gnutls_pubkey_t key,
goto cleanup;
}
key->params.params_nr++;
- key->pk_algorithm = GNUTLS_PK_EC;
return 0;
@@ -1870,6 +1902,30 @@ dsa_verify_hashed_data(gnutls_pk_algorithm_t pk,
}
static int
+eddsa_verify_data(gnutls_pk_algorithm_t pk,
+ const mac_entry_st * algo,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature,
+ gnutls_pk_params_st * params)
+{
+ int ret;
+ uint8_t _digest[MAX_HASH_SIZE];
+ gnutls_datum_t digest;
+
+ if (algo == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = _gnutls_hash_fast(algo->id, data->data, data->size, _digest);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ digest.data = _digest;
+ digest.size = _gnutls_hash_get_algo_len(algo);
+
+ return _gnutls_pk_verify(pk, &digest, signature, params);
+}
+
+static int
dsa_verify_data(gnutls_pk_algorithm_t pk,
const mac_entry_st * algo,
const gnutls_datum_t * data,
@@ -1957,7 +2013,15 @@ pubkey_verify_data(gnutls_pk_algorithm_t pk,
return 1;
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_EDDSA:
+ if (eddsa_verify_data(pk, me, data, signature, issuer_params) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ }
+
+ return 1;
+ break;
+ case GNUTLS_PK_ECDSA:
case GNUTLS_PK_DSA:
if (dsa_verify_data(pk, me, data, signature, issuer_params)
!= 0) {
diff --git a/lib/x509/common.h b/lib/x509/common.h
index dc6dccec83..9946bf6b6b 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -84,6 +84,8 @@
#define SIG_RSA_SHA3_384_OID "2.16.840.1.101.3.4.3.15"
#define SIG_RSA_SHA3_512_OID "2.16.840.1.101.3.4.3.16"
+#define SIG_EDDSA_SHA512_OID "1.3.101.100"
+
#define XMPP_OID "1.3.6.1.5.5.7.8.5"
#define KRB5_PRINCIPAL_OID "1.3.6.1.5.2.2"
diff --git a/lib/x509/key_decode.c b/lib/x509/key_decode.c
index 049e93a951..b3ba2cacae 100644
--- a/lib/x509/key_decode.c
+++ b/lib/x509/key_decode.c
@@ -37,6 +37,8 @@ static int _gnutls_x509_read_dsa_pubkey(uint8_t * der, int dersize,
gnutls_pk_params_st * params);
static int _gnutls_x509_read_ecc_pubkey(uint8_t * der, int dersize,
gnutls_pk_params_st * params);
+static int _gnutls_x509_read_eddsa_pubkey(uint8_t * der, int dersize,
+ gnutls_pk_params_st * params);
static int
_gnutls_x509_read_dsa_params(uint8_t * der, int dersize,
@@ -109,6 +111,60 @@ _gnutls_x509_read_ecc_pubkey(uint8_t * der, int dersize,
&params->params[ECC_Y]);
}
+int _gnutls_x509_read_eddsa_pubkey(uint8_t * der, int dersize,
+ gnutls_pk_params_st * params)
+{
+ return _gnutls_set_datum(&params->raw_pub, der, dersize);
+}
+
+/* params as defined in draft-ietf-curdle-pkix-00
+ */
+int
+_gnutls_x509_read_eddsa_params(uint8_t * der, int dersize,
+ unsigned int * curve)
+{
+ int ret;
+ ASN1_TYPE spk = ASN1_TYPE_EMPTY;
+ unsigned int cid;
+
+ if ((ret = asn1_create_element
+ (_gnutls_get_gnutls_asn(), "GNUTLS.EdDSAParameters",
+ &spk)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(ret);
+ }
+
+ ret = asn1_der_decoding(&spk, der, dersize, NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ /* read the curve */
+ ret = _gnutls_x509_read_uint(spk, "", &cid);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (cid != 2) {
+ _gnutls_debug_log("EdDSA curve %u is not supported\n", cid);
+ gnutls_assert();
+ ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE;
+ goto cleanup;
+ }
+
+ *curve = GNUTLS_ECC_CURVE_ED25519PH;
+
+ ret = 0;
+
+ cleanup:
+
+ asn1_delete_structure(&spk);
+
+ return ret;
+}
/* reads p,q and g
* from the certificate (subjectPublicKey BIT STRING).
@@ -247,11 +303,14 @@ int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t * der,
if (ret >= 0)
params->params_nr = DSA_PUBLIC_PARAMS;
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
ret = _gnutls_x509_read_ecc_pubkey(der, dersize, params);
if (ret >= 0)
params->params_nr = ECC_PUBLIC_PARAMS;
break;
+ case GNUTLS_PK_EDDSA:
+ ret = _gnutls_x509_read_eddsa_pubkey(der, dersize, params);
+ break;
default:
ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
break;
@@ -268,8 +327,10 @@ int _gnutls_x509_read_pubkey_params(gnutls_pk_algorithm_t algo,
return 0;
case GNUTLS_PK_DSA:
return _gnutls_x509_read_dsa_params(der, dersize, params);
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
return _gnutls_x509_read_ecc_params(der, dersize, &params->flags);
+ case GNUTLS_PK_EDDSA:
+ return _gnutls_x509_read_eddsa_params(der, dersize, &params->flags);
default:
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
diff --git a/lib/x509/key_encode.c b/lib/x509/key_encode.c
index 8ebc9fabc7..acc13492bc 100644
--- a/lib/x509/key_encode.c
+++ b/lib/x509/key_encode.c
@@ -128,6 +128,34 @@ _gnutls_x509_write_ecc_pubkey(gnutls_pk_params_st * params,
return 0;
}
+/*
+ * some x509 certificate functions that relate to MPI parameter
+ * setting. This writes a raw public key.
+ *
+ * Allocates the space used to store the data.
+ */
+int
+_gnutls_x509_write_eddsa_pubkey(gnutls_pk_params_st * params,
+ gnutls_datum_t * raw)
+{
+ int ret;
+
+ raw->data = NULL;
+ raw->size = 0;
+
+ if (params->raw_pub.size == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (params->flags != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ ret = _gnutls_set_datum(raw, params->raw_pub.data, params->raw_pub.size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
int
_gnutls_x509_write_pubkey_params(gnutls_pk_algorithm_t algo,
gnutls_pk_params_st * params,
@@ -144,8 +172,10 @@ _gnutls_x509_write_pubkey_params(gnutls_pk_algorithm_t algo,
memcpy(der->data, ASN1_NULL, ASN1_NULL_SIZE);
der->size = ASN1_NULL_SIZE;
return 0;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
return _gnutls_x509_write_ecc_params(params->flags, der);
+ case GNUTLS_PK_EDDSA:
+ return _gnutls_x509_write_eddsa_params(params->flags, der);
default:
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
@@ -161,14 +191,63 @@ _gnutls_x509_write_pubkey(gnutls_pk_algorithm_t algo,
return _gnutls_x509_write_dsa_pubkey(params, der);
case GNUTLS_PK_RSA:
return _gnutls_x509_write_rsa_pubkey(params, der);
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
return _gnutls_x509_write_ecc_pubkey(params, der);
+ case GNUTLS_PK_EDDSA:
+ return _gnutls_x509_write_eddsa_pubkey(params, der);
default:
return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
}
}
/*
+ * This function writes the parameters for EdDSA keys.
+ * That is the EdDSAParameters struct.
+ *
+ * Allocates the space used to store the DER data.
+ */
+int
+_gnutls_x509_write_eddsa_params(gnutls_ecc_curve_t curve,
+ gnutls_datum_t * der)
+{
+ int result;
+ ASN1_TYPE spk = ASN1_TYPE_EMPTY;
+ const uint8_t two = '\x02';
+
+ der->data = NULL;
+ der->size = 0;
+
+ if (curve != GNUTLS_ECC_CURVE_ED25519PH)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ if ((result = asn1_create_element
+ (_gnutls_get_gnutls_asn(), "GNUTLS.EdDSAParameters", &spk))
+ != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ if ((result =
+ asn1_write_value(spk, "", &two, 1)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_der_encode(spk, "", der, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ asn1_delete_structure(&spk);
+ return result;
+}
+
+/*
* This function writes the parameters for DSS keys.
* Needs 3 parameters (p,q,g).
*
@@ -249,7 +328,6 @@ _gnutls_x509_write_ecc_params(gnutls_ecc_curve_t curve,
if (oid == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
if ((result = asn1_create_element
(_gnutls_get_gnutls_asn(), "GNUTLS.ECParameters", &spk))
!= ASN1_SUCCESS) {
@@ -502,19 +580,9 @@ _gnutls_asn1_encode_ecc(ASN1_TYPE * c2, gnutls_pk_params_st * params)
oid = gnutls_ecc_curve_get_oid(params->flags);
- if (params->params_nr != ECC_PRIVATE_PARAMS || oid == NULL)
+ if (oid == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- ret =
- _gnutls_ecc_ansi_x963_export(params->flags,
- params->params[ECC_X],
- params->params[ECC_Y], &pubkey);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- /* Ok. Now we have the data. Create the asn1 structures
- */
-
/* first make sure that no previously allocated data are leaked */
if (*c2 != ASN1_TYPE_EMPTY) {
asn1_delete_structure(c2);
@@ -536,20 +604,51 @@ _gnutls_asn1_encode_ecc(ASN1_TYPE * c2, gnutls_pk_params_st * params)
goto cleanup;
}
- ret =
- _gnutls_x509_write_key_int(*c2, "privateKey",
- params->params[ECC_K], 1);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ if (curve_is_eddsa(params->flags)) {
+ if (params->raw_pub.size == 0 || params->raw_priv.size == 0)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- if ((ret =
- asn1_write_value(*c2, "publicKey", pubkey.data,
- pubkey.size * 8)) != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(ret);
- goto cleanup;
+ ret =
+ asn1_write_value(*c2, "privateKey", params->raw_priv.data, params->raw_priv.size);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ ret =
+ asn1_write_value(*c2, "publicKey", params->raw_pub.data, params->raw_pub.size*8);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+ } else {
+ if (params->params_nr != ECC_PRIVATE_PARAMS)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret =
+ _gnutls_ecc_ansi_x963_export(params->flags,
+ params->params[ECC_X],
+ params->params[ECC_Y], &pubkey);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret =
+ _gnutls_x509_write_key_int(*c2, "privateKey",
+ params->params[ECC_K], 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if ((ret =
+ asn1_write_value(*c2, "publicKey", pubkey.data,
+ pubkey.size * 8)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
}
/* write our choice */
@@ -684,7 +783,8 @@ int _gnutls_asn1_encode_privkey(gnutls_pk_algorithm_t pk, ASN1_TYPE * c2,
return _gnutls_asn1_encode_rsa(c2, params, compat);
case GNUTLS_PK_DSA:
return _gnutls_asn1_encode_dsa(c2, params, compat);
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
+ case GNUTLS_PK_EDDSA:
return _gnutls_asn1_encode_ecc(c2, params);
default:
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
diff --git a/lib/x509/output.c b/lib/x509/output.c
index 34f2c70b68..2bfb41d957 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -1669,7 +1669,7 @@ static void print_keyid(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
if (err < 0)
return;
- if (err == GNUTLS_PK_EC) {
+ if (IS_EC(err)) {
gnutls_ecc_curve_t curve;
err = gnutls_x509_crt_get_pk_ecc_raw(cert, &curve, NULL, NULL);
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index 4d6a3a32eb..1783b18d32 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -279,7 +279,6 @@ _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t * raw_k
gnutls_pk_params_init(&pkey->params);
- pkey->params.algo = GNUTLS_PK_EC;
if ((ret =
asn1_create_element(_gnutls_get_gnutls_asn(),
"GNUTLS.ECPrivateKey",
@@ -325,6 +324,7 @@ _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t * raw_k
}
pkey->params.flags = gnutls_oid_to_ecc_curve(oid);
+ curve = pkey->params.flags;
if (pkey->params.flags == GNUTLS_ECC_CURVE_INVALID) {
_gnutls_debug_log("Curve %s is not supported\n", oid);
@@ -336,35 +336,57 @@ _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t * raw_k
pkey->params.flags = curve;
}
+ if (curve_is_eddsa(curve)) {
+ pkey->pk_algorithm = GNUTLS_PK_EDDSA;
+ pkey->params.algo = GNUTLS_PK_EDDSA;
- /* read the public key */
- ret = _gnutls_x509_read_value(*pkey_asn, "publicKey", &out);
- if (ret < 0) {
- gnutls_assert();
- goto error;
- }
+ ret =
+ _gnutls_x509_read_value(*pkey_asn, "privateKey",
+ &pkey->params.raw_priv);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
- ret =
- _gnutls_ecc_ansi_x963_import(out.data, out.size,
- &pkey->params.params[ECC_X],
- &pkey->params.params[ECC_Y]);
+ /* make the public key */
+ ret = _gnutls_pk_fixup(GNUTLS_PK_EDDSA, GNUTLS_IMPORT, &pkey->params);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ } else { /* Normal EC curves */
+ pkey->pk_algorithm = GNUTLS_PK_ECDSA;
+ pkey->params.algo = GNUTLS_PK_ECDSA;
- _gnutls_free_datum(&out);
- if (ret < 0) {
- gnutls_assert();
- goto error;
- }
- pkey->params.params_nr += 2;
+ /* read the public key */
+ ret = _gnutls_x509_read_value(*pkey_asn, "publicKey", &out);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
- /* read the private key */
- ret =
- _gnutls_x509_read_key_int(*pkey_asn, "privateKey",
- &pkey->params.params[ECC_K]);
- if (ret < 0) {
- gnutls_assert();
- goto error;
+ ret =
+ _gnutls_ecc_ansi_x963_import(out.data, out.size,
+ &pkey->params.params[ECC_X],
+ &pkey->params.params[ECC_Y]);
+
+ _gnutls_free_datum(&out);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ pkey->params.params_nr += 2;
+
+ /* read the private key */
+ ret =
+ _gnutls_x509_read_key_int(*pkey_asn, "privateKey",
+ &pkey->params.params[ECC_K]);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+ pkey->params.params_nr++;
}
- pkey->params.params_nr++;
return 0;
@@ -373,10 +395,8 @@ _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t * raw_k
gnutls_pk_params_clear(&pkey->params);
gnutls_pk_params_release(&pkey->params);
return ret;
-
}
-
static ASN1_TYPE
decode_dsa_key(const gnutls_datum_t * raw_key, gnutls_x509_privkey_t pkey)
{
@@ -477,6 +497,7 @@ decode_dsa_key(const gnutls_datum_t * raw_key, gnutls_x509_privkey_t pkey)
#define PEM_KEY_DSA_PROVABLE "FIPS186-4 DSA PRIVATE KEY"
#define PEM_KEY_RSA_PROVABLE "FIPS186-4 RSA PRIVATE KEY"
#define PEM_KEY_ECC "EC PRIVATE KEY"
+#define PEM_KEY_EDDSA "EdDSA PRIVATE KEY"
#define PEM_KEY_PKCS8 "PRIVATE KEY"
#define MAX_PEM_HEADER_SIZE 25
@@ -554,6 +575,7 @@ gnutls_x509_privkey_import(gnutls_x509_privkey_t key,
IF_CHECK_FOR(PEM_KEY_RSA, GNUTLS_PK_RSA, ptr, begin_ptr, left, key)
else IF_CHECK_FOR(PEM_KEY_ECC, GNUTLS_PK_EC, ptr, begin_ptr, left, key)
+ else IF_CHECK_FOR(PEM_KEY_EDDSA, GNUTLS_PK_EDDSA, ptr, begin_ptr, left, key)
else IF_CHECK_FOR(PEM_KEY_DSA, GNUTLS_PK_DSA, ptr, begin_ptr, left, key)
else IF_CHECK_FOR(PEM_KEY_RSA_PROVABLE, GNUTLS_PK_RSA, ptr, begin_ptr, left, key)
else IF_CHECK_FOR(PEM_KEY_DSA_PROVABLE, GNUTLS_PK_DSA, ptr, begin_ptr, left, key)
@@ -604,7 +626,7 @@ gnutls_x509_privkey_import(gnutls_x509_privkey_t key,
key->key = decode_dsa_key(&_data, key);
if (key->key == NULL)
gnutls_assert();
- } else if (key->pk_algorithm == GNUTLS_PK_EC) {
+ } else if (key->pk_algorithm == GNUTLS_PK_EC || key->pk_algorithm == GNUTLS_PK_EDDSA) {
result = _gnutls_privkey_decode_ecc_key(&key->key, &_data, key, 0);
if (result < 0) {
gnutls_assert();
@@ -622,7 +644,6 @@ gnutls_x509_privkey_import(gnutls_x509_privkey_t key,
key->pk_algorithm = GNUTLS_PK_DSA;
key->key = decode_dsa_key(&_data, key);
if (key->key == NULL) {
- key->pk_algorithm = GNUTLS_PK_EC;
result =
_gnutls_privkey_decode_ecc_key(&key->key, &_data, key, 0);
if (result < 0) {
@@ -635,7 +656,6 @@ gnutls_x509_privkey_import(gnutls_x509_privkey_t key,
key->key = NULL;
}
}
-
}
}
}
@@ -739,9 +759,9 @@ gnutls_x509_privkey_import2(gnutls_x509_privkey_t key,
if (ptr != NULL) {
left = data->size - ((ptrdiff_t)ptr - (ptrdiff_t)data->data);
- if (data->size - left > 15) {
- ptr -= 15;
- left += 15;
+ if (data->size - left > MAX_PEM_HEADER_SIZE) {
+ ptr -= MAX_PEM_HEADER_SIZE;
+ left += MAX_PEM_HEADER_SIZE;
} else {
ptr = (char*)data->data;
left = data->size;
@@ -756,6 +776,7 @@ gnutls_x509_privkey_import2(gnutls_x509_privkey_t key,
if (ptr != NULL && left > sizeof(PEM_KEY_RSA)) {
if (memcmp(ptr, PEM_KEY_RSA, sizeof(PEM_KEY_RSA)-1) == 0 ||
memcmp(ptr, PEM_KEY_ECC, sizeof(PEM_KEY_ECC)-1) == 0 ||
+ memcmp(ptr, PEM_KEY_EDDSA, sizeof(PEM_KEY_EDDSA)-1) == 0 ||
memcmp(ptr, PEM_KEY_DSA, sizeof(PEM_KEY_DSA)-1) == 0) {
head_enc = 0;
}
@@ -1111,6 +1132,25 @@ gnutls_x509_privkey_import_ecc_raw(gnutls_x509_privkey_t key,
}
key->params.flags = curve;
+ if (curve_is_eddsa(curve)) {
+ key->params.algo = GNUTLS_PK_EDDSA;
+
+ ret = _gnutls_set_datum(&key->params.raw_pub, x->data, x->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_set_datum(&key->params.raw_priv, k->data, k->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ return 0;
+ }
+
+ key->params.algo = GNUTLS_PK_ECDSA;
if (_gnutls_mpi_init_scan_nz
(&key->params.params[ECC_X], x->data, x->size)) {
@@ -1136,8 +1176,6 @@ gnutls_x509_privkey_import_ecc_raw(gnutls_x509_privkey_t key,
}
key->params.params_nr++;
- key->pk_algorithm = GNUTLS_PK_EC;
-
return 0;
cleanup:
@@ -1212,9 +1250,11 @@ static const char *set_msg(gnutls_x509_privkey_t key)
return PEM_KEY_DSA_PROVABLE;
else
return PEM_KEY_DSA;
- } else if (key->pk_algorithm == GNUTLS_PK_EC)
+ } else if (key->pk_algorithm == GNUTLS_PK_EC) {
return PEM_KEY_ECC;
- else
+ } else if (key->pk_algorithm == GNUTLS_PK_EDDSA) {
+ return PEM_KEY_EDDSA;
+ } else
return "UNKNOWN";
}
@@ -1343,6 +1383,7 @@ gnutls_sec_param_t gnutls_x509_privkey_sec_param(gnutls_x509_privkey_t key)
* This function will export the ECC private key's parameters found
* in the given structure. The new parameters will be allocated using
* gnutls_malloc() and will be stored in the appropriate datum.
+ * For EdDSA keys, the @y value should be %NULL.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
@@ -1502,7 +1543,8 @@ char* gen_data = NULL;
/* Here we don't know the purpose of the key. Check both
* signing and encryption.
*/
- case GNUTLS_PK_EC: /* we only do keys for ECDSA */
+ case GNUTLS_PK_EDDSA:
+ case GNUTLS_PK_ECDSA:
case GNUTLS_PK_DSA:
ret = _gnutls_pk_sign(algo, &sig, &ddata, params);
if (ret < 0) {
@@ -1618,11 +1660,16 @@ gnutls_x509_privkey_generate2(gnutls_x509_privkey_t key,
}
}
- if (algo == GNUTLS_PK_EC) {
+ if (IS_EC(algo)) {
if (GNUTLS_BITS_ARE_CURVE(bits))
bits = GNUTLS_BITS_TO_CURVE(bits);
else
- bits = _gnutls_ecc_bits_to_curve(bits);
+ bits = _gnutls_ecc_bits_to_curve(algo, bits);
+
+ if (gnutls_ecc_curve_get_pk(bits) != algo) {
+ _gnutls_debug_log("curve is incompatible with public key algorithm\n");
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
}
if (flags & GNUTLS_PRIVKEY_FLAG_PROVABLE) {
diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c
index ca438656b4..4372064fab 100644
--- a/lib/x509/privkey_pkcs8.c
+++ b/lib/x509/privkey_pkcs8.c
@@ -112,7 +112,8 @@ _encode_privkey(gnutls_x509_privkey_t pkey, gnutls_datum_t * raw)
switch (pkey->pk_algorithm) {
case GNUTLS_PK_RSA:
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
+ case GNUTLS_PK_EDDSA:
ret =
gnutls_x509_privkey_export2(pkey, GNUTLS_X509_FMT_DER,
raw);
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 782365d8c4..7f82aa5cc7 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -227,10 +227,17 @@ int _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t *
gnutls_x509_privkey_t pkey,
gnutls_ecc_curve_t curve);
+int _gnutls_privkey_decode_eddsa_key(ASN1_TYPE* pkey_asn,
+ const gnutls_datum_t *raw_key,
+ gnutls_x509_privkey_t pkey,
+ gnutls_ecc_curve_t curve);
+
int
_gnutls_x509_read_ecc_params(uint8_t * der, int dersize,
unsigned int *curve);
+int _gnutls_x509_read_eddsa_params(uint8_t * der, int dersize, unsigned int *curve);
+
int _gnutls_asn1_encode_privkey(gnutls_pk_algorithm_t pk, ASN1_TYPE * c2,
gnutls_pk_params_st * params, unsigned compat);
@@ -306,6 +313,12 @@ int _gnutls_x509_write_ecc_params(gnutls_ecc_curve_t curve,
int _gnutls_x509_write_ecc_pubkey(gnutls_pk_params_st * params,
gnutls_datum_t * der);
+int _gnutls_x509_write_eddsa_params(gnutls_ecc_curve_t curve,
+ gnutls_datum_t * der);
+
+int _gnutls_x509_write_eddsa_pubkey(gnutls_pk_params_st * params,
+ gnutls_datum_t * der);
+
int
_gnutls_x509_write_pubkey_params(gnutls_pk_algorithm_t algo,
gnutls_pk_params_st * params,
diff --git a/src/certtool-args.def b/src/certtool-args.def
index 0eee218cea..7cba434a1d 100644
--- a/src/certtool-args.def
+++ b/src/certtool-args.def
@@ -448,6 +448,12 @@ flag = {
};
flag = {
+ name = eddsa;
+ descrip = "Generate EdDSA key";
+ doc = "When combined with --generate-privkey generates an elliptic curve private key to be used with EdDSA.";
+};
+
+flag = {
name = hash;
arg-type = string;
descrip = "Hash algorithm to use for signing";
diff --git a/src/certtool-common.c b/src/certtool-common.c
index dab6c59f99..e30882c632 100644
--- a/src/certtool-common.c
+++ b/src/certtool-common.c
@@ -866,14 +866,20 @@ print_ecc_pkey(FILE * outfile, gnutls_ecc_curve_t curve,
fprintf(outfile, "curve:\t%s\n",
gnutls_ecc_curve_get_name(curve));
- if (k) {
+ if (k && k->data) {
print_head(outfile, "private key", k->size, cprint);
print_hex_datum(outfile, k, cprint);
}
- print_head(outfile, "x", x->size, cprint);
- print_hex_datum(outfile, x, cprint);
- print_head(outfile, "y", y->size, cprint);
- print_hex_datum(outfile, y, cprint);
+
+ if (x && x->data) {
+ print_head(outfile, "x", x->size, cprint);
+ print_hex_datum(outfile, x, cprint);
+ }
+
+ if (y && y->data) {
+ print_head(outfile, "y", y->size, cprint);
+ print_hex_datum(outfile, y, cprint);
+ }
}
@@ -1143,7 +1149,7 @@ static void privkey_info_int(FILE *outfile, common_info_st * cinfo,
gnutls_free(q.data);
gnutls_free(g.data);
}
- } else if (key_type == GNUTLS_PK_EC) {
+ } else if (key_type == GNUTLS_PK_EC || key_type == GNUTLS_PK_EDDSA) {
gnutls_datum_t y, x, k;
gnutls_ecc_curve_t curve;
diff --git a/src/certtool.c b/src/certtool.c
index db8e626164..d0ce96cb5b 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -132,8 +132,10 @@ generate_private_key_int(common_info_st * cinfo)
bits = get_bits(key_type, cinfo->bits, cinfo->sec_param, 1);
- fprintf(stdlog, "Generating a %d bit %s private key...\n",
- bits, gnutls_pk_algorithm_get_name(key_type));
+ if (GNUTLS_BITS_ARE_CURVE(bits))
+ fprintf(stdlog, "Generating an %s private key...\n", gnutls_pk_algorithm_get_name(key_type));
+ else
+ fprintf(stdlog, "Generating a %d bit %s private key...\n", bits, gnutls_pk_algorithm_get_name(key_type));
if (bits < 256 && key_type == GNUTLS_PK_EC)
fprintf(stderr,
@@ -1084,7 +1086,9 @@ static void cmd_parser(int argc, char **argv)
if (HAVE_OPT(DSA))
req_key_type = GNUTLS_PK_DSA;
else if (HAVE_OPT(ECC))
- req_key_type = GNUTLS_PK_ECC;
+ req_key_type = GNUTLS_PK_ECDSA;
+ else if (HAVE_OPT(EDDSA))
+ req_key_type = GNUTLS_PK_EDDSA;
else
req_key_type = GNUTLS_PK_RSA;
diff --git a/tests/cert-tests/Makefile.am b/tests/cert-tests/Makefile.am
index 50301d5159..515181519f 100644
--- a/tests/cert-tests/Makefile.am
+++ b/tests/cert-tests/Makefile.am
@@ -39,7 +39,7 @@ EXTRA_DIST = ca-no-pathlen.pem no-ca-or-pathlen.pem aki-cert.pem \
template-othername-xmpp.tmpl template-othername-xmpp.pem template-krb5name.tmpl \
template-krb5name.pem template-krb5name-full.pem template-test-ecc.key \
template-rsa-sha3-256.pem template-rsa-sha3-512.pem template-rsa-sha3-224.pem template-rsa-sha3-384.pem \
- name-constraints-ip2.pem chain-md5.pem gost-cert.pem
+ name-constraints-ip2.pem chain-md5.pem gost-cert.pem pkcs7-detached.eddsa.sig
dist_check_SCRIPTS = pathlen aki certtool invalid-sig email \
pkcs7 pkcs7-broken-sigs privkey-import name-constraints certtool-long-cn crl provable-privkey
@@ -53,7 +53,8 @@ dist_check_SCRIPTS += crq
endif
if !WINDOWS
-dist_check_SCRIPTS += template-test pem-decoding othername-test krb5-test sha3-test md5-test
+dist_check_SCRIPTS += template-test pem-decoding othername-test krb5-test sha3-test md5-test \
+ ed25519
endif
if ENABLE_DANE
diff --git a/tests/cert-tests/ed25519 b/tests/cert-tests/ed25519
new file mode 100755
index 0000000000..72b5148672
--- /dev/null
+++ b/tests/cert-tests/ed25519
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+# Copyright (C) 2016 Red Hat, Inc.
+# Copyright (C) 2015-2016 Nikos Mavrogiannopoulos
+#
+# This file is part of GnuTLS.
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GnuTLS is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#set -e
+
+srcdir="${srcdir:-.}"
+CERTTOOL="${CERTTOOL:-../../src/certtool${EXEEXT}}"
+DIFF="${DIFF:-diff}"
+if ! test -z "${VALGRIND}"; then
+ VALGRIND="${LIBTOOL:-libtool} --mode=execute ${VALGRIND} --error-exitcode=15"
+fi
+OUTFILE=out-ed25519.tmp
+OUTFILE2=out2-ed25519.tmp
+
+# Verifying and existing sig
+FILE="shipped-sig-verify"
+${VALGRIND} "${CERTTOOL}" --p7-verify --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" <"pkcs7-detached.eddsa.sig"
+rc=$?
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing failed verification"
+ exit ${rc}
+fi
+
+# Test signing
+FILE="signing"
+${VALGRIND} "${CERTTOOL}" --p7-sign --load-privkey "${srcdir}/../../doc/credentials/x509/key-eddsa.pem" --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" --infile "${srcdir}/pkcs7-detached.txt" >"${OUTFILE}"
+rc=$?
+
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing failed"
+ exit ${rc}
+fi
+
+FILE="signing-verify"
+${VALGRIND} "${CERTTOOL}" --p7-verify --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" <"${OUTFILE}"
+rc=$?
+
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing failed verification"
+ exit ${rc}
+fi
+
+FILE="signing-detached"
+${VALGRIND} "${CERTTOOL}" --p7-detached-sign --load-privkey "${srcdir}/../../doc/credentials/x509/key-eddsa.pem" --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" --infile "${srcdir}/pkcs7-detached.txt" >"${OUTFILE}"
+rc=$?
+
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing-detached failed"
+ exit ${rc}
+fi
+
+FILE="signing-detached-verify"
+${VALGRIND} "${CERTTOOL}" --p7-verify --load-certificate "${srcdir}/../../doc/credentials/x509/cert-eddsa.pem" --load-data "${srcdir}/pkcs7-detached.txt" <"${OUTFILE}"
+rc=$?
+
+if test "${rc}" != "0"; then
+ echo "${FILE}: PKCS7-Ed25519 struct signing-detached failed verification"
+ exit ${rc}
+fi
+
+rm -f "${OUTFILE}"
+rm -f "${OUTFILE2}"
+
+exit 0
diff --git a/tests/cert-tests/pkcs7-detached.eddsa.sig b/tests/cert-tests/pkcs7-detached.eddsa.sig
new file mode 100644
index 0000000000..5f48db2822
--- /dev/null
+++ b/tests/cert-tests/pkcs7-detached.eddsa.sig
@@ -0,0 +1,14 @@
+-----BEGIN PKCS7-----
+MIICEQYJKoZIhvcNAQcCoIICAjCCAf4CAQExDTALBglghkgBZQMEAgMwKQYJKoZI
+hvcNAQcBoBwEGkhlbGxvIHRoZXJlLiBIb3cgYXJlIHlvdT8KoIIBPTCCATkwgeyg
+AwIBAgIIVyDIdBqWBggwBQYDK2VkMBUxEzARBgNVBAMTClRlc3QgRWREU0EwIBcN
+MTYwNDI3MTQxMTAxWhgPOTk5OTEyMzEyMzU5NTlaMBUxEzARBgNVBAMTClRlc3Qg
+RWREU0EwLTAIBgMrZWQKAQIDIQCk5H6zmyibZ7bTSM8UAYBYhSm/+/Nk5IUNcd8z
+yg5bpqNVMFMwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNV
+HQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBTgZCbV/Mo6WyF5xYpN3QAtdKOWvzAFBgMr
+ZWQDQQDQxdN9sb51PucYzhK7kHtDAS3SL/Ust+KEC6Qwuw/D3s+mzX9PwjMJchHh
+NtsAlmLw0TcO7BN+YRXvo9u0rU8PMX4wfAIBATAhMBUxEzARBgNVBAMTClRlc3Qg
+RWREU0ECCFcgyHQalgYIMAsGCWCGSAFlAwQCAzAFBgMrZWQEQDgOzyf+REobJlwS
+VAHqRBjGY9TfjZQlAaHYWesNM248McIjStGf/jbv/19cKt9EZKekr+gHBORe82DZ
+jaDddQU=
+-----END PKCS7-----