diff --git a/.travis.yml b/.travis.yml index 7e70df553..3a62e2c15 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,6 +81,8 @@ matrix: # the crypto plugins are build-tested with clang via "all" above - env: TEST=botan - env: TEST=botan LEAK_DETECTIVE=yes + - env: TEST=wolfssl + - env: TEST=wolfssl LEAK_DETECTIVE=yes - env: TEST=openssl - env: TEST=openssl LEAK_DETECTIVE=yes - env: TEST=openssl-1.0 diff --git a/conf/Makefile.am b/conf/Makefile.am index 9d8674049..0080a559d 100644 --- a/conf/Makefile.am +++ b/conf/Makefile.am @@ -101,6 +101,7 @@ plugins = \ plugins/updown.opt \ plugins/vici.opt \ plugins/whitelist.opt \ + plugins/wolfssl.opt \ plugins/xauth-eap.opt \ plugins/xauth-pam.opt diff --git a/conf/plugins/wolfssl.opt b/conf/plugins/wolfssl.opt new file mode 100644 index 000000000..02d37e07f --- /dev/null +++ b/conf/plugins/wolfssl.opt @@ -0,0 +1,2 @@ +charon.plugins.wolfssl.fips_mode = no + Enable to prevent loading the plugin if wolfSSL is not in FIPS mode. diff --git a/configure.ac b/configure.ac index 3659e6dca..9a1c5a30d 100644 --- a/configure.ac +++ b/configure.ac @@ -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/options.h],,[AC_MSG_ERROR([wolfSSL header wolfssl/options.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 diff --git a/scripts/test.sh b/scripts/test.sh index b958db1a0..0f206b381 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -34,6 +34,33 @@ build_botan() cd - } +build_wolfssl() +{ + WOLFSSL_REV=v4.0.0-stable + WOLFSSL_DIR=$TRAVIS_BUILD_DIR/../wolfssl + + if test -d "$WOLFSSL_DIR"; then + return + fi + + echo "$ build_wolfssl()" + + WOLFSSL_CFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DES_ECB" + WOLFSSL_CONFIG="--enable-keygen --enable-rsapss --enable-aesccm + --enable-aesctr --enable-des3 --enable-camellia + --enable-curve25519 --enable-ed25519" + + git clone https://github.com/wolfSSL/wolfssl.git $WOLFSSL_DIR && + cd $WOLFSSL_DIR && + git checkout -qf $WOLFSSL_REV && + ./autogen.sh && + ./configure C_EXTRA_FLAGS="$WOLFSSL_CFLAGS" $WOLFSSL_CONFIG && + make -j4 >/dev/null && + sudo make install >/dev/null && + sudo ldconfig || exit $? + cd - +} + build_tss2() { TSS2_REV=2.1.0 @@ -135,6 +162,14 @@ botan) build_botan fi ;; +wolfssl) + CONFIG="--disable-defaults --enable-pki --enable-wolfssl --enable-pem" + # build with custom options to enable all the features the plugin supports + DEPS="" + if test "$1" = "deps"; then + build_wolfssl + fi + ;; printf-builtin) CONFIG="--with-printf-hooks=builtin" ;; @@ -161,6 +196,7 @@ all|coverage|sonarcloud) PYDEPS="pytest" if test "$1" = "deps"; then build_botan + build_wolfssl build_tss2 fi use_custom_openssl $1 diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index e6d7ce74b..827e0adb2 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -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 index 000000000..5f3080a27 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/Makefile.am @@ -0,0 +1,35 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan + +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 index 000000000..2ea7c94cd --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_aead.c @@ -0,0 +1,466 @@ +/* + * 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 +#include +#include +#include + +/** 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) + +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 + */ + chunk_t salt; + + /** + * Size of the integrity check value + */ + size_t icv_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) +{ + chunk_t nonce; + u_char *out; + bool success = FALSE; + int ret; + + out = plain.ptr; + if (encrypted) + { + *encrypted = chunk_alloc(plain.len + this->icv_size); + out = encrypted->ptr; + } + + nonce = chunk_cata("cc", this->salt, iv); + + 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.ptr, 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: + /* wc_AesCcmEncrypt fails if the pointer is NULL */ + if (!plain.ptr && !plain.len) + { + plain.ptr = nonce.ptr; + } + 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.ptr, 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.ptr, + assoc.ptr, assoc.len, plain.ptr, plain.len, out, + out + plain.len); + success = (ret == 0); + break; +#endif + default: + break; + } + + memwipe(nonce.ptr, nonce.len); + return success; +} + +METHOD(aead_t, decrypt, bool, + private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv, + chunk_t *plain) +{ + chunk_t nonce; + u_char *out; + bool success = FALSE; + int ret = 0; + + 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; + } + + nonce = chunk_cata("cc", this->salt, iv); + + 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.ptr, 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: + /* wc_AesCcmDecrypt() fails if the pointers are NULL */ + if (!encrypted.ptr && !encrypted.len) + { + encrypted.ptr = nonce.ptr; + } + if (!out && !encrypted.len) + { + out = nonce.ptr; + } + 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.ptr, 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.ptr, + assoc.ptr, assoc.len, encrypted.ptr, encrypted.len, + encrypted.ptr + encrypted.len, out); + success = (ret == 0); + break; +#endif + default: + break; + } + + memwipe(nonce.ptr, nonce.len); + 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.ptr, 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); + chunk_clear(&this->salt); + 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 + 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; + size_t expected_salt_size; + + 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: + expected_salt_size = 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: + expected_salt_size = 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: + expected_salt_size = 4; + break; + default: + free(this); + return NULL; + } + break; +#endif + default: + free(this); + return NULL; + } + + if (salt_size && salt_size != expected_salt_size) + { + /* currently not supported */ + free(this); + return NULL; + } + + this->key = chunk_alloc(key_size); + this->salt = chunk_alloc(expected_salt_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 index 000000000..fd6dfdbd5 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_aead.h @@ -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 + +/** + * 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 index 000000000..3c9081a83 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_common.h @@ -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 + +/* 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 +#endif +#include + +#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 index 000000000..a39c25b95 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_crypter.c @@ -0,0 +1,530 @@ +/* + * 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 +#include +#include + +#include + +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 + */ + chunk_t salt; + + /** + * 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.ptr, 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; + } + + memwipe(nonce, sizeof(nonce)); + 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.ptr, 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.ptr, 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); + chunk_clear(&this->salt); + 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 +#ifndef NO_DES3 + case ENCR_3DES: + wc_Des3Free(&this->cipher.des3); + 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; + /* fall-through */ + 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; + /* fall-through */ + 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; + /* fall-through */ + 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: + #ifdef WOLFSSL_DES_ECB + case ENCR_DES_ECB: + #endif + if (key_size != 8) + { + return NULL; + } + block_size = DES_BLOCK_SIZE; + iv_size = DES_BLOCK_SIZE; + break; +#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, + .block_size = block_size, + .iv_size = iv_size, + ); + + 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 +#ifndef NO_DES3 + case ENCR_3DES: + ret = wc_Des3Init(&this->cipher.des3, NULL, INVALID_DEVID); + break; +#endif + default: + break; + } + if (ret != 0) + { + free(this); + return NULL; + } + + this->key = chunk_alloc(key_size); + this->salt = chunk_alloc(salt_len); + + 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 index 000000000..108c9cc94 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_crypter.h @@ -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 + +/** + * 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 index 000000000..6fefe523d --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_diffie_hellman.c @@ -0,0 +1,285 @@ +/* + * 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 + +#include "wolfssl_diffie_hellman.h" +#include "wolfssl_util.h" + +#include + +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; + + /** + * Length of public values + */ + int len; + + /** + * Private key + */ + chunk_t priv; + + /** + * Public key + */ + chunk_t pub; + + /** + * Shared secret + */ + chunk_t shared_secret; +}; + +METHOD(diffie_hellman_t, get_my_public_value, bool, + private_wolfssl_diffie_hellman_t *this, chunk_t *value) +{ + *value = chunk_copy_pad(chunk_alloc(this->len), this->pub, 0x00); + return TRUE; +} + +METHOD(diffie_hellman_t, get_shared_secret, bool, + private_wolfssl_diffie_hellman_t *this, chunk_t *secret) +{ + if (!this->shared_secret.len) + { + return FALSE; + } + *secret = chunk_copy_pad(chunk_alloc(this->len), this->shared_secret, 0x00); + 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 = chunk_alloc(this->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"); + chunk_free(&this->shared_secret); + return FALSE; + } + this->shared_secret.len = len; + 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; + + 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; + if (wc_DhAgree(&this->dh, this->pub.ptr, &len, this->priv.ptr, + this->priv.len, g.ptr, g.len) == 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; +} + +METHOD(diffie_hellman_t, destroy, void, + private_wolfssl_diffie_hellman_t *this) +{ + 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; +} + +/** + * Generic internal constructor + */ +static wolfssl_diffie_hellman_t *create_generic(diffie_hellman_group_t group, + chunk_t g, chunk_t p) +{ + private_wolfssl_diffie_hellman_t *this; + word32 privLen, pubLen; + WC_RNG rng; + + 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, + .len = p.len, + ); + + if (wc_InitDhKey(&this->dh) != 0) + { + free(this); + return NULL; + } + + if (wc_DhSetKey(&this->dh, p.ptr, p.len, g.ptr, g.len) != 0) + { + destroy(this); + return NULL; + } + + if (wc_InitRng(&rng) != 0) + { + 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, &rng, this->priv.ptr, &privLen, + this->pub.ptr, &pubLen) != 0) + { + wc_FreeRng(&rng); + destroy(this); + return NULL; + } + this->pub.len = pubLen; + this->priv.len = privLen; + wc_FreeRng(&rng); + + return &this->public; +} + +/* + * Described in header + */ +wolfssl_diffie_hellman_t *wolfssl_diffie_hellman_create( + diffie_hellman_group_t group, ...) +{ + diffie_hellman_params_t *params; + chunk_t g, p; + + if (group == MODP_CUSTOM) + { + VA_ARGS_GET(group, g, p); + return create_generic(group, g, p); + } + params = diffie_hellman_get_params(group); + if (!params) + { + return NULL; + } + /* wolfSSL doesn't support optimized exponent sizes according to RFC 3526 */ + return create_generic(group, params->generator, params->prime); +} + +#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 index 000000000..85952e798 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_diffie_hellman.h @@ -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 + +/** + * 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 index 000000000..ceff4172c --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_diffie_hellman.c @@ -0,0 +1,378 @@ +/* + * 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 + +#include "wolfssl_ec_diffie_hellman.h" +#include "wolfssl_util.h" + +#include + +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; + + /** + * Shared secret + */ + chunk_t shared_secret; +}; + +/** + * 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) +{ + mp_int a, prime; + int ret; + + if (mp_init(&a) != 0) + { + return FALSE; + } + if (mp_init(&prime) != 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, + ecc_point *pub_key, chunk_t *shared_secret) +{ + ecc_point* secret; + bool x_coordinate_only; + bool success = FALSE; + + if ((secret = wc_ecc_new_point()) == NULL) + { + return FALSE; + } + + if (wolfssl_ecc_multiply(this->key.dp, &this->key.k, 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) +{ + ecc_point *pub_key; + + if (!diffie_hellman_verify_value(this->group, value)) + { + return FALSE; + } + + if ((pub_key = wc_ecc_new_point()) == NULL) + { + return FALSE; + } + + if (!chunk2ecp(value, pub_key)) + { + DBG1(DBG_LIB, "ECDH public value is malformed"); + wc_ecc_del_point(pub_key); + return FALSE; + } + + chunk_clear(&this->shared_secret); + + if (!compute_shared_key(this, pub_key, &this->shared_secret)) + { + DBG1(DBG_LIB, "ECDH shared secret computation failed"); + chunk_clear(&this->shared_secret); + wc_ecc_del_point(pub_key); + return FALSE; + } + wc_ecc_del_point(pub_key); + 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->shared_secret.len) + { + 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_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; + WC_RNG rng; + + 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; + } + + 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: + destroy(this); + return NULL; + } + + if (wc_InitRng(&rng) != 0) + { + DBG1(DBG_LIB, "RNG init failed, ecdh create failed"); + destroy(this); + return NULL; + } + + /* generate an EC private (public) key */ + if (wc_ecc_make_key_ex(&rng, this->keysize, &this->key, + this->curve_id) != 0) + { + DBG1(DBG_LIB, "make key failed, wolfssl ECDH create failed"); + destroy(this); + return NULL; + } + wc_FreeRng(&rng); + + 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 index 000000000..c0a3e84f2 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_diffie_hellman.h @@ -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_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 + +/** + * 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 index 000000000..2a2b44e4c --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_private_key.c @@ -0,0 +1,513 @@ +/* + * 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 +#include + +#include + +#include +#include + +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 + */ + 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) +{ + chunk_t dgst = chunk_empty; + bool success = FALSE; + + 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) +{ + chunk_t dgst = chunk_empty; + bool success = FALSE; + word32 len; + + if (wolfssl_hash_chunk(hash, data, &dgst)) + { + *signature = chunk_alloc(wc_ecc_sig_size(&this->ec)); + len = signature->len; + if (wc_ecc_sign_hash(dgst.ptr, dgst.len, signature->ptr, &len, + &this->rng, &this->ec) == 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 len; + + /* space for algorithmIdentifier/bitString + one byte for the point type */ + key = chunk_alloc(2 * this->ec.dp->size + 2 * MAX_SEQ_SZ + 2 * MAX_ALGO_SZ + + TRAILING_ZERO + 1); + len = wc_EccPublicKeyToDer(&this->ec, key.ptr, key.len, 1); + if (len < 0) + { + chunk_free(&key); + return NULL; + } + key.len = len; + + 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) +{ + bool success = TRUE; + int len; + + switch (type) + { + case PRIVKEY_ASN1_DER: + case PRIVKEY_PEM: + /* include space for parameters, public key and contexts */ + *encoding = chunk_alloc(3 * this->ec.dp->size + 4 * MAX_SEQ_SZ + + MAX_VERSION_SZ + MAX_ALGO_SZ); + len = wc_EccKeyToDer(&this->ec, encoding->ptr, encoding->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_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, "RNG init failed"); + free(this); + return NULL; + } + return this; +} + +/* + * Described in 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(); + if (!this) + { + return NULL; + } + + 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"); + destroy(this); + return NULL; + } + return &this->public; +} + +/* + * Described in 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, key = chunk_empty; + word32 idx; + int oid = OID_UNKNOWN; + + 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) + { + return NULL; + } + this = create_empty(); + if (!this) + { + return NULL; + } + + 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, ensure we guessed correctly */ + if (asn1_unwrap(¶ms, ¶ms) == 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; + } + } + 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 index 000000000..971b6e98e --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_private_key.h @@ -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 +#include + +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 index 000000000..abcddab79 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.c @@ -0,0 +1,403 @@ +/* + * 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 + +#include +#include +#include + +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 + */ + wolfssl_ec_public_key_t public; + + /** + * Key size + */ + int keysize; + + /** + * EC key object + */ + ecc_key ec; + + /** + * Reference count + */ + 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, 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) +{ + chunk_t dgst; + int stat = 1, ret = -1; + + signature = chunk_skip_zero(signature); + if (wolfssl_hash_chunk(hash, data, &dgst)) + { + ret = wc_ecc_verify_hash(signature.ptr, signature.len, dgst.ptr, + dgst.len, &stat, &this->ec); + } + chunk_free(&dgst); + return ret == 0 && stat == 1; +} + +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 via wolfssl", + 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 an 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 len; + + if (lib->encoding->get_cache(lib->encoding, type, ec, fp)) + { + return TRUE; + } + + switch (type) + { + case KEYID_PUBKEY_SHA1: + case KEYID_PUBKEY_INFO_SHA1: + /* need an additional byte for the point type */ + len = ec->dp->size * 2 + 1; + if (type == KEYID_PUBKEY_INFO_SHA1) + { + /* additional space for algorithmIdentifier/bitString */ + len += 2 * MAX_SEQ_SZ + 2 * MAX_ALGO_SZ + TRAILING_ZERO; + } + key = chunk_alloca(len); + len = wc_EccPublicKeyToDer(ec, key.ptr, key.len, + type == KEYID_PUBKEY_INFO_SHA1); + break; + default: + return FALSE; + } + if (len < 0) + { + 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 not supported, fingerprinting failed"); + DESTROY_IF(hasher); + return FALSE; + } + hasher->destroy(hasher); + 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 len; + + /* space for algorithmIdentifier/bitString + one byte for the point type */ + *encoding = chunk_alloc(2 * this->ec.dp->size + 2 * MAX_SEQ_SZ + + 2 * MAX_ALGO_SZ + TRAILING_ZERO + 1); + len = wc_EccPublicKeyToDer(&this->ec, encoding->ptr, encoding->len, 1); + if (len < 0) + { + chunk_free(encoding); + return FALSE; + } + encoding->len = len; + + if (type != PUBKEY_SPKI_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; +} + +/* + * Described in 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; + + 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(); + if (!this) + { + return NULL; + } + + 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 index 000000000..ac82af334 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ec_public_key.h @@ -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 +#include + +/** + * 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 index 000000000..ed61b4b79 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ed_private_key.c @@ -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 + +#include +#include + +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; + + /** + * 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; + byte dummy[1]; + int ret; + + if (scheme != SIGN_ED25519) + { + DBG1(DBG_LIB, "signature scheme %N not supported by %N key", + signature_scheme_names, scheme, key_type_names, KEY_ED25519); + return FALSE; + } + + if (!data.ptr && !data.len) + { + 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 KEY_ED25519; +} + +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; + + key = chunk_alloca(len); + if (wc_ed25519_export_public(&this->key, key.ptr, &len) != 0) + { + return NULL; + } + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519, + 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; + + /* +4 is for the two octet strings */ + *encoding = chunk_alloc(ED25519_PRV_KEY_SIZE + 2 * MAX_SEQ_SZ + + MAX_VERSION_SZ + MAX_ALGO_SZ + 4); + 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() +{ + 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, + }, + .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; + + 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; + } + + this = create_internal(); + if (!this) + { + return NULL; + } + + if (wc_InitRng(&rng) != 0) + { + DBG1(DBG_LIB, "initializing random failed"); + destroy(this); + 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; +} + +/** + * Fix the internal state if only the private key is set + */ +static int set_public_key(private_private_key_t *this) +{ + int ret = 0; + + if (!this->key.pubKeySet) + { + ret = wc_ed25519_make_public(&this->key, this->key.p, + ED25519_PUB_KEY_SIZE); + if (ret == 0) + { + /* put public key after private key in the same buffer */ + memmove(this->key.k + ED25519_KEY_SIZE, this->key.p, + ED25519_PUB_KEY_SIZE); + this->key.pubKeySet = 1; + } + } + return ret; +} + +/* + * 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(); + if (!this) + { + 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); + } + else if (blob.len) + { + idx = 0; + ret = wc_Ed25519PrivateKeyDecode(blob.ptr, &idx, &this->key, blob.len); + } + if (ret == 0) + { + ret = set_public_key(this); + } + 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 index 000000000..2f44a49a4 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ed_private_key.h @@ -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 +#include + +/** + * 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 index 000000000..879dfa73f --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ed_public_key.c @@ -0,0 +1,299 @@ +/* + * 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 +#include + +#include +#include + +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; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(public_key_t, get_type, key_type_t, + private_public_key_t *this) +{ + return KEY_ED25519; +} + +METHOD(public_key_t, verify, bool, + private_public_key_t *this, signature_scheme_t scheme, + void *params, chunk_t data, chunk_t signature) +{ + byte dummy[1]; + int ret, res; + + if (scheme != SIGN_ED25519) + { + DBG1(DBG_LIB, "signature scheme %N not supported by %N key", + signature_scheme_names, scheme, key_type_names, KEY_ED25519); + return FALSE; + } + + if (!data.ptr && !data.len) + { + 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; +} + +/** + * Encode the given public key as ASN.1 DER with algorithm identifier + */ +static bool encode_pubkey(ed25519_key *key, chunk_t *encoding) +{ + int ret; + + /* account for algorithmIdentifier/bitString */ + *encoding = chunk_alloc(ED25519_PUB_KEY_SIZE + 2 * MAX_SEQ_SZ + + MAX_ALGO_SZ + TRAILING_ZERO); + ret = wc_Ed25519PublicKeyToDer(key, encoding->ptr, encoding->len, 1); + if (ret < 0) + { + return FALSE; + } + encoding->len = ret; + return TRUE; +} + +/** + * 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; + bool success = FALSE; + + 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_alloc(len); + if (wc_ed25519_export_public(key, blob.ptr, &len) != 0) + { + return FALSE; + } + break; + case KEYID_PUBKEY_INFO_SHA1: + if (!encode_pubkey(key, &blob)) + { + return FALSE; + } + 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"); + } + else + { + lib->encoding->cache(lib->encoding, type, key, *fp); + success = TRUE; + } + DESTROY_IF(hasher); + chunk_free(&blob); + return success; +} + +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; + + if (!encode_pubkey(&this->key, encoding)) + { + return FALSE; + } + + 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_free(&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() +{ + 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, + }, + .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(); + if (!this) + { + 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 index 000000000..b6239caa5 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_ed_public_key.h @@ -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 +#include + +/** + * 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 index 000000000..5e9d851c2 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_hasher.c @@ -0,0 +1,132 @@ +/* + * 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 + +typedef struct private_wolfssl_hasher_t private_wolfssl_hasher_t; + +/** + * Private data of wolfssl_hasher_t + */ +struct private_wolfssl_hasher_t { + + /** + * Public interface + */ + wolfssl_hasher_t public; + + /** + * The hasher to use + */ + wc_HashAlg hasher; + + /** + * The hash algorithm + */ + 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 index 000000000..a976f079f --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_hasher.h @@ -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 + +/** + * 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 index 000000000..a28beb444 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_hmac.c @@ -0,0 +1,164 @@ +/* + * 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 + +#include "wolfssl_hmac.h" +#include "wolfssl_util.h" + +#include +#include +#include + +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) + { + 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 index 000000000..23953da82 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_hmac.h @@ -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 +#include + +/** + * 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 index 000000000..925f08ee3 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_plugin.c @@ -0,0 +1,471 @@ +/* + * 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 +#include + +#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 interface + */ + 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); +} + +/* + * Described in header + */ +plugin_t *wolfssl_plugin_create() +{ + private_wolfssl_plugin_t *this; + bool fips_mode; + + fips_mode = lib->settings->get_bool(lib->settings, + "%s.plugins.wolfssl.fips_mode", FALSE, lib->ns); +#ifdef HAVE_FIPS + if (fips_mode) + { + int ret = wolfCrypt_GetStatus_fips(); + if (ret != 0) + { + DBG1(DBG_LIB, "wolfssl FIPS mode unavailable (%d)", ret); + return NULL; + } + } +#else + if (fips_mode) + { + DBG1(DBG_LIB, "wolfssl FIPS mode unavailable"); + 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 index 000000000..b29ce9eaa --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_plugin.h @@ -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 + +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 index 000000000..73b85840b --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_rng.c @@ -0,0 +1,184 @@ +/* + * 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 + +#ifndef WC_NO_RNG + +#include +#include + +#include + +#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 bool globalRngInit; + +/** + * 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 = TRUE; + } + } + return ret == 0; +} + +/* + * Described in header + */ +void wolfssl_rng_global_final() +{ + if (globalRngInit) + { +#ifndef SINGLE_THREADED + wc_FreeMutex(&globalRngMutex); +#endif + wc_FreeRng(&globalRng); + globalRngInit = FALSE; + } +} + +#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 index 000000000..abe9d9137 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_rng.h @@ -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 + +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 index 000000000..39d3e021b --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_private_key.c @@ -0,0 +1,757 @@ +/* + * 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 +#include +#include + +#include +#include + +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 + */ + 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_encode_public(RsaKey *rsa, chunk_t *encoding); +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, digestInfo; + int len; + + *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)) + { + digestInfo = chunk_alloc(MAX_DER_DIGEST_SZ); + len = wc_EncodeSignature(digestInfo.ptr, dgst.ptr, dgst.len, + wc_HashGetOID(hash)); + if (len > 0) + { + digestInfo.len = len; + success = build_signature(this, hash, digestInfo, sig); + } + chunk_free(&digestInfo); + 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, 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 via wolfssl", + 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; + + 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); + *plain = chunk_alloc(len); + len = wc_RsaPrivateDecrypt_ex(crypto.ptr, crypto.len, plain->ptr, len, + &this->rsa, padding, hash, mgf, NULL, 0); + if (len < 0) + { + DBG1(DBG_LIB, "RSA decryption failed"); + chunk_free(plain); + return FALSE; + } + plain->len = 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) +{ + public_key_t *key; + chunk_t enc; + + if (!wolfssl_rsa_encode_public(&this->rsa, &enc)) + { + return NULL; + } + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, + BUILD_BLOB_ASN1_DER, enc, BUILD_END); + chunk_free(&enc); + 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; + + /* n and d are of keysize length, p and q plus the three CRT + * params roughtly half that, the version and e are small */ + len = wc_RsaEncryptSize(&this->rsa) * 5 + MAX_SEQ_SZ; + *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"); + free(this); + return NULL; + } + if (wc_InitRsaKey(&this->rsa, NULL) != 0) + { + DBG1(DBG_LIB, "init RSA failed, rsa private key create failed"); + wc_FreeRng(&this->rng); + free(this); + return NULL; + } + this->rsa.rng = &this->rng; + + return this; +} + +/* + * Described in 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) + { + return NULL; + } + + if (wc_MakeRsaKey(&this->rsa, key_size, WC_RSA_EXPONENT, &this->rng) < 0) + { + destroy(this); + return NULL; + } + return &this->public; +} + +/** + * Allocate a random number in the range [0, n-1] + */ +static bool wolfssl_mp_rand(mp_int *n, WC_RNG *rng, mp_int *r) +{ + int len, 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(d, e, k) != 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(k, r) != 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(x, y) != 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 bool dmodpq1(mp_int *d, mp_int *pq, mp_int *res) +{ + /* p|q - 1 + * d (mod p|q -1) */ + return mp_sub_d(pq, 1, res) == 0 && + mp_mod(d, res, res) == 0; +} + +/** + * 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; +} + +/* + * Described in 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) + { + 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)) + { + 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 index 000000000..d1ba59e47 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_private_key.h @@ -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 +#include + +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 index 000000000..2824e9a17 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_public_key.c @@ -0,0 +1,526 @@ +/* + * 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 +#include +#include +#include + +#include +#include + +typedef struct private_wolfssl_rsa_public_key_t private_wolfssl_rsa_public_key_t; + +/** + * Private data + */ +struct private_wolfssl_rsa_public_key_t { + + /** + * Public interface + */ + 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); + chunk_t padded; + u_char *p; + + if (signature.len > len) + { + signature = chunk_skip(signature, signature.len - len); + } + + padded = chunk_copy_pad(chunk_alloca(len), signature, 0x00); + + len = wc_RsaSSL_VerifyInline(padded.ptr, len, &p, &this->rsa); + if (len > 0) + { + success = chunk_equals_const(data, chunk_create(p, len)); + } + 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) +{ + chunk_t dgst, digestInfo; + bool success = FALSE; + int len; + + if (wolfssl_hash_chunk(hash, data, &dgst)) + { + digestInfo = chunk_alloc(MAX_DER_DIGEST_SZ); + len = wc_EncodeSignature(digestInfo.ptr, dgst.ptr, dgst.len, + wc_HashGetOID(hash)); + if (len > 0) + { + digestInfo.len = len; + success = verify_signature(this, digestInfo, signature); + } + chunk_free(&digestInfo); + 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, padded; + enum wc_HashType hash; + u_char *p; + int mgf, len = 0; + bool success = FALSE; + + if (!wolfssl_hash2type(params->hash, &hash)) + { + return FALSE; + } + if (!wolfssl_hash2mgf1(params->mgf1_hash, &mgf)) + { + return FALSE; + } + if (!wolfssl_hash_chunk(hash, data, &dgst)) + { + return FALSE; + } + len = wc_RsaEncryptSize(&this->rsa); + if (signature.len > len) + { + signature = chunk_skip(signature, signature.len - len); + } + padded = chunk_copy_pad(chunk_alloca(len), signature, 0x00); + + len = wc_RsaPSS_VerifyInline_ex(padded.ptr, 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); + 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 via wolfssl", + 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; + + 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); + *crypto = chunk_alloc(len); + len = wc_RsaPublicEncrypt_ex(plain.ptr, plain.len, crypto->ptr, len, + &this->rsa, &this->rng, padding, hash, mgf, + NULL, 0); + if (len < 0) + { + DBG1(DBG_LIB, "RSA encryption failed"); + chunk_free(crypto); + return FALSE; + } + crypto->len = len; + return TRUE; +} + +METHOD(public_key_t, get_keysize, int, + private_wolfssl_rsa_public_key_t *this) +{ + return wc_RsaEncryptSize(&this->rsa) * 8; +} + +/** + * Encode the given public key as ASN.1 DER with algorithm identifier + */ +bool wolfssl_rsa_encode_public(RsaKey *rsa, chunk_t *encoding) +{ + int len; + + len = wc_RsaEncryptSize(rsa) * 2 + 4 * MAX_SEQ_SZ + MAX_ALGO_SZ; + *encoding = chunk_alloc(len); + len = wc_RsaKeyToPublicDer(rsa, encoding->ptr, len); + if (len < 0) + { + chunk_free(encoding); + return FALSE; + } + encoding->len = len; + return TRUE; +} + +/** + * 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; + bool success = FALSE; + + if (lib->encoding->get_cache(lib->encoding, type, rsa, fp)) + { + return TRUE; + } + switch (type) + { + case KEYID_PUBKEY_SHA1: + { + chunk_t n = chunk_empty, e = chunk_empty; + + if (wolfssl_mp2chunk(&rsa->n, &n) && + wolfssl_mp2chunk(&rsa->e, &e)) + { + key = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_integer("m", n), + asn1_integer("m", e)); + } + else + { + chunk_free(&n); + chunk_free(&e); + return FALSE; + } + break; + } + case KEYID_PUBKEY_INFO_SHA1: + if (!wolfssl_rsa_encode_public(rsa, &key)) + { + return FALSE; + } + break; + default: + return FALSE; + } + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher || !hasher->allocate_hash(hasher, key, fp)) + { + DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed"); + } + else + { + lib->encoding->cache(lib->encoding, type, rsa, *fp); + success = TRUE; + } + DESTROY_IF(hasher); + chunk_free(&key); + return success; +} + +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) +{ + chunk_t n = chunk_empty, e = chunk_empty; + bool success = FALSE; + + if (type == PUBKEY_SPKI_ASN1_DER) + { + return wolfssl_rsa_encode_public(&this->rsa, encoding); + } + + 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 failed, rsa public key load failed"); + free(this); + return NULL; + } + if (wc_InitRsaKey(&this->rsa, NULL) != 0) + { + DBG1(DBG_LIB, "init RSA failed, rsa public key load failed"); + wc_FreeRng(&this->rng); + free(this); + return NULL; + } + return this; +} + +/* + * Described in 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) + { + 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) + { + 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 index 000000000..54fbd3523 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_rsa_public_key.h @@ -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 + +/** + * 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 index 000000000..fa90288ed --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_sha1_prf.c @@ -0,0 +1,164 @@ +/* + * 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 +#include + +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); +} + +/* + * Described in header + */ +wolfssl_sha1_prf_t *wolfssl_sha1_prf_create(pseudo_random_function_t algo) +{ + private_wolfssl_sha1_prf_t *this; + + 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 index 000000000..89e12c482 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_sha1_prf.h @@ -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 + +/** + * 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 wolfssl_sha1_prf_t object + */ +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 index 000000000..c83c2982b --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_util.c @@ -0,0 +1,193 @@ +/* + * 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 + +#include +#include + +/* + * 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 index 000000000..35b09c405 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_util.h @@ -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 +#include + +/** + * 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 index 000000000..5c21eb66c --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.c @@ -0,0 +1,231 @@ +/* + * 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 + +#include +#include + +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; +}; + +/** + * Compute the shared secret + */ +static bool compute_shared_key(private_diffie_hellman_t *this, + curve25519_key *pub, chunk_t *shared_secret) +{ + word32 len = CURVE25519_KEYSIZE; + int ret; + + *shared_secret = chunk_alloc(len); + ret = wc_curve25519_shared_secret_ex(&this->key, pub, shared_secret->ptr, + &len, EC25519_LITTLE_ENDIAN); + return ret == 0; +} + +METHOD(diffie_hellman_t, set_other_public_value, bool, + private_diffie_hellman_t *this, chunk_t value) +{ + curve25519_key pub; + int ret; + + 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); + chunk_clear(&this->shared_secret); + wc_curve25519_free(&pub); + return FALSE; + } + 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) +{ + curve25519_key pub; + u_char basepoint[CURVE25519_KEYSIZE] = {9}; + word32 len = CURVE25519_KEYSIZE; + int ret; + + 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) + { + ret = wc_curve25519_shared_secret_ex(&this->key, &pub, + this->key.p.point, &len, EC25519_LITTLE_ENDIAN); + } + return ret == 0; +} + +METHOD(diffie_hellman_t, get_shared_secret, bool, + private_diffie_hellman_t *this, chunk_t *secret) +{ + if (!this->shared_secret.len) + { + 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; + + INIT(this, + .public = { + .get_shared_secret = _get_shared_secret, + .set_other_public_value = _set_other_public_value, + .get_my_public_value = _get_my_public_value, + .set_private_value = _set_private_value, + .get_dh_group = _get_dh_group, + .destroy = _destroy, + }, + .group = group, + ); + + if (wc_curve25519_init(&this->key) != 0) + { + DBG1(DBG_LIB, "initializing key failed"); + free(this); + return NULL; + } + + if (wc_InitRng(&rng) != 0) + { + DBG1(DBG_LIB, "initializing a random number generator failed"); + destroy(this); + return NULL; + } + ret = wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &this->key); + wc_FreeRng(&rng); + if (ret != 0) + { + DBG1(DBG_LIB, "making a key failed"); + destroy(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 index 000000000..a66ddc131 --- /dev/null +++ b/src/libstrongswan/plugins/wolfssl/wolfssl_x_diffie_hellman.h @@ -0,0 +1,43 @@ +/* + * 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 + +/** + * 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_ @}*/ diff --git a/src/libstrongswan/tests/suites/test_chunk.c b/src/libstrongswan/tests/suites/test_chunk.c index fbfb3ff9f..2f6b59f81 100644 --- a/src/libstrongswan/tests/suites/test_chunk.c +++ b/src/libstrongswan/tests/suites/test_chunk.c @@ -573,6 +573,40 @@ START_TEST(test_increment) } END_TEST +/******************************************************************************* + * chunk_copy_pad tests + */ + +static struct { + size_t len; + u_char chr; + chunk_t src; + chunk_t exp; +} copy_pad_data[] = { + {0, 0x00, { NULL, 0 }, { NULL, 0 }}, + {4, 0x00, { NULL, 0 }, chunk_from_chars(0x00,0x00,0x00,0x00)}, + {0, 0x00, chunk_from_chars(0x01), { NULL, 0 }}, + {1, 0x00, chunk_from_chars(0x01), chunk_from_chars(0x01)}, + {2, 0x00, chunk_from_chars(0x01), chunk_from_chars(0x00,0x01)}, + {3, 0x00, chunk_from_chars(0x01), chunk_from_chars(0x00,0x00,0x01)}, + {4, 0x00, chunk_from_chars(0x01), chunk_from_chars(0x00,0x00,0x00,0x01)}, + {4, 0x02, chunk_from_chars(0x01), chunk_from_chars(0x02,0x02,0x02,0x01)}, + {1, 0x00, chunk_from_chars(0x01,0x02,0x03,0x04), chunk_from_chars(0x04)}, + {2, 0x00, chunk_from_chars(0x01,0x02,0x03,0x04), chunk_from_chars(0x03,0x04)}, + {3, 0x00, chunk_from_chars(0x01,0x02,0x03,0x04), chunk_from_chars(0x02,0x03,0x04)}, + {4, 0x00, chunk_from_chars(0x01,0x02,0x03,0x04), chunk_from_chars(0x01,0x02,0x03,0x04)}, +}; + +START_TEST(test_copy_pad) +{ + chunk_t chunk; + + chunk = chunk_copy_pad(chunk_alloca(copy_pad_data[_i].len), + copy_pad_data[_i].src, copy_pad_data[_i].chr); + ck_assert_chunk_eq(chunk, copy_pad_data[_i].exp); +} +END_TEST + /******************************************************************************* * chunk_printable tests */ @@ -1076,6 +1110,10 @@ Suite *chunk_suite_create() tcase_add_loop_test(tc, test_increment, 0, countof(increment_data)); suite_add_tcase(s, tc); + tc = tcase_create("chunk_copy_pad"); + tcase_add_loop_test(tc, test_copy_pad, 0, countof(copy_pad_data)); + suite_add_tcase(s, tc); + tc = tcase_create("chunk_printable"); tcase_add_loop_test(tc, test_printable, 0, countof(printable_data)); tcase_add_loop_test(tc, test_printable_sanitize, 0, countof(printable_data)); diff --git a/src/libstrongswan/tests/suites/test_ecdsa.c b/src/libstrongswan/tests/suites/test_ecdsa.c index 6edae81ae..a5abbabbe 100644 --- a/src/libstrongswan/tests/suites/test_ecdsa.c +++ b/src/libstrongswan/tests/suites/test_ecdsa.c @@ -160,8 +160,14 @@ END_TEST /** * Private keys to load */ -static chunk_t keys[] = { - chunk_from_chars( /* ECDSA-256 */ +static struct { + chunk_t key; + chunk_t pkcs8; + chunk_t pub; + chunk_t fp_pk; + chunk_t fp_spki; +} keys[] = { + { chunk_from_chars( /* ECDSA-256 */ 0x30,0x77,0x02,0x01,0x01,0x04,0x20,0x42,0xc6,0x8c,0xff,0x2b,0x8b,0x87,0xa1,0xfb, 0x50,0xf6,0xfe,0xd6,0x88,0xb3,0x0a,0x48,0xb2,0xc5,0x8f,0x50,0xe0,0xcf,0x40,0xfa, 0x57,0xd1,0xc6,0x6c,0x20,0x64,0xc5,0xa0,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d, @@ -170,7 +176,31 @@ static chunk_t keys[] = { 0xe8,0x5e,0x3f,0x8e,0x64,0x33,0xb4,0x15,0xbb,0x1b,0xa5,0xed,0xf9,0x4b,0xa7,0xe8, 0x5e,0x6f,0x49,0x24,0xf7,0x32,0xf4,0x9b,0x4c,0x47,0xdc,0xf1,0x28,0x44,0x1c,0x37, 0xdb,0xee,0xfb,0xd8,0xbd,0x4e,0x5c,0xeb,0x07), - chunk_from_chars( /* ECDSA-384 */ + chunk_from_chars( + 0x30,0x81,0x87,0x02,0x01,0x00,0x30,0x13,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02, + 0x01,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x04,0x6d,0x30,0x6b,0x02, + 0x01,0x01,0x04,0x20,0x42,0xc6,0x8c,0xff,0x2b,0x8b,0x87,0xa1,0xfb,0x50,0xf6,0xfe, + 0xd6,0x88,0xb3,0x0a,0x48,0xb2,0xc5,0x8f,0x50,0xe0,0xcf,0x40,0xfa,0x57,0xd1,0xc6, + 0x6c,0x20,0x64,0xc5,0xa1,0x44,0x03,0x42,0x00,0x04,0x9c,0xb2,0x52,0xcb,0xc0,0x5c, + 0xcf,0x97,0xdd,0xd6,0xe7,0x49,0x32,0x47,0x0c,0x8e,0xdb,0x6d,0xbf,0xc8,0x1a,0x0a, + 0x01,0xe8,0x5e,0x3f,0x8e,0x64,0x33,0xb4,0x15,0xbb,0x1b,0xa5,0xed,0xf9,0x4b,0xa7, + 0xe8,0x5e,0x6f,0x49,0x24,0xf7,0x32,0xf4,0x9b,0x4c,0x47,0xdc,0xf1,0x28,0x44,0x1c, + 0x37,0xdb,0xee,0xfb,0xd8,0xbd,0x4e,0x5c,0xeb,0x07), + chunk_from_chars( + 0x30,0x59,0x30,0x13,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a, + 0x86,0x48,0xce,0x3d,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0x9c,0xb2,0x52,0xcb,0xc0, + 0x5c,0xcf,0x97,0xdd,0xd6,0xe7,0x49,0x32,0x47,0x0c,0x8e,0xdb,0x6d,0xbf,0xc8,0x1a, + 0x0a,0x01,0xe8,0x5e,0x3f,0x8e,0x64,0x33,0xb4,0x15,0xbb,0x1b,0xa5,0xed,0xf9,0x4b, + 0xa7,0xe8,0x5e,0x6f,0x49,0x24,0xf7,0x32,0xf4,0x9b,0x4c,0x47,0xdc,0xf1,0x28,0x44, + 0x1c,0x37,0xdb,0xee,0xfb,0xd8,0xbd,0x4e,0x5c,0xeb,0x07), + chunk_from_chars( + 0x07,0x64,0x50,0x1c,0x33,0x37,0x20,0x9b,0xe2,0x0e,0xe9,0x27,0xf0,0x29,0x5b,0x97, + 0x11,0x5f,0x7c,0xd1), + chunk_from_chars( + 0x1a,0x97,0x25,0x7a,0x48,0xae,0x8a,0x40,0x1a,0x4b,0xa0,0x0f,0x82,0x3c,0xa3,0x1f, + 0x61,0x91,0xd3,0x91), + }, + { chunk_from_chars( /* ECDSA-384 */ 0x30,0x81,0xa4,0x02,0x01,0x01,0x04,0x30,0x4b,0xbf,0x6c,0xf5,0x24,0x78,0x53,0x4b, 0x1a,0x91,0x23,0xae,0x30,0xc8,0xb3,0xc9,0xc2,0x9b,0x23,0x07,0x10,0x6f,0x1b,0x47, 0x7c,0xa0,0xd4,0x79,0x3c,0xc4,0x83,0x10,0xd1,0x44,0x07,0xc2,0x1b,0x66,0xff,0xae, @@ -182,7 +212,36 @@ static chunk_t keys[] = { 0xda,0xea,0xaf,0xfc,0x7a,0xaf,0x59,0x5f,0xbc,0x91,0x65,0xd3,0x21,0x19,0x61,0xbb, 0xfe,0x3c,0xdb,0x47,0xcb,0x7a,0xe7,0x5d,0xbd,0x28,0xde,0x25,0x64,0x9e,0x3a,0xa9, 0x18,0xed,0x24,0xe1,0x1f,0x73,0xcc), - chunk_from_chars( /* ECDSA-521 */ + chunk_from_chars( + 0x30,0x81,0xb6,0x02,0x01,0x00,0x30,0x10,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02, + 0x01,0x06,0x05,0x2b,0x81,0x04,0x00,0x22,0x04,0x81,0x9e,0x30,0x81,0x9b,0x02,0x01, + 0x01,0x04,0x30,0x4b,0xbf,0x6c,0xf5,0x24,0x78,0x53,0x4b,0x1a,0x91,0x23,0xae,0x30, + 0xc8,0xb3,0xc9,0xc2,0x9b,0x23,0x07,0x10,0x6f,0x1b,0x47,0x7c,0xa0,0xd4,0x79,0x3c, + 0xc4,0x83,0x10,0xd1,0x44,0x07,0xc2,0x1b,0x66,0xff,0xae,0x76,0x57,0x72,0x90,0x53, + 0xc2,0xf5,0x29,0xa1,0x64,0x03,0x62,0x00,0x04,0x1e,0xcf,0x1c,0x85,0x9d,0x06,0xa0, + 0x54,0xa2,0x24,0x2f,0xd8,0x63,0x56,0x7b,0x70,0x0b,0x7f,0x81,0x96,0xce,0xb9,0x2e, + 0x35,0x03,0x9c,0xf9,0x0a,0x5d,0x3b,0x10,0xf7,0x13,0x7a,0x0d,0xca,0x56,0xda,0x1d, + 0x44,0x84,0x07,0x6f,0x58,0xdc,0x34,0x7b,0x1d,0x4c,0xdd,0x28,0x10,0xc0,0xe2,0xae, + 0xf4,0xd6,0xda,0xea,0xaf,0xfc,0x7a,0xaf,0x59,0x5f,0xbc,0x91,0x65,0xd3,0x21,0x19, + 0x61,0xbb,0xfe,0x3c,0xdb,0x47,0xcb,0x7a,0xe7,0x5d,0xbd,0x28,0xde,0x25,0x64,0x9e, + 0x3a,0xa9,0x18,0xed,0x24,0xe1,0x1f,0x73,0xcc), + chunk_from_chars( + 0x30,0x76,0x30,0x10,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01,0x06,0x05,0x2b, + 0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x1e,0xcf,0x1c,0x85,0x9d,0x06,0xa0,0x54, + 0xa2,0x24,0x2f,0xd8,0x63,0x56,0x7b,0x70,0x0b,0x7f,0x81,0x96,0xce,0xb9,0x2e,0x35, + 0x03,0x9c,0xf9,0x0a,0x5d,0x3b,0x10,0xf7,0x13,0x7a,0x0d,0xca,0x56,0xda,0x1d,0x44, + 0x84,0x07,0x6f,0x58,0xdc,0x34,0x7b,0x1d,0x4c,0xdd,0x28,0x10,0xc0,0xe2,0xae,0xf4, + 0xd6,0xda,0xea,0xaf,0xfc,0x7a,0xaf,0x59,0x5f,0xbc,0x91,0x65,0xd3,0x21,0x19,0x61, + 0xbb,0xfe,0x3c,0xdb,0x47,0xcb,0x7a,0xe7,0x5d,0xbd,0x28,0xde,0x25,0x64,0x9e,0x3a, + 0xa9,0x18,0xed,0x24,0xe1,0x1f,0x73,0xcc), + chunk_from_chars( + 0x33,0xe5,0x8b,0x39,0xb7,0x88,0xa1,0xbe,0x86,0x2f,0x5f,0xdf,0x8c,0x48,0xe2,0x4a, + 0x51,0x4e,0xe8,0xea), + chunk_from_chars( + 0x57,0x5b,0xdb,0x2e,0xa4,0xa9,0xd5,0x53,0x26,0x91,0x76,0x21,0xce,0x68,0x90,0xb2, + 0xa7,0x09,0x74,0xb4), + }, + { chunk_from_chars( /* ECDSA-521 */ 0x30,0x81,0xdc,0x02,0x01,0x01,0x04,0x42,0x01,0xcf,0x38,0xaa,0xa7,0x7a,0x79,0x48, 0xa9,0x60,0x55,0x24,0xa8,0x7e,0xe1,0xbc,0x45,0x35,0x16,0xff,0x18,0xce,0x44,0xa2, 0x0b,0x72,0x6b,0xca,0x0a,0x40,0xb4,0x97,0x13,0x17,0x90,0x50,0x15,0xb9,0xba,0xfc, @@ -197,18 +256,78 @@ static chunk_t keys[] = { 0x69,0x3d,0x0f,0x2b,0xf3,0xb4,0x03,0x19,0x89,0xcf,0xfa,0x77,0x04,0x15,0xaf,0xdd, 0xf7,0x32,0x76,0x25,0x25,0x05,0x8d,0xfd,0x18,0x8a,0xda,0xd6,0xbc,0x71,0xb8,0x9f, 0x39,0xb0,0xaf,0xcc,0x54,0xb0,0x9c,0x4d,0x54,0xfb,0x46,0x53,0x5f,0xf8,0x45), + chunk_from_chars( + 0x30,0x81,0xee,0x02,0x01,0x00,0x30,0x10,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02, + 0x01,0x06,0x05,0x2b,0x81,0x04,0x00,0x23,0x04,0x81,0xd6,0x30,0x81,0xd3,0x02,0x01, + 0x01,0x04,0x42,0x01,0xcf,0x38,0xaa,0xa7,0x7a,0x79,0x48,0xa9,0x60,0x55,0x24,0xa8, + 0x7e,0xe1,0xbc,0x45,0x35,0x16,0xff,0x18,0xce,0x44,0xa2,0x0b,0x72,0x6b,0xca,0x0a, + 0x40,0xb4,0x97,0x13,0x17,0x90,0x50,0x15,0xb9,0xba,0xfc,0x08,0x0e,0xdb,0xf8,0xfc, + 0x06,0x35,0x37,0xbf,0xfb,0x25,0x74,0xfe,0x0f,0xe1,0x3c,0x3a,0xf0,0x0d,0xe0,0x52, + 0x15,0xa8,0x07,0x6f,0x3e,0xa1,0x81,0x89,0x03,0x81,0x86,0x00,0x04,0x00,0x56,0x81, + 0x28,0xd6,0xac,0xe9,0xc8,0x82,0x2c,0xac,0x61,0x6d,0xdd,0x88,0x79,0x00,0xe3,0x7a, + 0x4d,0x25,0xc4,0xea,0x05,0x80,0x75,0x48,0xbc,0x75,0x73,0xc4,0xe9,0x76,0x68,0xba, + 0x51,0xc3,0x29,0xce,0x7d,0x1b,0xb0,0x8b,0xac,0xc1,0xcc,0x23,0xa7,0x2d,0xa7,0x2c, + 0x95,0xf6,0x01,0x40,0x26,0x01,0x1c,0x1c,0x9c,0xe7,0xa7,0xb4,0x0f,0x8e,0xba,0x01, + 0x07,0xb3,0xf7,0xbe,0x45,0x20,0xa9,0x9e,0x70,0xf0,0xcf,0x9b,0xa0,0x91,0xe3,0x88, + 0x8f,0x04,0x69,0x3d,0x0f,0x2b,0xf3,0xb4,0x03,0x19,0x89,0xcf,0xfa,0x77,0x04,0x15, + 0xaf,0xdd,0xf7,0x32,0x76,0x25,0x25,0x05,0x8d,0xfd,0x18,0x8a,0xda,0xd6,0xbc,0x71, + 0xb8,0x9f,0x39,0xb0,0xaf,0xcc,0x54,0xb0,0x9c,0x4d,0x54,0xfb,0x46,0x53,0x5f,0xf8, + 0x45), + chunk_from_chars( + 0x30,0x81,0x9b,0x30,0x10,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01,0x06,0x05, + 0x2b,0x81,0x04,0x00,0x23,0x03,0x81,0x86,0x00,0x04,0x00,0x56,0x81,0x28,0xd6,0xac, + 0xe9,0xc8,0x82,0x2c,0xac,0x61,0x6d,0xdd,0x88,0x79,0x00,0xe3,0x7a,0x4d,0x25,0xc4, + 0xea,0x05,0x80,0x75,0x48,0xbc,0x75,0x73,0xc4,0xe9,0x76,0x68,0xba,0x51,0xc3,0x29, + 0xce,0x7d,0x1b,0xb0,0x8b,0xac,0xc1,0xcc,0x23,0xa7,0x2d,0xa7,0x2c,0x95,0xf6,0x01, + 0x40,0x26,0x01,0x1c,0x1c,0x9c,0xe7,0xa7,0xb4,0x0f,0x8e,0xba,0x01,0x07,0xb3,0xf7, + 0xbe,0x45,0x20,0xa9,0x9e,0x70,0xf0,0xcf,0x9b,0xa0,0x91,0xe3,0x88,0x8f,0x04,0x69, + 0x3d,0x0f,0x2b,0xf3,0xb4,0x03,0x19,0x89,0xcf,0xfa,0x77,0x04,0x15,0xaf,0xdd,0xf7, + 0x32,0x76,0x25,0x25,0x05,0x8d,0xfd,0x18,0x8a,0xda,0xd6,0xbc,0x71,0xb8,0x9f,0x39, + 0xb0,0xaf,0xcc,0x54,0xb0,0x9c,0x4d,0x54,0xfb,0x46,0x53,0x5f,0xf8,0x45), + chunk_from_chars( + 0x1d,0x3b,0x1b,0x05,0xd7,0xcb,0x87,0x17,0x49,0x2c,0x6a,0xed,0x3b,0x82,0xa8,0xc3, + 0xaa,0x76,0x72,0x91), + chunk_from_chars( + 0xd4,0x6d,0x34,0x22,0xd4,0xdd,0xca,0x63,0x26,0x95,0xb5,0x47,0x9b,0x8b,0x4a,0x30, + 0x67,0x27,0x3e,0xcd), + }, }; START_TEST(test_load) { private_key_t *privkey; public_key_t *pubkey; + chunk_t encoding, fp; privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA, - BUILD_BLOB_ASN1_DER, keys[_i], BUILD_END); + BUILD_BLOB_ASN1_DER, keys[_i].key, BUILD_END); ck_assert(privkey != NULL); + ck_assert(privkey->get_encoding(privkey, PRIVKEY_ASN1_DER, &encoding)); + if (encoding.len == keys[_i].pkcs8.len) + { + ck_assert_chunk_eq(keys[_i].pkcs8, encoding); + } + else + { + ck_assert_chunk_eq(keys[_i].key, encoding); + } + chunk_clear(&encoding); + + ck_assert(privkey->get_fingerprint(privkey, KEYID_PUBKEY_SHA1, &fp)); + ck_assert_chunk_eq(keys[_i].fp_pk, fp); + ck_assert(privkey->get_fingerprint(privkey, KEYID_PUBKEY_INFO_SHA1, &fp)); + ck_assert_chunk_eq(keys[_i].fp_spki, fp); + pubkey = privkey->get_public_key(privkey); ck_assert(pubkey != NULL); + ck_assert(pubkey->get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &encoding)); + ck_assert_chunk_eq(keys[_i].pub, encoding); + chunk_free(&encoding); + + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp)); + ck_assert_chunk_eq(keys[_i].fp_pk, fp); + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &fp)); + ck_assert_chunk_eq(keys[_i].fp_spki, fp); test_good_sig(privkey, pubkey); diff --git a/src/libstrongswan/tests/suites/test_ed25519.c b/src/libstrongswan/tests/suites/test_ed25519.c index c52b90885..057cc2af8 100644 --- a/src/libstrongswan/tests/suites/test_ed25519.c +++ b/src/libstrongswan/tests/suites/test_ed25519.c @@ -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)) { diff --git a/src/libstrongswan/tests/suites/test_rsa.c b/src/libstrongswan/tests/suites/test_rsa.c index a71fa0ce5..c90196f55 100644 --- a/src/libstrongswan/tests/suites/test_rsa.c +++ b/src/libstrongswan/tests/suites/test_rsa.c @@ -172,8 +172,14 @@ END_TEST /** * Private keys to load */ -static chunk_t keys[] = { - chunk_from_chars( /* RSA-768 */ +static struct { + chunk_t key; + chunk_t pkcs8; + chunk_t pub; + chunk_t fp_pk; + chunk_t fp_spki; +} keys[] = { + { chunk_from_chars( /* RSA-768 */ 0x30,0x82,0x01,0xcb,0x02,0x01,0x00,0x02,0x61,0x00,0xd1,0x5d,0x98,0x97,0x95,0x98, 0x19,0x87,0x20,0x3f,0x10,0xb0,0x05,0x36,0x1e,0x1b,0xcd,0xc8,0x93,0x66,0xd7,0x43, 0xed,0x84,0xb0,0x3e,0x96,0xd3,0xe7,0x27,0x0e,0xc0,0xba,0xdf,0x7e,0x32,0x05,0xd3, @@ -202,9 +208,56 @@ static chunk_t keys[] = { 0xfb,0x1e,0x82,0xe4,0x32,0x7a,0x4d,0x17,0x02,0x46,0x82,0x30,0x0b,0x02,0x30,0x09, 0xf3,0xce,0x9b,0x02,0xc5,0x53,0xe9,0xa2,0x89,0xe2,0x3b,0x8c,0x8b,0xe9,0xc2,0xba, 0x94,0x76,0x60,0x27,0x2b,0xe9,0x92,0xc1,0x5e,0x3c,0xc3,0x77,0x9b,0xc7,0xce,0xc6, - 0x67,0xd5,0x20,0x2c,0x54,0xa1,0x5d,0x2a,0x17,0x16,0x66,0xdf,0x5a,0xe9,0x87, - ), - chunk_from_chars( /* RSA-1024 */ + 0x67,0xd5,0x20,0x2c,0x54,0xa1,0x5d,0x2a,0x17,0x16,0x66,0xdf,0x5a,0xe9,0x87), + chunk_from_chars( + 0x30,0x82,0x01,0xe5,0x02,0x01,0x00,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, + 0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x01,0xcf,0x30,0x82,0x01,0xcb,0x02,0x01, + 0x00,0x02,0x61,0x00,0xd1,0x5d,0x98,0x97,0x95,0x98,0x19,0x87,0x20,0x3f,0x10,0xb0, + 0x05,0x36,0x1e,0x1b,0xcd,0xc8,0x93,0x66,0xd7,0x43,0xed,0x84,0xb0,0x3e,0x96,0xd3, + 0xe7,0x27,0x0e,0xc0,0xba,0xdf,0x7e,0x32,0x05,0xd3,0x08,0xd6,0x44,0xd5,0x01,0x2b, + 0x3e,0x5d,0xc0,0x37,0xae,0x4f,0xe0,0xea,0x8d,0x2c,0x42,0x4c,0xa9,0xa2,0x42,0xbe, + 0xdd,0xdb,0xf7,0xd3,0x28,0x07,0x10,0x88,0x53,0x15,0xb2,0x4f,0xb5,0x9d,0x47,0x9b, + 0xd6,0xc8,0xfe,0x5b,0xa2,0xd7,0xe1,0x13,0xca,0x0b,0xce,0x7a,0xed,0xa2,0x3e,0xd5, + 0x9b,0xb8,0x8b,0x4f,0x02,0x03,0x01,0x00,0x01,0x02,0x60,0x2d,0x83,0x82,0x53,0x99, + 0xb2,0xaa,0x02,0x05,0x11,0x90,0xa8,0x23,0x49,0xe3,0x7b,0xb9,0xdd,0x9b,0xa5,0xa4, + 0xb0,0x60,0xa7,0x12,0xc5,0x58,0x76,0x92,0x6e,0x9c,0x37,0x6b,0xa8,0x80,0x3f,0x91, + 0xa2,0x91,0xee,0x3a,0xa2,0x6f,0x91,0x9e,0x0a,0x35,0x69,0xc0,0xa7,0xdc,0xd8,0x46, + 0xe4,0x29,0x1c,0x3d,0x34,0x30,0xa2,0xb9,0x0d,0x34,0x94,0xa1,0x12,0xa7,0x85,0xd3, + 0x2c,0x47,0x1b,0xf0,0x78,0xd5,0x22,0xfc,0xa5,0xe0,0x75,0xac,0x71,0x21,0xe8,0xe8, + 0x19,0x9f,0xbb,0x98,0x5c,0xa6,0x9d,0x42,0xd7,0x9c,0x89,0x02,0x31,0x00,0xee,0xaa, + 0x9e,0x82,0xe1,0xb2,0xdd,0x05,0xbc,0x2e,0x53,0xe9,0x64,0x4b,0x48,0x06,0x3a,0xfd, + 0x9e,0x91,0xce,0x1b,0x7f,0x66,0xbc,0xd2,0xc4,0xab,0xbf,0xc5,0x5d,0x1a,0xbd,0xd6, + 0xb5,0x9c,0x5c,0x18,0x01,0xe6,0x79,0x19,0xf2,0xc3,0x1d,0x66,0x88,0x2d,0x02,0x31, + 0x00,0xe0,0x92,0x34,0x1e,0x09,0xf2,0x1b,0xf9,0xbf,0x11,0x65,0x3f,0xc8,0x85,0x5a, + 0xe6,0xc0,0xcf,0x93,0x44,0xb0,0x50,0xe4,0x8b,0x6f,0x30,0xde,0x42,0x0c,0x8a,0x77, + 0x0d,0x98,0x7f,0x52,0x59,0x9e,0x87,0xb8,0x6e,0xdc,0xed,0x15,0x80,0xbd,0xbb,0xf2, + 0xeb,0x02,0x31,0x00,0xb0,0x6b,0x36,0x98,0x90,0xb5,0x62,0x63,0xa6,0xe2,0xa7,0xec, + 0x51,0xd2,0xc3,0xfe,0xb7,0x04,0x5a,0x7e,0x74,0xd8,0x26,0xa8,0x8e,0xd3,0x4d,0xc5, + 0x97,0x10,0x10,0xee,0x7f,0x7d,0x82,0xe9,0x7d,0xb9,0xd1,0x4d,0xc8,0x1e,0xc2,0x30, + 0x30,0x3f,0x66,0x51,0x02,0x31,0x00,0xaa,0x75,0x2f,0x4c,0x11,0xbe,0x8d,0x0f,0x8f, + 0xc1,0x13,0x7a,0x4b,0xa9,0x35,0x6b,0x6b,0xb4,0xe3,0x92,0xc2,0xc6,0x54,0x03,0xa6, + 0x5d,0x90,0x86,0xcf,0xe0,0x16,0x27,0xe2,0xb5,0xd9,0xfb,0x1e,0x82,0xe4,0x32,0x7a, + 0x4d,0x17,0x02,0x46,0x82,0x30,0x0b,0x02,0x30,0x09,0xf3,0xce,0x9b,0x02,0xc5,0x53, + 0xe9,0xa2,0x89,0xe2,0x3b,0x8c,0x8b,0xe9,0xc2,0xba,0x94,0x76,0x60,0x27,0x2b,0xe9, + 0x92,0xc1,0x5e,0x3c,0xc3,0x77,0x9b,0xc7,0xce,0xc6,0x67,0xd5,0x20,0x2c,0x54,0xa1, + 0x5d,0x2a,0x17,0x16,0x66,0xdf,0x5a,0xe9,0x87), + chunk_from_chars( + 0x30,0x7c,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,0x05, + 0x00,0x03,0x6b,0x00,0x30,0x68,0x02,0x61,0x00,0xd1,0x5d,0x98,0x97,0x95,0x98,0x19, + 0x87,0x20,0x3f,0x10,0xb0,0x05,0x36,0x1e,0x1b,0xcd,0xc8,0x93,0x66,0xd7,0x43,0xed, + 0x84,0xb0,0x3e,0x96,0xd3,0xe7,0x27,0x0e,0xc0,0xba,0xdf,0x7e,0x32,0x05,0xd3,0x08, + 0xd6,0x44,0xd5,0x01,0x2b,0x3e,0x5d,0xc0,0x37,0xae,0x4f,0xe0,0xea,0x8d,0x2c,0x42, + 0x4c,0xa9,0xa2,0x42,0xbe,0xdd,0xdb,0xf7,0xd3,0x28,0x07,0x10,0x88,0x53,0x15,0xb2, + 0x4f,0xb5,0x9d,0x47,0x9b,0xd6,0xc8,0xfe,0x5b,0xa2,0xd7,0xe1,0x13,0xca,0x0b,0xce, + 0x7a,0xed,0xa2,0x3e,0xd5,0x9b,0xb8,0x8b,0x4f,0x02,0x03,0x01,0x00,0x01), + chunk_from_chars( + 0x06,0xad,0x82,0xc3,0x58,0x22,0xbb,0x79,0xb5,0xfc,0x48,0xdb,0xa0,0x3c,0x39,0x60, + 0x00,0x85,0x06,0xca), + chunk_from_chars( + 0x60,0xa2,0x6d,0x32,0x97,0xc5,0x91,0x44,0xa6,0xa6,0xfe,0xe2,0x15,0xb7,0xa5,0xdc, + 0x79,0x60,0xfd,0x3b), + }, + { chunk_from_chars( /* RSA-1024 */ 0x30,0x82,0x02,0x5c,0x02,0x01,0x00,0x02,0x81,0x81,0x00,0xc0,0xbd,0x48,0x83,0xbc, 0xea,0x0b,0x32,0x06,0x4b,0xf5,0x10,0x54,0x1b,0xba,0x88,0xc4,0x10,0x7e,0x47,0xec, 0x0e,0xf9,0xb4,0xcf,0x9a,0x02,0xc6,0xb3,0xaf,0x35,0xc8,0xaf,0x78,0x1a,0xbc,0x37, @@ -242,9 +295,68 @@ static chunk_t keys[] = { 0x42,0xee,0x12,0x91,0xf9,0x80,0x1e,0x60,0x0b,0xaa,0xbe,0xfd,0x09,0x84,0x93,0x0d, 0x09,0xd3,0x1e,0x37,0x52,0xb0,0xe8,0x51,0x4f,0xd3,0x9e,0xda,0x32,0x38,0x22,0x35, 0xdb,0x25,0x8b,0x9f,0x1a,0xb5,0xf1,0x75,0xfa,0x4d,0x09,0x42,0x01,0x64,0xe6,0xc4, - 0x6e,0xba,0x2d,0x88,0x92,0xbe,0xa9,0x1f,0x85,0x38,0x10,0xa3,0x0e,0x1a,0x92,0x54, - ), - chunk_from_chars( /* RSA-1536 */ + 0x6e,0xba,0x2d,0x88,0x92,0xbe,0xa9,0x1f,0x85,0x38,0x10,0xa3,0x0e,0x1a,0x92,0x54), + chunk_from_chars( + 0x30,0x82,0x02,0x76,0x02,0x01,0x00,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, + 0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x02,0x60,0x30,0x82,0x02,0x5c,0x02,0x01, + 0x00,0x02,0x81,0x81,0x00,0xc0,0xbd,0x48,0x83,0xbc,0xea,0x0b,0x32,0x06,0x4b,0xf5, + 0x10,0x54,0x1b,0xba,0x88,0xc4,0x10,0x7e,0x47,0xec,0x0e,0xf9,0xb4,0xcf,0x9a,0x02, + 0xc6,0xb3,0xaf,0x35,0xc8,0xaf,0x78,0x1a,0xbc,0x37,0x1a,0x25,0x7a,0x37,0x24,0x73, + 0x53,0x9a,0xf0,0x44,0x64,0x5b,0x6b,0x64,0x4c,0xfa,0x83,0x3a,0x0f,0x77,0x5d,0x7b, + 0x21,0xa2,0x25,0x00,0x11,0xae,0x72,0x36,0x35,0xd9,0x0d,0xef,0x5a,0xdd,0x98,0x35, + 0x49,0xaf,0x44,0xa0,0x33,0x29,0xc0,0xca,0xf5,0x6f,0xfe,0xc1,0x06,0x4c,0x80,0x9a, + 0x54,0xbe,0x46,0x1a,0x96,0xb1,0xf3,0x29,0xb8,0x9d,0x07,0x84,0x03,0x68,0x6b,0x9f, + 0xbf,0xe5,0xd8,0x14,0x2a,0xe0,0xef,0xbd,0x1a,0x61,0x0d,0x3a,0xc8,0x67,0xcd,0x99, + 0x90,0xe3,0xe6,0x52,0x83,0x02,0x03,0x01,0x00,0x01,0x02,0x81,0x80,0x13,0xd2,0xa3, + 0xe5,0xa0,0xb0,0x0a,0xe2,0x0f,0x3c,0x65,0x57,0xa8,0xe9,0x87,0xd5,0x79,0xcc,0xc9, + 0xca,0xc8,0x8a,0xd5,0xc0,0x74,0x90,0x3e,0x1e,0xda,0x40,0xcd,0x42,0xf7,0x01,0x09, + 0x9c,0x37,0xfd,0x41,0x6e,0x2b,0x6e,0x5d,0x4a,0x1e,0x52,0x53,0x1b,0xbb,0x3c,0x9f, + 0xfe,0x91,0x79,0x48,0xfc,0x69,0x90,0xbc,0xbc,0x3d,0xcf,0xee,0x62,0x0a,0xbd,0x57, + 0x6b,0xa9,0x51,0x3e,0xc2,0x7f,0x26,0xb1,0xaa,0x38,0xeb,0x40,0x91,0x3a,0x3c,0x80, + 0x1e,0x4e,0xe2,0xff,0xa2,0x8e,0x56,0xbb,0xb3,0xeb,0x24,0x81,0x4c,0x19,0x2c,0x8f, + 0x51,0x4c,0x04,0x81,0xaf,0x5e,0xc2,0xa6,0xf9,0xd3,0x48,0xee,0xe9,0x6d,0x9b,0xe1, + 0xe5,0x17,0x4f,0x07,0x18,0xea,0x96,0xd3,0x2c,0xce,0x44,0x71,0x51,0x02,0x41,0x00, + 0xe9,0xe9,0x46,0x7e,0xe1,0xc2,0x86,0x94,0x65,0x77,0x9c,0xc7,0x76,0x5d,0xa0,0xd3, + 0xcc,0x1f,0xa3,0xc7,0xfe,0xbb,0x4e,0x27,0xd6,0x43,0x6b,0xbd,0x0d,0x05,0x7a,0x10, + 0xe8,0x48,0x97,0x30,0xaa,0x53,0x61,0x57,0x1f,0x8a,0xf7,0x39,0x5e,0xa6,0xfe,0xe9, + 0x2c,0x19,0x5e,0x53,0xea,0xc2,0xb2,0xc2,0x11,0x3c,0x18,0xab,0xcf,0xc4,0x91,0x1b, + 0x02,0x41,0x00,0xd2,0xf0,0xb1,0x49,0xa1,0x6f,0xf1,0x83,0xa3,0xd2,0xa1,0x0e,0xb3, + 0xb3,0x33,0x01,0xed,0xd0,0x28,0xc1,0x2f,0x88,0x80,0x9f,0x43,0x7c,0x7e,0x5d,0x4c, + 0x15,0x05,0x86,0xff,0x75,0x9b,0xf1,0x64,0xde,0x06,0xbf,0xdd,0x98,0x50,0xd9,0x4a, + 0x3a,0xd6,0x25,0x1c,0xdd,0xc8,0x56,0x12,0x11,0xb9,0x02,0x42,0xc7,0x1d,0x86,0xeb, + 0xd9,0xc2,0xb9,0x02,0x41,0x00,0x80,0x25,0x8c,0xb9,0x76,0x75,0x5b,0xc5,0x70,0xd1, + 0x56,0xd2,0xef,0xc5,0xdb,0x96,0x2c,0xfe,0x28,0x7c,0x28,0xd1,0xf4,0xbf,0x5e,0x63, + 0x11,0x63,0x40,0xfe,0xff,0x20,0xc4,0x21,0x00,0xb3,0x68,0x9c,0xc5,0x77,0x35,0x90, + 0xac,0x60,0x81,0xba,0x7b,0x6c,0xc2,0xfc,0x22,0xf1,0x56,0x6b,0xd4,0x02,0xfd,0xee, + 0x2e,0x95,0xf1,0xfd,0x7e,0x81,0x02,0x40,0x47,0xaf,0x84,0x90,0x81,0x4c,0x89,0xc7, + 0x32,0xe5,0x61,0xd6,0x9d,0x3b,0x49,0x1a,0x5e,0xb7,0x5f,0x22,0x48,0x05,0x1b,0xb1, + 0x04,0x3e,0x4a,0xb3,0x6a,0x27,0xba,0xb9,0x26,0x17,0xd1,0xe7,0x37,0x60,0x3c,0xea, + 0xf7,0x63,0xcc,0x16,0x0c,0x23,0xf2,0xa2,0xaa,0x2c,0xb4,0xe8,0x8b,0x3b,0x7a,0xa4, + 0x4a,0x0d,0x60,0xfb,0x79,0x2b,0x88,0x01,0x02,0x40,0x42,0xee,0x12,0x91,0xf9,0x80, + 0x1e,0x60,0x0b,0xaa,0xbe,0xfd,0x09,0x84,0x93,0x0d,0x09,0xd3,0x1e,0x37,0x52,0xb0, + 0xe8,0x51,0x4f,0xd3,0x9e,0xda,0x32,0x38,0x22,0x35,0xdb,0x25,0x8b,0x9f,0x1a,0xb5, + 0xf1,0x75,0xfa,0x4d,0x09,0x42,0x01,0x64,0xe6,0xc4,0x6e,0xba,0x2d,0x88,0x92,0xbe, + 0xa9,0x1f,0x85,0x38,0x10,0xa3,0x0e,0x1a,0x92,0x54), + chunk_from_chars( + 0x30,0x81,0x9f,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, + 0x05,0x00,0x03,0x81,0x8d,0x00,0x30,0x81,0x89,0x02,0x81,0x81,0x00,0xc0,0xbd,0x48, + 0x83,0xbc,0xea,0x0b,0x32,0x06,0x4b,0xf5,0x10,0x54,0x1b,0xba,0x88,0xc4,0x10,0x7e, + 0x47,0xec,0x0e,0xf9,0xb4,0xcf,0x9a,0x02,0xc6,0xb3,0xaf,0x35,0xc8,0xaf,0x78,0x1a, + 0xbc,0x37,0x1a,0x25,0x7a,0x37,0x24,0x73,0x53,0x9a,0xf0,0x44,0x64,0x5b,0x6b,0x64, + 0x4c,0xfa,0x83,0x3a,0x0f,0x77,0x5d,0x7b,0x21,0xa2,0x25,0x00,0x11,0xae,0x72,0x36, + 0x35,0xd9,0x0d,0xef,0x5a,0xdd,0x98,0x35,0x49,0xaf,0x44,0xa0,0x33,0x29,0xc0,0xca, + 0xf5,0x6f,0xfe,0xc1,0x06,0x4c,0x80,0x9a,0x54,0xbe,0x46,0x1a,0x96,0xb1,0xf3,0x29, + 0xb8,0x9d,0x07,0x84,0x03,0x68,0x6b,0x9f,0xbf,0xe5,0xd8,0x14,0x2a,0xe0,0xef,0xbd, + 0x1a,0x61,0x0d,0x3a,0xc8,0x67,0xcd,0x99,0x90,0xe3,0xe6,0x52,0x83,0x02,0x03,0x01, + 0x00,0x01), + chunk_from_chars( + 0xda,0xab,0x50,0x22,0x4b,0x4f,0x3b,0xd0,0x82,0xc4,0xa4,0x14,0x06,0x64,0x0b,0x6f, + 0xad,0xbc,0x69,0xc0), + chunk_from_chars( + 0x92,0xf4,0x02,0x8a,0x3c,0x8f,0x05,0xad,0x3a,0x55,0x1f,0xcf,0x13,0xd8,0xff,0xf2, + 0x65,0x35,0x75,0xa0), + }, + { chunk_from_chars( /* RSA-1536 */ 0x30,0x82,0x03,0x7d,0x02,0x01,0x00,0x02,0x81,0xc1,0x00,0xba,0xe3,0x37,0x93,0x7e, 0x42,0x13,0x3c,0xba,0x41,0xc1,0x7b,0xf0,0xcc,0x7a,0x44,0xc6,0x54,0xc8,0x77,0x01, 0x70,0x2f,0x6e,0x4a,0xcf,0x2d,0x07,0xab,0x01,0xc0,0x43,0xab,0x8d,0x33,0xb3,0xd4, @@ -301,9 +413,90 @@ static chunk_t keys[] = { 0xf0,0x9b,0xba,0xf0,0x90,0xaf,0xa1,0xe8,0xa8,0x70,0xef,0x60,0x6a,0x68,0xed,0x5a, 0x21,0x77,0x69,0x7a,0xf2,0xee,0x3e,0xe5,0x90,0xd2,0x33,0x71,0x3b,0x82,0x88,0x75, 0xdd,0x8e,0x6e,0xbc,0x17,0x83,0xef,0x37,0x82,0x4e,0x83,0x30,0xcb,0x8a,0xbc,0x6c, - 0x41, - ), - chunk_from_chars( /* RSA-2048 */ + 0x41), + chunk_from_chars( + 0x30,0x82,0x03,0x97,0x02,0x01,0x00,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, + 0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x03,0x81,0x30,0x82,0x03,0x7d,0x02,0x01, + 0x00,0x02,0x81,0xc1,0x00,0xba,0xe3,0x37,0x93,0x7e,0x42,0x13,0x3c,0xba,0x41,0xc1, + 0x7b,0xf0,0xcc,0x7a,0x44,0xc6,0x54,0xc8,0x77,0x01,0x70,0x2f,0x6e,0x4a,0xcf,0x2d, + 0x07,0xab,0x01,0xc0,0x43,0xab,0x8d,0x33,0xb3,0xd4,0xeb,0xe3,0x90,0xf6,0x01,0x03, + 0x75,0x03,0x1d,0xe8,0x06,0x40,0x15,0xfa,0x96,0x0b,0xd5,0x26,0x64,0xea,0x55,0x82, + 0x16,0x7b,0xd5,0x1e,0xaa,0x08,0xc7,0x30,0x1a,0x59,0xf8,0xd9,0xe3,0x9e,0x89,0xd9, + 0x92,0x2c,0x32,0x79,0x0e,0xb3,0x25,0xbc,0x1d,0x7c,0x59,0xde,0x05,0x47,0x8f,0x61, + 0x77,0xf5,0x4f,0xed,0x82,0x2c,0xf8,0x2a,0x3e,0x02,0xf3,0xc0,0x15,0x51,0xde,0x05, + 0xc4,0xfc,0x80,0x91,0xae,0x06,0x1b,0xd7,0x39,0x8e,0x9a,0x6d,0xb3,0x2f,0xb0,0xd0, + 0xc8,0x96,0xa6,0x88,0xb3,0x17,0xca,0x58,0xbe,0x38,0x2c,0x64,0x35,0x5a,0x29,0xb7, + 0xf8,0x74,0x3d,0xbb,0xec,0x90,0x01,0x04,0x64,0x3d,0x38,0x0f,0x87,0xce,0xd7,0xfc, + 0xd2,0x96,0x93,0x31,0x85,0x0d,0x2d,0xa5,0x91,0xe2,0xfc,0x7b,0xea,0xb0,0x89,0x24, + 0xaa,0x00,0x29,0x8c,0x26,0x7c,0x94,0x54,0x74,0xe4,0x11,0xa8,0x04,0x6f,0x40,0xeb, + 0xaf,0xed,0xac,0x75,0x33,0x02,0x03,0x01,0x00,0x01,0x02,0x81,0xc0,0x0a,0x96,0xec, + 0x63,0xc1,0xa0,0x39,0xd9,0xd3,0x8d,0xfd,0x4a,0x2a,0x13,0x54,0x0c,0x48,0x96,0xae, + 0x43,0x3c,0x04,0x20,0xd3,0xe5,0x8e,0x46,0xb5,0x6c,0x05,0xad,0xe0,0xc7,0xbc,0x39, + 0x05,0x44,0x17,0xd7,0xad,0xb3,0x9a,0xcc,0x18,0xd9,0xc3,0xdc,0x8d,0x5a,0x1d,0x44, + 0xb5,0x32,0xd7,0x71,0x94,0xff,0x48,0x38,0x16,0x51,0x0e,0xfa,0xed,0x54,0x91,0x00, + 0xd3,0x45,0x6c,0xd9,0xdf,0xd1,0x70,0x6b,0x31,0x22,0xaa,0xfb,0x7c,0x0f,0x3f,0xa0, + 0xa0,0xa5,0x16,0xac,0x83,0x6d,0x12,0x1d,0x4a,0x40,0x4e,0xb6,0x9c,0xf4,0x67,0xaa, + 0xa9,0xb0,0xc8,0xb4,0x0a,0xd5,0x3b,0x5c,0x19,0xed,0x86,0x83,0x5a,0x75,0xbc,0xeb, + 0x17,0xc8,0x16,0xa0,0x60,0x2e,0xb6,0x25,0xc5,0x4d,0x59,0xba,0x62,0xcb,0x3d,0x91, + 0x7c,0x79,0x6a,0x4b,0x4a,0x54,0xbd,0xb7,0xa3,0x89,0x7f,0xbf,0x0e,0x77,0xe1,0x54, + 0x29,0x0d,0x45,0x6d,0xa8,0x15,0xa5,0x17,0x8c,0xcf,0x27,0x9e,0x47,0x4e,0x2a,0x91, + 0x7e,0x4e,0x14,0x59,0x8c,0x62,0x91,0xa3,0x40,0xa5,0x9e,0x67,0xbb,0x02,0x97,0xb4, + 0xe7,0x06,0x04,0xbc,0x16,0x24,0x3d,0x49,0xb1,0xf0,0xae,0xfc,0x1d,0x02,0x61,0x00, + 0xde,0x86,0x5d,0x49,0x88,0xeb,0x5c,0xd3,0xe5,0x11,0x48,0x0b,0x1e,0x52,0x95,0xa9, + 0x65,0x99,0x89,0xcf,0x51,0xb0,0x08,0xdd,0xb5,0x5b,0x64,0x1a,0x34,0xd2,0xee,0x4b, + 0x2d,0x8b,0xc1,0xd5,0xd6,0x1d,0x6c,0x0c,0x7e,0xa5,0x66,0x12,0xec,0xaf,0x5d,0xe9, + 0x33,0xd4,0xba,0x18,0x71,0x84,0x97,0xbe,0xc0,0x75,0x63,0x19,0xae,0xc6,0xc7,0x65, + 0xf3,0xf6,0xda,0x3f,0x91,0xfa,0x5e,0x87,0xf3,0xbc,0xd2,0x64,0x8d,0xcf,0xfb,0xdd, + 0x7f,0x9b,0x6c,0x81,0xba,0x9b,0x4e,0x94,0x5e,0x83,0xd1,0xcb,0xb9,0xf4,0x39,0x7f, + 0x02,0x61,0x00,0xd7,0x00,0x6d,0x8e,0x1b,0xa1,0x44,0xd9,0xff,0xe6,0x42,0x72,0x18, + 0x55,0x26,0x3e,0x87,0x40,0x71,0xb2,0x67,0x37,0x16,0xe9,0xbd,0x51,0x7f,0x0e,0x79, + 0x0e,0x75,0xa9,0x1f,0x0f,0x6b,0xa5,0x7c,0x5f,0xc8,0xdc,0x17,0xde,0x53,0x88,0x97, + 0x90,0x88,0xf2,0x4d,0x66,0x5e,0x0e,0x11,0x16,0x92,0x1e,0x61,0x56,0xe6,0xf0,0x74, + 0x81,0x58,0x95,0x05,0x29,0x71,0x9b,0xa0,0x69,0xed,0x14,0x23,0xf6,0x36,0x9b,0x8f, + 0x06,0x3a,0x76,0xab,0xeb,0xce,0xe8,0xdc,0x79,0xc1,0x29,0xb9,0xfc,0x49,0x7a,0x26, + 0x59,0xd6,0x4d,0x02,0x61,0x00,0xaf,0x3c,0xac,0xd6,0x2d,0xe6,0xfb,0x91,0x3a,0xc1, + 0x23,0x34,0xee,0x4a,0x26,0xe5,0xe1,0xc6,0xc9,0xc9,0xe4,0x10,0x76,0xca,0xf1,0xf8, + 0xe8,0x99,0xe2,0xa3,0x81,0x58,0xde,0xa3,0x42,0xa0,0x3d,0x1f,0xaa,0x69,0x24,0x8a, + 0xe8,0x19,0x5b,0x1e,0xb7,0x1b,0xe0,0xdf,0x53,0x35,0xd0,0x9f,0x94,0x48,0x79,0x93, + 0x77,0xd9,0x4f,0xd3,0xe6,0x4f,0x19,0x92,0x7a,0x48,0xb9,0x92,0xab,0x42,0xf0,0xe4, + 0xef,0xe2,0x93,0xf3,0x07,0xeb,0x64,0x84,0x67,0x2c,0xba,0x61,0x77,0xbe,0x4b,0xb8, + 0x0f,0x4d,0x1a,0x41,0x83,0xcd,0x02,0x60,0x56,0xec,0x55,0x5e,0x9e,0xcd,0x14,0x89, + 0x0e,0x6c,0x89,0x70,0x97,0x65,0xd5,0x90,0x72,0x1e,0x1b,0xd9,0x84,0xe1,0x40,0xe2, + 0x3f,0x28,0x33,0xb6,0x26,0x3b,0x32,0x56,0xad,0xb8,0x0e,0x4d,0x59,0x7b,0x60,0x39, + 0x9b,0x6c,0xc7,0x58,0xf1,0xed,0xfd,0x6f,0xf8,0xda,0xea,0x2b,0xc5,0xbc,0xda,0x56, + 0x6e,0x04,0x34,0x5a,0x02,0xc0,0x48,0x8f,0xf7,0x06,0x4a,0x68,0x20,0xf2,0xb2,0x66, + 0xf2,0x23,0x18,0xf0,0xcb,0x62,0x39,0x40,0xc1,0x41,0x14,0xe6,0x10,0x3d,0x29,0x5b, + 0x35,0x56,0x4a,0x5e,0x98,0x22,0xba,0x01,0x02,0x61,0x00,0xcc,0x80,0xb7,0xb9,0xb9, + 0x4a,0xaf,0x47,0x00,0x3e,0x21,0x0f,0xb8,0x4e,0x7c,0xb1,0xe4,0x25,0xd6,0x19,0x26, + 0x54,0xc6,0x8c,0x30,0x88,0x54,0x70,0xcf,0x1f,0x62,0x75,0xcb,0x18,0x58,0x6c,0x14, + 0xb0,0x9b,0x13,0x90,0xa2,0x1a,0x5a,0x79,0xa3,0x82,0xf0,0x9b,0xba,0xf0,0x90,0xaf, + 0xa1,0xe8,0xa8,0x70,0xef,0x60,0x6a,0x68,0xed,0x5a,0x21,0x77,0x69,0x7a,0xf2,0xee, + 0x3e,0xe5,0x90,0xd2,0x33,0x71,0x3b,0x82,0x88,0x75,0xdd,0x8e,0x6e,0xbc,0x17,0x83, + 0xef,0x37,0x82,0x4e,0x83,0x30,0xcb,0x8a,0xbc,0x6c,0x41), + chunk_from_chars( + 0x30,0x81,0xdf,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, + 0x05,0x00,0x03,0x81,0xcd,0x00,0x30,0x81,0xc9,0x02,0x81,0xc1,0x00,0xba,0xe3,0x37, + 0x93,0x7e,0x42,0x13,0x3c,0xba,0x41,0xc1,0x7b,0xf0,0xcc,0x7a,0x44,0xc6,0x54,0xc8, + 0x77,0x01,0x70,0x2f,0x6e,0x4a,0xcf,0x2d,0x07,0xab,0x01,0xc0,0x43,0xab,0x8d,0x33, + 0xb3,0xd4,0xeb,0xe3,0x90,0xf6,0x01,0x03,0x75,0x03,0x1d,0xe8,0x06,0x40,0x15,0xfa, + 0x96,0x0b,0xd5,0x26,0x64,0xea,0x55,0x82,0x16,0x7b,0xd5,0x1e,0xaa,0x08,0xc7,0x30, + 0x1a,0x59,0xf8,0xd9,0xe3,0x9e,0x89,0xd9,0x92,0x2c,0x32,0x79,0x0e,0xb3,0x25,0xbc, + 0x1d,0x7c,0x59,0xde,0x05,0x47,0x8f,0x61,0x77,0xf5,0x4f,0xed,0x82,0x2c,0xf8,0x2a, + 0x3e,0x02,0xf3,0xc0,0x15,0x51,0xde,0x05,0xc4,0xfc,0x80,0x91,0xae,0x06,0x1b,0xd7, + 0x39,0x8e,0x9a,0x6d,0xb3,0x2f,0xb0,0xd0,0xc8,0x96,0xa6,0x88,0xb3,0x17,0xca,0x58, + 0xbe,0x38,0x2c,0x64,0x35,0x5a,0x29,0xb7,0xf8,0x74,0x3d,0xbb,0xec,0x90,0x01,0x04, + 0x64,0x3d,0x38,0x0f,0x87,0xce,0xd7,0xfc,0xd2,0x96,0x93,0x31,0x85,0x0d,0x2d,0xa5, + 0x91,0xe2,0xfc,0x7b,0xea,0xb0,0x89,0x24,0xaa,0x00,0x29,0x8c,0x26,0x7c,0x94,0x54, + 0x74,0xe4,0x11,0xa8,0x04,0x6f,0x40,0xeb,0xaf,0xed,0xac,0x75,0x33,0x02,0x03,0x01, + 0x00,0x01), + chunk_from_chars( + 0x21,0x00,0x8c,0xe1,0x78,0x25,0x67,0x19,0xb7,0xd0,0xcb,0x13,0x01,0x7a,0xa3,0x71, + 0x67,0x46,0x96,0xf1), + chunk_from_chars( + 0x58,0x4d,0x4c,0x27,0x98,0x15,0x76,0xab,0x29,0xc9,0xf3,0xd1,0xa0,0xc4,0x50,0x0d, + 0x42,0x30,0x43,0x19), + }, + { chunk_from_chars( /* RSA-2048 */ 0x30,0x82,0x04,0xa2,0x02,0x01,0x00,0x02,0x82,0x01,0x01,0x00,0xba,0xbf,0x27,0x0b, 0x22,0x59,0xd8,0x6f,0xff,0x26,0x5d,0x41,0x3d,0xb0,0x94,0x58,0x5d,0xc0,0x46,0xb6, 0x77,0xa9,0x78,0x10,0x6d,0xe9,0xbf,0xca,0x6f,0x04,0xe1,0xda,0x85,0x12,0x1e,0xe0, @@ -378,20 +571,148 @@ static chunk_t keys[] = { 0x78,0x30,0x5f,0xdf,0x46,0xa6,0xb0,0x28,0x37,0x2b,0x55,0x08,0x4c,0xb6,0x6b,0xb8, 0xa9,0x11,0x7d,0x0b,0xab,0x97,0x4d,0x8c,0xc3,0xbf,0x3b,0xcd,0x3e,0xad,0x80,0xce, 0xe8,0xc6,0x01,0x35,0xd2,0x3e,0x31,0xdc,0x96,0xd7,0xc3,0xab,0x65,0xd1,0xc4,0xa3, - 0x47,0x14,0xa9,0xba,0xd0,0x30, - ), + 0x47,0x14,0xa9,0xba,0xd0,0x30), + chunk_from_chars( + 0x30,0x82,0x04,0xbc,0x02,0x01,0x00,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, + 0x0d,0x01,0x01,0x01,0x05,0x00,0x04,0x82,0x04,0xa6,0x30,0x82,0x04,0xa2,0x02,0x01, + 0x00,0x02,0x82,0x01,0x01,0x00,0xba,0xbf,0x27,0x0b,0x22,0x59,0xd8,0x6f,0xff,0x26, + 0x5d,0x41,0x3d,0xb0,0x94,0x58,0x5d,0xc0,0x46,0xb6,0x77,0xa9,0x78,0x10,0x6d,0xe9, + 0xbf,0xca,0x6f,0x04,0xe1,0xda,0x85,0x12,0x1e,0xe0,0xa6,0xc7,0xa2,0x71,0x04,0x8b, + 0x6e,0x84,0xf9,0x86,0x2b,0xeb,0x72,0x01,0x72,0xc8,0x0a,0x83,0xa6,0xf7,0xc0,0xd6, + 0x76,0x1d,0x28,0x38,0xb5,0x7e,0x6c,0x8c,0x6a,0x13,0xf4,0xf1,0x7f,0xf2,0x79,0xae, + 0x73,0xba,0x1a,0x3f,0x30,0x65,0xb6,0x23,0xa7,0x94,0x34,0x29,0x87,0xce,0x06,0x99, + 0xee,0x85,0x10,0xce,0x08,0xe2,0x8d,0xd5,0x47,0xf3,0xc8,0xf0,0x18,0x41,0xc0,0x59, + 0x66,0x06,0xda,0xb6,0x18,0xd2,0xa3,0xa0,0xbd,0x3a,0x90,0x7f,0x37,0x39,0xdf,0x98, + 0x55,0xa2,0x19,0x5e,0x37,0xbc,0x86,0xf3,0x02,0xf8,0x68,0x49,0x53,0xf2,0x4b,0x3d, + 0x7a,0xe3,0x1d,0xa4,0x15,0x10,0xa6,0xce,0x8c,0xb8,0xfd,0x95,0x54,0xa2,0x50,0xa2, + 0xd9,0x35,0x12,0x56,0xae,0xbc,0x51,0x33,0x6d,0xb8,0x63,0x7c,0x26,0xab,0x19,0x01, + 0xa5,0xda,0xfa,0x4b,0xb6,0x57,0xd3,0x4b,0xdd,0xc0,0x62,0xc5,0x05,0xb7,0xc3,0x2e, + 0x1f,0x17,0xc8,0x09,0x87,0x12,0x37,0x21,0xd7,0x7a,0x53,0xb0,0x47,0x60,0xa2,0xb5, + 0x23,0x3b,0x99,0xdf,0xea,0x8b,0x94,0xea,0x9d,0x53,0x5d,0x02,0x52,0xf7,0x29,0xfb, + 0x63,0xb0,0xff,0x27,0x5e,0xde,0x54,0x7d,0x95,0xd6,0x4e,0x58,0x12,0x06,0x60,0x22, + 0x33,0xf2,0x19,0x67,0x65,0xdd,0xf3,0x42,0xb5,0x00,0x51,0x35,0xe5,0x62,0x4d,0x90, + 0x44,0xfb,0x7f,0x5b,0xb5,0xe5,0x02,0x03,0x01,0x00,0x01,0x02,0x82,0x01,0x00,0x1c, + 0xf5,0x66,0xf5,0xce,0x4c,0x1d,0xe8,0xd2,0x29,0x6e,0x15,0x1f,0x9e,0x9a,0x06,0x70, + 0xf5,0x4f,0xd1,0xdc,0x51,0x02,0x8e,0x13,0xa9,0x47,0x85,0x39,0xfd,0x89,0x13,0x74, + 0x86,0xb8,0x94,0x90,0x30,0x4d,0x73,0x96,0xa7,0x93,0x8a,0x19,0xd2,0x91,0x4d,0x77, + 0xb6,0x9b,0x48,0xc3,0x7e,0xa2,0x5d,0xf1,0x80,0xa0,0x3c,0xc9,0xbf,0xaf,0x7f,0x4d, + 0x10,0x62,0x23,0xb9,0x9c,0x58,0x81,0xae,0x96,0x5b,0x9a,0x4c,0x97,0x27,0x67,0x62, + 0x5c,0xf9,0x8f,0xdd,0x1d,0xe2,0x92,0x13,0x8a,0x7b,0xc7,0x15,0x31,0xca,0x05,0x6d, + 0xc6,0x98,0xdb,0x88,0x39,0x99,0x1d,0x5b,0x19,0x51,0xdd,0xb6,0xbd,0x3d,0xb0,0xae, + 0x50,0x8e,0xff,0x7d,0xa8,0x48,0x95,0x58,0x23,0xbc,0x85,0xc0,0x46,0xd0,0xc0,0x0e, + 0xda,0xdd,0xa4,0x8e,0x8d,0x31,0x8b,0x89,0x0f,0x8b,0x76,0x9a,0xb5,0x99,0x56,0x5e, + 0xd3,0x0c,0x88,0x0b,0x03,0xf1,0xc9,0xe3,0x05,0x05,0x08,0x75,0xce,0x35,0x52,0xa0, + 0xc0,0xf2,0xf4,0xb9,0x87,0x22,0x21,0x3f,0x61,0xd6,0x99,0xae,0x0e,0x76,0x5d,0x9c, + 0x16,0xa3,0xe9,0xde,0x2d,0x2a,0x46,0xf7,0x89,0xbf,0x0d,0xb1,0x60,0xad,0xbc,0x24, + 0xe2,0xe5,0xb1,0xc1,0x1c,0x00,0x40,0x1c,0xbd,0xfa,0x6e,0xc7,0x0d,0xc1,0xda,0x4d, + 0x54,0x45,0x96,0xac,0xf7,0xfe,0x1b,0xf2,0x47,0x1e,0xf7,0x8b,0xcf,0x27,0xcc,0xe7, + 0x08,0xd6,0x43,0x60,0xea,0xda,0x19,0xd7,0x98,0x17,0x7c,0xab,0x0c,0x90,0x60,0x75, + 0x9f,0x8b,0xaa,0x13,0x63,0x98,0x9e,0xc6,0x41,0x9f,0xd4,0x85,0xa3,0xb2,0xb9,0x02, + 0x81,0x81,0x00,0xe1,0x20,0xf6,0xac,0xa9,0x01,0xbd,0x31,0xe6,0xb2,0x4e,0xcf,0x66, + 0xc3,0x11,0x0e,0x5b,0xfe,0x58,0x6b,0xc6,0x2d,0x7a,0x05,0x30,0x9a,0x6f,0xcc,0xcc, + 0xdf,0xd2,0x2c,0xe1,0x47,0x39,0x9e,0xf3,0x0c,0x81,0xd9,0x76,0x00,0xe2,0xb1,0x08, + 0x91,0xfb,0x12,0x04,0xf6,0x1f,0xea,0xff,0x82,0xe5,0x64,0x64,0x6f,0x14,0xbe,0x33, + 0x5f,0x41,0x5f,0x73,0x1f,0xa2,0x32,0xec,0x75,0xb3,0x98,0x4b,0x88,0x4d,0x1e,0xec, + 0x78,0xda,0x4c,0x2d,0xf8,0xbb,0xcf,0x0e,0x8f,0x2f,0x23,0xae,0xcd,0xe0,0x4c,0x13, + 0x1c,0x1c,0x16,0x8e,0xb9,0x9f,0x02,0x12,0x12,0xa5,0xf4,0x21,0xfe,0x57,0x08,0x7a, + 0xe8,0xbe,0x15,0xe9,0xdd,0x2a,0xd1,0x7b,0x39,0xd6,0x4f,0x70,0x74,0x7d,0xfd,0x39, + 0x97,0x80,0x8d,0x02,0x81,0x81,0x00,0xd4,0x5a,0xce,0x05,0x93,0x51,0x15,0x44,0xdd, + 0x4d,0x79,0x92,0x04,0xe6,0x64,0x7e,0x6c,0xb5,0x61,0x6b,0xc3,0xb3,0xae,0x4f,0x0a, + 0x75,0xbf,0x6c,0xec,0x47,0xf2,0xbc,0xea,0x76,0xc4,0xc2,0xe7,0xd2,0x50,0xc4,0xe0, + 0xaf,0x56,0x05,0x72,0x3c,0x34,0x8c,0x5b,0xae,0xb8,0x0e,0xfb,0x83,0x27,0xcf,0x61, + 0x05,0x44,0x97,0x3f,0x66,0x6d,0x26,0x7d,0xed,0xcd,0x5a,0x87,0x04,0xbc,0xb3,0x70, + 0x75,0x15,0x51,0xe9,0x18,0x85,0xf7,0x2a,0x45,0xd5,0xc7,0x93,0x32,0x07,0x2e,0x26, + 0x34,0x2d,0x18,0x63,0x45,0x06,0x6f,0xa9,0x75,0x5d,0x20,0x6b,0x0b,0x13,0x45,0x81, + 0x7e,0x5c,0xc5,0x48,0x16,0x4b,0x82,0x7c,0xad,0xbe,0xfd,0xa5,0x0a,0xd6,0xc2,0x21, + 0xfc,0xa5,0x84,0xaf,0xf3,0x10,0xb9,0x02,0x81,0x80,0x29,0x20,0x20,0x6f,0xc2,0x1f, + 0xf3,0x33,0xde,0x74,0xcc,0x38,0xcf,0x08,0xeb,0x60,0xb8,0x25,0x6a,0x79,0xa5,0xa6, + 0x41,0x18,0x19,0x9c,0xdc,0xb7,0x88,0xe5,0x8a,0x3b,0x70,0x9b,0xd6,0x46,0xd7,0x17, + 0x7d,0xd0,0xff,0xe1,0x81,0x87,0xdd,0x8c,0xed,0x54,0x89,0x5b,0x7c,0xd1,0x2d,0x03, + 0xf8,0x6b,0xb2,0x7d,0x28,0x48,0xe6,0x91,0x8c,0x1b,0xa7,0xa8,0x2b,0xb5,0x29,0xc5, + 0x06,0x9d,0xd7,0x8e,0x7a,0xa8,0x1f,0x82,0xa4,0x3e,0x2e,0x57,0xb5,0xd7,0x49,0x4d, + 0x96,0xca,0xe9,0xef,0xe9,0xfd,0x7b,0xb0,0x32,0xe1,0x5c,0x09,0x44,0xa6,0xd8,0x2e, + 0x57,0xea,0x95,0x1b,0x25,0x43,0x03,0x50,0xe9,0x08,0x8f,0xc4,0x3b,0x42,0x31,0x44, + 0x8b,0x85,0xcf,0x81,0x38,0x52,0xbd,0xe6,0x93,0x31,0x02,0x81,0x80,0x18,0x3d,0x79, + 0x51,0x07,0x9c,0xf4,0xd9,0x94,0x8d,0x78,0x78,0x23,0x99,0x0d,0x15,0xa5,0x61,0x1b, + 0x0a,0xcb,0x1f,0x22,0xa1,0xa1,0x27,0x09,0xbf,0xec,0x44,0xd6,0x3f,0x9c,0x60,0x0c, + 0x5b,0xd7,0x4c,0x99,0xad,0xaf,0x9c,0x34,0x2c,0x90,0xfa,0xb0,0x60,0xe9,0x42,0x4b, + 0x7e,0x62,0x55,0x79,0x60,0xe1,0xc9,0x51,0x28,0x16,0xb3,0xa1,0x78,0x08,0x5d,0xf1, + 0xd8,0x08,0x9b,0x90,0xd2,0xc6,0xde,0x86,0x9d,0x80,0x07,0x2d,0x9b,0xa6,0x36,0xac, + 0x8d,0x88,0x8e,0xe8,0x64,0xeb,0x35,0x7f,0x84,0x4e,0x28,0x9d,0xf0,0x77,0x1e,0x8f, + 0x8f,0xd8,0xc8,0x3d,0xdd,0xec,0x47,0x39,0x5d,0xc7,0xb9,0xcb,0xca,0xcc,0x62,0xa4, + 0xef,0x9d,0x3c,0x5c,0x81,0x72,0x91,0xbd,0x6f,0x25,0x0a,0x90,0xf9,0x02,0x81,0x80, + 0x51,0x42,0x23,0x64,0x3d,0xbc,0xcb,0xcb,0x77,0xd4,0x5c,0x6b,0xf4,0x16,0x3a,0x6b, + 0x05,0x5f,0xd4,0xf8,0x59,0xe6,0x98,0x0c,0x43,0x7e,0x6b,0x17,0x0d,0x01,0x23,0x6e, + 0x4c,0xff,0x35,0xe4,0xc5,0xba,0xe8,0x9e,0x12,0x94,0x34,0x78,0xe4,0x3d,0x35,0xa1, + 0xd4,0xa9,0xa3,0x7e,0xe4,0x57,0xef,0xa4,0x9a,0x6a,0x32,0xb3,0x9f,0xf8,0x3a,0xcf, + 0xea,0xf4,0xc7,0x59,0x92,0xd4,0x2a,0x5b,0x26,0x83,0x78,0x30,0x5f,0xdf,0x46,0xa6, + 0xb0,0x28,0x37,0x2b,0x55,0x08,0x4c,0xb6,0x6b,0xb8,0xa9,0x11,0x7d,0x0b,0xab,0x97, + 0x4d,0x8c,0xc3,0xbf,0x3b,0xcd,0x3e,0xad,0x80,0xce,0xe8,0xc6,0x01,0x35,0xd2,0x3e, + 0x31,0xdc,0x96,0xd7,0xc3,0xab,0x65,0xd1,0xc4,0xa3,0x47,0x14,0xa9,0xba,0xd0,0x30), + chunk_from_chars( + 0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01, + 0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01,0x0a,0x02,0x82,0x01,0x01, + 0x00,0xba,0xbf,0x27,0x0b,0x22,0x59,0xd8,0x6f,0xff,0x26,0x5d,0x41,0x3d,0xb0,0x94, + 0x58,0x5d,0xc0,0x46,0xb6,0x77,0xa9,0x78,0x10,0x6d,0xe9,0xbf,0xca,0x6f,0x04,0xe1, + 0xda,0x85,0x12,0x1e,0xe0,0xa6,0xc7,0xa2,0x71,0x04,0x8b,0x6e,0x84,0xf9,0x86,0x2b, + 0xeb,0x72,0x01,0x72,0xc8,0x0a,0x83,0xa6,0xf7,0xc0,0xd6,0x76,0x1d,0x28,0x38,0xb5, + 0x7e,0x6c,0x8c,0x6a,0x13,0xf4,0xf1,0x7f,0xf2,0x79,0xae,0x73,0xba,0x1a,0x3f,0x30, + 0x65,0xb6,0x23,0xa7,0x94,0x34,0x29,0x87,0xce,0x06,0x99,0xee,0x85,0x10,0xce,0x08, + 0xe2,0x8d,0xd5,0x47,0xf3,0xc8,0xf0,0x18,0x41,0xc0,0x59,0x66,0x06,0xda,0xb6,0x18, + 0xd2,0xa3,0xa0,0xbd,0x3a,0x90,0x7f,0x37,0x39,0xdf,0x98,0x55,0xa2,0x19,0x5e,0x37, + 0xbc,0x86,0xf3,0x02,0xf8,0x68,0x49,0x53,0xf2,0x4b,0x3d,0x7a,0xe3,0x1d,0xa4,0x15, + 0x10,0xa6,0xce,0x8c,0xb8,0xfd,0x95,0x54,0xa2,0x50,0xa2,0xd9,0x35,0x12,0x56,0xae, + 0xbc,0x51,0x33,0x6d,0xb8,0x63,0x7c,0x26,0xab,0x19,0x01,0xa5,0xda,0xfa,0x4b,0xb6, + 0x57,0xd3,0x4b,0xdd,0xc0,0x62,0xc5,0x05,0xb7,0xc3,0x2e,0x1f,0x17,0xc8,0x09,0x87, + 0x12,0x37,0x21,0xd7,0x7a,0x53,0xb0,0x47,0x60,0xa2,0xb5,0x23,0x3b,0x99,0xdf,0xea, + 0x8b,0x94,0xea,0x9d,0x53,0x5d,0x02,0x52,0xf7,0x29,0xfb,0x63,0xb0,0xff,0x27,0x5e, + 0xde,0x54,0x7d,0x95,0xd6,0x4e,0x58,0x12,0x06,0x60,0x22,0x33,0xf2,0x19,0x67,0x65, + 0xdd,0xf3,0x42,0xb5,0x00,0x51,0x35,0xe5,0x62,0x4d,0x90,0x44,0xfb,0x7f,0x5b,0xb5, + 0xe5,0x02,0x03,0x01,0x00,0x01), + chunk_from_chars( + 0x4f,0xe8,0x82,0xee,0xaa,0x2c,0x7b,0x3f,0x3a,0xf1,0xb4,0xe1,0xe3,0x85,0xd4,0xb1, + 0xb4,0x34,0x5c,0x2d), + chunk_from_chars( + 0x29,0xe3,0x4b,0x6c,0x41,0x08,0xf2,0x6d,0xe5,0x1a,0x99,0x02,0xdf,0x9c,0x02,0xe3, + 0x67,0xdf,0xfd,0xb3), + }, }; START_TEST(test_load) { private_key_t *privkey; public_key_t *pubkey; + chunk_t encoding, fp; privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_BLOB_ASN1_DER, keys[_i], BUILD_END); + BUILD_BLOB_ASN1_DER, keys[_i].key, BUILD_END); ck_assert(privkey != NULL); + ck_assert(privkey->get_encoding(privkey, PRIVKEY_ASN1_DER, &encoding)); + if (encoding.len == keys[_i].pkcs8.len) + { + ck_assert_chunk_eq(keys[_i].pkcs8, encoding); + } + else + { + ck_assert_chunk_eq(keys[_i].key, encoding); + } + chunk_clear(&encoding); + + ck_assert(privkey->get_fingerprint(privkey, KEYID_PUBKEY_SHA1, &fp)); + ck_assert_chunk_eq(keys[_i].fp_pk, fp); + ck_assert(privkey->get_fingerprint(privkey, KEYID_PUBKEY_INFO_SHA1, &fp)); + ck_assert_chunk_eq(keys[_i].fp_spki, fp); + pubkey = privkey->get_public_key(privkey); ck_assert(pubkey != NULL); + ck_assert(pubkey->get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &encoding)); + ck_assert_chunk_eq(keys[_i].pub, encoding); + chunk_free(&encoding); + + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp)); + ck_assert_chunk_eq(keys[_i].fp_pk, fp); + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &fp)); + ck_assert_chunk_eq(keys[_i].fp_spki, fp); test_good_sig(privkey, pubkey); diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c index 239353879..919b69578 100644 --- a/src/libstrongswan/utils/chunk.c +++ b/src/libstrongswan/utils/chunk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 Tobias Brunner + * Copyright (C) 2008-2019 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * HSR Hochschule fuer Technik Rapperswil @@ -752,6 +752,26 @@ bool chunk_increment(chunk_t chunk) return TRUE; } +/* + * Described in header + */ +chunk_t chunk_copy_pad(chunk_t dst, chunk_t src, u_char chr) +{ + if (dst.ptr) + { + if (dst.len > src.len) + { + memcpy(dst.ptr + dst.len - src.len, src.ptr, src.len); + memset(dst.ptr, chr, dst.len - src.len); + } + else + { + memcpy(dst.ptr, src.ptr + src.len - dst.len, dst.len); + } + } + return dst; +} + /** * Remove non-printable characters from a chunk. */ diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index 0dbe9dc80..ea1274668 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 Tobias Brunner + * Copyright (C) 2008-2019 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * HSR Hochschule fuer Technik Rapperswil @@ -292,6 +292,16 @@ static inline chunk_t chunk_skip_zero(chunk_t chunk) return chunk; } +/** + * Copy the data from src to dst, left-padded with chr if dst is longer, + * otherwise data is copied truncated on the left. + * + * @param dst data is copied here + * @param src data is copied from here + * @param chr value to use for padding if necessary + * @return the destination chunk + */ +chunk_t chunk_copy_pad(chunk_t dst, chunk_t src, u_char chr); /** * Compare two chunks, returns zero if a equals b diff --git a/src/pt-tls-client/Makefile.am b/src/pt-tls-client/Makefile.am index a17b5ddf0..18a76fd37 100644 --- a/src/pt-tls-client/Makefile.am +++ b/src/pt-tls-client/Makefile.am @@ -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 \ diff --git a/src/sw-collector/Makefile.am b/src/sw-collector/Makefile.am index 4ed73c925..b68f650ae 100644 --- a/src/sw-collector/Makefile.am +++ b/src/sw-collector/Makefile.am @@ -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)