summaryrefslogtreecommitdiff
path: root/lib/nettle/pk.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nettle/pk.c')
-rw-r--r--lib/nettle/pk.c205
1 files changed, 178 insertions, 27 deletions
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index 823c9b9809..4be8dc7eda 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -48,6 +48,12 @@
#include <nettle/ecdsa.h>
#include <nettle/ecc-curve.h>
#include <nettle/curve25519.h>
+#if HAVE_CURVE448
+#include <nettle/curve448.h>
+#else
+#include "curve448/curve448.h"
+#include "curve448/eddsa.h"
+#endif
#include <nettle/eddsa.h>
#include <nettle/version.h>
#if ENABLE_GOST
@@ -235,6 +241,22 @@ ecc_shared_secret(struct ecc_scalar *private_key,
*/
#define DH_EXPONENT_SIZE(p_size) (2*_gnutls_pk_bits_to_subgroup_bits(p_size))
+static inline int
+edwards_curve_mul(gnutls_pk_algorithm_t algo,
+ uint8_t *q, const uint8_t *n, const uint8_t *p)
+{
+ switch (algo) {
+ case GNUTLS_PK_ECDH_X25519:
+ curve25519_mul(q, n, p);
+ return 0;
+ case GNUTLS_PK_ECDH_X448:
+ curve448_mul(q, n, p);
+ return 0;
+ default:
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+ }
+}
+
/* This is used for DH or ECDH key derivation. In DH for example
* it is given the peers Y and our x, and calculates Y^x
*/
@@ -388,6 +410,7 @@ dh_cleanup:
break;
}
case GNUTLS_PK_ECDH_X25519:
+ case GNUTLS_PK_ECDH_X448:
{
unsigned size = gnutls_ecc_curve_get_size(priv->curve);
@@ -407,7 +430,9 @@ dh_cleanup:
out->size = size;
- curve25519_mul(out->data, priv->raw_priv.data, pub->raw_pub.data);
+ ret = edwards_curve_mul(algo, out->data, priv->raw_priv.data, pub->raw_pub.data);
+ if (ret < 0)
+ goto cleanup;
if (_gnutls_mem_is_zero(out->data, out->size)) {
gnutls_free(out->data);
@@ -739,11 +764,43 @@ _rsa_pss_sign_digest_tr(gnutls_digest_algorithm_t dig,
return ret;
}
+static inline gnutls_ecc_curve_t
+get_eddsa_curve(gnutls_pk_algorithm_t algo)
+{
+ switch (algo) {
+ case GNUTLS_PK_EDDSA_ED25519:
+ return GNUTLS_ECC_CURVE_ED25519;
+ case GNUTLS_PK_EDDSA_ED448:
+ return GNUTLS_ECC_CURVE_ED448;
+ default:
+ return gnutls_assert_val(GNUTLS_ECC_CURVE_INVALID);
+ }
+}
+
+static inline int
+eddsa_sign(gnutls_pk_algorithm_t algo,
+ const uint8_t *pub,
+ const uint8_t *priv,
+ size_t length, const uint8_t *msg,
+ uint8_t *signature)
+{
+ switch (algo) {
+ case GNUTLS_PK_EDDSA_ED25519:
+ ed25519_sha512_sign(pub, priv, length, msg, signature);
+ return 0;
+ case GNUTLS_PK_EDDSA_ED448:
+ ed448_shake256_sign(pub, priv, length, msg, signature);
+ return 0;
+ default:
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ }
+}
+
/* This is the lower-level part of privkey_sign_raw_data().
*
* It accepts data in the appropriate hash form, i.e., DigestInfo
* for PK_RSA, hash for PK_ECDSA, PK_DSA, PK_RSA_PSS, and raw data
- * for Ed25519.
+ * for Ed25519 and Ed448.
*
* in case of EC/DSA, signed data are encoded into r,s values
*/
@@ -774,10 +831,11 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
switch (algo) {
case GNUTLS_PK_EDDSA_ED25519: /* we do EdDSA */
+ case GNUTLS_PK_EDDSA_ED448:
{
const gnutls_ecc_curve_entry_st *e;
- if (pk_params->curve != GNUTLS_ECC_CURVE_ED25519)
+ if (unlikely(get_eddsa_curve(algo) != pk_params->curve))
return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
e = _gnutls_ecc_curve_get_params(pk_params->curve);
@@ -792,12 +850,18 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
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);
+ if (pk_params->raw_pub.size != e->size || pk_params->raw_priv.size != e->size) {
+ ret = gnutls_assert_val(GNUTLS_E_PK_SIGN_FAILED);
+ goto cleanup;
+ }
- ed25519_sha512_sign(pk_params->raw_pub.data,
- pk_params->raw_priv.data,
- vdata->size, vdata->data, signature->data);
+ ret = eddsa_sign(algo,
+ pk_params->raw_pub.data,
+ pk_params->raw_priv.data,
+ vdata->size, vdata->data,
+ signature->data);
+ if (ret < 0)
+ goto cleanup;
break;
}
@@ -1130,6 +1194,30 @@ _rsa_pss_verify_digest(gnutls_digest_algorithm_t dig,
return verify_func(pub, salt_size, digest, s);
}
+static inline int
+eddsa_verify(gnutls_pk_algorithm_t algo,
+ const uint8_t *pub,
+ size_t length, const uint8_t *msg,
+ const uint8_t *signature)
+{
+ int ret;
+
+ switch (algo) {
+ case GNUTLS_PK_EDDSA_ED25519:
+ ret = ed25519_sha512_verify(pub, length, msg, signature);
+ if (ret == 0)
+ return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+ return 0;
+ case GNUTLS_PK_EDDSA_ED448:
+ ret = ed448_shake256_verify(pub, length, msg, signature);
+ if (ret == 0)
+ return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+ return 0;
+ default:
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ }
+}
+
static int
_wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
const gnutls_datum_t * vdata,
@@ -1149,10 +1237,11 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
switch (algo) {
case GNUTLS_PK_EDDSA_ED25519: /* we do EdDSA */
+ case GNUTLS_PK_EDDSA_ED448:
{
const gnutls_ecc_curve_entry_st *e;
- if (pk_params->curve != GNUTLS_ECC_CURVE_ED25519)
+ if (unlikely(get_eddsa_curve(algo) != pk_params->curve))
return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
e = _gnutls_ecc_curve_get_params(pk_params->curve);
@@ -1165,13 +1254,10 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
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;
- }
+ ret = eddsa_verify(algo,
+ pk_params->raw_pub.data,
+ vdata->size, vdata->data,
+ signature->data);
break;
}
#if ENABLE_GOST
@@ -1431,6 +1517,8 @@ static int _wrap_nettle_pk_curve_exists(gnutls_ecc_curve_t curve)
switch (curve) {
case GNUTLS_ECC_CURVE_ED25519:
case GNUTLS_ECC_CURVE_X25519:
+ case GNUTLS_ECC_CURVE_ED448:
+ case GNUTLS_ECC_CURVE_X448:
return 1;
default:
return ((get_supported_nist_curve(curve)!=NULL ||
@@ -1556,6 +1644,7 @@ wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
case GNUTLS_PK_RSA:
case GNUTLS_PK_ECDSA:
case GNUTLS_PK_EDDSA_ED25519:
+ case GNUTLS_PK_EDDSA_ED448:
#if ENABLE_GOST
case GNUTLS_PK_GOST_01:
case GNUTLS_PK_GOST_12_256:
@@ -1914,6 +2003,7 @@ gnutls_x509_spki_st spki;
FALLTHROUGH;
case GNUTLS_PK_EC: /* we only do keys for ECDSA */
case GNUTLS_PK_EDDSA_ED25519:
+ case GNUTLS_PK_EDDSA_ED448:
case GNUTLS_PK_DSA:
case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_GOST_01:
@@ -1934,6 +2024,7 @@ gnutls_x509_spki_st spki;
break;
case GNUTLS_PK_DH:
case GNUTLS_PK_ECDH_X25519:
+ case GNUTLS_PK_ECDH_X448:
ret = 0;
goto cleanup;
default:
@@ -1953,6 +2044,38 @@ cleanup:
}
#endif
+static inline int
+eddsa_public_key(gnutls_pk_algorithm_t algo,
+ uint8_t *pub, const uint8_t *priv)
+{
+ switch (algo) {
+ case GNUTLS_PK_EDDSA_ED25519:
+ ed25519_sha512_public_key(pub, priv);
+ return 0;
+ case GNUTLS_PK_EDDSA_ED448:
+ ed448_shake256_public_key(pub, priv);
+ return 0;
+ default:
+ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ }
+}
+
+static inline int
+edwards_curve_mul_g(gnutls_pk_algorithm_t algo,
+ uint8_t *q, const uint8_t *n)
+{
+ switch (algo) {
+ case GNUTLS_PK_ECDH_X25519:
+ curve25519_mul_g(q, n);
+ return 0;
+ case GNUTLS_PK_ECDH_X448:
+ curve448_mul_g(q, n);
+ return 0;
+ default:
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+ }
+}
+
/* To generate a DH key either q must be set in the params or
* level should be set to the number of required bits.
*/
@@ -2190,13 +2313,14 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
break;
}
case GNUTLS_PK_EDDSA_ED25519:
+ case GNUTLS_PK_EDDSA_ED448:
{
unsigned size = gnutls_ecc_curve_get_size(level);
if (params->pkflags & GNUTLS_PK_FLAG_PROVABLE)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- if (level != GNUTLS_ECC_CURVE_ED25519)
+ if (unlikely(get_eddsa_curve(algo) != level))
return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
if (size == 0)
@@ -2222,7 +2346,11 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
params->raw_pub.size = size;
params->raw_priv.size = size;
- ed25519_sha512_public_key(params->raw_pub.data, params->raw_priv.data);
+ ret = eddsa_public_key(algo,
+ params->raw_pub.data,
+ params->raw_priv.data);
+ if (ret < 0)
+ goto fail;
break;
}
@@ -2335,6 +2463,7 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
}
#endif
case GNUTLS_PK_ECDH_X25519:
+ case GNUTLS_PK_ECDH_X448:
{
unsigned size = gnutls_ecc_curve_get_size(level);
@@ -2361,7 +2490,9 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
params->raw_pub.size = size;
params->raw_priv.size = size;
- curve25519_mul_g(params->raw_pub.data, params->raw_priv.data);
+ ret = edwards_curve_mul_g(algo, params->raw_pub.data, params->raw_priv.data);
+ if (ret < 0)
+ goto fail;
break;
}
default:
@@ -2595,18 +2726,29 @@ wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo,
mpz_clear(y2);
}
break;
- case GNUTLS_PK_EDDSA_ED25519: {
- uint8_t pub[32];
+ case GNUTLS_PK_EDDSA_ED25519:
+ case GNUTLS_PK_EDDSA_ED448: {
+ gnutls_ecc_curve_t curve;
+ const gnutls_ecc_curve_entry_st *e;
+ uint8_t pub[57]; /* can accommodate both curves */
+
+ curve = get_eddsa_curve(algo);
+ e = _gnutls_ecc_curve_get_params(curve);
+ if (e == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
if (params->raw_pub.data == NULL) {
return 0; /* nothing to verify */
}
- if (params->raw_pub.size != 32)
+ if (params->raw_pub.size != e->size)
return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
- ed25519_sha512_public_key(pub, params->raw_priv.data);
- if (memcmp(params->raw_pub.data, pub, 32) != 0)
+ ret = eddsa_public_key(algo, pub, params->raw_priv.data);
+ if (ret < 0)
+ return ret;
+
+ if (memcmp(params->raw_pub.data, pub, e->size) != 0)
return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
ret = 0;
@@ -2707,6 +2849,7 @@ wrap_nettle_pk_verify_pub_params(gnutls_pk_algorithm_t algo,
case GNUTLS_PK_RSA_PSS:
case GNUTLS_PK_DSA:
case GNUTLS_PK_EDDSA_ED25519:
+ case GNUTLS_PK_EDDSA_ED448:
return 0;
case GNUTLS_PK_ECDSA:
{
@@ -2892,8 +3035,9 @@ 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->curve != GNUTLS_ECC_CURVE_ED25519)
+ } else if (algo == GNUTLS_PK_EDDSA_ED25519 ||
+ algo == GNUTLS_PK_EDDSA_ED448) {
+ if (unlikely(get_eddsa_curve(algo) != params->curve))
return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
if (params->raw_priv.data == NULL)
@@ -2906,7 +3050,14 @@ wrap_nettle_pk_fixup(gnutls_pk_algorithm_t algo,
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);
+ ret = eddsa_public_key(algo,
+ params->raw_pub.data,
+ params->raw_priv.data);
+ if (ret < 0) {
+ gnutls_free(params->raw_pub.data);
+ return ret;
+ }
+
params->raw_pub.size = params->raw_priv.size;
} else if (algo == GNUTLS_PK_RSA_PSS) {
if (params->params_nr < RSA_PRIVATE_PARAMS - 3)