This adds support for draft-ietf-curdle-pkix-04.
Resolves #25
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
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,
/*
* Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
#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)
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;
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;
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 ||
.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}
};
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;
}
* 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;
}
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) \
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
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.
*
{"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}
};
{
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)
_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;
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;
* @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.
*/
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;
* @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.
*/
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;
/**
* @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.
*/
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()
#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
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;
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;
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:
/* 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,
}
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();
gnutls_pk_params_init(¶ms);
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, ¶ms, 0);
+ ret = _gnutls_pk_generate_keys(GNUTLS_PK_ECDSA, curve, ¶ms, 0);
if (ret < 0) {
return gnutls_assert_val(ret);
}
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
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;
* 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, ¶ms->sign);
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;
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);
}
#endif
+ params->algo = algo;
+
FAIL_IF_LIB_ERROR;
return 0;
}
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_ECDSA:
{
struct ecc_point r, pub;
struct ecc_scalar priv;
mpz_clear(y2);
}
break;
+ case GNUTLS_PK_EDDSA_ED25519:
+ ret = 0;
+ break;
default:
ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
}
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;
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;
}
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;
}
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);
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();
}
- 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;
}
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;
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);
#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
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)
}
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]);
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();
return ret;
}
- return privkey_sign_data(signer, data, signature, ¶ms);
+ if (_gnutls_pk_is_not_prehashed(signer->pk_algorithm)) {
+ return privkey_sign_raw_data(signer, data, signature, ¶ms);
+ } else {
+ return privkey_sign_and_hash_data(signer, data, signature, ¶ms);
+ }
}
/**
return ret;
}
- return privkey_sign_data(signer, data, signature, ¶ms);
+ return privkey_sign_and_hash_data(signer, data, signature, ¶ms);
}
/**
* 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
return ret;
}
- return privkey_sign_hash(signer, hash_data, signature, ¶ms, flags);
+ return privkey_sign_prehashed(signer, hash_data, signature, ¶ms, 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;
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) {
* 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.
return ret;
}
- return privkey_sign_hash(signer, hash_data, signature, ¶ms, flags);
+ return privkey_sign_prehashed(signer, hash_data, signature, ¶ms, 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,
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) {
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;
}
/*-
- * 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()
*
* 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
*
* 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.
*
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;
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:
* 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.
*
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;
}
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);
int result = 0, need_free = 0;
gnutls_datum_t _data;
ASN1_TYPE spk;
+ gnutls_ecc_curve_t curve;
if (key == NULL) {
gnutls_assert();
/* 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;
* @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.
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
goto cleanup;
}
key->params.params_nr++;
- key->pk_algorithm = GNUTLS_PK_EC;
+ key->pk_algorithm = GNUTLS_PK_ECDSA;
return 0;
return GNUTLS_E_INVALID_REQUEST;
}
+ if (_gnutls_pk_is_not_prehashed(key->pk_algorithm)) {
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
+
memcpy(¶ms, &key->params.sign, sizeof(gnutls_x509_spki_st));
if (flags & OLD_PUBKEY_VERIFY_FLAG_TLS1_RSA || flags & GNUTLS_VERIFY_USE_TLS1_RSA) {
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) {
break;
default:
gnutls_assert();
- return GNUTLS_E_INTERNAL_ERROR;
+ return GNUTLS_E_INVALID_REQUEST;
}
}
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
break;
default:
gnutls_assert();
- return GNUTLS_E_INTERNAL_ERROR;
+ return GNUTLS_E_INVALID_REQUEST;
}
}
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;
}
_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);
*/
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(¶ms);
-
_asnstr_append_name(name, sizeof(name), src_name,
".algorithm.algorithm");
len = sizeof(oid);
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, ¶ms);
- 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(¶ms);
- bits[0] = pubkey_to_bits(algo, ¶ms);
+ result = _gnutls_get_asn_mpis(src, src_name, ¶ms);
+ if (result < 0)
+ return gnutls_assert_val(result);
+
+ bits[0] = pubkey_to_bits(algo, ¶ms);
+ gnutls_pk_params_release(¶ms);
+ }
- gnutls_pk_params_release(¶ms);
return algo;
}
#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"
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
}
result = _gnutls_x509_get_pk_algorithm
- (crq->crq, "certificationRequestInfo.subjectPKInfo", bits);
+ (crq->crq, "certificationRequestInfo.subjectPKInfo", NULL, bits);
if (result < 0) {
gnutls_assert();
return result;
return result;
}
- result = privkey_sign_data(key, &tbs, &signature, ¶ms);
+ result = privkey_sign_and_hash_data(key, &tbs, &signature, ¶ms);
gnutls_free(tbs.data);
if (result < 0) {
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,
¶ms->params[ECC_Y]);
}
+int _gnutls_x509_read_eddsa_pubkey(uint8_t * der, int dersize,
+ gnutls_pk_params_st * params)
+{
+ return _gnutls_set_datum(¶ms->raw_pub, der, dersize);
+}
/* reads p,q and g
* from the certificate (subjectPublicKey BIT STRING).
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;
{
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, ¶ms->sign);
}
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);
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,
return 0;
case GNUTLS_PK_RSA_PSS:
return _gnutls_x509_write_rsa_pss_params(¶ms->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);
}
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);
}
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);
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 */
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;
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
*/
/* 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();
/*
* 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
*
}
break;
- case GNUTLS_PK_EC:
+ case GNUTLS_PK_EDDSA_ED25519:
+ case GNUTLS_PK_ECDSA:
{
gnutls_datum_t x, y;
gnutls_ecc_curve_t curve;
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 ==
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);
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);
goto cleanup;
}
- ret = privkey_sign_data(signer_key, &sigdata, &signature, ¶ms);
+ ret = privkey_sign_and_hash_data(signer_key, &sigdata, &signature, ¶ms);
if (ret < 0) {
gnutls_assert();
goto cleanup;
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 =
*
* 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.
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();
}
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) {
goto cleanup;
}
- key->pk_algorithm = GNUTLS_PK_EC;
- key->params.algo = key->pk_algorithm;
-
return 0;
cleanup:
* 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.
}
}
- 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) {
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);
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;
}
}
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
/* 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) {
return result;
}
- result = privkey_sign_data(issuer_key, &tbs, &signature, ¶ms);
+ if (_gnutls_pk_is_not_prehashed(issuer_key->pk_algorithm)) {
+ result = privkey_sign_raw_data(issuer_key, &tbs, &signature, ¶ms);
+ } else {
+ result = privkey_sign_and_hash_data(issuer_key, &tbs, &signature, ¶ms);
+ }
gnutls_free(tbs.data);
if (result < 0) {
result =
_gnutls_x509_get_pk_algorithm(cert->cert,
"tbsCertificate.subjectPublicKeyInfo",
+ NULL,
bits);
if (result < 0) {
return pk;
}
+ /* initializes params */
ret = _gnutls_x509_crt_get_mpis(crt, ¶ms);
if (ret < 0) {
gnutls_assert();
gnutls_x509_privkey_t pkey,
gnutls_ecc_curve_t curve);
+int _gnutls_privkey_decode_eddsa_key(ASN1_TYPE* pkey_asn,
+ const gnutls_datum_t *raw_key,
+ gnutls_x509_privkey_t pkey,
+ gnutls_ecc_curve_t curve);
+
int
_gnutls_x509_read_ecc_params(uint8_t * der, int dersize,
unsigned int *curve);
int _gnutls_x509_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,
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";
/*
* 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.
*
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);
+ }
}
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;
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,
/*
* Copyright (C) 2003-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* This file is part of GnuTLS.
*
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);
/*
* 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.
*
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)
{
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,
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