wolfssl: Add wolfSSL plugin for cryptographic implementations
authorSean Parkinson <sean@wolfssl.com>
Wed, 3 Apr 2019 07:06:34 +0000 (17:06 +1000)
committerTobias Brunner <tobias@strongswan.org>
Wed, 24 Apr 2019 09:40:14 +0000 (11:40 +0200)
41 files changed:
configure.ac
src/libstrongswan/Makefile.am
src/libstrongswan/plugins/wolfssl/Makefile.am [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_aead.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_aead.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_common.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_crypter.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_crypter.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_diffie_hellman.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_diffie_hellman.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ec_diffie_hellman.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ec_diffie_hellman.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ec_private_key.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ec_private_key.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ed_private_key.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ed_private_key.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ed_public_key.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_ed_public_key.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_hasher.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_hasher.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_hmac.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_hmac.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_plugin.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_plugin.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_rng.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_rng.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_rsa_private_key.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_rsa_private_key.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_rsa_public_key.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_rsa_public_key.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_sha1_prf.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_sha1_prf.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_util.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_util.h [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.c [new file with mode: 0644]
src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.h [new file with mode: 0644]
src/libstrongswan/tests/suites/test_ed25519.c
src/pt-tls-client/Makefile.am
src/sw-collector/Makefile.am

index 3659e6d..08e8306 100644 (file)
@@ -145,6 +145,7 @@ ARG_ENABL_SET([newhope],        [enable New Hope crypto plugin.])
 ARG_DISBL_SET([nonce],          [disable nonce generation plugin.])
 ARG_ENABL_SET([ntru],           [enables the NTRU crypto plugin.])
 ARG_ENABL_SET([openssl],        [enables the OpenSSL crypto plugin.])
+ARG_ENABL_SET([wolfssl],        [enables the wolfSSL crypto plugin.])
 ARG_ENABL_SET([padlock],        [enables VIA Padlock crypto plugin.])
 ARG_DISBL_SET([random],         [disable RNG implementation on top of /dev/(u)random.])
 ARG_DISBL_SET([rc2],            [disable RC2 software implementation plugin.])
@@ -444,7 +445,7 @@ if test x$imc_test = xtrue -o x$imv_test = xtrue -o x$imc_scanner = xtrue -o x$i
 fi
 
 if test x$fips_prf = xtrue; then
-       if test x$openssl = xfalse; then
+       if test x$openssl = xfalse -a x$wolfssl = xfalse; then
                sha1=true;
        fi
 fi
@@ -1136,6 +1137,14 @@ if test x$openssl = xtrue; then
        AC_CHECK_HEADER([openssl/evp.h],,[AC_MSG_ERROR([OpenSSL header openssl/evp.h not found!])])
 fi
 
+if test x$wolfssl = xtrue; then
+       wolfssl_lib=wolfssl
+       AC_CHECK_LIB([$wolfssl_lib],[wolfSSL_Init],[LIBS="$LIBS"],
+               [AC_MSG_ERROR([wolfSSL lib$wolfssl_lib not found])],[$DLLIB])
+       AC_SUBST(WOLFSSL_LIB, [-l$wolfssl_lib])
+       AC_CHECK_HEADER([wolfssl/ssl.h],,[AC_MSG_ERROR([wolfSSL header wolfssl/ssl.h not found!])])
+fi
+
 if test x$gcrypt = xtrue; then
        AC_CHECK_LIB([gcrypt],[gcry_control],[LIBS="$LIBS"],[AC_MSG_ERROR([gcrypt library not found])],[-lgpg-error])
        AC_CHECK_HEADER([gcrypt.h],,[AC_MSG_ERROR([gcrypt header gcrypt.h not found!])])
@@ -1408,6 +1417,7 @@ ADD_PLUGIN([ipseckey],             [c charon])
 ADD_PLUGIN([pem],                  [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen fuzz])
 ADD_PLUGIN([padlock],              [s charon])
 ADD_PLUGIN([openssl],              [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
+ADD_PLUGIN([wolfssl],              [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([gcrypt],               [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([botan],                [s charon scepclient pki scripts manager medsrv attest nm cmd aikgen])
 ADD_PLUGIN([af-alg],               [s charon scepclient pki scripts medsrv attest nm cmd aikgen])
@@ -1578,6 +1588,7 @@ AM_CONDITIONAL(USE_MYSQL, test x$mysql = xtrue)
 AM_CONDITIONAL(USE_SQLITE, test x$sqlite = xtrue)
 AM_CONDITIONAL(USE_PADLOCK, test x$padlock = xtrue)
 AM_CONDITIONAL(USE_OPENSSL, test x$openssl = xtrue)
+AM_CONDITIONAL(USE_WOLFSSL, test x$wolfssl = xtrue)
 AM_CONDITIONAL(USE_GCRYPT, test x$gcrypt = xtrue)
 AM_CONDITIONAL(USE_BOTAN, test x$botan = xtrue)
 AM_CONDITIONAL(USE_AGENT, test x$agent = xtrue)
@@ -1857,6 +1868,7 @@ AC_CONFIG_FILES([
        src/libstrongswan/plugins/sqlite/Makefile
        src/libstrongswan/plugins/padlock/Makefile
        src/libstrongswan/plugins/openssl/Makefile
+       src/libstrongswan/plugins/wolfssl/Makefile
        src/libstrongswan/plugins/gcrypt/Makefile
        src/libstrongswan/plugins/botan/Makefile
        src/libstrongswan/plugins/agent/Makefile
index e6d7ce7..827e0ad 100644 (file)
@@ -558,6 +558,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_WOLFSSL
+  SUBDIRS += plugins/wolfssl
+if MONOLITHIC
+  libstrongswan_la_LIBADD += plugins/wolfssl/libstrongswan-wolfssl.la
+endif
+endif
+
 if USE_GCRYPT
   SUBDIRS += plugins/gcrypt
 if MONOLITHIC
diff --git a/src/libstrongswan/plugins/wolfssl/Makefile.am b/src/libstrongswan/plugins/wolfssl/Makefile.am
new file mode 100644 (file)
index 0000000..cd0be7d
--- /dev/null
@@ -0,0 +1,36 @@
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -DFIPS_MODE=${fips_mode}
+
+AM_CFLAGS = \
+       $(PLUGIN_CFLAGS)
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-wolfssl.la
+else
+plugin_LTLIBRARIES = libstrongswan-wolfssl.la
+endif
+
+libstrongswan_wolfssl_la_SOURCES = \
+       wolfssl_common.h \
+       wolfssl_plugin.h wolfssl_plugin.c \
+       wolfssl_aead.h wolfssl_aead.c \
+       wolfssl_crypter.h wolfssl_crypter.c \
+       wolfssl_diffie_hellman.h wolfssl_diffie_hellman.c \
+       wolfssl_ec_diffie_hellman.h wolfssl_ec_diffie_hellman.c \
+       wolfssl_ec_private_key.h wolfssl_ec_private_key.c \
+       wolfssl_ec_public_key.h wolfssl_ec_public_key.c \
+       wolfssl_ed_private_key.h wolfssl_ed_private_key.c \
+       wolfssl_ed_public_key.h wolfssl_ed_public_key.c \
+       wolfssl_hasher.h wolfssl_hasher.c \
+       wolfssl_hmac.h wolfssl_hmac.c \
+       wolfssl_rsa_public_key.h wolfssl_rsa_public_key.c \
+       wolfssl_rsa_private_key.h wolfssl_rsa_private_key.c \
+       wolfssl_rng.h wolfssl_rng.c \
+       wolfssl_sha1_prf.h wolfssl_sha1_prf.c \
+       wolfssl_x_diffie_hellman.h wolfssl_x_diffie_hellman.c \
+       wolfssl_util.h wolfssl_util.c
+
+
+libstrongswan_wolfssl_la_LDFLAGS = -module -avoid-version
+libstrongswan_wolfssl_la_LIBADD  = $(WOLFSSL_LIB)
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_aead.c b/src/libstrongswan/plugins/wolfssl/wolfssl_aead.c
new file mode 100644 (file)
index 0000000..1ed0c71
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))) || \
+                                                               (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
+
+#include "wolfssl_aead.h"
+
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/chacha.h>
+#include <wolfssl/wolfcrypt/chacha20_poly1305.h>
+#include <crypto/iv/iv_gen_seq.h>
+
+/** as defined in RFC 4106 */
+#define IV_LEN                 8
+#define GCM_SALT_LEN   4
+#define GCM_NONCE_LEN  (GCM_SALT_LEN + IV_LEN)
+
+#define CCM_SALT_LEN   3
+#define CCM_NONCE_LEN  (CCM_SALT_LEN + IV_LEN)
+
+#if !defined(NO_AES) && defined(HAVE_AESGCM)
+#define MAX_NONCE_LEN  GCM_NONCE_LEN
+#define MAX_SALT_LEN   GCM_SALT_LEN
+#elif defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+#define MAX_NONCE_LEN  12
+#define MAX_SALT_LEN   4
+#elif !defined(NO_AES) && defined(HAVE_AESCCM)
+#define MAX_NONCE_LEN  CCM_NONCE_LEN
+#define MAX_SALT_LEN   GCM_SALT_LEN
+#endif
+
+typedef struct private_aead_t private_aead_t;
+
+/**
+ * Private data of aead_t
+ */
+struct private_aead_t {
+
+       /**
+        * Public interface
+        */
+       aead_t public;
+
+       /**
+        * The encryption key
+        */
+       chunk_t key;
+
+       /**
+        * Salt value
+        */
+       char salt[MAX_SALT_LEN];
+
+       /**
+        * Length of the salt
+        */
+       size_t salt_len;
+
+       /**
+        * Size of the integrity check value
+        */
+       size_t icv_size;
+
+       /**
+        * Size of the IV
+        */
+       size_t iv_size;
+
+       /**
+        * IV generator
+        */
+       iv_gen_t *iv_gen;
+
+       /**
+        * The cipher to use
+        */
+       union
+       {
+#if !defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))
+               Aes aes;
+#endif
+       } cipher;
+
+       /**
+        * The cipher to use
+        */
+       encryption_algorithm_t alg;
+};
+
+
+METHOD(aead_t, encrypt, bool,
+       private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
+       chunk_t *encrypted)
+{
+       bool success = FALSE;
+       int ret = 0;
+       u_char *out;
+       u_char nonce[MAX_NONCE_LEN];
+
+       out = plain.ptr;
+       if (encrypted)
+       {
+               *encrypted = chunk_alloc(plain.len + this->icv_size);
+               out = encrypted->ptr;
+       }
+
+       memcpy(nonce, this->salt, this->salt_len);
+       memcpy(nonce + this->salt_len, iv.ptr, IV_LEN);
+
+       switch (this->alg)
+       {
+#if !defined(NO_AES) && defined(HAVE_AESGCM)
+               case ENCR_AES_GCM_ICV8:
+               case ENCR_AES_GCM_ICV12:
+               case ENCR_AES_GCM_ICV16:
+                       ret = wc_AesGcmSetKey(&this->cipher.aes, this->key.ptr,
+                                                                 this->key.len);
+                       if (ret == 0)
+                       {
+                               ret = wc_AesGcmEncrypt(&this->cipher.aes, out, plain.ptr,
+                                       plain.len, nonce, GCM_NONCE_LEN, out + plain.len,
+                                       this->icv_size, assoc.ptr, assoc.len);
+                       }
+                       success = (ret == 0);
+                       break;
+#endif
+#if !defined(NO_AES) && defined(HAVE_AESCCM)
+               case ENCR_AES_CCM_ICV8:
+               case ENCR_AES_CCM_ICV12:
+               case ENCR_AES_CCM_ICV16:
+                       if (plain.ptr == NULL && plain.len == 0)
+                               plain.ptr = nonce;
+                       ret = wc_AesCcmSetKey(&this->cipher.aes, this->key.ptr,
+                                                                 this->key.len);
+                       if (ret == 0)
+                       {
+                               ret = wc_AesCcmEncrypt(&this->cipher.aes, out, plain.ptr,
+                                       plain.len, nonce, CCM_NONCE_LEN, out + plain.len,
+                                       this->icv_size, assoc.ptr, assoc.len);
+                       }
+                       success = (ret == 0);
+                       break;
+#endif
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+               case ENCR_CHACHA20_POLY1305:
+                       ret = wc_ChaCha20Poly1305_Encrypt(this->key.ptr, nonce, assoc.ptr,
+                                       assoc.len, plain.ptr, plain.len, out, out + plain.len);
+                       success = (ret == 0);
+                       break;
+#endif
+               default:
+                       break;
+       }
+
+       return success;
+}
+
+METHOD(aead_t, decrypt, bool,
+       private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
+       chunk_t *plain)
+{
+       bool success = FALSE;
+       int ret = 0;
+       u_char *out;
+       u_char nonce[MAX_NONCE_LEN];
+
+       if (encrypted.len < this->icv_size)
+       {
+               return FALSE;
+       }
+       encrypted.len -= this->icv_size;
+
+       out = encrypted.ptr;
+       if (plain)
+       {
+               *plain = chunk_alloc(encrypted.len);
+               out = plain->ptr;
+       }
+
+       memcpy(nonce, this->salt, this->salt_len);
+       memcpy(nonce + this->salt_len, iv.ptr, IV_LEN);
+
+       switch (this->alg)
+       {
+#if !defined(NO_AES) && defined(HAVE_AESGCM)
+               case ENCR_AES_GCM_ICV8:
+               case ENCR_AES_GCM_ICV12:
+               case ENCR_AES_GCM_ICV16:
+                       ret = wc_AesGcmSetKey(&this->cipher.aes, this->key.ptr,
+                                 this->key.len);
+                       if (ret == 0)
+                       {
+                               ret = wc_AesGcmDecrypt(&this->cipher.aes, out, encrypted.ptr,
+                                       encrypted.len, nonce, GCM_NONCE_LEN,
+                                       encrypted.ptr + encrypted.len, this->icv_size, assoc.ptr,
+                                       assoc.len);
+                       }
+                       success = (ret == 0);
+                       break;
+#endif
+#if !defined(NO_AES) && defined(HAVE_AESCCM)
+               case ENCR_AES_CCM_ICV8:
+               case ENCR_AES_CCM_ICV12:
+               case ENCR_AES_CCM_ICV16:
+                       if (encrypted.ptr == NULL && encrypted.len == 0)
+                               encrypted.ptr = nonce;
+                       if (out == NULL && encrypted.len == 0)
+                               out = nonce;
+                       ret = wc_AesCcmSetKey(&this->cipher.aes, this->key.ptr,
+                                 this->key.len);
+                       if (ret == 0)
+                       {
+                               ret = wc_AesCcmDecrypt(&this->cipher.aes, out, encrypted.ptr,
+                                       encrypted.len, nonce, CCM_NONCE_LEN,
+                                       encrypted.ptr + encrypted.len, this->icv_size, assoc.ptr,
+                                       assoc.len);
+                       }
+                       success = (ret == 0);
+                       break;
+#endif
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+               case ENCR_CHACHA20_POLY1305:
+                       ret = wc_ChaCha20Poly1305_Decrypt(this->key.ptr, nonce, assoc.ptr,
+                                       assoc.len, encrypted.ptr, encrypted.len,
+                                       encrypted.ptr + encrypted.len, out);
+                       success = (ret == 0);
+                       break;
+#endif
+               default:
+                       break;
+       }
+
+       return success;
+}
+
+METHOD(aead_t, get_block_size, size_t,
+       private_aead_t *this)
+{
+       /* All AEAD algorithms are streaming. */
+       return 1;
+}
+
+METHOD(aead_t, get_icv_size, size_t,
+       private_aead_t *this)
+{
+       return this->icv_size;
+}
+
+METHOD(aead_t, get_iv_size, size_t,
+       private_aead_t *this)
+{
+       return IV_LEN;
+}
+
+METHOD(aead_t, get_iv_gen, iv_gen_t*,
+       private_aead_t *this)
+{
+       return this->iv_gen;
+}
+
+METHOD(aead_t, get_key_size, size_t,
+       private_aead_t *this)
+{
+       return this->key.len + this->salt_len;
+}
+
+METHOD(aead_t, set_key, bool,
+       private_aead_t *this, chunk_t key)
+{
+       if (key.len != get_key_size(this))
+       {
+               return FALSE;
+       }
+       memcpy(this->salt, key.ptr + key.len - this->salt_len, this->salt_len);
+       memcpy(this->key.ptr, key.ptr, this->key.len);
+       return TRUE;
+}
+
+METHOD(aead_t, destroy, void,
+       private_aead_t *this)
+{
+       chunk_clear(&this->key);
+       switch (this->alg)
+       {
+#if !defined(NO_AES) && defined(HAVE_AESGCM)
+               case ENCR_AES_GCM_ICV8:
+               case ENCR_AES_GCM_ICV12:
+               case ENCR_AES_GCM_ICV16:
+                       wc_AesFree(&this->cipher.aes);
+                       break;
+#endif
+#if !defined(NO_AES) && defined(HAVE_AESCCM)
+               case ENCR_AES_CCM_ICV8:
+               case ENCR_AES_CCM_ICV12:
+               case ENCR_AES_CCM_ICV16:
+                       wc_AesFree(&this->cipher.aes);
+                       break;
+#endif
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+               case ENCR_CHACHA20_POLY1305:
+                       break;
+#endif
+               default:
+                       break;
+       }
+       this->iv_gen->destroy(this->iv_gen);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+aead_t *wolfssl_aead_create(encryption_algorithm_t algo,
+                                                       size_t key_size, size_t salt_size)
+{
+       private_aead_t *this;
+
+       INIT(this,
+               .public = {
+                       .encrypt = _encrypt,
+                       .decrypt = _decrypt,
+                       .get_block_size = _get_block_size,
+                       .get_icv_size = _get_icv_size,
+                       .get_iv_size = _get_iv_size,
+                       .get_iv_gen = _get_iv_gen,
+                       .get_key_size = _get_key_size,
+                       .set_key = _set_key,
+                       .destroy = _destroy,
+               },
+               .alg = algo,
+       );
+
+       switch (algo)
+       {
+#if !defined(NO_AES) && defined(HAVE_AESGCM)
+       #if WOLFSSL_MIN_AUTH_TAG_SZ <= 8
+               case ENCR_AES_GCM_ICV8:
+                       this->icv_size = 8;
+                       break;
+       #endif
+       #if WOLFSSL_MIN_AUTH_TAG_SZ <= 12
+               case ENCR_AES_GCM_ICV12:
+                       this->icv_size = 12;
+                       break;
+       #endif
+               case ENCR_AES_GCM_ICV16:
+                       this->icv_size = 16;
+                       break;
+#endif
+#if !defined(NO_AES) && defined(HAVE_AESCCM)
+               case ENCR_AES_CCM_ICV8:
+                       this->icv_size = 8;
+                       break;
+               case ENCR_AES_CCM_ICV12:
+                       this->icv_size = 12;
+                       break;
+               case ENCR_AES_CCM_ICV16:
+                       this->icv_size = 16;
+                       break;
+#endif
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+               case ENCR_CHACHA20_POLY1305:
+                       this->icv_size = 16;
+                       break;
+#endif
+               default:
+                       free(this);
+                       return NULL;
+       }
+
+       switch (algo)
+       {
+#if !defined(NO_AES) && defined(HAVE_AESGCM)
+               case ENCR_AES_GCM_ICV8:
+               case ENCR_AES_GCM_ICV12:
+               case ENCR_AES_GCM_ICV16:
+                       switch (key_size)
+                       {
+                               case 0:
+                                       key_size = 16;
+                                       /* FALL */
+                               case 16:
+                               case 24:
+                               case 32:
+                                       this->iv_size = GCM_NONCE_LEN;
+                                       this->salt_len = GCM_SALT_LEN;
+                                       if (wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID) != 0)
+                                       {
+                                               DBG1(DBG_LIB, "AES Init failed, aead create failed");
+                                               free(this);
+                                               return NULL;
+                                       }
+                                       break;
+                               default:
+                                       free(this);
+                                       return NULL;
+                       }
+                       break;
+#endif
+#if !defined(NO_AES) && defined(HAVE_AESCCM)
+               case ENCR_AES_CCM_ICV8:
+               case ENCR_AES_CCM_ICV12:
+               case ENCR_AES_CCM_ICV16:
+                       switch (key_size)
+                       {
+                               case 0:
+                                       key_size = 16;
+                                       /* FALL */
+                               case 16:
+                               case 24:
+                               case 32:
+                                       this->iv_size = CCM_NONCE_LEN;
+                                       this->salt_len = CCM_SALT_LEN;
+                                       if (wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID) != 0)
+                                       {
+                                               DBG1(DBG_LIB, "AES Init failed, aead create failed");
+                                               free(this);
+                                               return NULL;
+                                       }
+                                       break;
+                               default:
+                                       free(this);
+                                       return NULL;
+                       }
+                       break;
+#endif
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+               case ENCR_CHACHA20_POLY1305:
+                       switch (key_size)
+                       {
+                               case 0:
+                                       key_size = 32;
+                                       /* FALL */
+                               case 32:
+                                       this->iv_size = CHACHA_IV_BYTES;
+                                       this->salt_len = 4;
+                                       break;
+                               default:
+                                       free(this);
+                                       return NULL;
+                       }
+                       break;
+#endif
+               default:
+                       free(this);
+                       return NULL;
+       }
+
+       if (salt_size && salt_size != this->salt_len)
+       {
+               /* currently not supported */
+               free(this);
+               return NULL;
+       }
+
+       this->key = chunk_alloc(key_size);
+       this->iv_gen = iv_gen_seq_create();
+
+       return &this->public;
+}
+
+#endif
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_aead.h b/src/libstrongswan/plugins/wolfssl/wolfssl_aead.h
new file mode 100644 (file)
index 0000000..fd6dfdb
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Implements the aead_t interface using wolfSSL.
+ *
+ * @defgroup wolfssl_aead wolfssl_aead
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_AEAD_H_
+#define WOLFSSL_AEAD_H_
+
+#include <crypto/aead.h>
+
+/**
+ * Constructor to create aead_t implementation.
+ *
+ * @param algo                 algorithm to implement
+ * @param key_size             key size in bytes
+ * @param salt_size            size of implicit salt length
+ * @return                             aead_t object, NULL if not supported
+ */
+aead_t *wolfssl_aead_create(encryption_algorithm_t algo, size_t key_size,
+                                                       size_t salt_size);
+
+#endif /** WOLFSSL_AEAD_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_common.h b/src/libstrongswan/plugins/wolfssl/wolfssl_common.h
new file mode 100644 (file)
index 0000000..3c9081a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef WOLFSSL_COMMON_H_
+#define WOLFSSL_COMMON_H_
+
+#include <library.h>
+
+/* Undefine these as they are enum entries in wolfSSL - same values */
+#ifdef AES_BLOCK_SIZE
+#undef AES_BLOCK_SIZE
+#endif
+
+#ifdef CAMELLIA_BLOCK_SIZE
+#undef CAMELLIA_BLOCK_SIZE
+#endif
+
+#ifdef DES_BLOCK_SIZE
+#undef DES_BLOCK_SIZE
+#endif
+
+/* PARSE_ERROR is an enum entry in wolfSSL - not used in this plugin */
+#define PARSE_ERROR    WOLFSSL_PARSE_EROR
+
+#ifndef WOLFSSL_USER_SETTINGS
+       #include <wolfssl/options.h>
+#endif
+#include <wolfssl/ssl.h>
+
+#undef PARSE_ERROR
+
+#endif /* WOLFSSL_COMMON_H_ */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_crypter.c b/src/libstrongswan/plugins/wolfssl/wolfssl_crypter.c
new file mode 100644 (file)
index 0000000..cf4623a
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_crypter.h"
+
+#include "wolfssl_common.h"
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/camellia.h>
+#include <wolfssl/wolfcrypt/des3.h>
+
+#include <utils/debug.h>
+
+typedef struct private_wolfssl_crypter_t private_wolfssl_crypter_t;
+
+#define CTR_SALT_LEN   4
+
+/**
+ * Private data of wolfssl_crypter_t
+ */
+struct private_wolfssl_crypter_t {
+
+       /**
+        * Public part of this class.
+        */
+       wolfssl_crypter_t public;
+
+       /**
+        * wolfSSL cipher
+        */
+       union
+       {
+#if !defined(NO_AES) && (!defined(NO_AES_CBC) || defined(WOLFSSL_AES_COUNTER))
+               Aes aes;
+#endif
+#ifdef HAVE_CAMELLIA
+               Camellia camellia;
+#endif
+#ifndef NO_DES3
+               Des des;
+               Des3 des3;
+#endif
+       } cipher;
+
+       /**
+        * Encryption algorithm identifier
+        */
+       encryption_algorithm_t alg;
+
+       /** 
+        * Private key
+        */
+       chunk_t key;
+
+       /**
+        * Salt value
+        */
+       char salt[CTR_SALT_LEN];
+
+       /**
+        * Length of the salt
+        */
+       size_t salt_len;
+
+       /**
+        * Size of key
+        */
+       size_t key_size;
+
+       /**
+        * Size of block
+        */
+       size_t block_size;
+
+       /**
+        * Size of IV
+        */
+       size_t iv_size;
+};
+
+METHOD(crypter_t, decrypt, bool,
+       private_wolfssl_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
+{
+       u_char *out;
+       bool success = FALSE;
+       int ret;
+       u_char nonce[AES_BLOCK_SIZE] = {0};
+#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
+       chunk_t d = chunk_empty;
+#endif
+
+       out = data.ptr;
+       if (dst)
+       {
+               *dst = chunk_alloc(data.len);
+               out = dst->ptr;
+       }
+
+       if (this->salt_len > 0)
+       {
+               memcpy(nonce, this->salt, this->salt_len);
+               memcpy(nonce + this->salt_len, iv.ptr, this->iv_size);
+               nonce[AES_BLOCK_SIZE - 1] = 1;
+       }
+
+       switch (this->alg)
+       {
+               case ENCR_NULL:
+                       memcpy(out, data.ptr, data.len);
+                       success = TRUE;
+                       break;
+#if !defined(NO_AES) && !defined(NO_AES_CBC)
+               case ENCR_AES_CBC:
+                       ret = wc_AesSetKey(&this->cipher.aes, this->key.ptr, this->key.len,
+                                                          iv.ptr, AES_DECRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_AesCbcDecrypt(&this->cipher.aes, out, data.ptr,
+                                                                          data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+#endif
+#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
+               case ENCR_AES_CTR:
+                       if (out == data.ptr)
+                       {
+                               d = chunk_alloc(data.len);
+                               out = d.ptr;
+                       }
+                       ret = wc_AesSetKeyDirect(&this->cipher.aes, this->key.ptr,
+                                                                        this->key.len, nonce, AES_ENCRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_AesCtrEncrypt(&this->cipher.aes, out, data.ptr,
+                                                                          data.len);
+                       }
+                       if (ret == 0 && out == d.ptr)
+                       {
+                               memcpy(data.ptr, out, data.len);
+                       }
+                       chunk_free(&d);
+                       success = (ret == 0);
+                       break;
+#endif
+#ifdef HAVE_CAMELLIA
+               case ENCR_CAMELLIA_CBC:
+                       ret = wc_CamelliaSetKey(&this->cipher.camellia, this->key.ptr,
+                                                                       this->key.len, iv.ptr);
+                       if (ret == 0)
+                       {
+                               ret = wc_CamelliaCbcDecrypt(&this->cipher.camellia, out,
+                                                                                       data.ptr, data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+#endif
+#ifndef NO_DES3
+               case ENCR_3DES:
+                       ret = wc_Des3_SetKey(&this->cipher.des3, this->key.ptr, iv.ptr,
+                                                                DES_DECRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_Des3_CbcDecrypt(&this->cipher.des3, out, data.ptr,
+                                                                                data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+               case ENCR_DES:
+                       ret = wc_Des_SetKey(&this->cipher.des, this->key.ptr, iv.ptr,
+                                                               DES_DECRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_Des_CbcDecrypt(&this->cipher.des, out, data.ptr,
+                                                                               data.len);
+                       }
+                       if (ret == 0)
+                               success = TRUE;
+                       break;
+       #ifdef WOLFSSL_DES_ECB
+               case ENCR_DES_ECB:
+                       ret = wc_Des_SetKey(&this->cipher.des, this->key.ptr, iv.ptr,
+                                                               DES_DECRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_Des_EcbDecrypt(&this->cipher.des, out, data.ptr,
+                                                                               data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+       #endif
+#endif
+               default:
+                       break;
+       }
+
+       return success;
+}
+
+METHOD(crypter_t, encrypt, bool,
+       private_wolfssl_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
+{
+       u_char *out;
+       bool success = FALSE;
+       int ret;
+       u_char nonce[AES_BLOCK_SIZE] = {0};
+#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
+       chunk_t d = chunk_empty;
+#endif
+
+       out = data.ptr;
+       if (dst)
+       {
+               *dst = chunk_alloc(data.len);
+               out = dst->ptr;
+       }
+
+       if (this->salt_len > 0)
+       {
+               memcpy(nonce, this->salt, this->salt_len);
+               memcpy(nonce + this->salt_len, iv.ptr, this->iv_size);
+               nonce[AES_BLOCK_SIZE - 1] = 1;
+       }
+
+       switch (this->alg)
+       {
+               case ENCR_NULL:
+                       memcpy(out, data.ptr, data.len);
+                       success = TRUE;
+                       break;
+#if !defined(NO_AES) && !defined(NO_AES_CBC)
+               case ENCR_AES_CBC:
+                       ret = wc_AesSetKey(&this->cipher.aes, this->key.ptr, this->key.len,
+                                                          iv.ptr, AES_ENCRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_AesCbcEncrypt(&this->cipher.aes, out, data.ptr,
+                                                                          data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+#endif
+#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
+               case ENCR_AES_CTR:
+                       if (out == data.ptr)
+                       {
+                               d = chunk_alloc(data.len);
+                               out = d.ptr;
+                       }
+                       ret = wc_AesSetKeyDirect(&this->cipher.aes, this->key.ptr,
+                                                                        this->key.len, nonce, AES_ENCRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_AesCtrEncrypt(&this->cipher.aes, out, data.ptr,
+                                                                          data.len);
+                       }
+                       if (ret == 0 && out == d.ptr)
+                       {
+                               memcpy(data.ptr, out, data.len);
+                       }
+                       chunk_free(&d);
+                       success = (ret == 0);
+                       break;
+#endif
+#ifdef HAVE_CAMELLIA
+               case ENCR_CAMELLIA_CBC:
+                       ret = wc_CamelliaSetKey(&this->cipher.camellia, this->key.ptr,
+                                                                       this->key.len, iv.ptr);
+                       if (ret == 0)
+                       {
+                               ret = wc_CamelliaCbcEncrypt(&this->cipher.camellia, out,
+                                                                                       data.ptr, data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+#endif
+#ifndef NO_DES3
+               case ENCR_3DES:
+                       ret = wc_Des3_SetKey(&this->cipher.des3, this->key.ptr, iv.ptr,
+                                                                DES_ENCRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_Des3_CbcEncrypt(&this->cipher.des3, out, data.ptr,
+                                                                                data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+               case ENCR_DES:
+                       ret = wc_Des_SetKey(&this->cipher.des, this->key.ptr, iv.ptr,
+                                                               DES_ENCRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_Des_CbcEncrypt(&this->cipher.des, out, data.ptr,
+                                                                               data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+       #ifdef WOLFSSL_DES_ECB
+               case ENCR_DES_ECB:
+                       ret = wc_Des_SetKey(&this->cipher.des, this->key.ptr, iv.ptr,
+                                                               DES_ENCRYPTION);
+                       if (ret == 0)
+                       {
+                               ret = wc_Des_EcbEncrypt(&this->cipher.des, out, data.ptr,
+                                                                               data.len);
+                       }
+                       success = (ret == 0);
+                       break;
+       #endif
+#endif
+               default:
+                       break;
+       }
+
+       return success;
+}
+
+METHOD(crypter_t, get_block_size, size_t,
+       private_wolfssl_crypter_t *this)
+{
+       return this->block_size;
+}
+
+METHOD(crypter_t, get_iv_size, size_t,
+       private_wolfssl_crypter_t *this)
+{
+       return this->iv_size;
+}
+
+METHOD(crypter_t, get_key_size, size_t,
+       private_wolfssl_crypter_t *this)
+{
+       return this->key.len + this->salt_len;
+}
+
+METHOD(crypter_t, set_key, bool,
+       private_wolfssl_crypter_t *this, chunk_t key)
+{
+       if (key.len != get_key_size(this))
+       {
+               return FALSE;
+       }
+       memcpy(this->salt, key.ptr + key.len - this->salt_len, this->salt_len);
+       memcpy(this->key.ptr, key.ptr, this->key.len);
+       return TRUE;
+}
+
+METHOD(crypter_t, destroy, void,
+       private_wolfssl_crypter_t *this)
+{
+       chunk_clear(&this->key);
+       switch (this->alg)
+       {
+#if !defined(NO_AES) && !defined(NO_AES_CBC)
+               case ENCR_AES_CBC:
+                       wc_AesFree(&this->cipher.aes);
+                       break;
+#endif
+#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
+               case ENCR_AES_CTR:
+                       wc_AesFree(&this->cipher.aes);
+                       break;
+#endif
+#ifdef HAVE_CAMELLIA
+               case ENCR_CAMELLIA_CBC:
+                       break;
+#endif
+#ifndef NO_DES3
+               case ENCR_3DES:
+                       wc_Des3Free(&this->cipher.des3);
+                       break;
+               case ENCR_DES:
+       #ifdef WOLFSSL_DES_ECB
+               case ENCR_DES_ECB:
+       #endif
+                       break;
+#endif
+               default:
+                       break;
+       }
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+wolfssl_crypter_t *wolfssl_crypter_create(encryption_algorithm_t algo,
+                                                                               size_t key_size)
+{
+       private_wolfssl_crypter_t *this;
+       size_t block_size;
+       size_t iv_size;
+       size_t salt_len = 0;
+       int ret = 0;
+
+       switch (algo)
+       {
+               case ENCR_NULL:
+                       key_size = 0;
+                       block_size = 1;
+                       iv_size = 0;
+                       break;
+#if !defined(NO_AES) && !defined(NO_AES_CBC)
+               case ENCR_AES_CBC:
+                       switch (key_size)
+                       {
+                               case 0:
+                                       key_size = 16;
+                               case 16:
+                               case 24:
+                               case 32:
+                                       block_size = AES_BLOCK_SIZE;
+                                       iv_size = AES_IV_SIZE;
+                                       break;
+                               default:
+                                       return NULL;
+                       }
+                       break;
+#endif
+#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
+               case ENCR_AES_CTR:
+                       switch (key_size)
+                       {
+                               case 0:
+                                       key_size = 16;
+                               case 16:
+                               case 24:
+                               case 32:
+                                       block_size = 1;
+                                       iv_size = 8;
+                                       salt_len = CTR_SALT_LEN;
+                                       break;
+                               default:
+                                       return NULL;
+                       }
+                       break;
+#endif
+#ifdef HAVE_CAMELLIA
+               case ENCR_CAMELLIA_CBC:
+                       switch (key_size)
+                       {
+                               case 0:
+                                       key_size = 16;
+                               case 16:
+                               case 24:
+                               case 32:
+                                       block_size = CAMELLIA_BLOCK_SIZE;
+                                       iv_size = CAMELLIA_BLOCK_SIZE;
+                                       break;
+                               default:
+                                       return NULL;
+                       }
+                       break;
+#endif
+#ifndef NO_DES3
+               case ENCR_3DES:
+                       if (key_size != 24)
+                       {
+                               return NULL;
+                       }
+                       block_size = DES_BLOCK_SIZE;
+                       iv_size = DES_BLOCK_SIZE;
+                       break;
+               case ENCR_DES:
+                       if (key_size != 8)
+                       {
+                               return NULL;
+                       }
+                       block_size = DES_BLOCK_SIZE;
+                       iv_size = DES_BLOCK_SIZE;
+                       break;
+       #ifdef WOLFSSL_DES_ECB
+               case ENCR_DES_ECB:
+                       if (key_size != 8)
+                       {
+                               return NULL;
+                       }
+                       key_size = DES_BLOCK_SIZE;
+                       block_size = DES_BLOCK_SIZE;
+                       iv_size = DES_BLOCK_SIZE;
+                       break;
+       #endif
+#endif
+               default:
+                       return NULL;
+       }
+
+       INIT(this,
+               .public = {
+                       .crypter = {
+                               .encrypt = _encrypt,
+                               .decrypt = _decrypt,
+                               .get_block_size = _get_block_size,
+                               .get_iv_size = _get_iv_size,
+                               .get_key_size = _get_key_size,
+                               .set_key = _set_key,
+                               .destroy = _destroy,
+                       },
+               },
+               .alg = algo,
+               .key_size = key_size,
+               .block_size = block_size,
+               .iv_size = iv_size,
+               .salt_len = salt_len,
+       );
+
+       switch (algo)
+       {
+#if !defined(NO_AES) && !defined(NO_AES_CBC)
+               case ENCR_AES_CBC:
+                       ret = wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID);
+                       break;
+#endif
+#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
+               case ENCR_AES_CTR:
+                       ret = wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID);
+                       break;
+#endif
+#ifdef HAVE_CAMELLIA
+               case ENCR_CAMELLIA_CBC:
+                       break;
+#endif
+#ifndef NO_DES3
+               case ENCR_3DES:
+                       ret = wc_Des3Init(&this->cipher.des3, NULL, INVALID_DEVID);
+                       break;
+               case ENCR_DES:
+       #ifdef WOLFSSL_DES_ECB
+               case ENCR_DES_ECB:
+       #endif
+                       break;
+#endif
+               default:
+                       break;
+       }
+       if (ret != 0)
+       {
+               free(this);
+               return NULL;
+       }
+
+       this->key = chunk_alloc(key_size);
+
+       return &this->public;
+}
+
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_crypter.h b/src/libstrongswan/plugins/wolfssl/wolfssl_crypter.h
new file mode 100644 (file)
index 0000000..31519c4
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_crypter wolfssl_crypter
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_CRYPTER_H_
+#define WOLFSSL_CRYPTER_H_
+
+typedef struct wolfssl_crypter_t wolfssl_crypter_t;
+
+#include <crypto/crypters/crypter.h>
+
+/**
+ * Implementation of crypters using wolfssl.
+ */
+struct wolfssl_crypter_t {
+
+       /**
+        * Implements crypter_t interface.
+        */
+       crypter_t crypter;
+};
+
+/**
+ * Constructor to create wolfssl_crypter_t.
+ *
+ * @param algo                 algorithm to implement
+ * @param key_size             key size in bytes
+ * @return                             wolfssl_crypter_t, NULL if not supported
+ */
+wolfssl_crypter_t *wolfssl_crypter_create(encryption_algorithm_t algo,
+                                                                               size_t key_size);
+
+#endif /** WOLFSSL_CRYPTER_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_diffie_hellman.c b/src/libstrongswan/plugins/wolfssl/wolfssl_diffie_hellman.c
new file mode 100644 (file)
index 0000000..fc6815c
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifndef NO_DH
+
+#include <wolfssl/wolfcrypt/dh.h>
+
+#include "wolfssl_diffie_hellman.h"
+#include "wolfssl_util.h"
+
+#include <utils/debug.h>
+
+typedef struct private_wolfssl_diffie_hellman_t private_wolfssl_diffie_hellman_t;
+
+/**
+ * Private data of an wolfssl_diffie_hellman_t object.
+ */
+struct private_wolfssl_diffie_hellman_t {
+       /**
+        * Public wolfssl_diffie_hellman_t interface.
+        */
+       wolfssl_diffie_hellman_t public;
+
+       /**
+        * Diffie Hellman group number.
+        */
+       diffie_hellman_group_t group;
+
+       /**
+        * Diffie Hellman object
+        */
+       DhKey dh;
+
+       /**
+        * Random number generator to use with RSA operations.
+        */
+       WC_RNG rng;
+
+       /**
+        * Length of public values
+        */
+       int len;
+
+       /**
+        * Private key
+        */
+       chunk_t priv;
+
+       /**
+        * Public key
+        */
+       chunk_t pub;
+
+       /**
+        * Shared secret
+        */
+       chunk_t shared_secret;
+
+       /**
+        * True if shared secret is computed
+        */
+       bool computed;
+};
+
+METHOD(diffie_hellman_t, get_my_public_value, bool,
+       private_wolfssl_diffie_hellman_t *this, chunk_t *value)
+{
+       /* Front pad the value with zeros to length of prime */
+       *value = chunk_alloc(this->len);
+       memset(value->ptr, 0, value->len - this->pub.len);
+       memcpy(value->ptr + value->len - this->pub.len, this->pub.ptr,
+                  this->pub.len);
+       return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_shared_secret, bool,
+       private_wolfssl_diffie_hellman_t *this, chunk_t *secret)
+{
+       if (!this->computed)
+       {
+               return FALSE;
+       }
+
+       /* Front pad with zeros to length of prime */
+       *secret = chunk_alloc(this->len);
+       memset(secret->ptr, 0, secret->len);
+       memcpy(secret->ptr + secret->len - this->shared_secret.len,
+                  this->shared_secret.ptr, this->shared_secret.len);
+       return TRUE;
+}
+
+
+METHOD(diffie_hellman_t, set_other_public_value, bool,
+       private_wolfssl_diffie_hellman_t *this, chunk_t value)
+{
+       word32 len;
+
+       if (!diffie_hellman_verify_value(this->group, value))
+       {
+               return FALSE;
+       }
+
+       chunk_clear(&this->shared_secret);
+       this->shared_secret.ptr = malloc(this->len);
+       memset(this->shared_secret.ptr, 0xFF, this->shared_secret.len);
+       len = this->shared_secret.len;
+       if (wc_DhAgree(&this->dh, this->shared_secret.ptr, &len, this->priv.ptr,
+                                  this->priv.len, value.ptr, value.len) != 0)
+       {
+               DBG1(DBG_LIB, "DH shared secret computation failed");
+               return FALSE;
+       }
+       this->shared_secret.len = len;
+       this->computed = TRUE;
+       return TRUE;
+}
+
+METHOD(diffie_hellman_t, set_private_value, bool,
+       private_wolfssl_diffie_hellman_t *this, chunk_t value)
+{
+       bool success = FALSE;
+       chunk_t g;
+       word32 len;
+       int ret;
+
+       chunk_clear(&this->priv);
+       this->priv = chunk_clone(value);
+
+       /* Calculate public value - g^priv mod p */
+       if (wolfssl_mp2chunk(&this->dh.g, &g))
+       {
+               len = this->pub.len;
+               ret = wc_DhAgree(&this->dh, this->pub.ptr, &len, this->priv.ptr,
+                                                this->priv.len, g.ptr, g.len);
+               if (ret == 0) {
+                       this->pub.len = len;
+                       success = TRUE;
+               }
+       }
+
+       free(g.ptr);
+       return success;
+}
+
+METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
+       private_wolfssl_diffie_hellman_t *this)
+{
+       return this->group;
+}
+
+/**
+ * Lookup the modulus in modulo table
+ */
+static status_t set_modulus(private_wolfssl_diffie_hellman_t *this)
+{
+       diffie_hellman_params_t *params = diffie_hellman_get_params(this->group);
+       if (!params)
+       {
+               return NOT_FOUND;
+       }
+
+       this->len = params->prime.len;
+       if (wc_DhSetKey(&this->dh, params->prime.ptr, params->prime.len,
+                                       params->generator.ptr, params->generator.len) != 0)
+       {
+               return FAILED;
+       }
+
+       return SUCCESS;
+}
+
+METHOD(diffie_hellman_t, destroy, void,
+       private_wolfssl_diffie_hellman_t *this)
+{
+       wc_FreeRng(&this->rng);
+       wc_FreeDhKey(&this->dh);
+       chunk_clear(&this->pub);
+       chunk_clear(&this->priv);
+       chunk_clear(&this->shared_secret);
+       free(this);
+}
+
+/**
+ * Maximum private key length when generating key
+ */
+static int wolfssl_priv_key_size(int len)
+{
+       if (len <= 128)
+       {
+               return 21;
+       }
+       if (len <= 256)
+       {
+               return 29;
+       }
+       if (len <= 384)
+       {
+               return 34;
+       }
+       if (len <= 512)
+       {
+               return 39;
+       }
+       if (len <= 640)
+       {
+               return 42;
+       }
+       if (len <= 768)
+       {
+               return 46;
+       }
+       if (len <= 896)
+       {
+               return 49;
+       }
+       if (len <= 1024)
+       {
+               return 52;
+       }
+       return len / 20;
+}
+
+/*
+ * Described in header.
+ */
+wolfssl_diffie_hellman_t *wolfssl_diffie_hellman_create(
+                                                                                       diffie_hellman_group_t group, ...)
+{
+       private_wolfssl_diffie_hellman_t *this;
+       word32 privLen, pubLen;
+
+       INIT(this,
+               .public = {
+                       .dh = {
+                               .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,
+                       },
+               },
+       );
+
+       if (wc_InitRng(&this->rng) != 0)
+       {
+               free(this);
+               return NULL;
+       }
+       if (wc_InitDhKey(&this->dh) != 0)
+       {
+               wc_FreeRng(&this->rng);
+               free(this);
+               return NULL;
+       }
+
+       this->group = group;
+       this->computed = FALSE;
+       this->priv = chunk_empty;
+       this->pub = chunk_empty;
+       this->shared_secret = chunk_empty;
+
+
+       if (group == MODP_CUSTOM)
+       {
+               chunk_t g, p;
+
+               VA_ARGS_GET(group, g, p);
+               this->len = p.len;
+               if (wc_DhSetKey(&this->dh, p.ptr, p.len, g.ptr, g.len) != 0)
+               {
+                       destroy(this);
+                       return NULL;
+               }
+       }
+       else
+       {
+               /* find a modulus according to group */
+               if (set_modulus(this) != SUCCESS)
+               {
+                       destroy(this);
+                       return NULL;
+               }
+       }
+
+       this->priv = chunk_alloc(wolfssl_priv_key_size(this->len));
+       this->pub = chunk_alloc(this->len);
+       privLen = this->priv.len;
+       pubLen = this->pub.len;
+       /* generate my public and private values */
+       if (wc_DhGenerateKeyPair(&this->dh, &this->rng, this->priv.ptr, &privLen,
+                                                        this->pub.ptr, &pubLen) != 0)
+       {
+               destroy(this);
+               return NULL;
+       }
+       this->pub.len = pubLen;
+       this->priv.len = privLen;
+
+       return &this->public;
+}
+
+#endif /* NO_DH */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_diffie_hellman.h b/src/libstrongswan/plugins/wolfssl/wolfssl_diffie_hellman.h
new file mode 100644 (file)
index 0000000..85952e7
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_diffie_hellman wolfssl_diffie_hellman
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_DIFFIE_HELLMAN_H_
+#define WOLFSSL_DIFFIE_HELLMAN_H_
+
+typedef struct wolfssl_diffie_hellman_t wolfssl_diffie_hellman_t;
+
+#include <library.h>
+
+/**
+ * Implementation of the Diffie-Hellman algorithm using wolfSSL.
+ */
+struct wolfssl_diffie_hellman_t {
+
+       /**
+        * Implements diffie_hellman_t interface.
+        */
+       diffie_hellman_t dh;
+};
+
+/**
+ * Creates a new wolfssl_diffie_hellman_t object.
+ *
+ * @param group                        Diffie Hellman group number to use
+ * @param ...                  expects generator and prime as chunk_t if MODP_CUSTOM
+ * @return                             wolfssl_diffie_hellman_t object, NULL if not supported
+ */
+wolfssl_diffie_hellman_t *wolfssl_diffie_hellman_create(
+                                                                                       diffie_hellman_group_t group, ...);
+
+#endif /** WOLFSSL_DIFFIE_HELLMAN_H_ @}*/
+
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ec_diffie_hellman.c b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_diffie_hellman.c
new file mode 100644 (file)
index 0000000..20f1031
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifdef HAVE_ECC_DHE
+
+#include <wolfssl/wolfcrypt/ecc.h>
+
+#include "wolfssl_ec_diffie_hellman.h"
+#include "wolfssl_util.h"
+
+#include <utils/debug.h>
+
+typedef struct private_wolfssl_ec_diffie_hellman_t private_wolfssl_ec_diffie_hellman_t;
+
+/**
+ * Private data of an wolfssl_ec_diffie_hellman_t object.
+ */
+struct private_wolfssl_ec_diffie_hellman_t {
+       /**
+        * Public wolfssl_ec_diffie_hellman_t interface.
+        */
+       wolfssl_ec_diffie_hellman_t public;
+
+       /**
+        * Diffie Hellman group number.
+        */
+       diffie_hellman_group_t group;
+
+       /**
+        * EC curve id for creating keys
+        */
+       ecc_curve_id curve_id;
+
+       /**
+        * Size of an ordinate in bytes
+        */
+       int keysize;
+
+       /**
+        * EC private (public) key
+        */
+       ecc_key key;
+
+       /**
+        * Other public key
+        */
+       ecc_point *pub_key;
+
+       /**
+        * Shared secret
+        */
+       chunk_t shared_secret;
+
+       /**
+        * Random number generator
+        */
+       WC_RNG rng;
+
+       /**
+        * True if shared secret is computed
+        */
+       bool computed;
+};
+
+/**
+ * Convert a chunk to an ecc_point (which must already exist). The x and y
+ * coordinates of the point have to be concatenated in the chunk.
+ */
+static bool chunk2ecp(chunk_t chunk, ecc_point *point)
+{
+       if (!wolfssl_mp_split(chunk, point->x, point->y))
+               return FALSE;
+       if (mp_set(point->z, 1) != 0)
+               return FALSE;
+       return TRUE;
+}
+
+/**
+ * Convert an ec_point to a chunk by concatenating the x and y coordinates of
+ * the point. This function allocates memory for the chunk.
+ */
+static bool ecp2chunk(int keysize, ecc_point *point, chunk_t *chunk,
+                                         bool x_coordinate_only)
+{
+       mp_int *y = NULL;
+
+       if (!x_coordinate_only)
+       {
+               keysize *= 2;
+               y = point->y;
+       }
+       return wolfssl_mp_cat(keysize, point->x, y, chunk);
+}
+
+
+/**
+ * Perform the elliptic curve scalar multiplication.
+ */
+static bool wolfssl_ecc_multiply(const ecc_set_type *ecc_set, mp_int *scalar,
+                                                                ecc_point* point, ecc_point* r)
+{
+       int ret;
+       mp_int a, prime;
+
+       ret = mp_init(&a);
+       if (ret != 0)
+       {
+               return FALSE;
+       }
+       ret = mp_init(&prime);
+       if (ret != 0)
+       {
+               mp_free(&a);
+               return FALSE;
+       }
+
+       ret = mp_read_radix(&a, ecc_set->Af, MP_RADIX_HEX);
+       if (ret == 0)
+       {
+               ret = mp_read_radix(&prime, ecc_set->prime, MP_RADIX_HEX);
+       }
+       if (ret == 0)
+       {
+               /* Multiply the point by our secret */
+               ret = wc_ecc_mulmod(scalar, point, r, &a, &prime, 1);
+       }
+
+       mp_free(&prime);
+       mp_free(&a);
+
+       return ret == 0;
+}
+
+/**
+ * Compute the shared secret.
+ *
+ * We cannot use the function wc_ecc_shared_secret() because that returns only
+ * the x coordinate of the shared secret point (which is defined, for instance,
+ * in 'NIST SP 800-56A').
+ * However, we need both coordinates as RFC 4753 says: "The Diffie-Hellman
+ *   public value is obtained by concatenating the x and y values. The format
+ *   of the Diffie-Hellman shared secret value is the same as that of the
+ *   Diffie-Hellman public value."
+ */
+static bool compute_shared_key(private_wolfssl_ec_diffie_hellman_t *this,
+                                                          chunk_t *shared_secret)
+{
+       bool success = FALSE;
+       ecc_point* secret;
+       bool x_coordinate_only;
+
+       if ((secret = wc_ecc_new_point()) == NULL)
+       {
+               return FALSE;
+       }
+
+       if (wolfssl_ecc_multiply(this->key.dp, &this->key.k, this->pub_key, secret))
+       {
+               /*
+               * The default setting ecp_x_coordinate_only = TRUE
+               * applies the following errata for RFC 4753:
+               * http://www.rfc-editor.org/errata_search.php?eid=9
+               */
+               x_coordinate_only = lib->settings->get_bool(lib->settings,
+                                                                        "%s.ecp_x_coordinate_only", TRUE, lib->ns);
+               success = ecp2chunk(this->keysize, secret, shared_secret,
+                                                       x_coordinate_only);
+       }
+
+       wc_ecc_del_point(secret);
+       return success;
+}
+
+METHOD(diffie_hellman_t, set_other_public_value, bool,
+       private_wolfssl_ec_diffie_hellman_t *this, chunk_t value)
+{
+       if (!diffie_hellman_verify_value(this->group, value))
+       {
+               return FALSE;
+       }
+
+       if (!chunk2ecp(value, this->pub_key))
+       {
+               DBG1(DBG_LIB, "ECDH public value is malformed");
+               return FALSE;
+       }
+
+       chunk_clear(&this->shared_secret);
+
+       if (!compute_shared_key(this, &this->shared_secret))
+       {
+               DBG1(DBG_LIB, "ECDH shared secret computation failed");
+               return FALSE;
+       }
+
+       this->computed = TRUE;
+       return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_my_public_value, bool,
+       private_wolfssl_ec_diffie_hellman_t *this,chunk_t *value)
+{
+       return ecp2chunk(this->keysize, &this->key.pubkey, value, FALSE);
+}
+
+METHOD(diffie_hellman_t, set_private_value, bool,
+       private_wolfssl_ec_diffie_hellman_t *this, chunk_t value)
+{
+       bool success = FALSE;
+       ecc_point *base;
+       int ret;
+
+       if ((base = wc_ecc_new_point()) == NULL)
+       {
+               return FALSE;
+       }
+
+       ret = mp_read_unsigned_bin(&this->key.k, value.ptr, value.len);
+       /* Get base point */
+       if (ret == 0)
+       {
+               ret = mp_read_radix(base->x, this->key.dp->Gx, MP_RADIX_HEX);
+       }
+       if (ret == 0)
+       {
+               ret = mp_read_radix(base->y, this->key.dp->Gy, MP_RADIX_HEX);
+       }
+       if (ret == 0)
+       {
+               ret = mp_set(base->z, 1);
+       }
+       if (ret == 0)
+       {
+               /* Calculate public key */
+               success = wolfssl_ecc_multiply(this->key.dp, &this->key.k, base,
+                                                                          &this->key.pubkey);
+       }
+
+       wc_ecc_del_point(base);
+
+       return success;
+}
+
+METHOD(diffie_hellman_t, get_shared_secret, bool,
+       private_wolfssl_ec_diffie_hellman_t *this, chunk_t *secret)
+{
+       if (!this->computed)
+       {
+               return FALSE;
+       }
+       *secret = chunk_clone(this->shared_secret);
+       return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
+       private_wolfssl_ec_diffie_hellman_t *this)
+{
+       return this->group;
+}
+
+METHOD(diffie_hellman_t, destroy, void,
+       private_wolfssl_ec_diffie_hellman_t *this)
+{
+       wc_FreeRng(&this->rng);
+       wc_ecc_del_point(this->pub_key);
+       wc_ecc_free(&this->key);
+       chunk_clear(&this->shared_secret);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+wolfssl_ec_diffie_hellman_t *wolfssl_ec_diffie_hellman_create(diffie_hellman_group_t group)
+{
+       private_wolfssl_ec_diffie_hellman_t *this;
+
+       INIT(this,
+               .public = {
+                       .dh = {
+                               .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_ecc_init(&this->key) != 0)
+       {
+               DBG1(DBG_LIB, "key init failed, ecdh create failed");
+               free(this);
+               return NULL;
+       }
+       if ((this->pub_key = wc_ecc_new_point()) == NULL)
+       {
+               wc_ecc_free(&this->key);
+               DBG1(DBG_LIB, "pub_key init failed, ecdh create failed");
+               free(this);
+               return NULL;
+       }
+       if (wc_InitRng(&this->rng) != 0)
+       {
+               wc_ecc_del_point(this->pub_key);
+               wc_ecc_free(&this->key);
+               DBG1(DBG_LIB, "RNG init failed, ecdh create failed");
+               free(this);
+               return NULL;
+       }
+
+       switch (group)
+       {
+               case ECP_192_BIT:
+                       this->curve_id = ECC_SECP192R1;
+                       this->keysize = 192 / 8;
+                       break;
+               case ECP_224_BIT:
+                       this->curve_id = ECC_SECP224R1;
+                       this->keysize = 224 / 8;
+                       break;
+               case ECP_256_BIT:
+                       this->curve_id = ECC_SECP256R1;
+                       this->keysize = 256 / 8;
+                       break;
+               case ECP_384_BIT:
+                       this->curve_id = ECC_SECP384R1;
+                       this->keysize = 384 / 8;
+                       break;
+               case ECP_521_BIT:
+                       this->curve_id = ECC_SECP521R1;
+                       this->keysize = (521 + 7) / 8;
+                       break;
+#ifdef HAVE_BRAINPOOL
+               case ECP_224_BP:
+                       this->curve_id = ECC_BRAINPOOLP224R1;
+                       this->keysize = 224 / 8;
+                       break;
+               case ECP_256_BP:
+                       this->curve_id = ECC_BRAINPOOLP256R1;
+                       this->keysize = 256 / 8;
+                       break;
+               case ECP_384_BP:
+                       this->curve_id = ECC_BRAINPOOLP384R1;
+                       this->keysize = 384 / 8;
+                       break;
+               case ECP_512_BP:
+                       this->curve_id = ECC_BRAINPOOLP512R1;
+                       this->keysize = 512 / 8;
+                       break;
+#endif
+               default:
+                       DBG1(DBG_LIB, "EC group not supported");
+                       destroy(this);
+                       return NULL;
+       }
+
+       /* generate an EC private (public) key */
+       if (wc_ecc_make_key_ex(&this->rng, this->keysize, &this->key,
+                                                  this->curve_id) != 0)
+       {
+               DBG1(DBG_LIB, "Make key failed, wolfssl ECDH create failed");
+               destroy(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
+#endif /* HAVE_ECC_DHE */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ec_diffie_hellman.h b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_diffie_hellman.h
new file mode 100644 (file)
index 0000000..d9e3769
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_ec_diffie_hellman wolfssl_ec_diffie_hellman
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_EC_DIFFIE_HELLMAN_H_
+#define WOLFSSL_EC_DIFFIE_HELLMAN_H_
+
+typedef struct wolfssl_ec_diffie_hellman_t wolfssl_ec_diffie_hellman_t;
+
+#include <library.h>
+
+/**
+ * Implementation of the EC Diffie-Hellman algorithm using wolfSSL.
+ */
+struct wolfssl_ec_diffie_hellman_t {
+
+       /**
+        * Implements diffie_hellman_t interface.
+        */
+       diffie_hellman_t dh;
+};
+
+/**
+ * Creates a new wolfssl_ec_diffie_hellman_t object.
+ *
+ * @param group                        EC Diffie Hellman group number to use
+ * @return                             wolfssl_ec_diffie_hellman_t object, NULL if not supported
+ */
+wolfssl_ec_diffie_hellman_t *wolfssl_ec_diffie_hellman_create(diffie_hellman_group_t group);
+
+#endif /** WOLFSSL_EC_DIFFIE_HELLMAN_H_ @}*/
+
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ec_private_key.c b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_private_key.c
new file mode 100644 (file)
index 0000000..f127bd1
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifdef HAVE_ECC_SIGN
+
+#include "wolfssl_ec_private_key.h"
+#include "wolfssl_ec_public_key.h"
+#include "wolfssl_util.h"
+
+#include <asn1/asn1.h>
+#include <asn1/oid.h>
+
+#include <utils/debug.h>
+
+#include <wolfssl/wolfcrypt/ecc.h>
+
+
+typedef struct private_wolfssl_ec_private_key_t private_wolfssl_ec_private_key_t;
+
+/**
+ * Private data of a wolfssl_ec_private_key_t object.
+ */
+struct private_wolfssl_ec_private_key_t {
+       /**
+        * Public interface for this signer.
+        */
+       wolfssl_ec_private_key_t public;
+
+       /**
+        * Key size
+        */
+       int keysize;
+
+       /**
+        * EC key object
+        */
+       ecc_key ec;
+
+       /**
+        * Random number generator
+        */
+       WC_RNG rng;
+
+       /**
+        * reference count
+        */
+       refcount_t ref;
+};
+
+/* from ec public key */
+bool wolfssl_ec_fingerprint(ecc_key *ec, cred_encoding_type_t type, chunk_t *fp);
+
+/**
+ * Build a signature as in RFC 4754
+ */
+static bool build_signature(private_wolfssl_ec_private_key_t *this,
+                                                       chunk_t hash, chunk_t *signature)
+{
+       bool success = FALSE;
+       mp_int r, s;
+
+       if (mp_init(&r) != 0)
+       {
+               return FALSE;
+       }
+       if (mp_init(&s) != 0)
+       {
+               mp_free(&r);
+               return FALSE;
+       }
+       if (wc_ecc_sign_hash_ex(hash.ptr, hash.len, &this->rng, &this->ec, &r,
+                                                       &s) == 0)
+       {
+               success = wolfssl_mp_cat(this->ec.dp->size * 2, &r, &s, signature);
+       }
+
+       mp_free(&s);
+       mp_free(&r);
+       
+       return success;
+}
+
+/**
+ * Build a RFC 4754 signature for a specified curve and hash algorithm
+ */
+static bool build_curve_signature(private_wolfssl_ec_private_key_t *this,
+               signature_scheme_t scheme, enum wc_HashType hash, ecc_curve_id curve_id,
+               chunk_t data, chunk_t *signature)
+{
+       bool success = FALSE;
+       chunk_t dgst = chunk_empty;
+
+       if (curve_id != this->ec.dp->id)
+       {
+               DBG1(DBG_LIB, "signature scheme %N not supported by private key",
+                       signature_scheme_names, scheme);
+               return FALSE;
+       }
+       if (wolfssl_hash_chunk(hash, data, &dgst))
+       {
+               success = build_signature(this, dgst, signature);
+       }
+       chunk_free(&dgst);
+       return success;
+}
+
+/**
+ * Build a DER encoded signature as in RFC 3279
+ */
+static bool build_der_signature(private_wolfssl_ec_private_key_t *this,
+               enum wc_HashType hash, chunk_t data, chunk_t *signature)
+{
+       bool success = FALSE;
+       chunk_t dgst = chunk_empty;
+       int ret;
+       word32 len;
+
+       if (wolfssl_hash_chunk(hash, data, &dgst))
+       {
+               *signature = chunk_alloc(this->ec.dp->size * 2 + 10);
+               len = signature->len;
+               ret = wc_ecc_sign_hash(dgst.ptr, dgst.len, signature->ptr, &len,
+                                                          &this->rng, &this->ec);
+               if (ret == 0)
+               {
+                       signature->len = len;
+                       success = TRUE;
+               }
+               else
+               {
+                       chunk_free(signature);
+               }
+       }
+
+       chunk_free(&dgst);
+       return success;
+}
+
+METHOD(private_key_t, sign, bool,
+       private_wolfssl_ec_private_key_t *this, signature_scheme_t scheme,
+       void *params, chunk_t data, chunk_t *signature)
+{
+       switch (scheme)
+       {
+               case SIGN_ECDSA_WITH_NULL:
+                       return build_signature(this, data, signature);
+       #ifndef NO_SHA
+               case SIGN_ECDSA_WITH_SHA1_DER:
+                       return build_der_signature(this, WC_HASH_TYPE_SHA, data, signature);
+       #endif
+       #ifndef NO_SHA256
+               case SIGN_ECDSA_WITH_SHA256_DER:
+                       return build_der_signature(this, WC_HASH_TYPE_SHA256, data,
+                                                                          signature);
+       #endif
+       #ifdef WOLFSSL_SHA384
+               case SIGN_ECDSA_WITH_SHA384_DER:
+                       return build_der_signature(this, WC_HASH_TYPE_SHA384, data,
+                                                                          signature);
+       #endif
+       #ifdef WOLFSSL_SHA512
+               case SIGN_ECDSA_WITH_SHA512_DER:
+                       return build_der_signature(this, WC_HASH_TYPE_SHA512, data,
+                                                                          signature);
+       #endif
+       #ifndef NO_SHA256
+               case SIGN_ECDSA_256:
+                       return build_curve_signature(this, scheme, WC_HASH_TYPE_SHA256,
+                                                                                ECC_SECP256R1, data, signature);
+       #endif
+       #ifdef WOLFSSL_SHA384
+               case SIGN_ECDSA_384:
+                       return build_curve_signature(this, scheme, WC_HASH_TYPE_SHA384,
+                                                                                ECC_SECP384R1, data, signature);
+       #endif
+       #ifdef WOLFSSL_SHA512
+               case SIGN_ECDSA_521:
+                       return build_curve_signature(this, scheme, WC_HASH_TYPE_SHA512,
+                                                                                ECC_SECP521R1, data, signature);
+       #endif
+               default:
+                       DBG1(DBG_LIB, "signature scheme %N not supported",
+                                signature_scheme_names, scheme);
+                       return FALSE;
+       }
+}
+
+METHOD(private_key_t, decrypt, bool,
+       private_wolfssl_ec_private_key_t *this, encryption_scheme_t scheme,
+       chunk_t crypto, chunk_t *plain)
+{
+       DBG1(DBG_LIB, "EC private key decryption not implemented");
+       return FALSE;
+}
+
+METHOD(private_key_t, get_keysize, int,
+       private_wolfssl_ec_private_key_t *this)
+{
+       return this->keysize;
+}
+
+METHOD(private_key_t, get_type, key_type_t,
+       private_wolfssl_ec_private_key_t *this)
+{
+       return KEY_ECDSA;
+}
+
+METHOD(private_key_t, get_public_key, public_key_t*,
+       private_wolfssl_ec_private_key_t *this)
+{
+       public_key_t *public;
+       chunk_t key;
+       int ret;
+
+       key = chunk_alloc((this->keysize + 7) / 8 * 5);
+       ret = wc_EccPublicKeyToDer(&this->ec, key.ptr, key.len, 1);
+       if (ret < 0)
+       {
+               chunk_free(&key);
+               return NULL;
+       }
+       key.len = ret;
+
+       public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA,
+                                                               BUILD_BLOB_ASN1_DER, key, BUILD_END);
+       free(key.ptr);
+       return public;
+}
+
+METHOD(private_key_t, get_fingerprint, bool,
+       private_wolfssl_ec_private_key_t *this, cred_encoding_type_t type,
+       chunk_t *fingerprint)
+{
+       return wolfssl_ec_fingerprint(&this->ec, type, fingerprint);
+}
+
+METHOD(private_key_t, get_encoding, bool,
+       private_wolfssl_ec_private_key_t *this, cred_encoding_type_t type,
+       chunk_t *encoding)
+{
+       switch (type)
+       {
+               case PRIVKEY_ASN1_DER:
+               case PRIVKEY_PEM:
+               {
+                       bool success = TRUE;
+
+                       *encoding = chunk_alloc(this->keysize * 4 + 30);
+                       if (wc_EccPrivateKeyToDer(&this->ec, encoding->ptr,
+                                                                         encoding->len) < 0)
+                       {
+                               chunk_free(encoding);
+                               return FALSE;
+                       }
+
+                       if (type == PRIVKEY_PEM)
+                       {
+                               chunk_t asn1_encoding = *encoding;
+
+                               success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM,
+                                                               NULL, encoding, CRED_PART_ECDSA_PRIV_ASN1_DER,
+                                                               asn1_encoding, CRED_PART_END);
+                               chunk_clear(&asn1_encoding);
+                       }
+                       return success;
+               }
+               default:
+                       return FALSE;
+       }
+}
+
+METHOD(private_key_t, get_ref, private_key_t*,
+       private_wolfssl_ec_private_key_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public.key;
+}
+
+METHOD(private_key_t, destroy, void,
+       private_wolfssl_ec_private_key_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               lib->encoding->clear_cache(lib->encoding, &this->ec);
+               wc_FreeRng(&this->rng);
+               wc_ecc_free(&this->ec);
+               free(this);
+       }
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_wolfssl_ec_private_key_t *create_empty(void)
+{
+       private_wolfssl_ec_private_key_t *this;
+
+       INIT(this,
+               .public = {
+                       .key = {
+                               .get_type = _get_type,
+                               .sign = _sign,
+                               .decrypt = _decrypt,
+                               .get_keysize = _get_keysize,
+                               .get_public_key = _get_public_key,
+                               .equals = private_key_equals,
+                               .belongs_to = private_key_belongs_to,
+                               .get_fingerprint = _get_fingerprint,
+                               .has_fingerprint = private_key_has_fingerprint,
+                               .get_encoding = _get_encoding,
+                               .get_ref = _get_ref,
+                               .destroy = _destroy,
+                       },
+               },
+               .ref = 1,
+       );
+
+       if (wc_InitRng(&this->rng) < 0)
+       {
+               DBG1(DBG_LIB, "Random number generation init failed");
+               free(this);
+               return NULL;
+       }
+
+       return this;
+}
+
+/*
+ * See header.
+ */
+wolfssl_ec_private_key_t *wolfssl_ec_private_key_gen(key_type_t type,
+                                                                                                        va_list args)
+{
+       private_wolfssl_ec_private_key_t *this;
+       u_int key_size = 0;
+       ecc_curve_id curve_id;
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_KEY_SIZE:
+                               key_size = va_arg(args, u_int);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+       if (!key_size)
+       {
+               return NULL;
+       }
+       this = create_empty();
+       this->keysize = key_size;
+       switch (key_size)
+       {
+               case 256:
+                       curve_id = ECC_SECP256R1;
+                       break;
+               case 384:
+                       curve_id = ECC_SECP384R1;
+                       break;
+               case 521:
+                       curve_id = ECC_SECP521R1;
+                       break;
+               default:
+                       DBG1(DBG_LIB, "EC private key size %d not supported", key_size);
+                       destroy(this);
+                       return NULL;
+       }
+
+       if (wc_ecc_make_key_ex(&this->rng, (key_size + 7) / 8, &this->ec,
+                                                  curve_id) < 0)
+       {
+               DBG1(DBG_LIB, "EC private key generation failed", key_size);
+               destroy(this);
+               return NULL;
+       }
+       return &this->public;
+}
+
+/**
+ * See header.
+ */
+wolfssl_ec_private_key_t *wolfssl_ec_private_key_load(key_type_t type,
+                                                                                                         va_list args)
+{
+       private_wolfssl_ec_private_key_t *this;
+       chunk_t params = chunk_empty;
+       chunk_t key = chunk_empty;
+       chunk_t alg_id = chunk_empty;
+       word32 idx;
+       int oid;
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_BLOB_ALGID_PARAMS:
+                               params = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_BLOB_ASN1_DER:
+                               key = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+       if (key.ptr == NULL)
+       {
+               return NULL;
+       }
+
+       this = create_empty();
+
+       idx = 0;
+       if (wc_EccPrivateKeyDecode(key.ptr, &idx, &this->ec, key.len) < 0)
+       {
+               destroy(this);
+               return NULL;
+       }
+       switch (this->ec.dp->id)
+       {
+               case ECC_SECP256R1:
+                       this->keysize = 256;
+                       break;
+               case ECC_SECP384R1:
+                       this->keysize = 384;
+                       break;
+               case ECC_SECP521R1:
+                       this->keysize = 521;
+                       break;
+               default:
+                       break;
+       }
+
+       if (params.ptr)
+       {
+               /* if ECParameters is passed, check we guessed correct */
+               alg_id = asn1_algorithmIdentifier_params(OID_EC_PUBLICKEY,
+                                                                                                chunk_clone(params));
+               if (asn1_unwrap(&params, &params) == ASN1_OID)
+               {
+                       oid = asn1_known_oid(params);
+                       switch (oid)
+                       {
+                               case OID_PRIME256V1:
+                                       if (this->ec.dp->id != ECC_SECP256R1)
+                                       {
+                                               oid = OID_UNKNOWN;
+                                       }
+                                       break;
+                               case OID_SECT384R1:
+                                       if (this->ec.dp->id != ECC_SECP384R1)
+                                       {
+                                               oid = OID_UNKNOWN;
+                                       }
+                                       break;
+                               case OID_SECT521R1:
+                                       if (this->ec.dp->id != ECC_SECP521R1)
+                                       {
+                                               oid = OID_UNKNOWN;
+                                       }
+                                       break;
+                               default:
+                                       oid = OID_UNKNOWN;
+                                       break;
+                       }
+               }
+               chunk_free(&alg_id);
+               if (oid == OID_UNKNOWN)
+               {
+                       DBG1(DBG_LIB, "parameters do not match private key data");
+                       destroy(this);
+                       return NULL;
+               }
+       }
+
+       return &this->public;
+}
+#endif /* HAVE_ECC_SIGN */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ec_private_key.h b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_private_key.h
new file mode 100644 (file)
index 0000000..971b6e9
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_ec_private_key wolfssl_ec_private_key
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_EC_PRIVATE_KEY_H_
+#define WOLFSSL_EC_PRIVATE_KEY_H_
+
+#include <credentials/builder.h>
+#include <credentials/keys/private_key.h>
+
+typedef struct wolfssl_ec_private_key_t wolfssl_ec_private_key_t;
+
+/**
+ * private_key_t implementation of ECDSA using wolfSSL.
+ */
+struct wolfssl_ec_private_key_t {
+
+       /**
+        * Implements private_key_t interface
+        */
+       private_key_t key;
+};
+
+/**
+ * Generate a ECDSA private key using wolfSSL.
+ *
+ * Accepts the BUILD_KEY_SIZE argument.
+ *
+ * @param type         type of the key, must be KEY_ECDSA
+ * @param args         builder_part_t argument list
+ * @return                     generated key, NULL on failure
+ */
+wolfssl_ec_private_key_t *wolfssl_ec_private_key_gen(key_type_t type,
+                                                                                                        va_list args);
+
+/**
+ * Load a ECDSA private key using wolfSSL.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type         type of the key, must be KEY_ECDSA
+ * @param args         builder_part_t argument list
+ * @return                     loaded key, NULL on failure
+ */
+wolfssl_ec_private_key_t *wolfssl_ec_private_key_load(key_type_t type,
+                                                                                                         va_list args);
+
+#endif /** WOLFSSL_EC_PRIVATE_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.c b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.c
new file mode 100644 (file)
index 0000000..1bca252
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifdef HAVE_ECC_VERIFY
+
+#include "wolfssl_ec_public_key.h"
+#include "wolfssl_util.h"
+
+#include <utils/debug.h>
+
+#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/wolfcrypt/hash.h>
+
+
+typedef struct private_wolfssl_ec_public_key_t private_wolfssl_ec_public_key_t;
+
+/**
+ * Private data structure with signing context.
+ */
+struct private_wolfssl_ec_public_key_t {
+       /**
+        * Public interface for this signer.
+        */
+       wolfssl_ec_public_key_t public;
+
+       /**
+        * Key size
+        */
+       int keysize;
+
+       /**
+        * EC key object
+        */
+       ecc_key ec;
+
+       /**
+        * reference counter
+        */
+       refcount_t ref;
+};
+
+/**
+ * Verification of a signature as in RFC 4754
+ */
+static bool verify_signature(private_wolfssl_ec_public_key_t *this,
+                                                        chunk_t hash, chunk_t signature)
+{
+       int stat = 1;
+       int ret = -1;
+       mp_int r, s;
+
+       if (mp_init(&r) < 0)
+       {
+               return FALSE;
+       }
+       if (mp_init(&s) < 0)
+       {
+               mp_free(&r);
+               return FALSE;
+       }
+
+       if (wolfssl_mp_split(signature, &r, &s))
+       {
+               ret = wc_ecc_verify_hash_ex(&r, &s, hash.ptr, hash.len, &stat,
+                                                                       &this->ec);
+       }
+
+       mp_free(&s);
+       mp_free(&r);
+
+       return ret == 0 && stat == 1;
+}
+
+/**
+ * Verify a RFC 4754 signature for a specified curve and hash algorithm
+ */
+static bool verify_curve_signature(private_wolfssl_ec_public_key_t *this,
+               signature_scheme_t scheme, enum wc_HashType hash, ecc_curve_id curve_id,
+               chunk_t data, chunk_t signature)
+{
+       bool success = FALSE;
+       chunk_t dgst;
+
+       if (curve_id != this->ec.dp->id)
+       {
+               DBG1(DBG_LIB, "signature scheme %N not supported by private key",
+                        signature_scheme_names, scheme);
+               return FALSE;
+       }
+
+       if (wolfssl_hash_chunk(hash, data, &dgst))
+       {
+               success = verify_signature(this, dgst, signature);
+       }
+
+       chunk_free(&dgst);
+       return success;
+}
+
+/**
+ * Verification of a DER encoded signature as in RFC 3279
+ */
+static bool verify_der_signature(private_wolfssl_ec_public_key_t *this,
+               enum wc_HashType hash, chunk_t data, chunk_t signature)
+{
+       bool success = FALSE;
+       chunk_t dgst;
+       int stat = 1;
+       int ret;
+
+       /* remove any preceding 0-bytes from signature */
+       while (signature.len && signature.ptr[0] == 0x00)
+       {
+               signature = chunk_skip(signature, 1);
+       }
+       if (wolfssl_hash_chunk(hash, data, &dgst))
+       {
+               ret = wc_ecc_verify_hash(signature.ptr, signature.len, dgst.ptr,
+                                                                dgst.len, &stat, &this->ec);
+               if (ret == 0 && stat == 1)
+               {
+                       success = TRUE;
+               }
+       }
+
+       chunk_free(&dgst);
+       return success;
+}
+
+METHOD(public_key_t, get_type, key_type_t,
+       private_wolfssl_ec_public_key_t *this)
+{
+       return KEY_ECDSA;
+}
+
+METHOD(public_key_t, verify, bool,
+       private_wolfssl_ec_public_key_t *this, signature_scheme_t scheme,
+       void *params, chunk_t data, chunk_t signature)
+{
+       switch (scheme)
+       {
+       #ifndef NO_SHA
+               case SIGN_ECDSA_WITH_SHA1_DER:
+                       return verify_der_signature(this, WC_HASH_TYPE_SHA, data,
+                                                                               signature);
+       #endif
+       #ifndef NO_SHA256
+               case SIGN_ECDSA_WITH_SHA256_DER:
+                       return verify_der_signature(this, WC_HASH_TYPE_SHA256, data,
+                                                                               signature);
+       #endif
+       #ifdef WOLFSSL_SHA384
+               case SIGN_ECDSA_WITH_SHA384_DER:
+                       return verify_der_signature(this, WC_HASH_TYPE_SHA384, data,
+                                                                               signature);
+       #endif
+       #ifdef WOLFSSL_SHA512
+               case SIGN_ECDSA_WITH_SHA512_DER:
+                       return verify_der_signature(this, WC_HASH_TYPE_SHA512, data,
+                                                                               signature);
+       #endif
+               case SIGN_ECDSA_WITH_NULL:
+                       return verify_signature(this, data, signature);
+       #ifndef NO_SHA256
+               case SIGN_ECDSA_256:
+                       return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA256,
+                                                                                 ECC_SECP256R1, data, signature);
+       #endif
+       #ifdef WOLFSSL_SHA384
+               case SIGN_ECDSA_384:
+                       return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA384,
+                                                                                 ECC_SECP384R1, data, signature);
+       #endif
+       #ifdef WOLFSSL_SHA512
+               case SIGN_ECDSA_521:
+                       return verify_curve_signature(this, scheme, WC_HASH_TYPE_SHA512,
+                                                                                 ECC_SECP521R1, data, signature);
+       #endif
+               default:
+                       DBG1(DBG_LIB, "signature scheme %N not supported in EC",
+                                signature_scheme_names, scheme);
+                       return FALSE;
+       }
+}
+
+METHOD(public_key_t, encrypt, bool,
+       private_wolfssl_ec_public_key_t *this, encryption_scheme_t scheme,
+       chunk_t crypto, chunk_t *plain)
+{
+       DBG1(DBG_LIB, "EC public key encryption not implemented");
+       return FALSE;
+}
+
+METHOD(public_key_t, get_keysize, int,
+       private_wolfssl_ec_public_key_t *this)
+{
+       return this->keysize;
+}
+
+/**
+ * Calculate fingerprint from a EC_KEY, also used in ec private key.
+ */
+bool wolfssl_ec_fingerprint(ecc_key *ec, cred_encoding_type_t type, chunk_t *fp)
+{
+       hasher_t *hasher;
+       chunk_t key;
+       int ret;
+       bool success;
+
+       if (lib->encoding->get_cache(lib->encoding, type, ec, fp))
+       {
+               return TRUE;
+       }
+
+       key = chunk_alloc(ec->dp->size * 4 + 30);
+       ret = wc_EccPublicKeyToDer(ec, key.ptr, key.len, 1);
+       if (ret < 0)
+       {
+               free(key.ptr);
+               return FALSE;
+       }
+       key.len = ret;
+
+       switch (type)
+       {
+               case KEYID_PUBKEY_SHA1:
+                       break;
+               default:
+                       success = lib->encoding->encode(lib->encoding, type, ec, fp,
+                                                                                       CRED_PART_ECDSA_PUB_ASN1_DER, key,
+                                                                                       CRED_PART_END);
+                       chunk_free(&key);
+                       return success;
+       }
+
+       hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+       if (!hasher || !hasher->allocate_hash(hasher, key, fp))
+       {
+               DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
+               DESTROY_IF(hasher);
+               free(key.ptr);
+               return FALSE;
+       }
+       hasher->destroy(hasher);
+       free(key.ptr);
+       lib->encoding->cache(lib->encoding, type, ec, *fp);
+       return TRUE;
+}
+
+METHOD(public_key_t, get_fingerprint, bool,
+       private_wolfssl_ec_public_key_t *this, cred_encoding_type_t type,
+       chunk_t *fingerprint)
+{
+       return wolfssl_ec_fingerprint(&this->ec, type, fingerprint);
+}
+
+METHOD(public_key_t, get_encoding, bool,
+       private_wolfssl_ec_public_key_t *this, cred_encoding_type_t type,
+       chunk_t *encoding)
+{
+       bool success = TRUE;
+       int ret;
+
+       *encoding = chunk_alloc(this->ec.dp->size * 2 + 30);
+       ret = wc_EccPublicKeyToDer(&this->ec, encoding->ptr, encoding->len, 1);
+       if (ret < 0)
+       {
+               chunk_free(encoding);
+               return FALSE;
+       }
+       encoding->len = ret;
+
+       if (type != PUBKEY_ASN1_DER)
+       {
+               chunk_t asn1_encoding = *encoding;
+
+               success = lib->encoding->encode(lib->encoding, type,
+                                               NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER,
+                                               asn1_encoding, CRED_PART_END);
+               chunk_clear(&asn1_encoding);
+       }
+       return success;
+}
+
+METHOD(public_key_t, get_ref, public_key_t*,
+       private_wolfssl_ec_public_key_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public.key;
+}
+
+METHOD(public_key_t, destroy, void,
+       private_wolfssl_ec_public_key_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               lib->encoding->clear_cache(lib->encoding, &this->ec);
+               wc_ecc_free(&this->ec);
+               free(this);
+       }
+}
+
+/**
+ * Generic private constructor
+ */
+static private_wolfssl_ec_public_key_t *create_empty()
+{
+       private_wolfssl_ec_public_key_t *this;
+
+       INIT(this,
+               .public = {
+                       .key = {
+                               .get_type = _get_type,
+                               .verify = _verify,
+                               .encrypt = _encrypt,
+                               .get_keysize = _get_keysize,
+                               .equals = public_key_equals,
+                               .get_fingerprint = _get_fingerprint,
+                               .has_fingerprint = public_key_has_fingerprint,
+                               .get_encoding = _get_encoding,
+                               .get_ref = _get_ref,
+                               .destroy = _destroy,
+                       },
+               },
+               .ref = 1,
+       );
+
+       if (wc_ecc_init(&this->ec) < 0)
+       {
+               free(this);
+               return NULL;
+       }
+
+       return this;
+}
+
+/**
+ * See header.
+ */
+wolfssl_ec_public_key_t *wolfssl_ec_public_key_load(key_type_t type,
+                                                                                                       va_list args)
+{
+       private_wolfssl_ec_public_key_t *this;
+       chunk_t blob = chunk_empty;
+       word32 idx;
+       int ret;
+
+       if (type != KEY_ECDSA)
+       {
+               return NULL;
+       }
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_BLOB_ASN1_DER:
+                               blob = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+       this = create_empty();
+       idx = 0;
+       ret = wc_EccPublicKeyDecode(blob.ptr, &idx, &this->ec, blob.len);
+       if (ret < 0)
+       {
+               destroy(this);
+               return NULL;
+       }
+       switch (this->ec.dp->id)
+       {
+               case ECC_SECP256R1:
+                       this->keysize = 256;
+                       break;
+               case ECC_SECP384R1:
+                       this->keysize = 384;
+                       break;
+               case ECC_SECP521R1:
+                       this->keysize = 521;
+                       break;
+               default:
+                       break;
+       }
+       return &this->public;
+}
+#endif /* HAVE_ECC_VERIFY */
+
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.h b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.h
new file mode 100644 (file)
index 0000000..ac82af3
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_ec_public_key wolfssl_ec_public_key
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_EC_PUBLIC_KEY_H_
+#define WOLFSSL_EC_PUBLIC_KEY_H_
+
+typedef struct wolfssl_ec_public_key_t wolfssl_ec_public_key_t;
+
+#include <credentials/builder.h>
+#include <credentials/keys/public_key.h>
+
+/**
+ * public_key_t implementation of ECDSA using wolfSSL.
+ */
+struct wolfssl_ec_public_key_t {
+
+       /**
+        * Implements the public_key_t interface
+        */
+       public_key_t key;
+};
+
+/**
+ * Load a ECDSA public key using wolfSSL.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type         type of the key, must be KEY_ECDSA
+ * @param args         builder_part_t argument list
+ * @return                     loaded key, NULL on failure
+ */
+wolfssl_ec_public_key_t *wolfssl_ec_public_key_load(key_type_t type,
+                                                                                                       va_list args);
+
+#endif /** WOLFSSL_EC_PUBLIC_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ed_private_key.c b/src/libstrongswan/plugins/wolfssl/wolfssl_ed_private_key.c
new file mode 100644 (file)
index 0000000..bee0a33
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifdef HAVE_ED25519
+
+#include "wolfssl_ed_private_key.h"
+
+#include <utils/debug.h>
+
+#include <wolfssl/wolfcrypt/ed25519.h>
+
+typedef struct private_private_key_t private_private_key_t;
+
+/**
+ * Private data
+ */
+struct private_private_key_t {
+
+       /**
+        * Public interface
+        */
+       private_key_t public;
+
+       /**
+        * Key object
+        */
+       ed25519_key key;
+
+       /**
+        * Key type
+        */
+       key_type_t type;
+
+       /**
+        * reference count
+        */
+       refcount_t ref;
+};
+
+
+/* from ed public key */
+bool wolfssl_ed_fingerprint(ed25519_key *key, cred_encoding_type_t type,
+                                                       chunk_t *fp);
+
+METHOD(private_key_t, sign, bool,
+       private_private_key_t *this, signature_scheme_t scheme,
+       void *params, chunk_t data, chunk_t *signature)
+{
+       word32 len;
+       int ret;
+       byte dummy[1];
+
+       if (this->type == KEY_ED25519 && scheme != SIGN_ED25519)
+       {
+               DBG1(DBG_LIB, "signature scheme %N not supported by %N key",
+                        signature_scheme_names, scheme, key_type_names, this->type);
+               return FALSE;
+       }
+
+       if (data.ptr == NULL && data.len == 0)
+       {
+               data.ptr = dummy;
+       }
+
+       len = ED25519_SIG_SIZE;
+       *signature = chunk_alloc(len);
+       ret = wc_ed25519_sign_msg(data.ptr, data.len, signature->ptr, &len,
+                                                          &this->key);
+       return ret == 0;
+}
+
+METHOD(private_key_t, decrypt, bool,
+       private_private_key_t *this, encryption_scheme_t scheme,
+       chunk_t crypto, chunk_t *plain)
+{
+       DBG1(DBG_LIB, "EdDSA private key decryption not implemented");
+       return FALSE;
+}
+
+METHOD(private_key_t, get_keysize, int,
+       private_private_key_t *this)
+{
+       return ED25519_KEY_SIZE * 8;
+}
+
+METHOD(private_key_t, get_type, key_type_t,
+       private_private_key_t *this)
+{
+       return this->type;
+}
+
+METHOD(private_key_t, get_public_key, public_key_t*,
+       private_private_key_t *this)
+{
+       public_key_t *public;
+       chunk_t key;
+       word32 len = ED25519_PUB_KEY_SIZE;
+
+       /* Allocate on stack */
+       key = chunk_alloca(len);
+       if (wc_ed25519_export_public(&this->key, key.ptr, &len) != 0)
+       {
+               chunk_free(&key);
+               return NULL;
+       }
+       public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, this->type,
+                                                               BUILD_EDDSA_PUB, key, BUILD_END);
+       return public;
+}
+
+METHOD(private_key_t, get_fingerprint, bool,
+       private_private_key_t *this, cred_encoding_type_t type,
+       chunk_t *fingerprint)
+{
+       return wolfssl_ed_fingerprint(&this->key, type, fingerprint);
+}
+
+METHOD(private_key_t, get_encoding, bool,
+       private_private_key_t *this, cred_encoding_type_t type, chunk_t *encoding)
+{
+       int ret;
+
+       switch (type)
+       {
+               case PRIVKEY_ASN1_DER:
+               case PRIVKEY_PEM:
+               {
+                       bool success = TRUE;
+
+                       *encoding = chunk_alloc(ED25519_PRV_KEY_SIZE + 20);
+                       ret = wc_Ed25519PrivateKeyToDer(&this->key, encoding->ptr,
+                                                                                       encoding->len);
+                       if (ret < 0)
+                       {
+                               chunk_free(encoding);
+                               return FALSE;
+                       }
+                       encoding->len = ret;
+
+                       if (type == PRIVKEY_PEM)
+                       {
+                               chunk_t asn1_encoding = *encoding;
+
+                               success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM,
+                                                               NULL, encoding, CRED_PART_EDDSA_PRIV_ASN1_DER,
+                                                               asn1_encoding, CRED_PART_END);
+                               chunk_clear(&asn1_encoding);
+                       }
+                       return success;
+               }
+               default:
+                       return FALSE;
+       }
+}
+
+METHOD(private_key_t, get_ref, private_key_t*,
+       private_private_key_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public;
+}
+
+METHOD(private_key_t, destroy, void,
+       private_private_key_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               lib->encoding->clear_cache(lib->encoding, &this->key);
+               wc_ed25519_free(&this->key);
+               free(this);
+       }
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_private_key_t *create_internal(key_type_t type)
+{
+       private_private_key_t *this;
+
+       INIT(this,
+               .public = {
+                       .get_type = _get_type,
+                       .sign = _sign,
+                       .decrypt = _decrypt,
+                       .get_keysize = _get_keysize,
+                       .get_public_key = _get_public_key,
+                       .equals = private_key_equals,
+                       .belongs_to = private_key_belongs_to,
+                       .get_fingerprint = _get_fingerprint,
+                       .has_fingerprint = private_key_has_fingerprint,
+                       .get_encoding = _get_encoding,
+                       .get_ref = _get_ref,
+                       .destroy = _destroy,
+               },
+               .type = type,
+               .ref = 1,
+       );
+
+       if (wc_ed25519_init(&this->key) != 0)
+       {
+               free(this);
+               this = NULL;
+       }
+       return this;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *wolfssl_ed_private_key_gen(key_type_t type, va_list args)
+{
+       private_private_key_t *this;
+       WC_RNG rng;
+       int ret;
+
+       if (wc_InitRng(&rng) != 0)
+       {
+               DBG1(DBG_LIB, "initializing random failed");
+               return NULL;
+       }
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_KEY_SIZE:
+                               /* just ignore the key size */
+                               va_arg(args, u_int);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+
+       switch (type)
+       {
+               case KEY_ED25519:
+                       break;
+               default:
+                       return NULL;
+       }
+       this = create_internal(type);
+       if (this == NULL)
+       {
+               return NULL;
+       }
+
+       ret = wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &this->key);
+       wc_FreeRng(&rng);
+       if (ret < 0)
+       {
+               DBG1(DBG_LIB, "generating %N key failed", key_type_names, type);
+               destroy(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
+private_key_t *wolfssl_ed_private_key_load(key_type_t type, va_list args)
+{
+       private_private_key_t *this;
+       chunk_t blob = chunk_empty, priv = chunk_empty;
+       int idx;
+       int ret = -1;
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_BLOB_ASN1_DER:
+                               blob = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_EDDSA_PRIV_ASN1_DER:
+                               priv = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+       this = create_internal(type);
+       if (this == NULL)
+       {
+               return NULL;
+       }
+
+       if (priv.len)
+       {
+               /* Check for ASN.1 wrapped key (Octet String == 0x04) */
+               if (priv.len == ED25519_KEY_SIZE + 2 && priv.ptr[0] == 0x04 &&
+                                                                                               priv.ptr[1] == ED25519_KEY_SIZE)
+               {
+                       priv = chunk_skip(priv, 2);
+               }
+               ret = wc_ed25519_import_private_only(priv.ptr, priv.len, &this->key);
+               if (ret == 0)
+               {
+                       ret = wc_ed25519_make_public(&this->key, this->key.p,
+                                                                                ED25519_PUB_KEY_SIZE);
+               }
+               if (ret == 0)
+               {
+                       /* Fix internal state now public key set */
+                       memmove(this->key.k + ED25519_KEY_SIZE, this->key.p,
+                                       ED25519_PUB_KEY_SIZE);
+                       this->key.pubKeySet = 1;
+               }
+       }
+       else if (blob.len)
+       {
+               idx = 0;
+               ret = wc_Ed25519PrivateKeyDecode(blob.ptr, &idx, &this->key, blob.len);
+       }
+
+       if (ret != 0)
+       {
+               destroy(this);
+               return NULL;
+       }
+       return &this->public;
+}
+
+#endif /* HAVE_ED25519 */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ed_private_key.h b/src/libstrongswan/plugins/wolfssl/wolfssl_ed_private_key.h
new file mode 100644 (file)
index 0000000..2f44a49
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_ed_private_key wolfssl_ed_private_key
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_ED_PRIVATE_KEY_H_
+#define WOLFSSL_ED_PRIVATE_KEY_H_
+
+#include <credentials/builder.h>
+#include <credentials/keys/private_key.h>
+
+/**
+ * Generate an EdDSA private key using wolfSSL.
+ *
+ * @param type         type of the key, must be KEY_ED25519
+ * @param args         builder_part_t argument list
+ * @return                     generated key, NULL on failure
+ */
+private_key_t *wolfssl_ed_private_key_gen(key_type_t type, va_list args);
+
+/**
+ * Load an EdDSA private key using wolfSSL.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type         type of the key, must be KEY_ED25519
+ * @param args         builder_part_t argument list
+ * @return                     loaded key, NULL on failure
+ */
+private_key_t *wolfssl_ed_private_key_load(key_type_t type, va_list args);
+
+#endif /** WOLFSSL_ED_PRIVATE_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ed_public_key.c b/src/libstrongswan/plugins/wolfssl/wolfssl_ed_public_key.c
new file mode 100644 (file)
index 0000000..d09eb48
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifdef HAVE_ED25519
+
+#include "wolfssl_ed_public_key.h"
+
+#include <utils/debug.h>
+
+#include <wolfssl/wolfcrypt/ed25519.h>
+
+typedef struct private_public_key_t private_public_key_t;
+
+/**
+ * Private data
+ */
+struct private_public_key_t {
+
+       /**
+        * Public interface
+        */
+       public_key_t public;
+
+       /**
+        * Key object
+        */
+       ed25519_key key;
+
+       /**
+        * Key type
+        */
+       key_type_t type;
+
+       /**
+        * Reference counter
+        */
+       refcount_t ref;
+};
+
+
+METHOD(public_key_t, get_type, key_type_t,
+       private_public_key_t *this)
+{
+       return this->type;
+}
+
+METHOD(public_key_t, verify, bool,
+       private_public_key_t *this, signature_scheme_t scheme,
+       void *params, chunk_t data, chunk_t signature)
+{
+       int ret;
+       int res;
+       byte dummy[1];
+
+       if (this->type == KEY_ED25519 && scheme != SIGN_ED25519)
+       {
+               DBG1(DBG_LIB, "signature scheme %N not supported by %N key",
+                        signature_scheme_names, scheme, key_type_names, this->type);
+               return FALSE;
+       }
+
+       if (data.ptr == NULL && data.len == 0)
+       {
+               data.ptr = dummy;
+       }
+
+       ret = wc_ed25519_verify_msg(signature.ptr, signature.len, data.ptr,
+                                                               data.len, &res, &this->key);
+       return ret == 0 && res == 1;
+}
+
+METHOD(public_key_t, encrypt, bool,
+       private_public_key_t *this, encryption_scheme_t scheme,
+       chunk_t crypto, chunk_t *plain)
+{
+       DBG1(DBG_LIB, "encryption scheme %N not supported", encryption_scheme_names,
+                scheme);
+       return FALSE;
+}
+
+METHOD(public_key_t, get_keysize, int,
+       private_public_key_t *this)
+{
+       return ED25519_KEY_SIZE * 8;
+}
+
+/**
+ * Calculate fingerprint from an EdDSA key, also used in ed private key.
+ */
+bool wolfssl_ed_fingerprint(ed25519_key *key, cred_encoding_type_t type,
+                                                       chunk_t *fp)
+{
+       hasher_t *hasher;
+       chunk_t blob;
+       word32 len;
+       int ret;
+
+       if (lib->encoding->get_cache(lib->encoding, type, key, fp))
+       {
+               return TRUE;
+       }
+       switch (type)
+       {
+               case KEYID_PUBKEY_SHA1:
+                       len = ED25519_PUB_KEY_SIZE;
+                       blob = chunk_alloca(len);
+                       if (wc_ed25519_export_public(key, blob.ptr, &len) != 0)
+                       {
+                               return FALSE;
+                       }
+                       break;
+               case KEYID_PUBKEY_INFO_SHA1:
+                       len = ED25519_PUB_KEY_SIZE + 40;
+                       blob = chunk_alloca(len);
+                       ret = wc_Ed25519PublicKeyToDer(key, blob.ptr, blob.len, 1);
+                       if (ret < 0)
+                       {
+                               return FALSE;
+                       }
+                       blob.len = ret;
+                       break;
+               default:
+                       return FALSE;
+       }
+       hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+       if (!hasher || !hasher->allocate_hash(hasher, blob, fp))
+       {
+               DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed");
+               DESTROY_IF(hasher);
+               return FALSE;
+       }
+       hasher->destroy(hasher);
+       lib->encoding->cache(lib->encoding, type, key, *fp);
+       return TRUE;
+}
+
+METHOD(public_key_t, get_fingerprint, bool,
+       private_public_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint)
+{
+       return wolfssl_ed_fingerprint(&this->key, type, fingerprint);
+}
+
+METHOD(public_key_t, get_encoding, bool,
+       private_public_key_t *this, cred_encoding_type_t type, chunk_t *encoding)
+{
+       bool success = TRUE;
+       int ret;
+
+       *encoding = chunk_alloc(ED25519_PUB_KEY_SIZE + 32);
+       ret = wc_Ed25519PublicKeyToDer(&this->key, encoding->ptr, encoding->len, 1);
+       if (ret < 0)
+       {
+               return FALSE;
+       }
+       encoding->len = ret;
+
+       if (type != PUBKEY_SPKI_ASN1_DER)
+       {
+               chunk_t asn1_encoding = *encoding;
+
+               success = lib->encoding->encode(lib->encoding, type,
+                                                               NULL, encoding, CRED_PART_EDDSA_PUB_ASN1_DER,
+                                                               asn1_encoding, CRED_PART_END);
+               chunk_clear(&asn1_encoding);
+       }
+       return success;
+}
+
+METHOD(public_key_t, get_ref, public_key_t*,
+       private_public_key_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public;
+}
+
+METHOD(public_key_t, destroy, void,
+       private_public_key_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               lib->encoding->clear_cache(lib->encoding, &this->key);
+               wc_ed25519_free(&this->key);
+               free(this);
+       }
+}
+
+/**
+ * Generic private constructor
+ */
+static private_public_key_t *create_empty(key_type_t type)
+{
+       private_public_key_t *this;
+
+       INIT(this,
+               .public = {
+                       .get_type = _get_type,
+                       .verify = _verify,
+                       .encrypt = _encrypt,
+                       .get_keysize = _get_keysize,
+                       .equals = public_key_equals,
+                       .get_fingerprint = _get_fingerprint,
+                       .has_fingerprint = public_key_has_fingerprint,
+                       .get_encoding = _get_encoding,
+                       .get_ref = _get_ref,
+                       .destroy = _destroy,
+               },
+               .type = type,
+               .ref = 1,
+       );
+       if (wc_ed25519_init(&this->key) != 0)
+       {
+               free(this);
+               return NULL;
+       }
+
+       return this;
+}
+
+/*
+ * Described in header
+ */
+public_key_t *wolfssl_ed_public_key_load(key_type_t type, va_list args)
+{
+       private_public_key_t *this;
+       chunk_t blob = chunk_empty, pub = chunk_empty;
+       int idx;
+       int ret = -1;
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_BLOB_ASN1_DER:
+                               blob = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_EDDSA_PUB:
+                               pub = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+
+       this = create_empty(type);
+       if (this == NULL)
+       {
+               return NULL;
+       }
+
+       if (pub.len)
+       {
+               ret = wc_ed25519_import_public(pub.ptr, pub.len, &this->key);
+       }
+       else if (blob.len)
+       {
+               idx = 0;
+               ret = wc_Ed25519PublicKeyDecode(blob.ptr, &idx, &this->key, blob.len);
+       }
+       if (ret != 0)
+       {
+               destroy(this);
+               return NULL;
+       }
+       return &this->public;
+}
+
+#endif /* HAVE_ED25519 */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_ed_public_key.h b/src/libstrongswan/plugins/wolfssl/wolfssl_ed_public_key.h
new file mode 100644 (file)
index 0000000..b6239ca
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_ed_public_key wolfssl_ed_public_key
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_ED_PUBLIC_KEY_H_
+#define WOLFSSL_ED_PUBLIC_KEY_H_
+
+#include <credentials/builder.h>
+#include <credentials/keys/public_key.h>
+
+/**
+ * Load an EdDSA public key using wolfSSL.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type         type of the key, must be KEY_ED25519
+ * @param args         builder_part_t argument list
+ * @return                     loaded key, NULL on failure
+ */
+public_key_t *wolfssl_ed_public_key_load(key_type_t type, va_list args);
+
+#endif /** WOLFSSL_ED_PUBLIC_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_hasher.c b/src/libstrongswan/plugins/wolfssl/wolfssl_hasher.c
new file mode 100644 (file)
index 0000000..d87364a
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+#include "wolfssl_hasher.h"
+#include "wolfssl_util.h"
+
+#include <wolfssl/wolfcrypt/hash.h>
+
+typedef struct private_wolfssl_hasher_t private_wolfssl_hasher_t;
+
+/**
+ * Private data of wolfssl_hasher_t
+ */
+struct private_wolfssl_hasher_t {
+
+       /**
+        * Public part of this class.
+        */
+       wolfssl_hasher_t public;
+
+       /**
+        * the hasher to use
+        */
+       wc_HashAlg hasher;
+
+       /**
+        * the hash algiorithm
+        */
+       enum wc_HashType type;
+};
+
+METHOD(hasher_t, get_hash_size, size_t,
+       private_wolfssl_hasher_t *this)
+{
+       return wc_HashGetDigestSize(this->type);
+}
+
+METHOD(hasher_t, reset, bool,
+       private_wolfssl_hasher_t *this)
+{
+       return wc_HashInit(&this->hasher, this->type) == 0;
+}
+
+METHOD(hasher_t, get_hash, bool,
+       private_wolfssl_hasher_t *this, chunk_t chunk, uint8_t *hash)
+{
+       int ret;
+
+       ret = wc_HashUpdate(&this->hasher, this->type, chunk.ptr, chunk.len);
+       if (ret == 0 && hash)
+       {
+               ret = wc_HashFinal(&this->hasher, this->type, hash);
+               if (ret == 0)
+               {
+                       return reset(this);
+               }
+       }
+       return ret == 0;
+}
+
+METHOD(hasher_t, allocate_hash, bool,
+       private_wolfssl_hasher_t *this, chunk_t chunk, chunk_t *hash)
+{
+       if (hash)
+       {
+               *hash = chunk_alloc(get_hash_size(this));
+               return get_hash(this, chunk, hash->ptr);
+       }
+       return get_hash(this, chunk, NULL);
+}
+
+METHOD(hasher_t, destroy, void,
+       private_wolfssl_hasher_t *this)
+{
+       wc_HashFree(&this->hasher, this->type);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+wolfssl_hasher_t *wolfssl_hasher_create(hash_algorithm_t algo)
+{
+       private_wolfssl_hasher_t *this;
+       enum wc_HashType type;
+
+       if (!wolfssl_hash2type(algo, &type))
+       {
+               return NULL;
+       }
+
+       INIT(this,
+               .public = {
+                       .hasher = {
+                               .get_hash = _get_hash,
+                               .allocate_hash = _allocate_hash,
+                               .get_hash_size = _get_hash_size,
+                               .reset = _reset,
+                               .destroy = _destroy,
+                       },
+               },
+               .type = type,
+       );
+
+       /* initialization */
+       if (!reset(this))
+       {
+               destroy(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_hasher.h b/src/libstrongswan/plugins/wolfssl/wolfssl_hasher.h
new file mode 100644 (file)
index 0000000..a976f07
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_hasher wolfssl_hasher
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_HASHER_H_
+#define WOLFSSL_HASHER_H_
+
+typedef struct wolfssl_hasher_t wolfssl_hasher_t;
+
+#include <crypto/hashers/hasher.h>
+
+/**
+ * Implementation of hashers using wolfSSL.
+ */
+struct wolfssl_hasher_t {
+
+       /**
+        * Implements hasher_t interface.
+        */
+       hasher_t hasher;
+};
+
+/**
+ * Constructor to create wolfssl_hasher_t.
+ *
+ * @param algo                 algorithm
+ * @return                             wolfssl_hasher_t, NULL if not supported
+ */
+wolfssl_hasher_t *wolfssl_hasher_create(hash_algorithm_t algo);
+
+#endif /** WOLFSSL_HASHER_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_hmac.c b/src/libstrongswan/plugins/wolfssl/wolfssl_hmac.c
new file mode 100644 (file)
index 0000000..27eb6a6
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifndef NO_HMAC
+
+#include <wolfssl/wolfcrypt/hmac.h>
+
+#include "wolfssl_hmac.h"
+#include "wolfssl_util.h"
+
+#include <crypto/mac.h>
+#include <crypto/prfs/mac_prf.h>
+#include <crypto/signers/mac_signer.h>
+
+typedef struct private_mac_t private_mac_t;
+
+/**
+ * Private data of a mac_t object.
+ */
+struct private_mac_t {
+
+       /**
+        * Public interface
+        */
+       mac_t public;
+
+       /**
+        * Current HMAC
+        */
+       Hmac hmac;
+
+       /**
+        * Hasher to use
+        */
+       enum wc_HashType type;
+
+       /**
+        * Key set on Hmac?
+        */
+       bool key_set;
+};
+
+METHOD(mac_t, set_key, bool,
+       private_mac_t *this, chunk_t key)
+{
+       int ret = wc_HmacSetKey(&this->hmac, this->type, key.ptr, key.len);
+       this->key_set = (ret == 0);
+       return ret == 0;
+}
+
+METHOD(mac_t, get_mac, bool,
+       private_mac_t *this, chunk_t data, uint8_t *out)
+{
+       int ret = -1;
+
+       if (this->key_set)
+       {
+               ret = wc_HmacUpdate(&this->hmac, data.ptr, data.len);
+       }
+       if (ret == 0 && out != NULL)
+       {
+               ret = wc_HmacFinal(&this->hmac, out);
+       }
+       return ret == 0;
+}
+
+METHOD(mac_t, get_mac_size, size_t,
+       private_mac_t *this)
+{
+       return wc_HmacSizeByType(this->type);
+}
+
+METHOD(mac_t, destroy, void,
+       private_mac_t *this)
+{
+       wc_HmacFree(&this->hmac);
+       free(this);
+}
+
+/*
+ * Create an wolfSSL-backed implementation of the mac_t interface
+ */
+static mac_t *hmac_create(hash_algorithm_t algo)
+{
+       private_mac_t *this;
+       enum wc_HashType type;
+
+       if (!wolfssl_hash2type(algo, &type))
+       {
+               return NULL;
+       }
+
+       INIT(this,
+               .public = {
+                       .get_mac = _get_mac,
+                       .get_mac_size = _get_mac_size,
+                       .set_key = _set_key,
+                       .destroy = _destroy,
+               },
+               .type = type,
+       );
+
+       
+       if (wc_HmacInit(&this->hmac, NULL, INVALID_DEVID) != 0)
+       {
+               DBG1(DBG_LIB, "HMAC init failed, hmac create failed\n");
+               free(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
+
+/*
+ * Described in header
+ */
+prf_t *wolfssl_hmac_prf_create(pseudo_random_function_t algo)
+{
+       mac_t *hmac;
+
+       hmac = hmac_create(hasher_algorithm_from_prf(algo));
+       if (hmac)
+       {
+               return mac_prf_create(hmac);
+       }
+       return NULL;
+}
+
+/*
+ * Described in header
+ */
+signer_t *wolfssl_hmac_signer_create(integrity_algorithm_t algo)
+{
+       mac_t *hmac;
+       size_t trunc;
+
+       hmac = hmac_create(hasher_algorithm_from_integrity(algo, &trunc));
+       if (hmac)
+       {
+               return mac_signer_create(hmac, trunc);
+       }
+       return NULL;
+}
+
+#endif /* NO_HMAC */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_hmac.h b/src/libstrongswan/plugins/wolfssl/wolfssl_hmac.h
new file mode 100644 (file)
index 0000000..23953da
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Implements HMAC based PRF and signer using wolfSSL's HMAC functions.
+ *
+ * @defgroup wolfssl_hmac wolfssl_hmac
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_HMAC_H_
+#define WOLFSSL_HMAC_H_
+
+#include <crypto/prfs/prf.h>
+#include <crypto/signers/signer.h>
+
+/**
+ * Creates a new prf_t object based on an HMAC.
+ *
+ * @param algo         algorithm to implement
+ * @return                     prf_t object, NULL if not supported
+ */
+prf_t *wolfssl_hmac_prf_create(pseudo_random_function_t algo);
+
+/**
+ * Creates a new signer_t object based on an HMAC.
+ *
+ * @param algo         algorithm to implement
+ * @return                     signer_t, NULL if not supported
+ */
+signer_t *wolfssl_hmac_signer_create(integrity_algorithm_t algo);
+
+#endif /** WOLFSSL_HMAC_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_plugin.c b/src/libstrongswan/plugins/wolfssl/wolfssl_plugin.c
new file mode 100644 (file)
index 0000000..b091a20
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <library.h>
+#include <utils/debug.h>
+
+#include "wolfssl_common.h"
+#include "wolfssl_plugin.h"
+#include "wolfssl_aead.h"
+#include "wolfssl_crypter.h"
+#include "wolfssl_diffie_hellman.h"
+#include "wolfssl_ec_diffie_hellman.h"
+#include "wolfssl_ec_private_key.h"
+#include "wolfssl_ec_public_key.h"
+#include "wolfssl_ed_private_key.h"
+#include "wolfssl_ed_public_key.h"
+#include "wolfssl_hasher.h"
+#include "wolfssl_hmac.h"
+#include "wolfssl_rsa_private_key.h"
+#include "wolfssl_rsa_public_key.h"
+#include "wolfssl_rng.h"
+#include "wolfssl_sha1_prf.h"
+#include "wolfssl_x_diffie_hellman.h"
+
+#ifndef FIPS_MODE
+#define FIPS_MODE 0
+#endif
+
+
+typedef struct private_wolfssl_plugin_t private_wolfssl_plugin_t;
+
+/**
+ * private data of wolfssl_plugin
+ */
+struct private_wolfssl_plugin_t {
+
+       /**
+        * public functions
+        */
+       wolfssl_plugin_t public;
+};
+
+
+METHOD(plugin_t, get_name, char*,
+       private_wolfssl_plugin_t *this)
+{
+       return "wolfssl";
+}
+
+METHOD(plugin_t, get_features, int,
+       private_wolfssl_plugin_t *this, plugin_feature_t *features[])
+{
+       static plugin_feature_t f[] = {
+               /* crypters */
+               PLUGIN_REGISTER(CRYPTER, wolfssl_crypter_create),
+#if !defined(NO_AES) && !defined(NO_AES_CTR)
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 16),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 24),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 32),
+#endif
+#if !defined(NO_AES) && !defined(NO_AES_CBC)
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 16),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 24),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 32),
+#endif
+#ifdef HAVE_CAMELLIA
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 16),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 24),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 32),
+#endif
+#ifndef NO_DES3
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_3DES, 24),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_DES, 8),
+       #ifdef WOLFSSL_DES_ECB
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_DES_ECB, 8),
+       #endif
+#endif
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_NULL, 0),
+               /* hashers */
+               PLUGIN_REGISTER(HASHER, wolfssl_hasher_create),
+#ifndef NO_MD5
+                       PLUGIN_PROVIDE(HASHER, HASH_MD5),
+#endif
+#ifndef NO_SHA
+                       PLUGIN_PROVIDE(HASHER, HASH_SHA1),
+#endif
+#ifdef WOLFSSL_SHA224
+                       PLUGIN_PROVIDE(HASHER, HASH_SHA224),
+#endif
+#ifndef NO_SHA256
+                       PLUGIN_PROVIDE(HASHER, HASH_SHA256),
+#endif
+#ifdef WOLFSSL_SHA384
+                       PLUGIN_PROVIDE(HASHER, HASH_SHA384),
+#endif
+#ifdef WOLFSSL_SHA512
+                       PLUGIN_PROVIDE(HASHER, HASH_SHA512),
+#endif
+#ifndef NO_SHA
+               /* keyed sha1 hasher (aka prf) */
+               PLUGIN_REGISTER(PRF, wolfssl_sha1_prf_create),
+                       PLUGIN_PROVIDE(PRF, PRF_KEYED_SHA1),
+#endif
+#ifndef NO_HMAC
+               PLUGIN_REGISTER(PRF, wolfssl_hmac_prf_create),
+#ifndef NO_MD5
+                       PLUGIN_PROVIDE(PRF, PRF_HMAC_MD5),
+#endif
+#ifndef NO_SHA
+                       PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA1),
+#endif
+#ifndef NO_SHA256
+                       PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_256),
+#endif
+#ifdef WOLFSSL_SHA384
+                       PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_384),
+#endif
+#ifdef WOLFSSL_SHA512
+                       PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_512),
+#endif
+               PLUGIN_REGISTER(SIGNER, wolfssl_hmac_signer_create),
+#ifndef NO_MD5
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_MD5_96),
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_MD5_128),
+#endif
+#ifndef NO_SHA
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_96),
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_128),
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_160),
+#endif
+#ifndef NO_SHA256
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_256_128),
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_256_256),
+#endif
+#ifdef WOLFSSL_SHA384
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_384_192),
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_384_384),
+#endif
+#ifdef WOLFSSL_SHA512
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_256),
+                       PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_512),
+#endif
+#endif /* NO_HMAC */
+#if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))) || \
+                                                               (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
+               PLUGIN_REGISTER(AEAD, wolfssl_aead_create),
+#if !defined(NO_AES) && defined(HAVE_AESGCM)
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 16),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 24),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV16, 32),
+       #if WOLFSSL_MIN_AUTH_TAG_SZ <= 12
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 16),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 24),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV12, 32),
+       #endif
+       #if WOLFSSL_MIN_AUTH_TAG_SZ <= 8
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  16),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  24),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  32),
+       #endif
+#endif /* !NO_AES && HAVE_AESGCM */
+#if !defined(NO_AES) && defined(HAVE_AESCCM)
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 16),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 24),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 32),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 16),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 24),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 32),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  16),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  24),
+                       PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  32),
+#endif /* !NO_AES && HAVE_AESCCM */
+#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
+                       PLUGIN_PROVIDE(AEAD, ENCR_CHACHA20_POLY1305, 32),
+#endif /* HAVE_CHACHA && HAVE_POLY1305 */
+#endif
+#ifdef HAVE_ECC_DHE
+               /* EC DH groups */
+               PLUGIN_REGISTER(DH, wolfssl_ec_diffie_hellman_create),
+       #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_256_BIT),
+       #endif
+       #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_384_BIT),
+       #endif
+       #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_521_BIT),
+       #endif
+       #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_224_BIT),
+       #endif
+       #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_192_BIT),
+       #endif
+       #ifdef HAVE_BRAINPOOL
+               #if !define(NO_ECC256) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_256_BP),
+               #endif
+               #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_384_BP),
+               #endif
+               #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_512_BP),
+               #endif
+               #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+                       PLUGIN_PROVIDE(DH, ECP_224_BP),
+               #endif
+       #endif
+#endif /* HAVE_ECC_DHE */
+#ifndef NO_DH
+               /* MODP DH groups */
+               PLUGIN_REGISTER(DH, wolfssl_diffie_hellman_create),
+       #if !defined(USE_FAST_MATH) || FP_MAX_BITS >= (3072 * 2)
+                       PLUGIN_PROVIDE(DH, MODP_3072_BIT),
+       #endif
+       #if !defined(USE_FAST_MATH) || FP_MAX_BITS >= (4096 * 2)
+                       PLUGIN_PROVIDE(DH, MODP_4096_BIT),
+       #endif
+       #if !defined(USE_FAST_MATH) || FP_MAX_BITS >= (6144 * 2)
+                       PLUGIN_PROVIDE(DH, MODP_6144_BIT),
+       #endif
+       #if !defined(USE_FAST_MATH) || FP_MAX_BITS >= (8192 * 2)
+                       PLUGIN_PROVIDE(DH, MODP_8192_BIT),
+       #endif
+       #if !defined(USE_FAST_MATH) || FP_MAX_BITS >= (2048 * 2)
+                       PLUGIN_PROVIDE(DH, MODP_2048_BIT),
+                       PLUGIN_PROVIDE(DH, MODP_2048_224),
+                       PLUGIN_PROVIDE(DH, MODP_2048_256),
+       #endif
+       #if !defined(USE_FAST_MATH) || FP_MAX_BITS >= (1536 * 2)
+                       PLUGIN_PROVIDE(DH, MODP_1536_BIT),
+       #endif
+       #if !defined(USE_FAST_MATH) || FP_MAX_BITS >= (1024 * 2)
+                       PLUGIN_PROVIDE(DH, MODP_1024_BIT),
+                       PLUGIN_PROVIDE(DH, MODP_1024_160),
+       #endif
+       #if !defined(USE_FAST_MATH) || FP_MAX_BITS >= (768 * 2)
+                       PLUGIN_PROVIDE(DH, MODP_768_BIT),
+       #endif
+                       PLUGIN_PROVIDE(DH, MODP_CUSTOM),
+#endif /* NO_DH */
+#ifndef NO_RSA
+               /* RSA private/public key loading */
+               PLUGIN_REGISTER(PRIVKEY, wolfssl_rsa_private_key_load, TRUE),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
+               PLUGIN_REGISTER(PUBKEY, wolfssl_rsa_public_key_load, TRUE),
+                       PLUGIN_PROVIDE(PUBKEY, KEY_RSA),
+       #ifdef WOLFSSL_KEY_GEN
+               PLUGIN_REGISTER(PRIVKEY_GEN, wolfssl_rsa_private_key_gen, FALSE),
+                       PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA),
+       #endif
+               /* signature/encryption schemes */
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_NULL),
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_NULL),
+#ifdef WC_RSA_PSS
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS),
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PSS),
+#endif
+#ifndef NO_SHA
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1),
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1),
+#endif
+#ifdef WOLFSSL_SHA224
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_224),
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_224),
+#endif
+#ifndef NO_SHA256
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_256),
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_256),
+#endif
+#ifdef WOLFSSL_SHA384
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_384),
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_384),
+#endif
+#ifdef WOLFSSL_SHA512
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_512),
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_512),
+#endif
+#ifndef NO_MD5
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_MD5),
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_MD5),
+#endif
+               PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_PKCS1),
+               PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_PKCS1),
+#ifndef WC_NO_RSA_OAEP
+       #ifndef NO_SHA
+               PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA1),
+               PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_OAEP_SHA1),
+       #endif
+       #ifdef WOLFSSL_SHA224
+               PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA224),
+               PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_OAEP_SHA224),
+       #endif
+       #ifndef NO_SHA256
+               PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA256),
+               PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_OAEP_SHA256),
+       #endif
+       #ifdef WOLFSSL_SHA384
+               PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA384),
+               PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_OAEP_SHA384),
+       #endif
+       #ifdef WOLFSSL_SHA512
+               PLUGIN_PROVIDE(PUBKEY_ENCRYPT, ENCRYPT_RSA_OAEP_SHA512),
+               PLUGIN_PROVIDE(PRIVKEY_DECRYPT, ENCRYPT_RSA_OAEP_SHA512),
+       #endif
+#endif /* !WC_NO_RSA_OAEP */
+#endif /* !NO_RSA */
+#ifdef HAVE_ECC
+       #ifdef HAVE_ECC_KEY_IMPORT
+               /* EC private/public key loading */
+               PLUGIN_REGISTER(PRIVKEY, wolfssl_ec_private_key_load, TRUE),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
+       #endif
+       #ifdef HAVE_ECC_DHE
+               PLUGIN_REGISTER(PRIVKEY_GEN, wolfssl_ec_private_key_gen, FALSE),
+                       PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ECDSA),
+       #endif
+       #ifdef HAVE_ECC_KEY_IMPORT
+               PLUGIN_REGISTER(PUBKEY, wolfssl_ec_public_key_load, TRUE),
+                       PLUGIN_PROVIDE(PUBKEY, KEY_ECDSA),
+       #endif
+       #ifdef HAVE_ECC_SIGN
+               /* signature encryption schemes */
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_NULL),
+               #ifndef NO_SHA
+                       PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_SHA1_DER),
+               #endif
+               #ifndef NO_SHA256
+                       PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_SHA256_DER),
+                       PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_256),
+               #endif
+               #ifdef WOLFSSL_SHA384
+                       PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_SHA384_DER),
+                       PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_384),
+               #endif
+               #ifdef WOLFSSL_SHA512
+                       PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_WITH_SHA512_DER),
+                       PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ECDSA_521),
+               #endif
+       #endif /* HAVE_ECC_SIGN */
+       #ifdef HAVE_ECC_VERIFY
+               /* signature encryption schemes */
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_NULL),
+               #ifndef NO_SHA
+                       PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_SHA1_DER),
+               #endif
+               #ifndef NO_SHA256
+                       PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_SHA256_DER),
+                       PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_256),
+               #endif
+               #ifdef WOLFSSL_SHA384
+                       PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_SHA384_DER),
+                       PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_384),
+               #endif
+               #ifdef WOLFSSL_SHA512
+                       PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_WITH_SHA512_DER),
+                       PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_521),
+               #endif
+       #endif /* HAVE_ECC_VERIFY */
+#endif /* HAVE_ECC */
+#ifdef HAVE_CURVE25519
+               PLUGIN_REGISTER(DH, wolfssl_x_diffie_hellman_create),
+                       PLUGIN_PROVIDE(DH, CURVE_25519),
+#endif
+#ifdef HAVE_ED25519
+               /* EdDSA private/public key loading */
+               PLUGIN_REGISTER(PUBKEY, wolfssl_ed_public_key_load, TRUE),
+                       PLUGIN_PROVIDE(PUBKEY, KEY_ED25519),
+               PLUGIN_REGISTER(PRIVKEY, wolfssl_ed_private_key_load, TRUE),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ED25519),
+               PLUGIN_REGISTER(PRIVKEY_GEN, wolfssl_ed_private_key_gen, FALSE),
+                       PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ED25519),
+       #ifdef HAVE_ED25519_SIGN
+               PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ED25519),
+       #endif
+       #ifdef HAVE_ED25519_VERIFY
+               PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ED25519),
+       #endif
+               /* register a pro forma identity hasher, never instantiated */
+               PLUGIN_REGISTER(HASHER, return_null),
+                       PLUGIN_PROVIDE(HASHER, HASH_IDENTITY),
+#endif /* HAVE_ED25519 */
+#ifndef WC_NO_RNG
+               /* generic key loader */
+               PLUGIN_REGISTER(RNG, wolfssl_rng_create),
+                       PLUGIN_PROVIDE(RNG, RNG_STRONG),
+                       PLUGIN_PROVIDE(RNG, RNG_WEAK),
+#endif
+       };
+       *features = f;
+       return countof(f);
+}
+
+METHOD(plugin_t, destroy, void,
+       private_wolfssl_plugin_t *this)
+{
+#ifndef WC_NO_RNG
+       wolfssl_rng_global_final();
+#endif
+       wolfSSL_Cleanup();
+
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *wolfssl_plugin_create()
+{
+       private_wolfssl_plugin_t *this;
+       int fips_mode;
+
+       fips_mode = lib->settings->get_int(lib->settings,
+                                                       "%s.plugins.wolfssl.fips_mode", FIPS_MODE, lib->ns);
+#ifdef HAVE_FIPS
+       if (fips_mode)
+       {
+               int ret = wolfCrypt_GetStatus_fips(); 
+               if (ret != 0)
+               {
+                       DBG1(DBG_LIB, "wolfssl FIPS mode(%d) unavailable (%d)", fips_mode,
+                                ret);
+                       return NULL;
+               }
+       }
+#else
+       if (fips_mode)
+       {
+               DBG1(DBG_LIB, "wolfssl FIPS mode(%d) unavailable", fips_mode);
+               return NULL;
+       }
+#endif
+
+       wolfSSL_Init();
+#ifndef WC_NO_RNG
+       if (!wolfssl_rng_global_init())
+       {
+               return NULL;
+       }
+#endif
+
+       INIT(this,
+               .public = {
+                       .plugin = {
+                               .get_name = _get_name,
+                               .get_features = _get_features,
+                               .destroy = _destroy,
+                       },
+               },
+       );
+
+       return &this->public.plugin;
+}
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_plugin.h b/src/libstrongswan/plugins/wolfssl/wolfssl_plugin.h
new file mode 100644 (file)
index 0000000..b29ce9e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_p wolfssl
+ * @ingroup plugins
+ *
+ * @defgroup wolfssl_plugin wolfssl_plugin
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_PLUGIN_H_
+#define WOLFSSL_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct wolfssl_plugin_t wolfssl_plugin_t;
+
+/**
+ * Plugin implementing crypto functions via the wolfSSL library
+ */
+struct wolfssl_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+#endif /** WOLFSSL_PLUGIN_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_rng.c b/src/libstrongswan/plugins/wolfssl/wolfssl_rng.c
new file mode 100644 (file)
index 0000000..86a8d8a
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <wolfssl_common.h>
+
+#ifndef WC_NO_RNG
+
+#include <library.h>
+#include <utils/debug.h>
+
+#include <wolfssl/wolfcrypt/random.h>
+
+#include "wolfssl_rng.h"
+
+typedef struct private_wolfssl_rng_t private_wolfssl_rng_t;
+
+#ifndef SINGLE_THREADED
+wolfSSL_Mutex globalRngMutex;
+#endif
+static WC_RNG globalRng;
+static int globalRngInit = 0;
+
+/**
+ * Private data of wolfssl_rng_t
+ */
+struct private_wolfssl_rng_t {
+
+       /**
+        * Public part of this class.
+        */
+       wolfssl_rng_t public;
+
+       /**
+        * Random number generator to use
+        * Either own instance or reference to global.
+        */
+       WC_RNG *rng;
+};
+
+METHOD(rng_t, get_bytes, bool,
+       private_wolfssl_rng_t *this, size_t bytes, uint8_t *buffer)
+{
+       int ret;
+
+#ifndef SINGLE_THREADED
+       if (this->rng == &globalRng)
+       {
+               ret = wc_LockMutex(&globalRngMutex);
+               if (ret != 0)
+               {
+                       DBG1(DBG_LIB, "Locking failed, get bytes failed");
+                       return FALSE;
+               }
+       }
+#endif
+       ret = wc_RNG_GenerateBlock(this->rng, buffer, bytes);
+#ifndef SINGLE_THREADED
+       if (this->rng == &globalRng)
+       {
+               wc_UnLockMutex(&globalRngMutex);
+       }
+#endif
+
+       return ret == 0;
+}
+
+METHOD(rng_t, allocate_bytes, bool,
+       private_wolfssl_rng_t *this, size_t bytes, chunk_t *chunk)
+{
+       *chunk = chunk_alloc(bytes);
+       if (!get_bytes(this, chunk->len, chunk->ptr))
+       {
+               chunk_free(chunk);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+METHOD(rng_t, destroy, void,
+       private_wolfssl_rng_t *this)
+{
+       if (this->rng != &globalRng)
+       {
+               wc_FreeRng(this->rng);
+               free(this->rng);
+       }
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+wolfssl_rng_t *wolfssl_rng_create(rng_quality_t quality)
+{
+       private_wolfssl_rng_t *this;
+
+       INIT(this,
+               .public = {
+                       .rng = {
+                               .get_bytes = _get_bytes,
+                               .allocate_bytes = _allocate_bytes,
+                               .destroy = _destroy,
+                       },
+               },
+               .rng = &globalRng,
+       );
+
+       if (quality > RNG_WEAK)
+       {
+               this->rng = malloc(sizeof(*this->rng));
+               if (wc_InitRng(this->rng) != 0)
+               {
+                       DBG1(DBG_LIB, "Init RNG failed, rng create failed");
+                       free(this->rng);
+                       free(this);
+                       return NULL;
+               }
+       }
+       return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+int wolfssl_rng_global_init()
+{
+       int ret = 0;
+
+       if (!globalRngInit)
+       {
+               ret = wc_InitRng(&globalRng);
+               if (ret != 0)
+               {
+                       DBG1(DBG_LIB, "Init RNG failed, rng global init failed");
+               }
+#ifndef SINGLE_THREADED
+               else if ((ret = wc_InitMutex(&globalRngMutex)) != 0)
+               {
+                       DBG1(DBG_LIB, "Init Mutex failed, rng global init failed");
+               }
+#endif
+               else
+               {
+                       globalRngInit = 1;
+               }
+       }
+
+       return ret == 0;
+}
+
+/*
+ * Described in header.
+ */
+void wolfssl_rng_global_final()
+{
+       if (globalRngInit)
+       {
+#ifndef SINGLE_THREADED
+               wc_FreeMutex(&globalRngMutex);
+#endif
+               wc_FreeRng(&globalRng);
+               globalRngInit = 0;
+       }
+}
+
+#endif /* WC_NO_RNG */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_rng.h b/src/libstrongswan/plugins/wolfssl/wolfssl_rng.h
new file mode 100644 (file)
index 0000000..abe9d91
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_rng wolfssl_rng
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_RNG_H_
+#define WOLFSSL_RNG_H_
+
+#include <library.h>
+
+typedef struct wolfssl_rng_t wolfssl_rng_t;
+
+/**
+ * Implementation of random number using wolfSSL.
+ */
+struct wolfssl_rng_t {
+
+       /**
+        * Implements rng_t interface.
+        */
+       rng_t rng;
+};
+
+/**
+ * Constructor to create wolfssl_rng_t.
+ *
+ * @param quality      quality of randomness
+ * @return                     wolfssl_rng_t
+ */
+wolfssl_rng_t *wolfssl_rng_create(rng_quality_t quality);
+
+/**
+ * Initializes the global random number generator.
+ *
+ * @return     TRUE on success and FALSE on failure.
+ */
+int wolfssl_rng_global_init();
+
+/**
+ * Finalizes the global random number generator.
+ */
+void wolfssl_rng_global_final();
+
+#endif /** WOLFSSL_RNG_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_private_key.c b/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_private_key.c
new file mode 100644 (file)
index 0000000..c3ddd5c
--- /dev/null
@@ -0,0 +1,763 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifndef NO_RSA
+
+#include "wolfssl_rsa_private_key.h"
+#include "wolfssl_rsa_public_key.h"
+#include "wolfssl_util.h"
+
+#include <crypto/hashers/hasher.h>
+#include <utils/debug.h>
+#include <credentials/keys/signature_params.h>
+
+#include <wolfssl/wolfcrypt/rsa.h>
+
+typedef struct private_wolfssl_rsa_private_key_t private_wolfssl_rsa_private_key_t;
+
+/**
+ * Private data of a wolfssl_rsa_private_key_t object.
+ */
+struct private_wolfssl_rsa_private_key_t {
+       /**
+        * Public interface for this signer.
+        */
+       wolfssl_rsa_private_key_t public;
+
+       /**
+        * RSA key object from wolfSSL
+        */
+       RsaKey rsa;
+
+       /**
+        * Random number generator to use with RSA operations.
+        */
+       WC_RNG rng;
+
+       /**
+        * reference count
+        */
+       refcount_t ref;
+};
+
+/* implemented in rsa public key */
+bool wolfssl_rsa_fingerprint(RsaKey *rsa, cred_encoding_type_t type, chunk_t *fp);
+
+
+/**
+ * Build RSA signature
+ */
+static bool build_signature(private_wolfssl_rsa_private_key_t *this,
+                                                       enum wc_HashType hash, chunk_t data, chunk_t *sig)
+{
+       int ret = wc_RsaSSL_Sign(data.ptr, data.len, sig->ptr, sig->len, &this->rsa,
+                                                        &this->rng);
+       if (ret > 0)
+       {
+               sig->len = ret;
+       }
+       return ret > 0;
+}
+
+/**
+ * Build an EMSA PKCS1 signature described in PKCS#1
+ */
+static bool build_emsa_pkcs1_signature(private_wolfssl_rsa_private_key_t *this,
+                                                                          enum wc_HashType hash, chunk_t data,
+                                                                          chunk_t *sig)
+{
+       bool success = FALSE;
+       chunk_t dgst, encDgst;
+       int ret;
+
+       *sig = chunk_alloc(wc_RsaEncryptSize(&this->rsa));
+
+       if (hash == WC_HASH_TYPE_NONE)
+       {
+               success = build_signature(this, hash, data, sig);
+       }
+       else if (wolfssl_hash_chunk(hash, data, &dgst))
+       {
+               encDgst = chunk_alloc(dgst.len + 20);
+               ret = wc_EncodeSignature(encDgst.ptr, dgst.ptr, dgst.len,
+                                                                wc_HashGetOID(hash));
+               if (ret > 0)
+               {
+                       encDgst.len = ret;
+                       success = build_signature(this, hash, encDgst, sig);
+               }
+
+               chunk_free(&encDgst);
+               chunk_free(&dgst);
+       }
+
+       if (!success)
+       {
+               chunk_free(sig);
+       }
+       return success;
+}
+
+#ifdef WC_RSA_PSS
+/**
+ * Build an EMSA PSS signature described in PKCS#1
+ */
+static bool build_emsa_pss_signature(private_wolfssl_rsa_private_key_t *this,
+                                                                        rsa_pss_params_t *params, chunk_t data,
+                                                                        chunk_t *sig)
+{
+       bool success = FALSE;
+       chunk_t dgst = chunk_empty;
+       enum wc_HashType hash;
+       int mgf;
+       int ret;
+
+       if (!wolfssl_hash2type(params->hash, &hash))
+       {
+               return FALSE;
+       }
+       if (!wolfssl_hash2mgf1(params->mgf1_hash, &mgf))
+       {
+               return FALSE;
+       }
+
+       *sig = chunk_alloc(wc_RsaEncryptSize(&this->rsa));
+
+       if (wolfssl_hash_chunk(hash, data, &dgst))
+       {
+               ret = wc_RsaPSS_Sign_ex(dgst.ptr, dgst.len, sig->ptr, sig->len, hash,
+                                                               mgf, params->salt_len, &this->rsa, &this->rng);
+               if (ret > 0)
+               {
+                       sig->len = ret;
+                       success = TRUE;
+               }
+       }
+
+       chunk_free(&dgst);
+       if (!success)
+       {
+               chunk_free(sig);
+       }
+       return success;
+}
+#endif
+
+
+METHOD(private_key_t, get_type, key_type_t,
+       private_wolfssl_rsa_private_key_t *this)
+{
+       return KEY_RSA;
+}
+
+METHOD(private_key_t, sign, bool,
+       private_wolfssl_rsa_private_key_t *this, signature_scheme_t scheme,
+       void *params, chunk_t data, chunk_t *signature)
+{
+       switch (scheme)
+       {
+               case SIGN_RSA_EMSA_PKCS1_NULL:
+                       return build_emsa_pkcs1_signature(this, WC_HASH_TYPE_NONE, data,
+                                                                                         signature);
+#ifdef WOLFSSL_SHA224
+               case SIGN_RSA_EMSA_PKCS1_SHA2_224:
+                       return build_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA224, data,
+                                                                                         signature);
+#endif
+#ifndef NO_SHA256
+               case SIGN_RSA_EMSA_PKCS1_SHA2_256:
+                       return build_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA256, data,
+                                                                                         signature);
+#endif
+#ifdef WOLFSSL_SHA384
+               case SIGN_RSA_EMSA_PKCS1_SHA2_384:
+                       return build_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA384, data,
+                                                                                         signature);
+#endif
+#ifdef WOLFSSL_SHA512
+               case SIGN_RSA_EMSA_PKCS1_SHA2_512:
+                       return build_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA512, data,
+                                                                                         signature);
+#endif
+#ifndef NO_SHA
+               case SIGN_RSA_EMSA_PKCS1_SHA1:
+                       return build_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA, data,
+                                                                                         signature);
+#endif
+#ifndef NO_MD5
+               case SIGN_RSA_EMSA_PKCS1_MD5:
+                       return build_emsa_pkcs1_signature(this, WC_HASH_TYPE_MD5, data,
+                                                                                         signature);
+#endif
+#ifdef WC_RSA_PSS
+               case SIGN_RSA_EMSA_PSS:
+                       return build_emsa_pss_signature(this, params, data, signature);
+#endif
+               default:
+                       DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
+                                signature_scheme_names, scheme);
+                       return FALSE;
+       }
+}
+
+METHOD(private_key_t, decrypt, bool,
+       private_wolfssl_rsa_private_key_t *this, encryption_scheme_t scheme,
+       chunk_t crypto, chunk_t *plain)
+{
+       int padding, mgf, len;
+       enum wc_HashType hash;
+       char *decrypted;
+
+       switch (scheme)
+       {
+               case ENCRYPT_RSA_PKCS1:
+                       hash = WC_HASH_TYPE_NONE;
+                       padding = WC_RSA_PKCSV15_PAD;
+                       mgf = WC_MGF1NONE;
+                       break;
+#ifndef WC_NO_RSA_OAEP
+       #ifndef NO_SHA
+               case ENCRYPT_RSA_OAEP_SHA1:
+                       hash = WC_HASH_TYPE_SHA;
+                       padding = WC_RSA_OAEP_PAD;
+                       mgf = WC_MGF1SHA1;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA224
+               case ENCRYPT_RSA_OAEP_SHA224:
+                       hash = WC_HASH_TYPE_SHA224;
+                       padding = WC_RSA_OAEP_PAD;
+                       mgf = WC_MGF1SHA224;
+                       break;
+       #endif
+       #ifndef NO_SHA256
+               case ENCRYPT_RSA_OAEP_SHA256:
+                       hash = WC_HASH_TYPE_SHA256;
+                       padding = WC_RSA_OAEP_PAD;
+                       mgf = WC_MGF1SHA256;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA384
+               case ENCRYPT_RSA_OAEP_SHA384:
+                       hash = WC_HASH_TYPE_SHA384;
+                       padding = WC_RSA_OAEP_PAD;
+                       mgf = WC_MGF1SHA384;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA512
+               case ENCRYPT_RSA_OAEP_SHA512:
+                       hash = WC_HASH_TYPE_SHA512;
+                       padding = WC_RSA_OAEP_PAD;
+                       mgf = WC_MGF1SHA512;
+                       break;
+       #endif
+#endif
+               default:
+                       DBG1(DBG_LIB, "encryption scheme %N not supported via wolfssl",
+                                encryption_scheme_names, scheme);
+                       return FALSE;
+       }
+       len = wc_RsaEncryptSize(&this->rsa);
+       decrypted = malloc(len);
+       len = wc_RsaPrivateDecrypt_ex(crypto.ptr, crypto.len, decrypted, len,
+                                                                 &this->rsa, padding, hash, mgf, NULL, 0);
+       if (len < 0)
+       {
+               DBG1(DBG_LIB, "RSA decryption failed");
+               free(decrypted);
+               return FALSE;
+       }
+       *plain = chunk_create(decrypted, len);
+       return TRUE;
+}
+
+METHOD(private_key_t, get_keysize, int,
+       private_wolfssl_rsa_private_key_t *this)
+{
+       return wc_RsaEncryptSize(&this->rsa) * 8;
+}
+
+METHOD(private_key_t, get_public_key, public_key_t*,
+       private_wolfssl_rsa_private_key_t *this)
+{
+       chunk_t enc;
+       public_key_t *key;
+       int len = wc_RsaEncryptSize(&this->rsa) * 2 + 20;
+
+       enc = chunk_alloc(len);
+       enc.len = wc_RsaKeyToPublicDer(&this->rsa, enc.ptr, len);
+       key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
+                                                        BUILD_BLOB_ASN1_DER, enc, BUILD_END);
+       free(enc.ptr);
+       return key;
+}
+
+METHOD(private_key_t, get_fingerprint, bool,
+       private_wolfssl_rsa_private_key_t *this, cred_encoding_type_t type,
+       chunk_t *fingerprint)
+{
+       return wolfssl_rsa_fingerprint(&this->rsa, type, fingerprint);
+}
+
+METHOD(private_key_t, get_encoding, bool,
+       private_wolfssl_rsa_private_key_t *this, cred_encoding_type_t type,
+       chunk_t *encoding)
+{
+       switch (type)
+       {
+               case PRIVKEY_ASN1_DER:
+               case PRIVKEY_PEM:
+               {
+                       bool success = TRUE;
+                       int len = wc_RsaEncryptSize(&this->rsa) * 5 + 20;
+
+                       *encoding = chunk_alloc(len);
+                       len = wc_RsaKeyToDer(&this->rsa, encoding->ptr, len);
+                       if (len < 0)
+                       {
+                               chunk_free(encoding);
+                               return FALSE;
+                       }
+                       encoding->len = len;
+
+                       if (type == PRIVKEY_PEM)
+                       {
+                               chunk_t asn1_encoding = *encoding;
+
+                               success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM,
+                                                               NULL, encoding, CRED_PART_RSA_PRIV_ASN1_DER,
+                                                               asn1_encoding, CRED_PART_END);
+                               chunk_clear(&asn1_encoding);
+                       }
+                       return success;
+               }
+               default:
+                       return FALSE;
+       }
+}
+
+METHOD(private_key_t, get_ref, private_key_t*,
+       private_wolfssl_rsa_private_key_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public.key;
+}
+
+METHOD(private_key_t, destroy, void,
+       private_wolfssl_rsa_private_key_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               lib->encoding->clear_cache(lib->encoding, &this->rsa);
+               wc_FreeRsaKey(&this->rsa);
+               wc_FreeRng(&this->rng);
+               free(this);
+       }
+}
+
+/**
+ * Internal generic constructor
+ */
+static private_wolfssl_rsa_private_key_t *create_empty()
+{
+       private_wolfssl_rsa_private_key_t *this;
+
+       INIT(this,
+               .public = {
+                       .key = {
+                               .get_type = _get_type,
+                               .sign = _sign,
+                               .decrypt = _decrypt,
+                               .get_keysize = _get_keysize,
+                               .get_public_key = _get_public_key,
+                               .equals = private_key_equals,
+                               .belongs_to = private_key_belongs_to,
+                               .get_fingerprint = _get_fingerprint,
+                               .has_fingerprint = private_key_has_fingerprint,
+                               .get_encoding = _get_encoding,
+                               .get_ref = _get_ref,
+                               .destroy = _destroy,
+                       },
+               },
+               .ref = 1,
+       );
+
+       if (wc_InitRng(&this->rng) != 0)
+       {
+               DBG1(DBG_LIB, "Init RNG failed, rsa private key create failed\n");
+               free(this);
+               return NULL;
+       }
+       if (wc_InitRsaKey(&this->rsa, NULL) != 0)
+       {
+               DBG1(DBG_LIB, "Init RSA failed, rsa private key create failed\n");
+               wc_FreeRng(&this->rng);
+               free(this);
+               return NULL;
+       }
+       this->rsa.rng = &this->rng;
+
+       return this;
+}
+
+/*
+ * See header.
+ */
+wolfssl_rsa_private_key_t *wolfssl_rsa_private_key_gen(key_type_t type,
+                                                                                                          va_list args)
+{
+       private_wolfssl_rsa_private_key_t *this;
+       u_int key_size = 0;
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_KEY_SIZE:
+                               key_size = va_arg(args, u_int);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+       if (!key_size)
+       {
+               return NULL;
+       }
+
+       this = create_empty();
+       if (this == NULL)
+       {
+               return NULL;
+       }
+
+       if (wc_MakeRsaKey(&this->rsa, key_size, WC_RSA_EXPONENT, &this->rng) < 0)
+       {
+               destroy(this);
+               return NULL;
+       }
+       return &this->public;
+}
+
+static bool wolfssl_mp_rand(mp_int* n, WC_RNG* rng, mp_int* r)
+{
+       int len;
+       int ret;
+
+       /* Ensure the number has enough memory. */
+       ret = mp_set_bit(r, mp_count_bits(n));
+       if (ret == 0)
+       {
+               len = sizeof(*r->dp) * n->used;
+               ret = wc_RNG_GenerateBlock(rng, (byte *)r->dp, len);
+       }
+       if (ret == 0)
+       {
+               ret = mp_mod(r, n, r);
+       }
+
+       return ret == 0;
+}
+
+/**
+ * Recover the primes from n, e and d using the algorithm described in
+ * Appendix C of NIST SP 800-56B.
+ */
+static bool calculate_pq(mp_int *n, mp_int *e, mp_int *d, mp_int *p, mp_int *q,
+                                                mp_int *t1, mp_int *t2, WC_RNG* rng)
+{
+       int i, t, j;
+       bool success = FALSE;
+       mp_int* k = p;
+       mp_int* r = p;
+       mp_int* n1 = q;
+       mp_int* g = t2;
+       mp_int* y = t2;
+       mp_int* x = t1;
+
+
+       /* k = (d * e) - 1 */
+       if (mp_mul(k, d, e) != 0)
+       {
+               goto error;
+       }
+       if (mp_sub_d(k, 1, k) != 0)
+       {
+               goto error;
+       }
+       /* k must be even */
+       if (mp_isodd(k))
+       {
+               goto error;
+       }
+       /* k = 2^t * r, where r is the largest odd integer dividing k, and t >= 1 */
+       if (mp_copy(r, k) != 0)
+       {
+               goto error;
+       }
+       for (t = 0; !mp_isodd(r); t++)
+       {   /* r = r/2 */
+               if (mp_div_2(r, r) != 0)
+                       goto error;
+       }
+       /* we need n-1 below */
+       if (mp_sub_d(n, 1, n1) != 0)
+       {
+               goto error;
+       }
+       for (i = 0; i < 100; i++)
+       {   /* generate random integer g in [0, n-1] */
+               if (!wolfssl_mp_rand(n, rng, g))
+               {
+                       goto error;
+               }
+               /* y = g^r mod n */
+               if (mp_exptmod(g, r, n, y) != 0)
+               {
+                       goto error;
+               }
+               /* try again if y == 1 or y == n-1 */
+               if (mp_isone(y) || mp_cmp(y, n1) == MP_EQ)
+               {
+                       continue;
+               }
+               for (j = 0; j < t; j++)
+               {   /* x = y^2 mod n */
+                       if (mp_sqrmod(y, n, x) != 0)
+                       {
+                               goto error;
+                       }
+                       /* stop if x == 1 */
+                       if (mp_isone(x))
+                       {
+                               goto done;
+                       }
+                       /* retry with new g if x = n-1 */
+                       if (mp_cmp(x, n1) == MP_EQ)
+                       {
+                               break;
+                       }
+                       /* y = x */
+                       if (mp_copy(y, x) != 0)
+                       {
+                               goto error;
+                       }
+               }
+       }
+       goto error;
+       
+done:
+       /* p = gcd(y-1, n) */
+       if (mp_sub_d(y, 1, y) != 0)
+       {
+               goto error;
+       }
+       if (mp_gcd(y, n, p) != 0)
+       {
+               goto error;
+       }
+       /* q = n/p */
+       if (mp_div(n, p, q, NULL) != 0)
+       {
+               goto error;
+       }
+
+       success = TRUE;
+       
+error:
+       return success;
+}
+
+/**
+ * Calculates dp = d (mod p-1) or dq = d (mod q-1) for the Chinese remainder
+ * algorithm.
+ */
+static int dmodpq1(mp_int *d, mp_int *pq, mp_int *res)
+{
+       /* p|q - 1 */
+       if (mp_sub_d(pq, 1, res) != 0)
+       {
+               return FALSE;
+       }
+       /* d (mod p|q -1) */
+       if (mp_mod(d, res, res) != 0)
+       {
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/**
+ * Calculates qinv = q^-1 (mod p) for the Chinese remainder algorithm.
+ */
+static int qinv(mp_int *q, mp_int *p, mp_int *res)
+{
+       /* q^-1 (mod p) */
+       return mp_invmod(q, p, res) == 0;
+}
+
+/*
+ * See header
+ */
+wolfssl_rsa_private_key_t *wolfssl_rsa_private_key_load(key_type_t type,
+                                                                                                               va_list args)
+{
+       private_wolfssl_rsa_private_key_t *this;
+       chunk_t blob, n, e, d, p, q, exp1, exp2, coeff;
+       word32 idx;
+       int ret;
+
+       blob = n = e = d = p = q = exp1 = exp2 = coeff = chunk_empty;
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_BLOB_ASN1_DER:
+                               blob = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_MODULUS:
+                               n = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_PUB_EXP:
+                               e = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_PRIV_EXP:
+                               d = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_PRIME1:
+                               p = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_PRIME2:
+                               q = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_EXP1:
+                               exp1 = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_EXP2:
+                               exp2 = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_COEFF:
+                               coeff = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+
+       this = create_empty();
+       if (this == NULL)
+       {
+               return NULL;
+       }
+
+       if (blob.ptr)
+       {
+               idx = 0;
+               ret = wc_RsaPrivateKeyDecode(blob.ptr, &idx, &this->rsa, blob.len);
+               if (ret == 0)
+               {
+                       return &this->public;
+               }
+       }
+       else if (n.ptr && e.ptr && d.ptr)
+       {
+               if (mp_read_unsigned_bin(&this->rsa.n, n.ptr, n.len) != 0)
+               {
+                       goto error;
+               }
+               if (mp_read_unsigned_bin(&this->rsa.e, e.ptr, e.len) != 0)
+               {
+                       goto error;
+               }
+               if (mp_read_unsigned_bin(&this->rsa.d, d.ptr, d.len) != 0)
+               {
+                       goto error;
+               }
+               if (p.ptr && q.ptr)
+               {
+                       if (mp_read_unsigned_bin(&this->rsa.p, p.ptr, p.len) != 0)
+                       {
+                               goto error;
+                       }
+                       if (mp_read_unsigned_bin(&this->rsa.q, q.ptr, q.len) != 0)
+                       {
+                               goto error;
+                       }
+               }
+               else if (!calculate_pq(&this->rsa.n, &this->rsa.e, &this->rsa.d,
+                                                          &this->rsa.p, &this->rsa.q, &this->rsa.dP,
+                                                          &this->rsa.dQ, &this->rng))
+               {
+                       DBG1(DBG_LIB, "calculate pq failed, rsa private key load failed\n");
+                       goto error;
+               }
+               if (exp1.ptr)
+               {
+                       if (mp_read_unsigned_bin(&this->rsa.dP, exp1.ptr, exp1.len) != 0)
+                       {
+                               goto error;
+                       }
+               }
+               else if (!dmodpq1(&this->rsa.d, &this->rsa.p, &this->rsa.dP))
+               {
+                       goto error;
+               }
+               if (exp2.ptr)
+               {
+                       if (mp_read_unsigned_bin(&this->rsa.dQ, exp2.ptr, exp2.len) != 0)
+                       {
+                               goto error;
+                       }
+               }
+               else if (!dmodpq1(&this->rsa.d, &this->rsa.q, &this->rsa.dQ))
+               {
+                       goto error;
+               }
+               if (coeff.ptr)
+               {
+                       if (mp_read_unsigned_bin(&this->rsa.u, coeff.ptr, coeff.len) != 0)
+                       {
+                               goto error;
+                       }
+               }
+               else if (!qinv(&this->rsa.q, &this->rsa.p, &this->rsa.u))
+               {
+                       goto error;
+               }
+
+               return &this->public;
+       }
+error:
+       destroy(this);
+       return NULL;
+}
+
+#endif /* NO_RSA */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_private_key.h b/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_private_key.h
new file mode 100644 (file)
index 0000000..d1ba59e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_rsa_private_key wolfssl_rsa_private_key
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_RSA_PRIVATE_KEY_H_
+#define WOLFSSL_RSA_PRIVATE_KEY_H_
+
+#include <credentials/builder.h>
+#include <credentials/keys/private_key.h>
+
+typedef struct wolfssl_rsa_private_key_t wolfssl_rsa_private_key_t;
+
+/**
+ * private_key_t implementation of RSA algorithm using wolfSSL.
+ */
+struct wolfssl_rsa_private_key_t {
+
+       /**
+        * Implements private_key_t interface
+        */
+       private_key_t key;
+};
+
+/**
+ * Generate an RSA private key using wolfSSL.
+ *
+ * Accepts the BUILD_KEY_SIZE argument.
+ *
+ * @param type         type of the key, must be KEY_RSA
+ * @param args         builder_part_t argument list
+ * @return                     generated key, NULL on failure
+ */
+wolfssl_rsa_private_key_t *wolfssl_rsa_private_key_gen(key_type_t type,
+                                                                                                          va_list args);
+
+/**
+ * Load an RSA private key using wolfSSL.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type         type of the key, must be KEY_RSA
+ * @param args         builder_part_t argument list
+ * @return                     loaded key, NULL on failure
+ */
+wolfssl_rsa_private_key_t *wolfssl_rsa_private_key_load(key_type_t type,
+                                                                                                               va_list args);
+
+#endif /** WOLFSSL_RSA_PRIVATE_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_public_key.c b/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_public_key.c
new file mode 100644 (file)
index 0000000..669dc08
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifndef NO_RSA
+
+#include "wolfssl_rsa_public_key.h"
+#include "wolfssl_util.h"
+
+#include <crypto/hashers/hasher.h>
+#include <utils/debug.h>
+#include <credentials/keys/signature_params.h>
+
+#include <wolfssl/wolfcrypt/rsa.h>
+
+
+typedef struct private_wolfssl_rsa_public_key_t private_wolfssl_rsa_public_key_t;
+
+/**
+ * Private data structure with signing context.
+ */
+struct private_wolfssl_rsa_public_key_t {
+       /**
+        * Public interface for this signer.
+        */
+       wolfssl_rsa_public_key_t public;
+
+       /**
+        * RSA key object from wolfSSL.
+        */
+       RsaKey rsa;
+
+       /**
+        * Random number generator to use with RSA operations.
+        */
+       WC_RNG rng;
+
+       /**
+        * reference counter
+        */
+       refcount_t ref;
+};
+
+
+/**
+ * Verify RSA signature
+ */
+static bool verify_signature(private_wolfssl_rsa_public_key_t *this,
+                                                        chunk_t data, chunk_t signature)
+{
+       bool success = FALSE;
+       int len = wc_RsaEncryptSize(&this->rsa);
+       u_char *buf;
+       u_char *p;
+
+       if (signature.len > len)
+       {
+               signature = chunk_skip(signature, signature.len - len);
+       }
+
+       buf = malloc(len);
+       memcpy(buf + len - signature.len, signature.ptr, signature.len);
+       memset(buf, 0, len - signature.len);
+
+       len = wc_RsaSSL_VerifyInline(buf, len, &p, &this->rsa);
+       if (len > 0)
+       {
+               success = chunk_equals_const(data, chunk_create(p, len));
+       }
+       free(buf);
+
+       return success;
+}
+
+/**
+ * Verification of an EMSA PKCS1 signature described in PKCS#1
+ */
+static bool verify_emsa_pkcs1_signature(private_wolfssl_rsa_public_key_t *this,
+                                                                               enum wc_HashType hash, chunk_t data,
+                                                                               chunk_t signature)
+{
+       bool success = FALSE;
+       chunk_t dgst = chunk_empty, encDgst;
+       int len;
+
+       encDgst = chunk_alloc(wc_HashGetDigestSize(hash) + 20);
+       if (wolfssl_hash_chunk(hash, data, &dgst))
+       {
+               len = wc_EncodeSignature(encDgst.ptr, dgst.ptr, dgst.len,
+                                                                wc_HashGetOID(hash));
+               if (len > 0)
+               {
+                       encDgst.len = len;
+                       success = verify_signature(this, encDgst, signature);
+               }
+       }
+
+       chunk_free(&encDgst);
+       chunk_free(&dgst);
+       return success;
+}
+
+#ifdef WC_RSA_PSS
+/**
+ * Verification of an EMSA PSS signature described in PKCS#1
+ */
+static bool verify_emsa_pss_signature(private_wolfssl_rsa_public_key_t *this,
+                                                                         rsa_pss_params_t *params, chunk_t data,
+                                                                         chunk_t signature)
+{
+       chunk_t dgst = chunk_empty;
+       enum wc_HashType hash;
+       int mgf;
+       bool success = FALSE;
+       int len = 0;
+       u_char *buf = NULL;
+       u_char *p;
+
+       if (!wolfssl_hash2type(params->hash, &hash))
+       {
+               return FALSE;
+       }
+       if (!wolfssl_hash2mgf1(params->mgf1_hash, &mgf))
+       {
+               return FALSE;
+       }
+
+       if (wolfssl_hash_chunk(hash, data, &dgst))
+       {
+               len = wc_RsaEncryptSize(&this->rsa);
+               if (signature.len > len)
+               {
+                       signature = chunk_skip(signature, signature.len - len);
+               }
+
+               buf = malloc(len);
+               memcpy(buf + len - signature.len, signature.ptr, signature.len);
+               memset(buf, 0, len - signature.len);
+
+               len = wc_RsaPSS_VerifyInline_ex(buf, len, &p, hash, mgf,
+                                                                               params->salt_len, &this->rsa);
+               if (len > 0)
+               {
+                       success = wc_RsaPSS_CheckPadding_ex(dgst.ptr, dgst.len, p, len,
+                                       hash, params->salt_len, mp_count_bits(&this->rsa.n)) == 0;
+               }
+       }
+
+       chunk_free(&dgst);
+       if (buf != NULL)
+       {
+               free(buf);
+       }
+
+       return success;
+}
+#endif
+
+METHOD(public_key_t, get_type, key_type_t,
+       private_wolfssl_rsa_public_key_t *this)
+{
+       return KEY_RSA;
+}
+
+METHOD(public_key_t, verify, bool,
+       private_wolfssl_rsa_public_key_t *this, signature_scheme_t scheme,
+       void *params, chunk_t data, chunk_t signature)
+{
+       switch (scheme)
+       {
+               case SIGN_RSA_EMSA_PKCS1_NULL:
+                       return verify_signature(this, data, signature);
+               case SIGN_RSA_EMSA_PKCS1_SHA2_224:
+                       return verify_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA224, data,
+                                                                                          signature);
+               case SIGN_RSA_EMSA_PKCS1_SHA2_256:
+                       return verify_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA256, data,
+                                                                                          signature);
+               case SIGN_RSA_EMSA_PKCS1_SHA2_384:
+                       return verify_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA384, data,
+                                                                                          signature);
+               case SIGN_RSA_EMSA_PKCS1_SHA2_512:
+                       return verify_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA512, data,
+                                                                                          signature);
+               case SIGN_RSA_EMSA_PKCS1_SHA1:
+                       return verify_emsa_pkcs1_signature(this, WC_HASH_TYPE_SHA, data,
+                                                                                          signature);
+               case SIGN_RSA_EMSA_PKCS1_MD5:
+                       return verify_emsa_pkcs1_signature(this, WC_HASH_TYPE_MD5, data,
+                                                                                          signature);
+#ifdef WC_RSA_PSS
+               case SIGN_RSA_EMSA_PSS:
+                       return verify_emsa_pss_signature(this, params, data, signature);
+#endif
+               default:
+                       DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
+                                signature_scheme_names, scheme);
+                       return FALSE;
+       }
+}
+
+METHOD(public_key_t, encrypt, bool,
+       private_wolfssl_rsa_public_key_t *this, encryption_scheme_t scheme,
+       chunk_t plain, chunk_t *crypto)
+{
+       int padding, mgf, len;
+       enum wc_HashType hash;
+       char *encrypted;
+
+       switch (scheme)
+       {
+               case ENCRYPT_RSA_PKCS1:
+                       padding = WC_RSA_PKCSV15_PAD;
+                       hash = WC_HASH_TYPE_NONE;
+                       mgf = WC_MGF1NONE;
+                       break;
+#ifndef WC_NO_RSA_OAEP
+       #ifndef NO_SHA
+               case ENCRYPT_RSA_OAEP_SHA1:
+                       padding = WC_RSA_OAEP_PAD;
+                       hash = WC_HASH_TYPE_SHA;
+                       mgf = WC_MGF1SHA1;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA224
+               case ENCRYPT_RSA_OAEP_SHA224:
+                       padding = WC_RSA_OAEP_PAD;
+                       hash = WC_HASH_TYPE_SHA224;
+                       mgf = WC_MGF1SHA224;
+                       break;
+       #endif
+       #ifndef NO_SHA256
+               case ENCRYPT_RSA_OAEP_SHA256:
+                       padding = WC_RSA_OAEP_PAD;
+                       hash = WC_HASH_TYPE_SHA256;
+                       mgf = WC_MGF1SHA256;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA384
+               case ENCRYPT_RSA_OAEP_SHA384:
+                       padding = WC_RSA_OAEP_PAD;
+                       hash = WC_HASH_TYPE_SHA384;
+                       mgf = WC_MGF1SHA384;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA512
+               case ENCRYPT_RSA_OAEP_SHA512:
+                       padding = WC_RSA_OAEP_PAD;
+                       hash = WC_HASH_TYPE_SHA512;
+                       mgf = WC_MGF1SHA512;
+                       break;
+       #endif
+#endif
+               default:
+                       DBG1(DBG_LIB, "decryption scheme %N not supported via wolfssl",
+                                encryption_scheme_names, scheme);
+                       return FALSE;
+       }
+       len = wc_RsaEncryptSize(&this->rsa);
+       encrypted = malloc(len);
+       len = wc_RsaPublicEncrypt_ex(plain.ptr, plain.len, encrypted, len,
+                                                                &this->rsa, &this->rng, padding, hash, mgf,
+                                                                NULL, 0);
+       if (len < 0)
+       {
+               DBG1(DBG_LIB, "RSA encryption failed");
+               free(encrypted);
+               return FALSE;
+       }
+       *crypto = chunk_create(encrypted, len);
+       return TRUE;
+}
+
+METHOD(public_key_t, get_keysize, int,
+       private_wolfssl_rsa_public_key_t *this)
+{
+       return wc_RsaEncryptSize(&this->rsa) * 8;
+}
+
+/**
+ * Calculate fingerprint from a RSA key, also used in rsa private key.
+ */
+bool wolfssl_rsa_fingerprint(RsaKey *rsa, cred_encoding_type_t type,
+                                                        chunk_t *fp)
+{
+       hasher_t *hasher;
+       chunk_t key;
+       int len;
+
+       if (lib->encoding->get_cache(lib->encoding, type, rsa, fp))
+       {
+               return TRUE;
+       }
+       switch (type)
+       {
+               case KEYID_PUBKEY_SHA1:
+                       len = wc_RsaEncryptSize(rsa) * 2 + 20;
+                       key = chunk_alloc(len);
+                       len = wc_RsaKeyToPublicDer(rsa, key.ptr, len);
+                       break;
+               default:
+               {
+                       chunk_t n = chunk_empty, e = chunk_empty;
+                       bool success = FALSE;
+
+                       if (wolfssl_mp2chunk(&rsa->n, &n) && wolfssl_mp2chunk(&rsa->e, &e))
+                       {
+                               success = lib->encoding->encode(lib->encoding, type, rsa, fp,
+                                                                       CRED_PART_RSA_MODULUS, n,
+                                                                       CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
+                       }
+                       chunk_free(&n);
+                       chunk_free(&e);
+                       return success;
+               }
+       }
+       if (len < 0)
+       {
+               chunk_free(&key);
+               return FALSE;
+       }
+       key.len = len;
+
+       hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+       if (!hasher || !hasher->allocate_hash(hasher, key, fp))
+       {
+               DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed");
+               DESTROY_IF(hasher);
+               free(key.ptr);
+               return FALSE;
+       }
+       free(key.ptr);
+       hasher->destroy(hasher);
+       lib->encoding->cache(lib->encoding, type, rsa, *fp);
+       return TRUE;
+}
+
+METHOD(public_key_t, get_fingerprint, bool,
+       private_wolfssl_rsa_public_key_t *this, cred_encoding_type_t type,
+       chunk_t *fingerprint)
+{
+       return wolfssl_rsa_fingerprint(&this->rsa, type, fingerprint);
+}
+
+METHOD(public_key_t, get_encoding, bool,
+       private_wolfssl_rsa_public_key_t *this, cred_encoding_type_t type,
+       chunk_t *encoding)
+{
+       bool success = FALSE;
+       int len;
+
+       switch (type)
+       {
+               case PUBKEY_ASN1_DER:
+                       len = wc_RsaEncryptSize(&this->rsa) * 2 + 20;
+                       *encoding = chunk_alloc(len);
+                       len = wc_RsaKeyToPublicDer(&this->rsa, encoding->ptr, len);
+                       if (len < 0)
+                       {
+                               DBG1(DBG_LIB, "Public Der failed, get encoding failed");
+                               chunk_free(encoding);
+                               return FALSE;
+                       }
+                       encoding->len = len;
+                       return TRUE;
+               default:
+               {
+                       chunk_t n = chunk_empty, e = chunk_empty;
+
+                       if (wolfssl_mp2chunk(&this->rsa.n, &n) &&
+                               wolfssl_mp2chunk(&this->rsa.e, &e))
+                       {
+                               success = lib->encoding->encode(lib->encoding, type, NULL,
+                                                                       encoding, CRED_PART_RSA_MODULUS, n,
+                                                                       CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
+                       }
+                       chunk_free(&n);
+                       chunk_free(&e);
+                       return success;
+               }
+       }
+}
+
+METHOD(public_key_t, get_ref, public_key_t*,
+       private_wolfssl_rsa_public_key_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public.key;
+}
+
+METHOD(public_key_t, destroy, void,
+       private_wolfssl_rsa_public_key_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               lib->encoding->clear_cache(lib->encoding, &this->rsa);
+               wc_FreeRsaKey(&this->rsa);
+               wc_FreeRng(&this->rng);
+               free(this);
+       }
+}
+
+/**
+ * Generic private constructor
+ */
+static private_wolfssl_rsa_public_key_t *create_empty()
+{
+       private_wolfssl_rsa_public_key_t *this;
+
+       INIT(this,
+               .public = {
+                       .key = {
+                               .get_type = _get_type,
+                               .verify = _verify,
+                               .encrypt = _encrypt,
+                               .equals = public_key_equals,
+                               .get_keysize = _get_keysize,
+                               .get_fingerprint = _get_fingerprint,
+                               .has_fingerprint = public_key_has_fingerprint,
+                               .get_encoding = _get_encoding,
+                               .get_ref = _get_ref,
+                               .destroy = _destroy,
+                       },
+               },
+               .ref = 1,
+       );
+
+       if (wc_InitRng(&this->rng) != 0)
+       {
+               DBG1(DBG_LIB, "Init RNG, rsa public key load failed");
+               free(this);
+               return NULL;
+       }
+       if (wc_InitRsaKey(&this->rsa, NULL) != 0)
+       {
+               DBG1(DBG_LIB, "Init RSA, rsa public key load failed");
+               wc_FreeRng(&this->rng);
+               free(this);
+               return NULL;
+       }
+       return this;
+}
+
+/**
+ * See header.
+ */
+wolfssl_rsa_public_key_t *wolfssl_rsa_public_key_load(key_type_t type,
+                                                                                                         va_list args)
+{
+       private_wolfssl_rsa_public_key_t *this;
+       chunk_t blob, n, e;
+       word32 idx;
+
+       n = e = blob = chunk_empty;
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_BLOB_ASN1_DER:
+                               blob = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_MODULUS:
+                               n = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_RSA_PUB_EXP:
+                               e = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+
+       this = create_empty();
+       if (this == NULL)
+       {
+               return NULL;
+       }
+
+       if (blob.ptr)
+       {
+               switch (type)
+               {
+                       case KEY_ANY:
+                       case KEY_RSA:
+                               idx = 0;
+                               if (wc_RsaPublicKeyDecode(blob.ptr, &idx, &this->rsa,
+                                                                                 blob.len) != 0)
+                               {
+                                       DBG1(DBG_LIB, "Public , rsa public key load failed");
+                                       destroy(this);
+                                       return NULL;
+                               }
+                               break;
+                       default:
+                               destroy(this);
+                               return NULL;
+               }
+               return &this->public;
+       }
+       else if (n.ptr && e.ptr && type == KEY_RSA)
+       {
+               if (wc_RsaPublicKeyDecodeRaw(n.ptr, n.len, e.ptr, e.len,
+                                                                        &this->rsa) != 0)
+               {
+                       destroy(this);
+                       return NULL;
+               }
+               return &this->public;
+       }
+       destroy(this);
+       return NULL;
+}
+
+#endif /* NO_RSA */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_public_key.h b/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_public_key.h
new file mode 100644 (file)
index 0000000..54fbd35
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_rsa_public_key wolfssl_rsa_public_key
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_RSA_PUBLIC_KEY_H_
+#define WOLFSSL_RSA_PUBLIC_KEY_H_
+
+typedef struct wolfssl_rsa_public_key_t wolfssl_rsa_public_key_t;
+
+#include <credentials/keys/public_key.h>
+
+/**
+ * public_key_t implementation of RSA algorithm using wolfSSL.
+ */
+struct wolfssl_rsa_public_key_t {
+
+       /**
+        * Implements the public_key_t interface
+        */
+       public_key_t key;
+};
+
+/**
+ * Load a RSA public key using wolfSSL.
+ *
+ * Accepts a BUILD_BLOB_ASN1_DER argument.
+ *
+ * @param type         type of the key, must be KEY_RSA
+ * @param args         builder_part_t argument list
+ * @return                     loaded key, NULL on failure
+ */
+wolfssl_rsa_public_key_t *wolfssl_rsa_public_key_load(key_type_t type,
+                                                                                                         va_list args);
+
+#endif /** WOLFSSL_RSA_PUBLIC_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_sha1_prf.c b/src/libstrongswan/plugins/wolfssl/wolfssl_sha1_prf.c
new file mode 100644 (file)
index 0000000..fa08356
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifndef NO_SHA
+
+#include "wolfssl_sha1_prf.h"
+
+#include <wolfssl/wolfcrypt/sha.h>
+#include <crypto/hashers/hasher.h>
+
+typedef struct private_wolfssl_sha1_prf_t private_wolfssl_sha1_prf_t;
+
+/**
+ * Private data of an wolfssl_sha1_prf_t object.
+ */
+struct private_wolfssl_sha1_prf_t {
+
+       /**
+        * Public wolfssl_sha1_prf_t interface.
+        */
+       wolfssl_sha1_prf_t public;
+
+       /**
+        * SHA1 context
+        */
+       wc_Sha sha1;
+};
+
+METHOD(prf_t, get_bytes, bool,
+       private_wolfssl_sha1_prf_t *this, chunk_t seed, uint8_t *bytes)
+{
+       if (wc_ShaUpdate(&this->sha1, seed.ptr, seed.len) != 0)
+       {
+               return FALSE;
+       }
+
+       if (bytes)
+       {
+               uint32_t *hash = (uint32_t*)bytes;
+
+               hash[0] = htonl(this->sha1.digest[0]);
+               hash[1] = htonl(this->sha1.digest[1]);
+               hash[2] = htonl(this->sha1.digest[2]);
+               hash[3] = htonl(this->sha1.digest[3]);
+               hash[4] = htonl(this->sha1.digest[4]);
+       }
+
+       return TRUE;
+}
+
+METHOD(prf_t, get_block_size, size_t,
+       private_wolfssl_sha1_prf_t *this)
+{
+       return HASH_SIZE_SHA1;
+}
+
+METHOD(prf_t, allocate_bytes, bool,
+       private_wolfssl_sha1_prf_t *this, chunk_t seed, chunk_t *chunk)
+{
+       if (chunk)
+       {
+               *chunk = chunk_alloc(HASH_SIZE_SHA1);
+               return get_bytes(this, seed, chunk->ptr);
+       }
+       return get_bytes(this, seed, NULL);
+}
+
+METHOD(prf_t, get_key_size, size_t,
+       private_wolfssl_sha1_prf_t *this)
+{
+       return HASH_SIZE_SHA1;
+}
+
+METHOD(prf_t, set_key, bool,
+       private_wolfssl_sha1_prf_t *this, chunk_t key)
+{
+       if (wc_InitSha(&this->sha1) != 0)
+       {
+               return FALSE;
+       }
+
+       if (key.len % 4)
+       {
+               return FALSE;
+       }
+       if (key.len >= 4)
+       {
+               this->sha1.digest[0] ^= untoh32(key.ptr);
+       }
+       if (key.len >= 8)
+       {
+               this->sha1.digest[1] ^= untoh32(key.ptr + 4);
+       }
+       if (key.len >= 12)
+       {
+               this->sha1.digest[2] ^= untoh32(key.ptr + 8);
+       }
+       if (key.len >= 16)
+       {
+               this->sha1.digest[3] ^= untoh32(key.ptr + 12);
+       }
+       if (key.len >= 20)
+       {
+               this->sha1.digest[4] ^= untoh32(key.ptr + 16);
+       }
+       return TRUE;
+}
+
+METHOD(prf_t, destroy, void,
+       private_wolfssl_sha1_prf_t *this)
+{
+       wc_ShaFree(&this->sha1);
+       free(this);
+}
+
+/**
+ * See header
+ */
+wolfssl_sha1_prf_t *wolfssl_sha1_prf_create(pseudo_random_function_t algo)
+{
+       private_wolfssl_sha1_prf_t *this;
+
+       if (algo != PRF_KEYED_SHA1)
+       {
+               return NULL;
+       }
+
+       INIT(this,
+               .public = {
+                       .prf = {
+                               .get_block_size = _get_block_size,
+                               .get_bytes = _get_bytes,
+                               .allocate_bytes = _allocate_bytes,
+                               .get_key_size = _get_key_size,
+                               .set_key = _set_key,
+                               .destroy = _destroy,
+                       },
+               },
+       );
+
+       if (wc_InitSha(&this->sha1) != 0)
+       {
+               free(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
+
+#endif /* NO_SHA */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_sha1_prf.h b/src/libstrongswan/plugins/wolfssl/wolfssl_sha1_prf.h
new file mode 100644 (file)
index 0000000..7f6a32e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_sha1_prf wolfssl_sha1_prf
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_SHA1_PRF_H_
+#define WOLFSSL_SHA1_PRF_H_
+
+typedef struct wolfssl_sha1_prf_t wolfssl_sha1_prf_t;
+
+#include <crypto/prfs/prf.h>
+
+/**
+ * Implementation of prf_t interface using keyed SHA1 algorithm as used
+ * in EAP-AKA/FIPS_PRF.
+ */
+struct wolfssl_sha1_prf_t {
+
+       /**
+        * Implements prf_t interface.
+        */
+       prf_t prf;
+};
+
+/**
+ * Creates a new wolfssl_sha1_prf_t.
+ *
+ * @param algo         algorithm, must be PRF_KEYED_SHA1
+ * @return                     sha1_keyed_prf_tobject
+ */
+wolfssl_sha1_prf_t *wolfssl_sha1_prf_create(pseudo_random_function_t algo);
+
+#endif /** WOLFSSL_SHA1_PRF_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_util.c b/src/libstrongswan/plugins/wolfssl/wolfssl_util.c
new file mode 100644 (file)
index 0000000..cc8054a
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+#include "wolfssl_util.h"
+
+#include <utils/debug.h>
+
+#include <wolfssl/wolfcrypt/hash.h>
+#include <wolfssl/wolfcrypt/rsa.h>
+
+/**
+ * Described in header.
+ */
+bool wolfssl_hash_chunk(int hash_type, chunk_t data, chunk_t *hash)
+{
+       int ret;
+
+       *hash = chunk_alloc(wc_HashGetDigestSize(hash_type));
+       ret = wc_Hash(hash_type, data.ptr, data.len, hash->ptr, hash->len);
+       if (ret < 0)
+       {
+               chunk_free(hash);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+/**
+ * Described in header.
+ */
+bool wolfssl_mp2chunk(mp_int *mp, chunk_t *chunk)
+{
+       *chunk = chunk_alloc(mp_unsigned_bin_size(mp));
+       if (mp_to_unsigned_bin(mp, chunk->ptr) == 0)
+       {
+               if (chunk->len && chunk->ptr[0] & 0x80)
+               {       /* if MSB is set, prepend a zero to make it non-negative */
+                       *chunk = chunk_cat("cm", chunk_from_chars(0x00), *chunk);
+               }
+               return TRUE;
+       }
+       chunk_free(chunk);
+       return FALSE;
+}
+
+/**
+ * Described in header.
+ */
+bool wolfssl_mp_split(chunk_t chunk, mp_int *a, mp_int *b)
+{
+       int ret;
+       int len;
+
+       if ((chunk.len % 2) == 1)
+       {
+               return FALSE;
+       }
+
+       len = chunk.len / 2;
+       ret = mp_read_unsigned_bin(a, chunk.ptr, len);
+       if (ret == 0)
+       {
+               ret = mp_read_unsigned_bin(b, chunk.ptr + len, len);
+       }
+
+       return ret == 0;
+}
+
+/**
+ * Described in header.
+ */
+bool wolfssl_mp_cat(int len, mp_int *a, mp_int *b, chunk_t *chunk)
+{
+       int ret;
+       int sz;
+
+       *chunk = chunk_alloc(len);
+       if (b != NULL)
+       {
+               len /= 2;
+       }
+
+       sz = mp_unsigned_bin_size(a);
+       memset(chunk->ptr, 0, len - sz);
+       ret = mp_to_unsigned_bin(a, chunk->ptr + len - sz);
+       if (ret == 0 && b != NULL)
+       {
+               sz = mp_unsigned_bin_size(b);
+               memset(chunk->ptr + len, 0, len - sz);
+               ret = mp_to_unsigned_bin(b, chunk->ptr + 2 * len - sz);
+       }
+
+       return ret == 0;
+}
+
+/**
+ * Described in header.
+ */
+bool wolfssl_hash2type(hash_algorithm_t hash, enum wc_HashType *type)
+{
+       switch (hash)
+       {
+       #ifndef NO_MD5
+               case HASH_MD5:
+                       *type = WC_HASH_TYPE_MD5;
+                       break;
+       #endif
+       #ifndef NO_SHA
+               case HASH_SHA1:
+                       *type = WC_HASH_TYPE_SHA;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA224
+               case HASH_SHA224:
+                       *type = WC_HASH_TYPE_SHA224;
+                       break;
+       #endif
+       #ifndef NO_SHA256
+               case HASH_SHA256:
+                       *type = WC_HASH_TYPE_SHA256;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA384
+               case HASH_SHA384:
+                       *type = WC_HASH_TYPE_SHA384;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA512
+               case HASH_SHA512:
+                       *type = WC_HASH_TYPE_SHA512;
+                       break;
+       #endif
+               default:
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+/**
+ * Described in header.
+ */
+bool wolfssl_hash2mgf1(hash_algorithm_t hash, int *mgf1)
+{
+       switch (hash)
+       {
+       #ifndef NO_SHA
+               case HASH_SHA1:
+                       *mgf1 = WC_MGF1SHA1;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA224
+               case HASH_SHA224:
+                       *mgf1 = WC_MGF1SHA224;
+                       break;
+       #endif
+       #ifndef NO_SHA256
+               case HASH_SHA256:
+                       *mgf1 = WC_MGF1SHA256;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA384
+               case HASH_SHA384:
+                       *mgf1 = WC_MGF1SHA384;
+                       break;
+       #endif
+       #ifdef WOLFSSL_SHA512
+               case HASH_SHA512:
+                       *mgf1 = WC_MGF1SHA512;
+                       break;
+       #endif
+               default:
+                       return FALSE;
+       }
+       return TRUE;
+}
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_util.h b/src/libstrongswan/plugins/wolfssl/wolfssl_util.h
new file mode 100644 (file)
index 0000000..35b09c4
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @defgroup wolfssl_util wolfssl_util
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_UTIL_H_
+#define WOLFSSL_UTIL_H_
+
+#include <wolfssl/wolfcrypt/integer.h>
+#include <wolfssl/wolfcrypt/hash.h>
+
+/**
+ * Creates a hash of a given type of a chunk of data.
+ *
+ * Note: this function allocates memory for the hash
+ *
+ * @param hash_type Hash enumeration
+ * @param data         the chunk of data to hash
+ * @param hash         chunk that contains the hash
+ * @return                     TRUE on success, FALSE otherwise
+ */
+bool wolfssl_hash_chunk(int hash_type, chunk_t data, chunk_t *hash);
+
+/**
+ * Exports the given integer (assumed to be a positive number) to a chunk in
+ * two's complement format (i.e. a zero byte is added if the MSB is set).
+ *
+ * @param mp           the integer to export
+ * @param chunk                the chunk (data gets allocated)
+ * @return                     TRUE on success, FALSE otherwise
+ */
+bool wolfssl_mp2chunk(mp_int *mp, chunk_t *chunk);
+
+/**
+ * Splits a chunk into two mp_ints of equal binary length.
+ *
+ * @param chunk                a chunk that contains the two integers
+ * @param a                    first mp_int
+ * @param b                    second mp_int
+ * @return                     TRUE on success, FALSE otherwise
+ */
+bool wolfssl_mp_split(chunk_t chunk, mp_int *a, mp_int *b);
+
+/**
+ * Concatenates two integers into a chunk, thereby enfocing the length of
+ * a single integer, if necessary, by pre-pending it with zeros.
+ *
+ * Note: this function allocates memory for the chunk
+ *
+ * @param len          the length of a single integer
+ * @param a                    first integer
+ * @param b                    second integer
+ * @param chunk                resulting chunk
+ * @return                     TRUE on success, FALSE otherwise
+ */
+bool wolfssl_mp_cat(int len, mp_int *a, mp_int *b, chunk_t *chunk);
+
+/**
+ * Convert the hash algorithm to a wolfSSL hash type.
+ *
+ * @param hash         hash algorithm
+ * @param type         Hash enumeration from wolfSSL
+ * @return                     TRUE on success, FALSE otherwise
+ */
+bool wolfssl_hash2type(hash_algorithm_t hash, enum wc_HashType *type);
+
+/**
+ * Convert the mgf1 hash algorithm to a wolfSSL mgf1 type.
+ *
+ * @param hash         hash algorithm
+ * @param mgf1         MGF1 algorithm from wolfSSL
+ * @return                     TRUE on success, FALSE otherwise
+ */
+bool wolfssl_hash2mgf1(hash_algorithm_t hash, int *mgf1);
+
+#endif /** WOLFSSL_UTIL_H_ @}*/
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.c b/src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.c
new file mode 100644 (file)
index 0000000..b752ce0
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "wolfssl_common.h"
+
+#ifdef HAVE_CURVE25519
+
+#include "wolfssl_x_diffie_hellman.h"
+
+#include <utils/debug.h>
+
+#include <wolfssl/wolfcrypt/curve25519.h>
+#include <wolfssl/wolfcrypt/fe_operations.h>
+
+typedef struct private_diffie_hellman_t private_diffie_hellman_t;
+
+/**
+ * Private data
+ */
+struct private_diffie_hellman_t {
+       /**
+        * Public interface.
+        */
+       diffie_hellman_t public;
+
+       /**
+        * Diffie Hellman group number.
+        */
+       diffie_hellman_group_t group;
+
+       /**
+        * Private (public) key
+        */
+       curve25519_key key;
+
+       /**
+        * Shared secret
+        */
+       chunk_t shared_secret;
+
+       /**
+        * True if shared secret is computed
+        */
+       bool computed;
+};
+
+/**
+ * Compute the shared secret
+ */
+static bool compute_shared_key(private_diffie_hellman_t *this,
+                                                          curve25519_key *pub, chunk_t *shared_secret)
+{
+       int ret;
+       word32 len = CURVE25519_KEYSIZE;
+
+       *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,
+       private_diffie_hellman_t *this, chunk_t value)
+{
+       int ret;
+       curve25519_key pub;
+
+       if (!diffie_hellman_verify_value(this->group, value))
+       {
+               return FALSE;
+       }
+
+       ret = wc_curve25519_init(&pub);
+       if (ret < 0)
+       {
+               DBG1(DBG_LIB, "%N public key initialization failed",
+                        diffie_hellman_group_names, this->group);
+               return FALSE;
+       }
+
+       ret = wc_curve25519_import_public_ex(value.ptr, value.len, &pub,
+                                                                                EC25519_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);
+
+       if (!compute_shared_key(this, &pub, &this->shared_secret))
+       {
+               DBG1(DBG_LIB, "%N shared secret computation failed",
+                        diffie_hellman_group_names, this->group);
+               wc_curve25519_free(&pub);
+               return FALSE;
+       }
+       this->computed = TRUE;
+       wc_curve25519_free(&pub);
+       return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_my_public_value, 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,
+                                                                          EC25519_LITTLE_ENDIAN) != 0)
+       {
+               chunk_free(value);
+               return FALSE;
+       }
+       return TRUE;
+}
+
+METHOD(diffie_hellman_t, set_private_value, bool,
+       private_diffie_hellman_t *this, chunk_t value)
+{
+       int ret;
+       unsigned char basepoint[CURVE25519_KEYSIZE] = {9};
+       curve25519_key pub;
+       int len;
+
+       ret = wc_curve25519_init(&pub);
+       /* Create base point for calculating public key */
+       if (ret == 0)
+       {
+               ret = wc_curve25519_import_public_ex(basepoint, CURVE25519_KEYSIZE,
+                                                                                        &pub, EC25519_LITTLE_ENDIAN);
+       }
+       if (ret == 0)
+       {
+               ret = wc_curve25519_import_private_ex(value.ptr, value.len, &this->key,
+                                                                                         EC25519_LITTLE_ENDIAN);
+       }
+       if (ret == 0)
+       {
+               len = CURVE25519_KEYSIZE;
+               ret = wc_curve25519_shared_secret_ex(&this->key, &pub,
+                               this->key.p.point, &len, EC25519_LITTLE_ENDIAN);
+               if (ret > 0)
+               {
+                       ret = 0;
+               }
+       }
+
+       return ret == 0;
+}
+
+METHOD(diffie_hellman_t, get_shared_secret, bool,
+       private_diffie_hellman_t *this, chunk_t *secret)
+{
+       if (!this->computed)
+       {
+               return FALSE;
+       }
+       *secret = chunk_clone(this->shared_secret);
+       return TRUE;
+}
+
+METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
+       private_diffie_hellman_t *this)
+{
+       return this->group;
+}
+
+METHOD(diffie_hellman_t, destroy, void,
+       private_diffie_hellman_t *this)
+{
+       wc_curve25519_free(&this->key);
+       chunk_clear(&this->shared_secret);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+diffie_hellman_t *wolfssl_x_diffie_hellman_create(diffie_hellman_group_t group)
+{
+       private_diffie_hellman_t *this;
+       WC_RNG rng;
+       int ret;
+
+       switch (group)
+       {
+               case CURVE_25519:
+                       break;
+               default:
+                       return NULL;
+       }
+
+       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");
+               free(this);
+               return NULL;
+       }
+       ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &this->key);
+       wc_FreeRng(&rng);
+       if (ret != 0)
+       {
+               DBG1(DBG_LIB, "Making a key failed");
+               free(this);
+               return NULL;
+       }
+       return &this->public;
+}
+
+#endif /* HAVE_CURVE25519 */
diff --git a/src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.h b/src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.h
new file mode 100644 (file)
index 0000000..5e0b7b1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Implementation of the X25519 Diffie-Hellman algorithm using wolfSSL.
+ *
+ * @defgroup wolfssl_x_diffie_hellman wolfssl_x_diffie_hellman
+ * @{ @ingroup wolfssl_p
+ */
+
+#ifndef WOLFSSL_X_DIFFIE_HELLMAN_H_
+#define WOLFSSL_X_DIFFIE_HELLMAN_H_
+
+#include <library.h>
+
+/**
+ * Creates a new diffie_hellman_t object.
+ *
+ * @param group                        Diffie Hellman group number to use
+ * @return                             object, NULL if not supported
+ */
+diffie_hellman_t *wolfssl_x_diffie_hellman_create(diffie_hellman_group_t group);
+
+#endif /** WOLFSSL_X_DIFFIE_HELLMAN_H_ @}*/
+
index c52b908..057cc2a 100644 (file)
@@ -532,8 +532,8 @@ START_TEST(test_ed25519_fail)
                                                          chunk_empty));
 
        /* RFC 8032, section 5.1.7 requires that 0 <= s < L to prevent signature
-        * malleability.  Only a warning because Botan and OpenSSL are both
-        * vulnerable to this. */
+        * malleability.  Only a warning because Botan, OpenSSL and wolfSSL are
+        * all vulnerable to this. */
        if (pubkey->verify(pubkey, SIGN_ED25519, NULL, sig_tests[0].msg,
                                           malleable_sig))
        {
index a17b5dd..18a76fd 100644 (file)
@@ -11,7 +11,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/libtncif \
        -I$(top_srcdir)/src/libtnccs \
        -DIPSEC_CONFDIR=\"${sysconfdir}\" \
-       -DPLUGINS="\"x509 pem pkcs1 pubkey openssl nonce tnc-tnccs tnc-imc tnccs-20\""
+       -DPLUGINS="\"x509 pem pkcs1 pubkey openssl wolfssl nonce tnc-tnccs tnc-imc tnccs-20\""
 
 pt_tls_client_LDADD = \
        $(top_builddir)/src/libstrongswan/libstrongswan.la \
index 4ed73c9..b68f650 100644 (file)
@@ -13,7 +13,7 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/src/libstrongswan \
        -I$(top_srcdir)/src/libtncif \
        -I$(top_srcdir)/src/libimcv \
-       -DPLUGINS=\""random openssl sqlite curl"\"
+       -DPLUGINS=\""random openssl wolfssl sqlite curl"\"
 
 AM_CFLAGS = $(json_CFLAGS)