]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added support for EdDSA (Ed25519) curve keys
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Fri, 26 May 2017 13:20:38 +0000 (15:20 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Mon, 17 Jul 2017 15:08:01 +0000 (17:08 +0200)
This adds support for draft-ietf-curdle-pkix-04.

Resolves #25

Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
31 files changed:
lib/abstract_int.h
lib/algorithms.h
lib/algorithms/ecc.c
lib/algorithms/publickey.c
lib/algorithms/sign.c
lib/auth/ecdhe.c
lib/crypto-backend.h
lib/includes/gnutls/gnutls.h.in
lib/nettle/pk.c
lib/pk.c
lib/pkcs11_privkey.c
lib/privkey.c
lib/privkey_raw.c
lib/pubkey.c
lib/x509/common.c
lib/x509/common.h
lib/x509/crq.c
lib/x509/key_decode.c
lib/x509/key_encode.c
lib/x509/mpi.c
lib/x509/output.c
lib/x509/pkcs7.c
lib/x509/privkey.c
lib/x509/privkey_pkcs8.c
lib/x509/sign.c
lib/x509/x509.c
lib/x509/x509_int.h
src/certtool-args.def
src/certtool-common.c
src/certtool-common.h
src/certtool.c

index b3a0131eae48a563a197e69e1419244891c70ce8..f82e4f922aa10d7142f902d2114e2035248199c1 100644 (file)
@@ -80,10 +80,15 @@ int _gnutls_privkey_update_sign_params(gnutls_privkey_t key,
 
 void _gnutls_privkey_cleanup(gnutls_privkey_t key);
 
-int privkey_sign_data(gnutls_privkey_t signer,
-                     const gnutls_datum_t * data,
-                     gnutls_datum_t * signature,
-                     gnutls_x509_spki_st *params);
+int privkey_sign_and_hash_data(gnutls_privkey_t signer,
+                              const gnutls_datum_t * data,
+                              gnutls_datum_t * signature,
+                              gnutls_x509_spki_st *params);
+int
+privkey_sign_raw_data(gnutls_privkey_t key,
+                            const gnutls_datum_t * data,
+                            gnutls_datum_t * signature,
+                            gnutls_x509_spki_st * params);
 
 unsigned pubkey_to_bits(gnutls_pk_algorithm_t pk, gnutls_pk_params_st * params);
 int _gnutls_pubkey_compatible_with_sig(gnutls_session_t,
index 623758fb6e7ed8ad757e32f72b9aedb4d18286f5..f449f8bf0bcf477ddbc977e22afc7b1b9f22aa79 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
  *
  * Author: Nikos Mavrogiannopoulos
  *
@@ -31,7 +32,7 @@
 #define GNUTLS_FALLBACK_SCSV_MAJOR 0x56
 #define GNUTLS_FALLBACK_SCSV_MINOR 0x00
 
-#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_ED25519))
 
 #define TLS_SIGN_AID_UNKNOWN {{255, 255}}
 #define HAVE_UNKNOWN_SIGAID(aid) ((aid)->id[0] == 255 && (aid)->id[1] == 255)
@@ -321,6 +322,8 @@ const sign_algorithm_st *_gnutls_sign_to_tls_aid(gnutls_sign_algorithm_t
 
 unsigned int _gnutls_pk_bits_to_subgroup_bits(unsigned int pk_bits);
 
+bool _gnutls_pk_is_not_prehashed(gnutls_pk_algorithm_t algorithm);
+
 /* ECC */
 struct gnutls_ecc_curve_entry_st {
        const char *name;
@@ -328,7 +331,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 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;
 
@@ -337,9 +341,27 @@ 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
 
+gnutls_pk_algorithm_t _gnutls_oid_to_pk_and_curve(const char *oid, gnutls_ecc_curve_t *curve);
+
+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_ED25519)
+               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 ||
index 5274a815cbaa32976ca1f87821765894a88d1a56..c59099747e59adfcb4c83fb227481620bc52aca2 100644 (file)
@@ -77,6 +77,14 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
         .pk = GNUTLS_PK_ECDHX,
         .size = 32,
        },
+       {
+        .name = "Ed25519",
+        .oid = SIG_EDDSA_SHA512_OID,
+        .id = GNUTLS_ECC_CURVE_ED25519,
+        .pk = GNUTLS_PK_EDDSA_ED25519,
+        .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 (p->oid && 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_ED25519;
 
        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;
                }
index cbdd0d64fc3a64cb3d5aa3f2e6683e00ffb275b3..a75feddf0dc452c7d7ca6c050ee08881b903115d 100644 (file)
@@ -103,26 +103,43 @@ struct gnutls_pk_entry {
        const char *name;
        const char *oid;
        gnutls_pk_algorithm_t id;
+       gnutls_ecc_curve_t curve; /* to map PK to specific OID, we need to know the curve for EdDSA */
+       bool no_prehashed; /* non-zero if the algorithm cannot sign pre-hashed data */
 };
 typedef struct gnutls_pk_entry gnutls_pk_entry;
 
 static const gnutls_pk_entry pk_algorithms[] = {
        /* having duplicate entries is ok, as long as the one
         * we want to return OID from is first */
-       {"UNKNOWN", NULL, GNUTLS_PK_UNKNOWN},
-       {"RSA", PK_PKIX1_RSA_OID, GNUTLS_PK_RSA},
-       {"RSA-PSS", PK_PKIX1_RSA_PSS_OID, GNUTLS_PK_RSA_PSS},
-       {"RSA (X.509)", PK_X509_RSA_OID, GNUTLS_PK_RSA},        /* some certificates use this OID for RSA */
-       {"RSA-MD5", SIG_RSA_MD5_OID, GNUTLS_PK_RSA},    /* some other broken certificates set RSA with MD5 as an indicator of RSA */
-       {"RSA-SHA1", SIG_RSA_SHA1_OID, GNUTLS_PK_RSA},  /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
-       {"RSA-SHA1", ISO_SIG_RSA_SHA1_OID, GNUTLS_PK_RSA},      /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
-       {"DSA", PK_DSA_OID, GNUTLS_PK_DSA},
-       {"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},
-       {"DH", NULL, GNUTLS_PK_DH},
-       {"ECDHX", NULL, GNUTLS_PK_ECDHX},
-       {0, 0, 0}
+       { .name = "RSA", .oid = PK_PKIX1_RSA_OID, .id = GNUTLS_PK_RSA,
+          .curve = GNUTLS_ECC_CURVE_INVALID },
+       { .name = "RSA-PSS", .oid = PK_PKIX1_RSA_PSS_OID, .id = GNUTLS_PK_RSA_PSS,
+          .curve = GNUTLS_ECC_CURVE_INVALID },
+       { .name = "RSA (X.509)", .oid = PK_X509_RSA_OID, .id = GNUTLS_PK_RSA,
+          .curve = GNUTLS_ECC_CURVE_INVALID }, /* some certificates use this OID for RSA */
+       { .name = "RSA-MD5", .oid = SIG_RSA_MD5_OID, .id = GNUTLS_PK_RSA,
+          .curve = GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with MD5 as an indicator of RSA */
+       { .name = "RSA-SHA1", .oid = SIG_RSA_SHA1_OID, .id = GNUTLS_PK_RSA,
+          .curve = GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
+       { .name = "RSA-SHA1", .oid = ISO_SIG_RSA_SHA1_OID, .id = GNUTLS_PK_RSA,
+          .curve = GNUTLS_ECC_CURVE_INVALID }, /* some other broken certificates set RSA with SHA1 as an indicator of RSA */
+       { .name = "DSA", .oid = PK_DSA_OID, .id = GNUTLS_PK_DSA,
+          .curve = GNUTLS_ECC_CURVE_INVALID },
+       { .name = "GOST R 34.10-2001", .oid = PK_GOST_R3410_2001_OID, .id = GNUTLS_PK_UNKNOWN,
+          .curve = GNUTLS_ECC_CURVE_INVALID },
+       { .name = "GOST R 34.10-94", .oid = PK_GOST_R3410_94_OID, .id = GNUTLS_PK_UNKNOWN,
+          .curve = GNUTLS_ECC_CURVE_INVALID },
+       { .name = "EC/ECDSA", .oid = "1.2.840.10045.2.1", .id = GNUTLS_PK_ECDSA,
+          .curve = GNUTLS_ECC_CURVE_INVALID },
+       { .name = "EdDSA (Ed25519)", .oid = SIG_EDDSA_SHA512_OID, .id = GNUTLS_PK_EDDSA_ED25519, 
+         .curve = GNUTLS_ECC_CURVE_ED25519, .no_prehashed = 1 },
+       { .name = "DH", .oid = NULL, .id = GNUTLS_PK_DH,
+          .curve = GNUTLS_ECC_CURVE_INVALID },
+       { .name = "ECDH (X25519)", .oid = "1.3.101.110", .id = GNUTLS_PK_ECDHX,
+         .curve = GNUTLS_ECC_CURVE_X25519 },
+       { .name = "UNKNOWN", .oid = NULL, .id = GNUTLS_PK_UNKNOWN, 
+         .curve = GNUTLS_ECC_CURVE_INVALID },
+       {0, 0, 0, 0}
 };
 
 #define GNUTLS_PK_LOOP(b) \
@@ -234,6 +251,27 @@ const char *gnutls_pk_get_name(gnutls_pk_algorithm_t algorithm)
        return ret;
 }
 
+/*-
+ * _gnutls_pk_is_not_prehashed:
+ * @algorithm: is a public key algorithm
+ *
+ * Returns non-zero when the public key algorithm does not support pre-hashed
+ * data.
+ *
+ * Since: 3.6.0
+ **/
+bool _gnutls_pk_is_not_prehashed(gnutls_pk_algorithm_t algorithm)
+{
+       const gnutls_pk_entry *p;
+
+       for (p = pk_algorithms; p->name != NULL; p++)
+               if (algorithm == p->id) {
+                       return p->no_prehashed;
+               }
+
+       return 0;
+}
+
 /**
  * gnutls_oid_to_pk:
  * @oid: is an object identifier
@@ -284,6 +322,37 @@ const char *gnutls_pk_get_oid(gnutls_pk_algorithm_t algorithm)
        return ret;
 }
 
+/*-
+ * _gnutls_oid_to_pk_and_curve:
+ * @oid: is an object identifier
+ *
+ * Convert an OID to a #gnutls_pk_algorithm_t and curve values. If no curve
+ * is applicable, curve will be set GNUTLS_ECC_CURVE_INVALID.
+ *
+ * Returns: a #gnutls_pk_algorithm_t id of the specified digest
+ *   algorithm, or %GNUTLS_PK_UNKNOWN on failure.
+ *
+ * Since: 3.6.0
+ -*/
+gnutls_pk_algorithm_t _gnutls_oid_to_pk_and_curve(const char *oid, gnutls_ecc_curve_t *curve)
+{
+       gnutls_pk_algorithm_t ret = GNUTLS_PK_UNKNOWN;
+       const gnutls_pk_entry *p;
+
+       for (p = pk_algorithms; p->name != NULL; p++)
+               if (p->oid && strcmp(p->oid, oid) == 0) {
+                       ret = p->id;
+                       if (curve)
+                               *curve = p->curve;
+                       break;
+               }
+
+       if (ret == GNUTLS_PK_UNKNOWN && curve)
+               *curve = GNUTLS_PK_UNKNOWN;
+
+       return ret;
+}
+
 /* Returns the encipher type for the given key exchange algorithm.
  * That one of CIPHER_ENCRYPT, CIPHER_SIGN, CIPHER_IGN.
  *
index 5f953f2b4041320b617c1a388898d3b777e35a34..be4b19ec18b59b946a5d3b87971e2afc1525e92c 100644 (file)
@@ -127,6 +127,9 @@ static const gnutls_sign_entry_st sign_algorithms[] = {
        {"RSA-PSS-SHA512", PK_PKIX1_RSA_PSS_OID, GNUTLS_SIGN_RSA_PSS_SHA512,
         GNUTLS_PK_RSA, GNUTLS_DIG_SHA512, {{8, 6}}},
 
+        {"EdDSA-Ed25519", SIG_EDDSA_SHA512_OID, GNUTLS_SIGN_EDDSA_ED25519,
+        GNUTLS_PK_EDDSA_ED25519, GNUTLS_DIG_SHA512, {{8, 7}}},
+
        {0, 0, 0, 0, 0, TLS_SIGN_AID_UNKNOWN}
 };
 
index c79e43347ebde6e33006091ff19fc1ea1506eadd..d9b8b42eae0e3764df675634e9a5913d521a792e 100644 (file)
@@ -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)
@@ -314,7 +314,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;
index 92e3092d8df0faa140b0807d82a3803dfb63f046..07b23cb0f14b936ee9f18b071b50706979b0db0f 100644 (file)
@@ -182,7 +182,7 @@ typedef struct gnutls_x509_spki_st {
 typedef struct {
        bigint_t params[GNUTLS_MAX_PK_PARAMS];
        unsigned int params_nr; /* the number of parameters */
-       unsigned int flags;
+       unsigned int flags; /* curve */
        gnutls_datum_t raw_pub; /* used by x25519 */
        gnutls_datum_t raw_priv;
 
index 8056a9fcbaf728f3d2ff7c64d20ea0782cf39b58..fa805f2f5e31af46c6a09f903e2f847862f1a4b0 100644 (file)
@@ -706,6 +706,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_ED25519: Edwards curve Digital signature algorithm.
  *
  * Enumeration of different public-key algorithms.
  */
@@ -717,7 +718,8 @@ typedef enum {
        GNUTLS_PK_ECDSA = 4,
        GNUTLS_PK_ECDHX = 5,
        GNUTLS_PK_RSA_PSS = 6,
-       GNUTLS_PK_MAX = GNUTLS_PK_RSA_PSS
+       GNUTLS_PK_EDDSA_ED25519 = 7,
+       GNUTLS_PK_MAX = GNUTLS_PK_EDDSA_ED25519
 } gnutls_pk_algorithm_t;
 
 
@@ -761,6 +763,7 @@ const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm);
  * @GNUTLS_SIGN_RSA_PSS_SHA256: Digital signature algorithm RSA with SHA-256, with PSS padding.
  * @GNUTLS_SIGN_RSA_PSS_SHA384: Digital signature algorithm RSA with SHA-384, with PSS padding.
  * @GNUTLS_SIGN_RSA_PSS_SHA512: Digital signature algorithm RSA with SHA-512, with PSS padding.
+ * @GNUTLS_SIGN_EDDSA_ED25519: Digital signature algorithm EdDSA with Ed25519 curve.
  *
  * Enumeration of different digital signature algorithms.
  */
@@ -803,7 +806,8 @@ typedef enum {
        GNUTLS_SIGN_RSA_PSS_SHA256 = 32,
        GNUTLS_SIGN_RSA_PSS_SHA384 = 33,
        GNUTLS_SIGN_RSA_PSS_SHA512 = 34,
-       GNUTLS_SIGN_MAX = GNUTLS_SIGN_RSA_PSS_SHA512
+       GNUTLS_SIGN_EDDSA_ED25519 = 35,
+       GNUTLS_SIGN_MAX = GNUTLS_SIGN_EDDSA_ED25519
 } gnutls_sign_algorithm_t;
 
 /**
@@ -815,6 +819,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_ED25519: the Ed25519 curve
  *
  * Enumeration of ECC curves.
  */
@@ -826,7 +831,8 @@ typedef enum {
        GNUTLS_ECC_CURVE_SECP521R1,
        GNUTLS_ECC_CURVE_SECP192R1,
        GNUTLS_ECC_CURVE_X25519,
-       GNUTLS_ECC_CURVE_MAX = GNUTLS_ECC_CURVE_X25519
+       GNUTLS_ECC_CURVE_ED25519,
+       GNUTLS_ECC_CURVE_MAX = GNUTLS_ECC_CURVE_ED25519
 } gnutls_ecc_curve_t;
 
 /* macros to allow specifying a specific curve in gnutls_privkey_generate()
index b635c645fff1b5092690c06f08f4bfe344ddb495..890a92b3d3408b7b613d778ec9d0a82b56166ffa 100644 (file)
@@ -48,6 +48,7 @@
 #include <nettle/ecdsa.h>
 #include <nettle/ecc-curve.h>
 #include <nettle/curve25519.h>
+#include <nettle/eddsa.h>
 #include <gnettle.h>
 #include <fips.h>
 #ifndef HAVE_NETTLE_RSA_PSS
@@ -566,8 +567,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_ED25519:   /* we do EdDSA */
+               {
+                       const gnutls_ecc_curve_entry_st *e;
+
+                       if (pk_params->flags != GNUTLS_ECC_CURVE_ED25519)
+                               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;
@@ -809,8 +844,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_ED25519:   /* we do EdDSA */
+               {
+                       const gnutls_ecc_curve_entry_st *e;
+
+                       if (pk_params->flags != GNUTLS_ECC_CURVE_ED25519)
+                               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;
@@ -998,6 +1065,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_ED25519:
                case GNUTLS_ECC_CURVE_X25519:
                        return 1;
                default:
@@ -1008,7 +1076,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,
@@ -1121,7 +1189,8 @@ wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
                }
        case GNUTLS_PK_RSA_PSS:
        case GNUTLS_PK_RSA:
-       case GNUTLS_PK_EC:
+       case GNUTLS_PK_ECDSA:
+       case GNUTLS_PK_EDDSA_ED25519:
                break;
        default:
                gnutls_assert();
@@ -1265,13 +1334,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, 0);
+       ret = _gnutls_pk_generate_keys(GNUTLS_PK_ECDSA, curve, &params, 0);
        if (ret < 0) {
                return gnutls_assert_val(ret);
        }
@@ -1320,7 +1389,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
@@ -1367,12 +1436,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;
@@ -1462,6 +1531,7 @@ char* gen_data = NULL;
                 * signing and encryption.
                 */
        case GNUTLS_PK_EC: /* we only do keys for ECDSA */
+       case GNUTLS_PK_EDDSA_ED25519:
        case GNUTLS_PK_DSA:
        case GNUTLS_PK_RSA_PSS:
                ret = _gnutls_pk_sign(algo, &sig, &ddata, params, &params->sign);
@@ -1512,6 +1582,12 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
        unsigned rnd_level;
        nettle_random_func *rnd_func;
 
+       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);
+       }
+
        if (ephemeral) {
                rnd_level = GNUTLS_RND_RANDOM;
                rnd_func = rnd_tmpkey_func;
@@ -1718,7 +1794,44 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
 
                        break;
                }
-       case GNUTLS_PK_EC:
+       case GNUTLS_PK_EDDSA_ED25519:
+               {
+                       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_ED25519)
+                               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(rnd_level, 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);
+
+                       break;
+               }
+       case GNUTLS_PK_ECDSA:
                if (params->flags & GNUTLS_PK_FLAG_PROVABLE)
                        return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 
@@ -1810,6 +1923,8 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
        }
 #endif
 
+       params->algo = algo;
+
        FAIL_IF_LIB_ERROR;
        return 0;
 
@@ -1955,7 +2070,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;
@@ -2028,6 +2143,9 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
                        mpz_clear(y2);
                }
                break;
+       case GNUTLS_PK_EDDSA_ED25519:
+               ret = 0;
+               break;
        default:
                ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
        }
@@ -2045,8 +2163,9 @@ wrap_nettle_pk_verify_pub_params(gnutls_pk_algorithm_t algo,
        case GNUTLS_PK_RSA:
        case GNUTLS_PK_RSA_PSS:
        case GNUTLS_PK_DSA:
+       case GNUTLS_PK_EDDSA_ED25519:
                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;
@@ -2186,8 +2305,22 @@ wrap_nettle_pk_fixup(gnutls_pk_algorithm_t algo,
                if (ret == 0) {
                        return gnutls_assert_val(GNUTLS_E_PK_INVALID_PRIVKEY);
                }
+       } else if (algo == GNUTLS_PK_EDDSA_ED25519) {
+               if (params->flags != GNUTLS_ECC_CURVE_ED25519)
+                       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;
 }
 
index a09f54457674703bf7361b88dfb7747a80a844bf..350d2f1a6c2331ebeb09b467eb5f305606f50a8b 100644 (file)
--- a/lib/pk.c
+++ b/lib/pk.c
@@ -299,7 +299,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;
        }
@@ -832,6 +832,31 @@ 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;
+       }
+
+
        /* X */
        if (x) {
                ret = dprint(params->params[ECC_X], x);
@@ -926,7 +951,8 @@ pk_prepare_hash(gnutls_pk_algorithm_t pk,
                break;
        case GNUTLS_PK_RSA_PSS:
        case GNUTLS_PK_DSA:
-       case GNUTLS_PK_EC:
+       case GNUTLS_PK_ECDSA:
+       case GNUTLS_PK_EDDSA_ED25519:
                break;
        default:
                gnutls_assert();
index 40def6cff5df9817d1c40f06ccdd68148988220b..86bdff4ef80d4cbffecb9925b79f94b2544fc402 100644 (file)
@@ -354,7 +354,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;
@@ -961,7 +961,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;
@@ -980,7 +980,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);
index 7d4cbb546bdaa058d06414d2673cb05227dbf855..6dc33e9e22c7a44ce4d0e110aa419707bd17dac6 100644 (file)
 #include <abstract_int.h>
 
 static int
-privkey_sign_hash(gnutls_privkey_t signer,
+privkey_sign_prehashed(gnutls_privkey_t signer,
                  const gnutls_datum_t * hash_data,
                  gnutls_datum_t * signature,
                  gnutls_x509_spki_st * params, unsigned flags);
 
-static int
-_gnutls_privkey_sign_raw_data(gnutls_privkey_t key,
-                            const gnutls_datum_t * data,
-                            gnutls_datum_t * signature,
-                            gnutls_x509_spki_st * params);
-
 /**
  * gnutls_privkey_get_type:
  * @key: should contain a #gnutls_privkey_t type
@@ -134,10 +128,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)
@@ -191,7 +185,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]);
 
@@ -203,6 +197,12 @@ privkey_to_pubkey(gnutls_pk_algorithm_t pk,
                        goto cleanup;
                }
 
+               break;
+       case GNUTLS_PK_EDDSA_ED25519:
+               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();
@@ -1007,7 +1007,11 @@ gnutls_privkey_sign_data(gnutls_privkey_t signer,
                return ret;
        }
 
-       return privkey_sign_data(signer, data, signature, &params);
+       if (_gnutls_pk_is_not_prehashed(signer->pk_algorithm)) {
+               return privkey_sign_raw_data(signer, data, signature, &params);
+       } else {
+               return privkey_sign_and_hash_data(signer, data, signature, &params);
+       }
 }
 
 /**
@@ -1059,7 +1063,7 @@ gnutls_privkey_sign_data2(gnutls_privkey_t signer,
                return ret;
        }
 
-       return privkey_sign_data(signer, data, signature, &params);
+       return privkey_sign_and_hash_data(signer, data, signature, &params);
 }
 
 /**
@@ -1082,7 +1086,7 @@ gnutls_privkey_sign_data2(gnutls_privkey_t signer,
  * In the former case this function will ignore @hash_algo and perform a raw PKCS1 signature,
  * and in the latter an RSA-PSS signature will be generated.
  *
- * Note that, not all algorithm support signing already signed data. When
+ * Note that, not all algorithm support signing already hashed data. When
  * signing with Ed25519, gnutls_privkey_sign_data() should be used.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
@@ -1118,14 +1122,14 @@ gnutls_privkey_sign_hash2(gnutls_privkey_t signer,
                return ret;
        }
 
-       return privkey_sign_hash(signer, hash_data, signature, &params, flags);
+       return privkey_sign_prehashed(signer, hash_data, signature, &params, flags);
 }
 
 int
-privkey_sign_data(gnutls_privkey_t signer,
-                 const gnutls_datum_t * data,
-                 gnutls_datum_t * signature,
-                 gnutls_x509_spki_st * params)
+privkey_sign_and_hash_data(gnutls_privkey_t signer,
+                          const gnutls_datum_t * data,
+                          gnutls_datum_t * signature,
+                          gnutls_x509_spki_st * params)
 {
        int ret;
        gnutls_datum_t digest;
@@ -1146,7 +1150,7 @@ privkey_sign_data(gnutls_privkey_t signer,
                goto cleanup;
        }
 
-       ret = _gnutls_privkey_sign_raw_data(signer, &digest, signature, params);
+       ret = privkey_sign_raw_data(signer, &digest, signature, params);
        _gnutls_free_datum(&digest);
 
        if (ret < 0) {
@@ -1178,8 +1182,12 @@ privkey_sign_data(gnutls_privkey_t signer,
  * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine
  * the hash algorithm.
  *
- * Note that if %GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA flag is specified this function
- * will ignore @hash_algo and perform a raw PKCS1 signature.
+ * The flags may be %GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA or %GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS.
+ * In the former case this function will ignore @hash_algo and perform a raw PKCS1 signature,
+ * and in the latter an RSA-PSS signature will be generated.
+ *
+ * Note that, not all algorithm support signing already hashed data. When
+ * signing with Ed25519, gnutls_privkey_sign_data() should be used.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
  *   negative error value.
@@ -1209,11 +1217,11 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer,
                return ret;
        }
 
-       return privkey_sign_hash(signer, hash_data, signature, &params, flags);
+       return privkey_sign_prehashed(signer, hash_data, signature, &params, flags);
 }
 
 static int
-privkey_sign_hash(gnutls_privkey_t signer,
+privkey_sign_prehashed(gnutls_privkey_t signer,
                  const gnutls_datum_t * hash_data,
                  gnutls_datum_t * signature,
                  gnutls_x509_spki_st * params,
@@ -1223,9 +1231,13 @@ privkey_sign_hash(gnutls_privkey_t signer,
        gnutls_datum_t digest;
 
        if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA)
-               return _gnutls_privkey_sign_raw_data(signer,
-                                                    hash_data, signature,
-                                                    params);
+               return privkey_sign_raw_data(signer,
+                                            hash_data, signature,
+                                            params);
+
+       if (_gnutls_pk_is_not_prehashed(signer->pk_algorithm)) {
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+       }
 
        digest.data = gnutls_malloc(hash_data->size);
        if (digest.data == NULL) {
@@ -1241,9 +1253,9 @@ privkey_sign_hash(gnutls_privkey_t signer,
                goto cleanup;
        }
 
-       ret = _gnutls_privkey_sign_raw_data(signer,
-                                           &digest, signature,
-                                           params);
+       ret = privkey_sign_raw_data(signer,
+                                   &digest, signature,
+                                   params);
        if (ret < 0) {
                gnutls_assert();
                goto cleanup;
@@ -1257,7 +1269,7 @@ privkey_sign_hash(gnutls_privkey_t signer,
 }
 
 /*-
- * gnutls_privkey_sign_raw_data:
+ * privkey_sign_raw_data:
  * @key: Holds the key
  * @data: holds the data to be signed
  * @signature: will contain the signature allocated with gnutls_malloc()
@@ -1277,11 +1289,11 @@ privkey_sign_hash(gnutls_privkey_t signer,
  *
  * Since: 3.1.10
  -*/
-static int
-_gnutls_privkey_sign_raw_data(gnutls_privkey_t key,
-                            const gnutls_datum_t * data,
-                            gnutls_datum_t * signature,
-                            gnutls_x509_spki_st * params)
+int
+privkey_sign_raw_data(gnutls_privkey_t key,
+                    const gnutls_datum_t * data,
+                    gnutls_datum_t * signature,
+                    gnutls_x509_spki_st * params)
 {
        switch (key->type) {
 #ifdef ENABLE_PKCS11
index 76e9c43f39351be73addc22462176eb29798131b..8e231b1808d553542aac72482c51b51a51777d8e 100644 (file)
@@ -46,7 +46,8 @@
  *
  * This function will export the RSA 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.
  *
index fa7bccc6795702da8b02c98b1d39d4f8b23f996a..7a77c307417d3db4ac5f2ab97e8356d599c230f7 100644 (file)
@@ -46,7 +46,8 @@ unsigned 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_ED25519:
                return gnutls_ecc_curve_get_size(params->flags) * 8;
        default:
                return 0;
@@ -285,12 +286,18 @@ 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)
                        *hash = (gnutls_digest_algorithm_t)me->id;
 
+               ret = 0;
+               break;
+       case GNUTLS_PK_EDDSA_ED25519:
+               if (hash)
+                       *hash = GNUTLS_DIG_SHA512;
+
                ret = 0;
                break;
        case GNUTLS_PK_RSA:
@@ -784,6 +791,7 @@ gnutls_pubkey_export_dsa_raw2(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.
  *
@@ -834,7 +842,7 @@ gnutls_pubkey_export_ecc_raw2(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;
        }
@@ -842,6 +850,21 @@ gnutls_pubkey_export_ecc_raw2(gnutls_pubkey_t key,
        if (curve)
                *curve = key->params.flags;
 
+       if (key->pk_algorithm == GNUTLS_PK_EDDSA_ED25519) {
+               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);
+               }
+               if (y) {
+                       y->data = NULL;
+                       y->size = 0;
+               }
+               return 0;
+       }
+
+       /* ECDSA */
+
        /* X */
        if (x) {
                ret = dprint(key->params.params[ECC_X], x);
@@ -937,6 +960,7 @@ gnutls_pubkey_import(gnutls_pubkey_t key,
        int result = 0, need_free = 0;
        gnutls_datum_t _data;
        ASN1_TYPE spk;
+       gnutls_ecc_curve_t curve;
 
        if (key == NULL) {
                gnutls_assert();
@@ -986,7 +1010,9 @@ gnutls_pubkey_import(gnutls_pubkey_t key,
        /* this has already been called by get_asn_mpis() thus it cannot
         * fail.
         */
-       key->pk_algorithm = _gnutls_x509_get_pk_algorithm(spk, "", NULL);
+       key->pk_algorithm = _gnutls_x509_get_pk_algorithm(spk, "", &curve, NULL);
+
+       key->params.flags = curve;
        key->bits = pubkey_to_bits(key->pk_algorithm, &key->params);
 
        result = 0;
@@ -1256,7 +1282,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.
@@ -1279,6 +1306,20 @@ gnutls_pubkey_import_ecc_raw(gnutls_pubkey_t key,
        gnutls_pk_params_release(&key->params);
        gnutls_pk_params_init(&key->params);
 
+       if (curve_is_eddsa(curve)) {
+               ret = _gnutls_set_datum(&key->params.raw_pub, x->data, x->size);
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
+
+               key->pk_algorithm = GNUTLS_PK_EDDSA_ED25519;
+               key->params.flags = curve;
+
+               return 0;
+       }
+
+       /* ECDSA */
        key->params.flags = curve;
 
        if (_gnutls_mpi_init_scan_nz
@@ -1296,7 +1337,7 @@ gnutls_pubkey_import_ecc_raw(gnutls_pubkey_t key,
                goto cleanup;
        }
        key->params.params_nr++;
-       key->pk_algorithm = GNUTLS_PK_EC;
+       key->pk_algorithm = GNUTLS_PK_ECDSA;
 
        return 0;
 
@@ -1565,6 +1606,10 @@ gnutls_pubkey_verify_hash2(gnutls_pubkey_t key,
                return GNUTLS_E_INVALID_REQUEST;
        }
 
+       if (_gnutls_pk_is_not_prehashed(key->pk_algorithm)) {
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+       }
+
        memcpy(&params, &key->params.sign, sizeof(gnutls_x509_spki_st));
 
        if (flags & OLD_PUBKEY_VERIFY_FLAG_TLS1_RSA || flags & GNUTLS_VERIFY_USE_TLS1_RSA) {
@@ -1866,7 +1911,7 @@ pubkey_verify_hashed_data(gnutls_pk_algorithm_t pk,
                return 1;
                break;
 
-       case GNUTLS_PK_EC:
+       case GNUTLS_PK_ECDSA:
        case GNUTLS_PK_DSA:
                if (dsa_verify_hashed_data
                    (pk, hash_algo, hash, signature, params, sign_params) != 0) {
@@ -1878,7 +1923,7 @@ pubkey_verify_hashed_data(gnutls_pk_algorithm_t pk,
                break;
        default:
                gnutls_assert();
-               return GNUTLS_E_INTERNAL_ERROR;
+               return GNUTLS_E_INVALID_REQUEST;
 
        }
 }
@@ -1906,6 +1951,15 @@ pubkey_verify_data(gnutls_pk_algorithm_t pk,
                return 1;
                break;
 
+       case GNUTLS_PK_EDDSA_ED25519:
+               if (_gnutls_pk_verify(pk, data, signature, params, sign_params) != 0) {
+                       gnutls_assert();
+                       return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+               }
+
+               return 1;
+               break;
+
        case GNUTLS_PK_EC:
        case GNUTLS_PK_DSA:
                if (dsa_verify_data
@@ -1918,7 +1972,7 @@ pubkey_verify_data(gnutls_pk_algorithm_t pk,
                break;
        default:
                gnutls_assert();
-               return GNUTLS_E_INTERNAL_ERROR;
+               return GNUTLS_E_INVALID_REQUEST;
 
        }
 }
index a07b0ec5ed66aae7c68f3a0f10ed53bb0931f1ea..b1be062c54a8b245597076edd31564940070a30f 100644 (file)
@@ -1036,13 +1036,13 @@ _gnutls_x509_encode_and_copy_PKI_params(ASN1_TYPE dst,
                                        pk_algorithm,
                                        gnutls_pk_params_st * params)
 {
-       const char *pk;
+       const char *oid;
        gnutls_datum_t der = { NULL, 0 };
        int result;
        char name[128];
 
-       pk = gnutls_pk_get_oid(pk_algorithm);
-       if (pk == NULL) {
+       oid = gnutls_pk_get_oid(pk_algorithm);
+       if (oid == NULL) {
                gnutls_assert();
                return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
        }
@@ -1052,7 +1052,7 @@ _gnutls_x509_encode_and_copy_PKI_params(ASN1_TYPE dst,
        _asnstr_append_name(name, sizeof(name), dst_name,
                            ".algorithm.algorithm");
 
-       result = asn1_write_value(dst, name, pk, 1);
+       result = asn1_write_value(dst, name, oid, 1);
        if (result != ASN1_SUCCESS) {
                gnutls_assert();
                return _gnutls_asn2err(result);
@@ -1141,17 +1141,16 @@ _gnutls_x509_encode_PKI_params(gnutls_datum_t * der,
  */
 int
 _gnutls_x509_get_pk_algorithm(ASN1_TYPE src, const char *src_name,
+                             gnutls_ecc_curve_t *curve,
                              unsigned int *bits)
 {
        int result;
        int algo;
        char oid[64];
        int len;
-       gnutls_pk_params_st params;
+       gnutls_ecc_curve_t lcurve = GNUTLS_ECC_CURVE_INVALID;
        char name[128];
 
-       gnutls_pk_params_init(&params);
-
        _asnstr_append_name(name, sizeof(name), src_name,
                            ".algorithm.algorithm");
        len = sizeof(oid);
@@ -1162,26 +1161,36 @@ _gnutls_x509_get_pk_algorithm(ASN1_TYPE src, const char *src_name,
                return _gnutls_asn2err(result);
        }
 
-       algo = gnutls_oid_to_pk(oid);
+       algo = _gnutls_oid_to_pk_and_curve(oid, &lcurve);
        if (algo == GNUTLS_PK_UNKNOWN) {
                _gnutls_debug_log
                    ("%s: unknown public key algorithm: %s\n", __func__,
                     oid);
        }
 
+       if (curve)
+               *curve = lcurve;
+
        if (bits == NULL) {
                return algo;
        }
 
        /* Now read the parameters' bits 
         */
-       result = _gnutls_get_asn_mpis(src, src_name, &params);
-       if (result < 0)
-               return gnutls_assert_val(result);
+       if (lcurve != GNUTLS_ECC_CURVE_INVALID) { /* curve present */
+               bits[0] = gnutls_ecc_curve_get_size(lcurve)*8;
+       } else {
+               gnutls_pk_params_st params;
+               gnutls_pk_params_init(&params);
 
-       bits[0] = pubkey_to_bits(algo, &params);
+               result = _gnutls_get_asn_mpis(src, src_name, &params);
+               if (result < 0)
+                       return gnutls_assert_val(result);
+
+               bits[0] = pubkey_to_bits(algo, &params);
+               gnutls_pk_params_release(&params);
+       }
 
-       gnutls_pk_params_release(&params);
        return algo;
 }
 
index 6d80b819b8d90d35d18c751c2901b1cd7e14b87c..34e6d5b5debf781d25296105711fc57e755aee70 100644 (file)
@@ -88,6 +88,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.112"
+
 #define XMPP_OID "1.3.6.1.5.5.7.8.5"
 #define KRB5_PRINCIPAL_OID "1.3.6.1.5.2.2"
 #define PKIX1_RSA_PSS_MGF1_OID "1.2.840.113549.1.1.8"
@@ -165,6 +167,7 @@ int _gnutls_x509_decode_and_read_attribute(ASN1_TYPE asn1_struct,
                                           int multi, int octet);
 
 int _gnutls_x509_get_pk_algorithm(ASN1_TYPE src, const char *src_name,
+                                 gnutls_ecc_curve_t *curve,
                                  unsigned int *bits);
 
 int
index 2e53bfadb3dbf5e1f2e1a85e08bac0abea1696ef..0f91278b4ec358aa6e3c59566126d52dd9cd46d3 100644 (file)
@@ -1314,7 +1314,7 @@ gnutls_x509_crq_get_pk_algorithm2(gnutls_x509_crq_t crq,
        }
 
        result = _gnutls_x509_get_pk_algorithm
-           (crq->crq, "certificationRequestInfo.subjectPKInfo", bits);
+           (crq->crq, "certificationRequestInfo.subjectPKInfo", NULL, bits);
        if (result < 0) {
                gnutls_assert();
                return result;
@@ -2862,7 +2862,7 @@ gnutls_x509_crq_privkey_sign(gnutls_x509_crq_t crq, gnutls_privkey_t key,
                return result;
        }
 
-       result = privkey_sign_data(key, &tbs, &signature, &params);
+       result = privkey_sign_and_hash_data(key, &tbs, &signature, &params);
        gnutls_free(tbs.data);
 
        if (result < 0) {
index 5db6d9ebf027c839b7c61d804b91521d63ce7cf6..a9b59d125bdb77693ec9953892f79ce59de47449 100644 (file)
@@ -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,11 @@ _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);
+}
 
 /* reads p,q and g 
  * from the certificate (subjectPublicKey BIT STRING).
@@ -398,13 +405,16 @@ int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t * der,
                        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->algo = GNUTLS_PK_ECDSA;
                        params->params_nr = ECC_PUBLIC_PARAMS;
                }
                break;
+       case GNUTLS_PK_EDDSA_ED25519:
+               ret = _gnutls_x509_read_eddsa_pubkey(der, dersize, params);
+               break;
        default:
                ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
                break;
@@ -420,6 +430,7 @@ int _gnutls_x509_read_pubkey_params(gnutls_pk_algorithm_t algo,
 {
        switch (algo) {
        case GNUTLS_PK_RSA:
+       case GNUTLS_PK_EDDSA_ED25519:
                return 0;
        case GNUTLS_PK_RSA_PSS:
                return _gnutls_x509_read_rsa_pss_params(der, dersize, &params->sign);
@@ -453,7 +464,8 @@ int _gnutls_x509_check_pubkey_params(gnutls_pk_algorithm_t algo,
        }
        case GNUTLS_PK_RSA:
        case GNUTLS_PK_DSA:
-       case GNUTLS_PK_EC:
+       case GNUTLS_PK_ECDSA:
+       case GNUTLS_PK_EDDSA_ED25519:
                return 0;
        default:
                return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
index af5e5be5a7ddb0a92d7b54352bd982f9b042f875..58b1362c58e45bbf8a37b852a3550736067f6eb2 100644 (file)
@@ -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_ED25519)
+               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,
@@ -146,8 +174,13 @@ _gnutls_x509_write_pubkey_params(gnutls_pk_algorithm_t algo,
                return 0;
        case GNUTLS_PK_RSA_PSS:
                return _gnutls_x509_write_rsa_pss_params(&params->sign, der);
-       case GNUTLS_PK_EC:
+       case GNUTLS_PK_ECDSA:
                return _gnutls_x509_write_ecc_params(params->flags, der);
+       case GNUTLS_PK_EDDSA_ED25519:
+               der->data = NULL;
+               der->size = 0;
+
+               return 0;
        default:
                return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
        }
@@ -164,8 +197,10 @@ _gnutls_x509_write_pubkey(gnutls_pk_algorithm_t algo,
        case GNUTLS_PK_RSA:
        case GNUTLS_PK_RSA_PSS:
                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_ED25519:
+               return _gnutls_x509_write_eddsa_pubkey(params, der);
        default:
                return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
        }
@@ -615,20 +650,9 @@ _gnutls_asn1_encode_ecc(ASN1_TYPE * c2, gnutls_pk_params_st * params)
        const char *oid;
 
        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_x962_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);
@@ -650,20 +674,50 @@ _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);
+               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;
+               }
 
-       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, "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_x962_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 */
@@ -799,7 +853,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_ED25519:
                return _gnutls_asn1_encode_ecc(c2, params);
        default:
                return GNUTLS_E_UNIMPLEMENTED_FEATURE;
index bd47d3244ce5e324b03d0fce22a4b1e1365b8590..384e6e9fda9a0f561f05b20502c20ef8ab34adc7 100644 (file)
@@ -114,16 +114,18 @@ _gnutls_get_asn_mpis(ASN1_TYPE asn, const char *root,
        char name[256];
        gnutls_datum_t tmp = { NULL, 0 };
        gnutls_pk_algorithm_t pk_algorithm;
+       gnutls_ecc_curve_t curve;
 
        gnutls_pk_params_init(params);
 
-       result = _gnutls_x509_get_pk_algorithm(asn, root, NULL);
+       result = _gnutls_x509_get_pk_algorithm(asn, root, &curve, NULL);
        if (result < 0) {
                gnutls_assert();
                return result;
        }
 
        pk_algorithm = result;
+       params->flags = curve;
 
        /* Read the algorithm's parameters
         */
@@ -132,9 +134,10 @@ _gnutls_get_asn_mpis(ASN1_TYPE asn, const char *root,
 
        /* FIXME: If the parameters are not included in the certificate
         * then the issuer's parameters should be used. This is not
-        * done yet.
+        * needed in practice though.
         */
-       if (pk_algorithm != GNUTLS_PK_RSA) { /* RSA doesn't use parameters */
+       if (pk_algorithm != GNUTLS_PK_RSA && pk_algorithm != GNUTLS_PK_EDDSA_ED25519 && pk_algorithm != GNUTLS_PK_ECDHX) {
+               /* RSA and EdDSA do not use parameters */
                result = _gnutls_x509_read_value(asn, name, &tmp);
                if (result < 0) {
                        gnutls_assert();
index 93eed2e57e7bc65d16a0046dff4c6a38ba500ac7..b12c4890e4b92c716733971fea2cc880f8705ce9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007-2016 Free Software Foundation, Inc.
- * Copyright (C) 2015-2016 Red Hat, Inc.
+ * Copyright (C) 2015-2017 Red Hat, Inc.
  *
  * Author: Simon Josefsson, Nikos Mavrogiannopoulos
  *
@@ -1279,7 +1279,8 @@ print_pubkey(gnutls_buffer_st * str, const char *key_name,
                }
                break;
 
-       case GNUTLS_PK_EC:
+       case GNUTLS_PK_EDDSA_ED25519:
+       case GNUTLS_PK_ECDSA:
                {
                        gnutls_datum_t x, y;
                        gnutls_ecc_curve_t curve;
@@ -1287,10 +1288,10 @@ print_pubkey(gnutls_buffer_st * str, const char *key_name,
                        err =
                            gnutls_pubkey_get_pk_ecc_raw(pubkey, &curve,
                                                         &x, &y);
-                       if (err < 0)
+                       if (err < 0) {
                                addf(str, "error: get_pk_ecc_raw: %s\n",
                                     gnutls_strerror(err));
-                       else {
+                       else {
                                addf(str, _("\t\tCurve:\t%s\n"),
                                     gnutls_ecc_curve_get_name(curve));
                                if (format ==
@@ -1300,20 +1301,24 @@ print_pubkey(gnutls_buffer_st * str, const char *key_name,
                                                                x.data,
                                                                x.size);
                                        adds(str, "\n");
-                                       adds(str, _("\t\tY: "));
-                                       _gnutls_buffer_hexprint(str,
-                                                               y.data,
-                                                               y.size);
-                                       adds(str, "\n");
+                                       if (y.size > 0) {
+                                               adds(str, _("\t\tY: "));
+                                               _gnutls_buffer_hexprint(str,
+                                                                       y.data,
+                                                                       y.size);
+                                               adds(str, "\n");
+                                       }
                                } else {
                                        adds(str, _("\t\tX:\n"));
                                        _gnutls_buffer_hexdump(str, x.data,
                                                               x.size,
                                                               "\t\t\t");
-                                       adds(str, _("\t\tY:\n"));
-                                       _gnutls_buffer_hexdump(str, y.data,
-                                                              y.size,
-                                                              "\t\t\t");
+                                       if (y.size > 0) {
+                                               adds(str, _("\t\tY:\n"));
+                                               _gnutls_buffer_hexdump(str, y.data,
+                                                                      y.size,
+                                                                      "\t\t\t");
+                                       }
                                }
 
                                gnutls_free(x.data);
@@ -1753,7 +1758,7 @@ static void print_keyid(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
 
        print_obj_id(str, "\t", cert, (get_id_func*)gnutls_x509_crt_get_key_id);
 
-       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);
index 2812b7f89d6f0be73425f2b38cd91f4ff628a254..b8670c8134b24e0a61fc3d303541360ce5f552bf 100644 (file)
@@ -2536,7 +2536,7 @@ int gnutls_pkcs7_sign(gnutls_pkcs7_t pkcs7,
                goto cleanup;
        }
 
-       ret = privkey_sign_data(signer_key, &sigdata, &signature, &params);
+       ret = privkey_sign_and_hash_data(signer_key, &sigdata, &signature, &params);
        if (ret < 0) {
                gnutls_assert();
                goto cleanup;
index b82d6d52369d50d6cf9ca2cceea11fb94200db39..7ecdab01296a8e2ce37bf0eaa7ffa9acabcdfbb7 100644 (file)
@@ -267,6 +267,10 @@ _gnutls_privkey_decode_ecc_key(ASN1_TYPE* pkey_asn, const gnutls_datum_t * raw_k
        int oid_size;
        gnutls_datum_t out;
 
+       if (curve_is_eddsa(curve)) {
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+       }
+
        gnutls_pk_params_init(&pkey->params);
 
        if ((ret =
@@ -1102,7 +1106,7 @@ gnutls_x509_privkey_import_dsa_raw(gnutls_x509_privkey_t key,
  *
  * This function will convert the given elliptic curve parameters to the
  * native #gnutls_x509_privkey_t format.  The output will be stored
- * in @key.
+ * in @key. For EdDSA keys, the @x and @k values will be read.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
  *   negative error value.
@@ -1125,6 +1129,26 @@ 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_ED25519;
+
+               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;
+               }
+
+               key->pk_algorithm = key->params.algo;
+
+               return 0;
+       }
+
        if (_gnutls_mpi_init_scan_nz
            (&key->params.params[ECC_X], x->data, x->size)) {
                gnutls_assert();
@@ -1149,6 +1173,8 @@ gnutls_x509_privkey_import_ecc_raw(gnutls_x509_privkey_t key,
        }
        key->params.params_nr++;
 
+       key->params.algo = key->pk_algorithm = GNUTLS_PK_EC;
+
        ret =
            _gnutls_pk_fixup(GNUTLS_PK_EC, GNUTLS_IMPORT, &key->params);
        if (ret < 0) {
@@ -1156,9 +1182,6 @@ gnutls_x509_privkey_import_ecc_raw(gnutls_x509_privkey_t key,
                goto cleanup;
        }
 
-       key->pk_algorithm = GNUTLS_PK_EC;
-       key->params.algo = key->pk_algorithm;
-
        return 0;
 
       cleanup:
@@ -1388,6 +1411,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.
@@ -1574,11 +1598,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) {
index 827794bec22bd3332eb5c573446ed0afea402d78..620357110f7e293f231f8e44358281d062d18b5d 100644 (file)
@@ -66,9 +66,19 @@ _encode_privkey(gnutls_x509_privkey_t pkey, gnutls_datum_t * raw)
        ASN1_TYPE spk = ASN1_TYPE_EMPTY;
 
        switch (pkey->pk_algorithm) {
+       case GNUTLS_PK_EDDSA_ED25519:
+               /* we encode as octet string (which is going to be stored inside
+                * another octet string). No comments. */
+               ret = _gnutls_x509_encode_string(ASN1_ETYPE_OCTET_STRING,
+                                        pkey->params.raw_priv.data, pkey->params.raw_priv.size,
+                                        raw);
+               if (ret < 0)
+                       gnutls_assert();
+               return ret;
+
        case GNUTLS_PK_RSA:
        case GNUTLS_PK_RSA_PSS:
-       case GNUTLS_PK_EC:
+       case GNUTLS_PK_ECDSA:
                ret =
                    gnutls_x509_privkey_export2(pkey, GNUTLS_X509_FMT_DER,
                                                raw);
@@ -999,6 +1009,7 @@ _decode_pkcs8_ecc_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
        if (result == ASN1_SUCCESS) {
                ret = _gnutls_x509_read_ecc_params(oid, len, &curve);
                if (ret < 0) {
+                       _gnutls_debug_log("PKCS#8: unknown curve OID %s\n", oid);
                        curve = GNUTLS_ECC_CURVE_INVALID;
                }
        }
@@ -1023,6 +1034,41 @@ _decode_pkcs8_ecc_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey)
        return ret;
 }
 
+static int
+_decode_pkcs8_eddsa_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey, const char *oid)
+{
+       int ret;
+       gnutls_datum_t tmp;
+       gnutls_ecc_curve_t curve = GNUTLS_ECC_CURVE_INVALID;
+       const gnutls_ecc_curve_entry_st *ce;
+
+       curve = gnutls_oid_to_ecc_curve(oid);
+       if (curve == GNUTLS_ECC_CURVE_INVALID) {
+               _gnutls_debug_log("PKCS#8: unknown curve OID %s\n", oid);
+               return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+       }
+
+       ce = _gnutls_ecc_curve_get_params(curve);
+       if (_curve_is_eddsa(ce)) {
+               ret = _gnutls_x509_read_string(pkcs8_asn, "privateKey", &tmp, ASN1_ETYPE_OCTET_STRING, 1);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return gnutls_assert_val(ret);
+               }
+
+               gnutls_free(pkey->params.raw_priv.data);
+               pkey->params.algo = GNUTLS_PK_EDDSA_ED25519;
+               pkey->params.raw_priv.data = tmp.data;
+               pkey->params.raw_priv.size = tmp.size;
+               pkey->params.flags = curve;
+
+               tmp.data = NULL;
+               return 0;
+       } else {
+               return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+       }
+}
+
 /* Decodes an DSA privateKey and params from a PKCS8 structure.
  */
 static int
@@ -1157,17 +1203,25 @@ decode_private_key_info(const gnutls_datum_t * der,
        /* Get the DER encoding of the actual private key.
         */
 
-       if (pkey->pk_algorithm == GNUTLS_PK_RSA)
-               result = _decode_pkcs8_rsa_key(pkcs8_asn, pkey);
-       else if (pkey->pk_algorithm == GNUTLS_PK_RSA_PSS)
-               result = _decode_pkcs8_rsa_pss_key(pkcs8_asn, pkey);
-       else if (pkey->pk_algorithm == GNUTLS_PK_DSA)
-               result = _decode_pkcs8_dsa_key(pkcs8_asn, pkey);
-       else if (pkey->pk_algorithm == GNUTLS_PK_EC)
-               result = _decode_pkcs8_ecc_key(pkcs8_asn, pkey);
-       else {
-               result = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
-               goto error;
+       switch(pkey->pk_algorithm) {
+               case GNUTLS_PK_RSA:
+                       result = _decode_pkcs8_rsa_key(pkcs8_asn, pkey);
+                       break;
+               case GNUTLS_PK_RSA_PSS:
+                       result = _decode_pkcs8_rsa_pss_key(pkcs8_asn, pkey);
+                       break;
+               case GNUTLS_PK_DSA:
+                       result = _decode_pkcs8_dsa_key(pkcs8_asn, pkey);
+                       break;
+               case GNUTLS_PK_ECDSA:
+                       result = _decode_pkcs8_ecc_key(pkcs8_asn, pkey);
+                       break;
+               case GNUTLS_PK_EDDSA_ED25519:
+                       result = _decode_pkcs8_eddsa_key(pkcs8_asn, pkey, oid);
+                       break;
+               default:
+                       result = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
+                       goto error;
        }
 
        if (result < 0) {
index 20387d8826f875978fabbda6c3a80aa6c52856f5..dd688ea9abeee8100c62cceceabff8ed89a00400 100644 (file)
@@ -168,7 +168,11 @@ _gnutls_x509_pkix_sign(ASN1_TYPE src, const char *src_name,
                return result;
        }
 
-       result = privkey_sign_data(issuer_key, &tbs, &signature, &params);
+       if (_gnutls_pk_is_not_prehashed(issuer_key->pk_algorithm)) {
+               result = privkey_sign_raw_data(issuer_key, &tbs, &signature, &params);
+       } else {
+               result = privkey_sign_and_hash_data(issuer_key, &tbs, &signature, &params);
+       }
        gnutls_free(tbs.data);
 
        if (result < 0) {
index f346c93b3b7533ecf920003ea48155f112435173..f779cd97b469b5dd9fe5e54bf51a565fc5b541ce 100644 (file)
@@ -1592,6 +1592,7 @@ gnutls_x509_crt_get_pk_algorithm2(gnutls_x509_crt_t cert,
        result =
            _gnutls_x509_get_pk_algorithm(cert->cert,
                                          "tbsCertificate.subjectPublicKeyInfo",
+                                         NULL,
                                          bits);
 
        if (result < 0) {
@@ -3019,6 +3020,7 @@ gnutls_x509_crt_get_key_id(gnutls_x509_crt_t crt, unsigned int flags,
                return pk;
        }
 
+       /* initializes params */
        ret = _gnutls_x509_crt_get_mpis(crt, &params);
        if (ret < 0) {
                gnutls_assert();
index 13cbc96e4b008637fcc797307527af5b20e360d0..6160a50e0cfbbb8a207bcf914d3eb6cfe1510ae4 100644 (file)
@@ -244,6 +244,11 @@ 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);
@@ -342,6 +347,9 @@ 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_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,
index e2d29090af69fd7fbe3a3957344a162b7dc7cb9a..edc5aa3ff4d650fe20cb2d89d06807955bc7f3d6 100644 (file)
@@ -436,6 +436,12 @@ flag = {
     aliases   = ecc;
 };
 
+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      = rsa-pss;
     descrip   = "Generate RSA-PSS key or certificate";
index 24530245678f3d6b902265540acc4de025b95aa4..6ab22384293f919f14935b16f5b0af10f9047c16 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003-2016 Free Software Foundation, Inc.
- * Copyright (C) 2015-2016 Red Hat, Inc.
+ * Copyright (C) 2015-2017 Red Hat, Inc.
  *
  * This file is part of GnuTLS.
  *
@@ -891,14 +891,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);
+       }
 }
 
 
@@ -1197,7 +1203,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_ECDSA || key_type == GNUTLS_PK_EDDSA_ED25519) {
                gnutls_datum_t y, x, k;
                gnutls_ecc_curve_t curve;
 
@@ -1264,11 +1270,14 @@ print_private_key(FILE *outfile, common_info_st * cinfo, gnutls_x509_privkey_t k
        if (!key)
                return;
 
+       /* Only print private key parameters when an unencrypted
+        * format is used */
+       if (cinfo->outcert_format == GNUTLS_X509_FMT_PEM)
+               privkey_info_int(outfile, cinfo, key);
+
+       switch_to_pkcs8_when_needed(cinfo, gnutls_x509_privkey_get_pk_algorithm(key));
+
        if (!cinfo->pkcs8) {
-               /* Only print private key parameters when an unencrypted
-                * format is used */
-               if (cinfo->outcert_format == GNUTLS_X509_FMT_PEM)
-                       privkey_info_int(outfile, cinfo, key);
 
                size = lbuffer_size;
                ret = gnutls_x509_privkey_export(key, cinfo->outcert_format,
index 16c3c53dfae34a4eaef01fdd396eacbf46b9e2c4..a4a8b5e085c1fa4f2e36d3eb9b5542b9a9be7483 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2003-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
  *
  * This file is part of GnuTLS.
  *
@@ -79,6 +80,18 @@ typedef struct common_info {
        unsigned sort_chain;
 } common_info_st;
 
+static inline
+void switch_to_pkcs8_when_needed(common_info_st *cinfo, unsigned key_type)
+{
+       if ((key_type == GNUTLS_PK_RSA_PSS || key_type == GNUTLS_PK_EDDSA_ED25519) && !cinfo->pkcs8) {
+               fprintf(stderr, "Assuming --pkcs8 is given; %s private keys can only be exported in PKCS#8 format\n",
+                       gnutls_pk_algorithm_get_name(key_type));
+               cinfo->pkcs8 = 1;
+               if (cinfo->password == NULL)
+                       cinfo->password = "";
+       }
+}
+
 /* this must be provided by the app */
 const char *get_pass(void);
 const char *get_confirmed_pass(bool empty_ok);
index abaac83d626cf8696f83e128b385d0ca089f25f3..4ba3fae775a43f0027579547eb1ceac931d18cf5 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2003-2016 Free Software Foundation, Inc.
- * Copyright (C) 2015-2016 Red Hat, Inc.
+ * Copyright (C) 2015-2017 Red Hat, Inc.
  *
  * This file is part of GnuTLS.
  *
@@ -128,11 +128,6 @@ int main(int argc, char **argv)
        return 0;
 }
 
-#define ENABLE_PKCS8(cinfo) \
-               cinfo->pkcs8 = 1; \
-               if (!HAVE_OPT(PASSWORD) && cinfo->password == NULL) \
-                       cinfo->password = ""
-
 static gnutls_x509_privkey_t
 generate_private_key_int(common_info_st * cinfo)
 {
@@ -151,22 +146,23 @@ generate_private_key_int(common_info_st * cinfo)
 
        bits = get_bits(key_type, cinfo->bits, cinfo->sec_param, 1);
 
-       if (key_type == GNUTLS_PK_RSA_PSS && !cinfo->pkcs8) {
-               fprintf(stderr, "Assuming --pkcs8 is given; RSA-PSS private keys can only be exported in PKCS#8 format\n");
-               ENABLE_PKCS8(cinfo);
-       }
+       switch_to_pkcs8_when_needed(cinfo, key_type);
 
-       if (key_type == GNUTLS_PK_EC) {
+       if (key_type == GNUTLS_PK_ECDSA || key_type == GNUTLS_PK_EDDSA_ED25519) {
+               char name[64];
                int ecc_bits;
 
                if (GNUTLS_BITS_ARE_CURVE(bits)) {
                        gnutls_ecc_curve_t curve = GNUTLS_BITS_TO_CURVE(bits);
                        ecc_bits = gnutls_ecc_curve_get_size(curve) * 8;
+                       snprintf(name, sizeof(name), "(%s)", gnutls_ecc_curve_get_name(curve));
                } else {
                        ecc_bits = bits;
+                       name[0] = 0;
                }
-               fprintf(stdlog, "Generating a %d bit %s private key...\n",
-                       ecc_bits, gnutls_pk_algorithm_get_name(key_type));
+
+               fprintf(stdlog, "Generating a %d bit %s private key %s...\n",
+                       ecc_bits, gnutls_pk_algorithm_get_name(key_type), name);
 
                if (ecc_bits < 256)
                        fprintf(stderr,
@@ -1182,7 +1178,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_ED25519;
        else if (HAVE_OPT(RSA_PSS))
                req_key_type = GNUTLS_PK_RSA_PSS;
        else