]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
wolfssl: Add support for x448 Diffie-Hellman
authorTobias Brunner <tobias@strongswan.org>
Thu, 23 Apr 2020 08:26:33 +0000 (10:26 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 7 May 2020 07:33:43 +0000 (09:33 +0200)
src/libstrongswan/plugins/wolfssl/wolfssl_plugin.c
src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.c
src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.h

index 925f08ee37c792c9275b1b8d4b5e533ba7023bf7..d692136396b15e95a9d39531e1c7b2dd44691991 100644 (file)
@@ -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),
index 5c21eb66c22837a1880e2269f6137f31113ca307..7325395fcb69162a03cf08ca44a6e9187f8bdbef 100644 (file)
@@ -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
 
 #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;
-
-       *shared_secret = chunk_alloc(len);
-       ret = wc_curve25519_shared_secret_ex(&this->key, pub, shared_secret->ptr,
-                                                                                &len, EC25519_LITTLE_ENDIAN);
-       return ret == 0;
-}
+#ifdef HAVE_CURVE25519
 
-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.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_curve25519_shared_secret_ex(&this->key, &pub,
-                                                               this->key.p.point, &len, EC25519_LITTLE_ENDIAN);
+               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 */
index 56760e5d2cfbd363e556dd15978b087c112bd04b..91b3e19f1846d29f4e376f918b72e91a7b4fe003 100644 (file)
@@ -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