summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-05-26 15:20:38 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-07-17 17:08:01 +0200
commit650dad4e18f458f60a2cdb43be32356753ed6518 (patch)
tree308661634af506842f12c709f3ab669d6be1cd7c
parentf7bc8c6eea0f0fc9d02cfd22fe9fea364061ee37 (diff)
downloadgnutls-650dad4e18f458f60a2cdb43be32356753ed6518.tar.gz
Added support for EdDSA (Ed25519) curve keys
This adds support for draft-ietf-curdle-pkix-04. Resolves #25 Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/abstract_int.h13
-rw-r--r--lib/algorithms.h28
-rw-r--r--lib/algorithms/ecc.c21
-rw-r--r--lib/algorithms/publickey.c97
-rw-r--r--lib/algorithms/sign.c3
-rw-r--r--lib/auth/ecdhe.c5
-rw-r--r--lib/crypto-backend.h2
-rw-r--r--lib/includes/gnutls/gnutls.h.in12
-rw-r--r--lib/nettle/pk.c157
-rw-r--r--lib/pk.c30
-rw-r--r--lib/pkcs11_privkey.c6
-rw-r--r--lib/privkey.c86
-rw-r--r--lib/privkey_raw.c3
-rw-r--r--lib/pubkey.c72
-rw-r--r--lib/x509/common.c35
-rw-r--r--lib/x509/common.h3
-rw-r--r--lib/x509/crq.c4
-rw-r--r--lib/x509/key_decode.c16
-rw-r--r--lib/x509/key_encode.c111
-rw-r--r--lib/x509/mpi.c9
-rw-r--r--lib/x509/output.c33
-rw-r--r--lib/x509/pkcs7.c2
-rw-r--r--lib/x509/privkey.c41
-rw-r--r--lib/x509/privkey_pkcs8.c78
-rw-r--r--lib/x509/sign.c6
-rw-r--r--lib/x509/x509.c2
-rw-r--r--lib/x509/x509_int.h8
-rw-r--r--src/certtool-args.def6
-rw-r--r--src/certtool-common.c31
-rw-r--r--src/certtool-common.h13
-rw-r--r--src/certtool.c26
31 files changed, 757 insertions, 202 deletions
diff --git a/lib/abstract_int.h b/lib/abstract_int.h
index b3a0131eae..f82e4f922a 100644
--- a/lib/abstract_int.h
+++ b/lib/abstract_int.h
@@ -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,
diff --git a/lib/algorithms.h b/lib/algorithms.h
index 623758fb6e..f449f8bf0b 100644
--- a/lib/algorithms.h
+++ b/lib/algorithms.h
@@ -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 ||
diff --git a/lib/algorithms/ecc.c b/lib/algorithms/ecc.c
index 5274a815cb..c59099747e 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 = "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;
}
diff --git a/lib/algorithms/publickey.c b/lib/algorithms/publickey.c
index cbdd0d64fc..a75feddf0d 100644
--- a/lib/algorithms/publickey.c
+++ b/lib/algorithms/publickey.c
@@ -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.
*
diff --git a/lib/algorithms/sign.c b/lib/algorithms/sign.c
index 5f953f2b40..be4b19ec18 100644
--- a/lib/algorithms/sign.c
+++ b/lib/algorithms/sign.c
@@ -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}
};
diff --git a/lib/auth/ecdhe.c b/lib/auth/ecdhe.c
index c79e43347e..d9b8b42eae 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)
@@ -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;
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index 92e3092d8d..07b23cb0f1 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -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;
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 8056a9fcba..fa805f2f5e 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -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()
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index b635c645ff..890a92b3d3 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -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;
}
diff --git a/lib/pk.c b/lib/pk.c
index a09f544576..350d2f1a6c 100644
--- 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();
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
index 40def6cff5..86bdff4ef8 100644
--- a/lib/pkcs11_privkey.c
+++ b/lib/pkcs11_privkey.c
@@ -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);
diff --git a/lib/privkey.c b/lib/privkey.c
index 7d4cbb546b..6dc33e9e22 100644
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -38,17 +38,11 @@
#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]);
@@ -204,6 +198,12 @@ privkey_to_pubkey(gnutls_pk_algorithm_t pk,
}
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();
return GNUTLS_E_INVALID_REQUEST;
@@ -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
diff --git a/lib/privkey_raw.c b/lib/privkey_raw.c
index 76e9c43f39..8e231b1808 100644
--- a/lib/privkey_raw.c
+++ b/lib/privkey_raw.c
@@ -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.
*
diff --git a/lib/pubkey.c b/lib/pubkey.c
index fa7bccc679..7a77c30741 100644
--- a/lib/pubkey.c
+++ b/lib/pubkey.c
@@ -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,7 +286,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)
@@ -293,6 +294,12 @@ gnutls_pubkey_get_preferred_hash_algorithm(gnutls_pubkey_t key,
ret = 0;
break;
+ case GNUTLS_PK_EDDSA_ED25519:
+ if (hash)
+ *hash = GNUTLS_DIG_SHA512;
+
+ ret = 0;
+ break;
case GNUTLS_PK_RSA:
case GNUTLS_PK_RSA_PSS:
if (hash)
@@ -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;
}
}
diff --git a/lib/x509/common.c b/lib/x509/common.c
index a07b0ec5ed..b1be062c54 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -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;
}
diff --git a/lib/x509/common.h b/lib/x509/common.h
index 6d80b819b8..34e6d5b5de 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -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
diff --git a/lib/x509/crq.c b/lib/x509/crq.c
index 2e53bfadb3..0f91278b4e 100644
--- a/lib/x509/crq.c
+++ b/lib/x509/crq.c
@@ -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) {
diff --git a/lib/x509/key_decode.c b/lib/x509/key_decode.c
index 5db6d9ebf0..a9b59d125b 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,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);
diff --git a/lib/x509/key_encode.c b/lib/x509/key_encode.c
index af5e5be5a7..58b1362c58 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_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;
diff --git a/lib/x509/mpi.c b/lib/x509/mpi.c
index bd47d3244c..384e6e9fda 100644
--- a/lib/x509/mpi.c
+++ b/lib/x509/mpi.c
@@ -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();
diff --git a/lib/x509/output.c b/lib/x509/output.c
index 93eed2e57e..b12c4890e4 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -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);
diff --git a/lib/x509/pkcs7.c b/lib/x509/pkcs7.c
index 2812b7f89d..b8670c8134 100644
--- a/lib/x509/pkcs7.c
+++ b/lib/x509/pkcs7.c
@@ -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;
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index b82d6d5236..7ecdab0129 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -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) {
diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c
index 827794bec2..620357110f 100644
--- a/lib/x509/privkey_pkcs8.c
+++ b/lib/x509/privkey_pkcs8.c
@@ -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) {
diff --git a/lib/x509/sign.c b/lib/x509/sign.c
index 20387d8826..dd688ea9ab 100644
--- a/lib/x509/sign.c
+++ b/lib/x509/sign.c
@@ -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) {
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index f346c93b3b..f779cd97b4 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -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();
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 13cbc96e4b..6160a50e0c 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -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,
diff --git a/src/certtool-args.def b/src/certtool-args.def
index e2d29090af..edc5aa3ff4 100644
--- a/src/certtool-args.def
+++ b/src/certtool-args.def
@@ -437,6 +437,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 = rsa-pss;
descrip = "Generate RSA-PSS key or certificate";
doc = "This option can be combined with --generate-privkey or --generate-certificate, to generate private key or certificate restricted to the use with the RSA-PSS padding scheme.";
diff --git a/src/certtool-common.c b/src/certtool-common.c
index 2453024567..6ab2238429 100644
--- a/src/certtool-common.c
+++ b/src/certtool-common.c
@@ -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,
diff --git a/src/certtool-common.h b/src/certtool-common.h
index 16c3c53dfa..a4a8b5e085 100644
--- a/src/certtool-common.h
+++ b/src/certtool-common.h
@@ -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);
diff --git a/src/certtool.c b/src/certtool.c
index abaac83d62..4ba3fae775 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -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