wolfssl: Add support for x448 Diffie-Hellman

This commit is contained in:
Tobias Brunner
2020-05-07 09:33:43 +02:00
parent b06374f6a5
commit 59a987b8f3
3 changed files with 182 additions and 43 deletions
@@ -377,10 +377,15 @@ METHOD(plugin_t, get_features, int,
#endif
#endif /* HAVE_ECC_VERIFY */
#endif /* HAVE_ECC */
#ifdef HAVE_CURVE25519
#if defined (HAVE_CURVE25519) || defined(HAVE_CURVE448)
PLUGIN_REGISTER(DH, wolfssl_x_diffie_hellman_create),
#ifdef HAVE_CURVE25519
PLUGIN_PROVIDE(DH, CURVE_25519),
#endif
#endif
#ifdef HAVE_CURVE448
PLUGIN_PROVIDE(DH, CURVE_448),
#endif
#endif /* HAVE_CURVE25519 || HAVE_CURVE448 */
#ifdef HAVE_ED25519
/* EdDSA private/public key loading */
PLUGIN_REGISTER(PUBKEY, wolfssl_ed_public_key_load, TRUE),
@@ -1,4 +1,7 @@
/*
* Copyright (C) 2020 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,13 +25,19 @@
#include "wolfssl_common.h"
#ifdef HAVE_CURVE25519
#if defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
#include "wolfssl_x_diffie_hellman.h"
#include <utils/debug.h>
#ifdef HAVE_CURVE25519
#include <wolfssl/wolfcrypt/curve25519.h>
#endif
#ifdef HAVE_CURVE448
#include <wolfssl/wolfcrypt/curve448.h>
#endif
#include <wolfssl/wolfcrypt/fe_operations.h>
typedef struct private_diffie_hellman_t private_diffie_hellman_t;
@@ -50,7 +59,14 @@ struct private_diffie_hellman_t {
/**
* Private (public) key
*/
curve25519_key key;
union {
#ifdef HAVE_CURVE25519
curve25519_key key25519;
#endif
#ifdef HAVE_CURVE448
curve448_key key448;
#endif
} key;
/**
* Shared secret
@@ -58,24 +74,12 @@ struct private_diffie_hellman_t {
chunk_t shared_secret;
};
/**
* Compute the shared secret
*/
static bool compute_shared_key(private_diffie_hellman_t *this,
curve25519_key *pub, chunk_t *shared_secret)
{
word32 len = CURVE25519_KEYSIZE;
int ret;
#ifdef HAVE_CURVE25519
*shared_secret = chunk_alloc(len);
ret = wc_curve25519_shared_secret_ex(&this->key, pub, shared_secret->ptr,
&len, EC25519_LITTLE_ENDIAN);
return ret == 0;
}
METHOD(diffie_hellman_t, set_other_public_value, bool,
METHOD(diffie_hellman_t, set_other_public_value_25519, bool,
private_diffie_hellman_t *this, chunk_t value)
{
word32 len = CURVE25519_KEYSIZE;
curve25519_key pub;
int ret;
@@ -102,8 +106,9 @@ METHOD(diffie_hellman_t, set_other_public_value, bool,
}
chunk_clear(&this->shared_secret);
if (!compute_shared_key(this, &pub, &this->shared_secret))
this->shared_secret = chunk_alloc(len);
if (wc_curve25519_shared_secret_ex(&this->key.key25519, &pub,
this->shared_secret.ptr, &len, EC25519_LITTLE_ENDIAN) != 0)
{
DBG1(DBG_LIB, "%N shared secret computation failed",
diffie_hellman_group_names, this->group);
@@ -115,13 +120,13 @@ METHOD(diffie_hellman_t, set_other_public_value, bool,
return TRUE;
}
METHOD(diffie_hellman_t, get_my_public_value, bool,
METHOD(diffie_hellman_t, get_my_public_value_25519, bool,
private_diffie_hellman_t *this, chunk_t *value)
{
word32 len = CURVE25519_KEYSIZE;
*value = chunk_alloc(len);
if (wc_curve25519_export_public_ex(&this->key, value->ptr, &len,
if (wc_curve25519_export_public_ex(&this->key.key25519, value->ptr, &len,
EC25519_LITTLE_ENDIAN) != 0)
{
chunk_free(value);
@@ -130,7 +135,7 @@ METHOD(diffie_hellman_t, get_my_public_value, bool,
return TRUE;
}
METHOD(diffie_hellman_t, set_private_value, bool,
METHOD(diffie_hellman_t, set_private_value_25519, bool,
private_diffie_hellman_t *this, chunk_t value)
{
curve25519_key pub;
@@ -147,17 +152,112 @@ METHOD(diffie_hellman_t, set_private_value, bool,
}
if (ret == 0)
{
ret = wc_curve25519_import_private_ex(value.ptr, value.len, &this->key,
EC25519_LITTLE_ENDIAN);
ret = wc_curve25519_import_private_ex(value.ptr, value.len,
&this->key.key25519, EC25519_LITTLE_ENDIAN);
}
if (ret == 0)
{
ret = wc_curve25519_shared_secret_ex(&this->key, &pub,
this->key.p.point, &len, EC25519_LITTLE_ENDIAN);
ret = wc_curve25519_shared_secret_ex(&this->key.key25519, &pub,
this->key.key25519.p.point, &len,
EC25519_LITTLE_ENDIAN);
}
return ret == 0;
}
#endif /* HAVE_CURVE25519 */
#ifdef HAVE_CURVE448
METHOD(diffie_hellman_t, set_other_public_value_448, bool,
private_diffie_hellman_t *this, chunk_t value)
{
word32 len = CURVE448_KEY_SIZE;
curve448_key pub;
int ret;
if (!diffie_hellman_verify_value(this->group, value))
{
return FALSE;
}
ret = wc_curve448_init(&pub);
if (ret != 0)
{
DBG1(DBG_LIB, "%N public key initialization failed",
diffie_hellman_group_names, this->group);
return FALSE;
}
ret = wc_curve448_import_public_ex(value.ptr, value.len, &pub,
EC448_LITTLE_ENDIAN);
if (ret != 0)
{
DBG1(DBG_LIB, "%N public value is malformed",
diffie_hellman_group_names, this->group);
return FALSE;
}
chunk_clear(&this->shared_secret);
this->shared_secret = chunk_alloc(len);
if (wc_curve448_shared_secret_ex(&this->key.key448, &pub,
this->shared_secret.ptr, &len, EC448_LITTLE_ENDIAN) != 0)
{
DBG1(DBG_LIB, "%N shared secret computation failed",
diffie_hellman_group_names, this->group);
chunk_clear(&this->shared_secret);
wc_curve448_free(&pub);
return FALSE;
}
wc_curve448_free(&pub);
return TRUE;
}
METHOD(diffie_hellman_t, get_my_public_value_448, bool,
private_diffie_hellman_t *this, chunk_t *value)
{
word32 len = CURVE448_KEY_SIZE;
*value = chunk_alloc(len);
if (wc_curve448_export_public_ex(&this->key.key448, value->ptr, &len,
EC448_LITTLE_ENDIAN) != 0)
{
chunk_free(value);
return FALSE;
}
return TRUE;
}
METHOD(diffie_hellman_t, set_private_value_448, bool,
private_diffie_hellman_t *this, chunk_t value)
{
curve448_key pub;
u_char basepoint[CURVE448_KEY_SIZE] = {5};
word32 len = CURVE448_KEY_SIZE;
int ret;
ret = wc_curve448_init(&pub);
/* create base point for calculating public key */
if (ret == 0)
{
ret = wc_curve448_import_public_ex(basepoint, CURVE448_KEY_SIZE,
&pub, EC448_LITTLE_ENDIAN);
}
if (ret == 0)
{
ret = wc_curve448_import_private_ex(value.ptr, value.len,
&this->key.key448, EC448_LITTLE_ENDIAN);
}
if (ret == 0)
{
ret = wc_curve448_shared_secret_ex(&this->key.key448, &pub,
this->key.key448.p, &len,
EC448_LITTLE_ENDIAN);
}
return ret == 0;
}
#endif /* HAVE_CURVE448 */
METHOD(diffie_hellman_t, get_shared_secret, bool,
private_diffie_hellman_t *this, chunk_t *secret)
{
@@ -178,7 +278,18 @@ METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
METHOD(diffie_hellman_t, destroy, void,
private_diffie_hellman_t *this)
{
wc_curve25519_free(&this->key);
if (this->group == CURVE_25519)
{
#ifdef HAVE_CURVE25519
wc_curve25519_free(&this->key.key25519);
#endif
}
else if (this->group == CURVE_448)
{
#ifdef HAVE_CURVE448
wc_curve448_free(&this->key.key448);
#endif
}
chunk_clear(&this->shared_secret);
free(this);
}
@@ -190,34 +301,57 @@ diffie_hellman_t *wolfssl_x_diffie_hellman_create(diffie_hellman_group_t group)
{
private_diffie_hellman_t *this;
WC_RNG rng;
int ret;
int ret = -1;
INIT(this,
.public = {
.get_shared_secret = _get_shared_secret,
.set_other_public_value = _set_other_public_value,
.get_my_public_value = _get_my_public_value,
.set_private_value = _set_private_value,
.get_dh_group = _get_dh_group,
.destroy = _destroy,
},
.group = group,
);
if (wc_curve25519_init(&this->key) != 0)
{
DBG1(DBG_LIB, "initializing key failed");
free(this);
return NULL;
}
if (wc_InitRng(&rng) != 0)
{
DBG1(DBG_LIB, "initializing a random number generator failed");
destroy(this);
return NULL;
}
ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &this->key);
if (group == CURVE_25519)
{
#ifdef HAVE_CURVE25519
this->public.set_other_public_value = _set_other_public_value_25519;
this->public.get_my_public_value = _get_my_public_value_25519;
this->public.set_private_value = _set_private_value_25519;
if (wc_curve25519_init(&this->key.key25519) != 0)
{
DBG1(DBG_LIB, "initializing key failed");
free(this);
return NULL;
}
ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE,
&this->key.key25519);
#endif
}
else if (group == CURVE_448)
{
#ifdef HAVE_CURVE448
this->public.set_other_public_value = _set_other_public_value_448;
this->public.get_my_public_value = _get_my_public_value_448;
this->public.set_private_value = _set_private_value_448;
if (wc_curve448_init(&this->key.key448) != 0)
{
DBG1(DBG_LIB, "initializing key failed");
free(this);
return NULL;
}
ret = wc_curve448_make_key(&rng, CURVE448_KEY_SIZE, &this->key.key448);
#endif
}
wc_FreeRng(&rng);
if (ret != 0)
{
@@ -228,4 +362,4 @@ diffie_hellman_t *wolfssl_x_diffie_hellman_create(diffie_hellman_group_t group)
return &this->public;
}
#endif /* HAVE_CURVE25519 */
#endif /* HAVE_CURVE25519 || HAVE_CURVE448 */
@@ -21,7 +21,7 @@
*/
/**
* Implementation of the X25519 Diffie-Hellman algorithm using wolfSSL.
* Implementation of the X25519/X448 Diffie-Hellman algorithm using wolfSSL.
*
* @defgroup wolfssl_x_diffie_hellman wolfssl_x_diffie_hellman
* @{ @ingroup wolfssl_p