summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2020-03-18 23:21:19 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2020-07-08 22:51:31 -0400
commitcb753ec5b51bda3f5630409e18205f874ecce7c7 (patch)
treee959902183887aa49a4ac53590ce93d3e9e5a337
parent7de51cc77bc0d7ed7f93e65ee9cbd91c5f963c1b (diff)
downloadlighttpd-git-cb753ec5b51bda3f5630409e18205f874ecce7c7.tar.gz
[mod_mbedtls] mbedTLS option for TLS
(experimental) mod_mbedtls supports most ssl.* config options supported by mod_openssl thx Ward Willats for the initial discussion and attempt in the comments https://redmine.lighttpd.net/boards/3/topics/7029
-rw-r--r--SConstruct12
-rw-r--r--configure.ac45
-rw-r--r--meson_options.txt5
-rw-r--r--src/CMakeLists.txt29
-rw-r--r--src/Makefile.am8
-rw-r--r--src/SConscript3
-rw-r--r--src/algo_sha1.h23
-rw-r--r--src/configfile.c4
-rw-r--r--src/meson.build18
-rw-r--r--src/mod_auth.c16
-rw-r--r--src/mod_authn_file.c32
-rw-r--r--src/mod_mbedtls.c3478
-rw-r--r--src/mod_secdownload.c34
-rw-r--r--src/network.c10
-rw-r--r--src/rand.c67
-rw-r--r--src/server.c15
-rw-r--r--src/sys-crypto.h6
17 files changed, 3792 insertions, 13 deletions
diff --git a/SConstruct b/SConstruct
index bcac49fe..7e593528 100644
--- a/SConstruct
+++ b/SConstruct
@@ -252,6 +252,7 @@ vars.AddVariables(
BoolVariable('with_memcached', 'enable memcached support', 'no'),
PackageVariable('with_mysql', 'enable mysql support', 'no'),
BoolVariable('with_openssl', 'enable openssl support', 'no'),
+ PackageVariable('with_mbedtls', 'enable mbedTLS support', 'no'),
PackageVariable('with_wolfssl', 'enable wolfSSL support', 'no'),
BoolVariable('with_nettle', 'enable Nettle support', 'no'),
BoolVariable('with_pam', 'enable PAM auth support', 'no'),
@@ -341,6 +342,7 @@ if 1:
LIBSQLITE3 = '',
LIBSSL = '',
LIBUUID = '',
+ LIBX509 = '',
LIBXML2 = '',
LIBZ = '',
)
@@ -609,6 +611,16 @@ if 1:
LIBCRYPTO = 'wolfssl',
)
+ if env['with_mbedtls']:
+ if not autoconf.CheckLibWithHeader('mbedtls', 'mbedtls/ssl.h', 'C'):
+ fail("Couldn't find mbedtls")
+ autoconf.env.Append(
+ CPPFLAGS = [ '-DHAVE_LIBMBEDCRYPTO' ],
+ LIBSSL = 'mbedtls',
+ LIBX509 = 'mbedx509',
+ LIBCRYPTO = 'mbedcrypto',
+ )
+
if env['with_nettle']:
if not autoconf.CheckLibWithHeader('nettle', 'nettle/nettle-types.h', 'C'):
fail("Couldn't find Nettle")
diff --git a/configure.ac b/configure.ac
index 83d273b8..4b309e91 100644
--- a/configure.ac
+++ b/configure.ac
@@ -686,7 +686,7 @@ if test "$WITH_OPENSSL" != no; then
[ -lcrypto "$DL_LIB" ]
)
- AC_DEFINE([HAVE_LIBSSL], [], [Have libssl])
+ AC_DEFINE([HAVE_LIBSSL], [1], [Have libssl])
AC_SUBST([SSL_LIB])
AC_SUBST([CRYPTO_LIB])
fi
@@ -737,6 +737,46 @@ if test "$WITH_OPENSSL" != no && test "$WITH_WOLFSSL" != no; then
AC_MSG_ERROR([lighttpd should not be built with both --with-openssl and --with-wolfssl])
fi
+dnl Check for mbedTLS
+AC_MSG_NOTICE([----------------------------------------])
+AC_MSG_CHECKING([for mbedTLS])
+AC_ARG_WITH([mbedtls],
+ AC_HELP_STRING([--with-mbedtls@<:@=DIR@:>@],[Include mbedTLS support. DIR points to the installation root. (default no)]),
+ [WITH_MBEDTLS=$withval],
+ [WITH_MBEDTLS=no]
+)
+
+if test "$WITH_MBEDTLS" != "no"; then
+ use_mbedtls=yes
+ if test "$WITH_MBEDTLS" != "yes"; then
+ CPPFLAGS="$CPPFLAGS -I$WITH_MBEDTLS/include"
+ LDFLAGS="$LDFLAGS -L$WITH_MBEDTLS/lib"
+ fi
+else
+ use_mbedtls=no
+fi
+AC_MSG_RESULT([$use_mbedtls])
+AM_CONDITIONAL(BUILD_WITH_MBEDTLS, test ! $WITH_MBEDTLS = no)
+
+if test "x$use_mbedtls" = "xyes"; then
+ AC_CHECK_HEADERS([mbedtls/ssl.h])
+ OLDLIBS="$LIBS"
+ AC_CHECK_LIB(mbedcrypto,mbedtls_base64_encode,
+ [AC_CHECK_LIB(mbedx509, mbedtls_x509_get_name,
+ [AC_CHECK_LIB(mbedtls, mbedtls_cipher_info_from_type,
+ [MTLS_LIB="-lmbedtls -lmbedx509 -lmbedcrypto"
+ CRYPTO_LIB="-lmbedcrypto"
+ AC_DEFINE(HAVE_LIBMBEDTLS, [1], [Have libmbedtls library])
+ AC_DEFINE(HAVE_LIBMBEDX509, [1], [Have libmbedx509 library])
+ AC_DEFINE(HAVE_LIBMBEDCRYPTO, [1], [Have libmbedcrypto library]) ],
+ [],[-lmbedcrypto "$DL_LIB"])
+ ],[],[-lmbedcrypto "$DL_LIB"])
+ ],[],[])
+ LIBS="$OLDLIBS"
+ AC_SUBST(MTLS_LIB)
+ AC_SUBST(CRYPTO_LIB)
+fi
+
dnl Check for Nettle (and overwrite CRYPTO_LIB if set by OpenSSL or wolfSSL)
AC_MSG_NOTICE([----------------------------------------])
AC_MSG_CHECKING([for Nettle])
@@ -1560,6 +1600,9 @@ lighty_track_feature "pam" "mod_authn_pam" \
lighty_track_feature "network-openssl" "mod_openssl" \
'test "$WITH_OPENSSL" != no || test "$WITH_WOLFSSL" != no'
+lighty_track_feature "network-mbedtls" "mod_mbedtls" \
+ 'test "$WITH_MBEDTLS" != no'
+
lighty_track_feature "auth-crypt" "" \
'test "$found_crypt" != no'
diff --git a/meson_options.txt b/meson_options.txt
index 92d3f4a9..17918e8b 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -53,6 +53,11 @@ option('with_maxminddb',
value: false,
description: 'with MaxMind GeoIP2-support mod_maxminddb [default: off]',
)
+option('with_mbedtls',
+ type: 'string',
+ value: 'false',
+ description: 'with mbedTLS-support [default: off]',
+)
option('with_memcached',
type: 'boolean',
value: false,
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fbfb5d93..18008b84 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -20,6 +20,7 @@ option(WITH_XATTR "with xattr-support for the stat-cache [default: off]")
option(WITH_MYSQL "with mysql-support for mod_vhostdb_mysql [default: off]")
option(WITH_PGSQL "with postgres-support for mod_vhostdb_pgsql [default: off]")
option(WITH_DBI "with dbi-support for mod_vhostdb_dbi [default: off]")
+option(WITH_MBEDTLS "with mbedTLS-support [default: off]")
option(WITH_OPENSSL "with openssl-support [default: off]")
option(WITH_WOLFSSL "with wolfSSL-support [default: off]")
option(WITH_NETTLE "with Nettle-support [default: off]")
@@ -371,6 +372,24 @@ if(WITH_OPENSSL AND WITH_WOLFSSL)
message(FATAL_ERROR "lighttpd should not be built with both --with-openssl and --with-wolfssl")
endif()
+if(WITH_MBEDTLS)
+ check_include_files(mbedtls/ssl.h HAVE_MBEDTLS_SSL_H)
+ if(HAVE_MBEDTLS_SSL_H)
+ check_library_exists(mbedcrypto mbedtls_base64_encode "" HAVE_LIBMBEDCRYPTO)
+ if(HAVE_LIBMEDTLSCRYPTO)
+ check_library_exists(mbedtls mbedtls_cipher_info_from_type "" HAVE_LIBMBEDTLS)
+ if(HAVE_LIBMBEDTLS)
+ check_library_exists(mbedx509 mbedtls_x509_get_name "" HAVE_LIBMBEDX509)
+ endif()
+ endif()
+ endif()
+else()
+ unset(HAVE_MBEDTLS_SSL_H)
+ unset(HAVE_LIBMBEDCRYPTO)
+ unset(HAVE_LIBMBEDTLS)
+ unset(HAVE_LIBMEDX509)
+endif()
+
if(WITH_NETTLE)
if(APPLE)
set(CMAKE_REQUIRED_INCLUDES /opt/local/include)
@@ -1070,6 +1089,16 @@ if(NOT ${CRYPTO_LIBRARY} EQUAL "")
target_link_libraries(mod_wstunnel ${CRYPTO_LIBRARY})
endif()
+if(HAVE_LIBMBEDTLS AND HAVE_LIBMEDCRYPTO AND HAVE_LIBMEDX509)
+ target_link_libraries(lighttpd mbedtls)
+ target_link_libraries(lighttpd mbedcrypto)
+ target_link_libraries(lighttpd mbedx509)
+ add_and_install_library(mod_mbedtls "mod_mbedtls.c")
+ set(L_MOD_MBEDTLS ${L_MOD_MBEDTLS} mbedtls mbedcrypto mbedx509)
+ target_link_libraries(mod_mbedtls ${L_MOD_MBEDTLS})
+ # not doing "cross module" linkage yet (e.g. mod_authn, secdownload)
+endif()
+
if(WITH_LIBEV)
target_link_libraries(lighttpd ${LIBEV_LDFLAGS})
add_target_properties(lighttpd COMPILE_FLAGS ${LIBEV_CFLAGS})
diff --git a/src/Makefile.am b/src/Makefile.am
index f9afabad..e9267c08 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -391,6 +391,14 @@ mod_openssl_la_LDFLAGS = $(common_module_ldflags)
mod_openssl_la_LIBADD = $(SSL_LIB) $(common_libadd)
endif
+if BUILD_WITH_MBEDTLS
+lib_LTLIBRARIES += mod_mbedtls.la
+mod_mbedtls_la_SOURCES = mod_mbedtls.c
+mod_mbedtls_la_LDFLAGS = $(common_module_ldflags)
+mod_mbedtls_la_LIBADD = $(MTLS_LIB) $(common_libadd)
+endif
+
+
lib_LTLIBRARIES += mod_rewrite.la
mod_rewrite_la_SOURCES = mod_rewrite.c
mod_rewrite_la_LDFLAGS = $(common_module_ldflags)
diff --git a/src/SConscript b/src/SConscript
index 989eb6c7..c540fc48 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -179,6 +179,9 @@ if env['with_openssl']:
if env['with_wolfssl']:
modules['mod_openssl'] = { 'src' : [ 'mod_openssl.c' ], 'lib' : [ env['LIBCRYPTO'], 'm' ] }
+if env['with_mbedtls']:
+ modules['mod_mbedtls'] = { 'src' : [ 'mod_mbedtls.c' ], 'lib' : [ env['LIBSSL'], env['LIBX509'], env['LIBCRYPTO'] ] }
+
staticenv = env.Clone(CPPFLAGS=[ env['CPPFLAGS'], '-DLIGHTTPD_STATIC' ])
## all the core-sources + the modules
diff --git a/src/algo_sha1.h b/src/algo_sha1.h
index a89efb90..34b9780d 100644
--- a/src/algo_sha1.h
+++ b/src/algo_sha1.h
@@ -4,6 +4,12 @@
#include "sys-crypto.h" /* USE_LIB_CRYPTO */
#ifdef USE_LIB_CRYPTO
+#if (!defined(USE_MBEDTLS_CRYPTO) || defined(MBEDTLS_SHA1_C))
+#define USE_LIB_CRYPTO_SHA1
+#endif
+#endif
+
+#ifdef USE_LIB_CRYPTO_SHA1
#ifdef USE_NETTLE_CRYPTO
#include <nettle/sha.h>
@@ -21,6 +27,23 @@ SHA1_Update(SHA_CTX *ctx, const void *data, size_t length)
sha1_update(ctx, length, data);
}
+#elif defined(USE_MBEDTLS_CRYPTO) && defined(MBEDTLS_SHA1_C)
+
+#include <mbedtls/sha1.h>
+#ifndef SHA_DIGEST_LENGTH
+#define SHA_DIGEST_LENGTH 20
+#endif
+typedef struct mbedtls_sha1_context SHA_CTX;
+#define SHA1_Init(ctx) \
+ (mbedtls_sha1_init(ctx), mbedtls_sha1_starts_ret(ctx))
+#define SHA1_Final(digest, ctx) \
+ (mbedtls_sha1_finish_ret((ctx),(digest)), mbedtls_sha1_free(ctx))
+static void
+SHA1_Update(SHA_CTX *ctx, const void *data, size_t length)
+{
+ mbedtls_sha1_update_ret(ctx, data, length);
+}
+
#elif defined(USE_OPENSSL_CRYPTO)
#include <openssl/sha.h>
diff --git a/src/configfile.c b/src/configfile.c
index fbe99745..8e415045 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -307,6 +307,8 @@ static void config_compat_module_load (server *srv) {
append_mod_staticfile = 0;
else if (buffer_eq_slen(m, CONST_STR_LEN("mod_dirlisting")))
append_mod_dirlisting = 0;
+ else if (buffer_eq_slen(m, CONST_STR_LEN("mod_mbedtls")))
+ append_mod_openssl = 0;
else if (buffer_eq_slen(m, CONST_STR_LEN("mod_openssl")))
append_mod_openssl = 0;
else if (buffer_eq_slen(m, CONST_STR_LEN("mod_authn_file")))
@@ -702,7 +704,7 @@ static int config_insert_srvconf(server *srv) {
break;
case 30:/* ssl.engine */
ssl_enabled = (0 != cpv->v.u);
- #ifndef USE_OPENSSL_CRYPTO
+ #if !defined(USE_OPENSSL_CRYPTO) && !defined(USE_MBEDTLS_CRYPTO)
if (ssl_enabled) {
log_error(srv->errh, __FILE__, __LINE__,
"ssl support is missing; "
diff --git a/src/meson.build b/src/meson.build
index 71e0cabe..ddbb67ad 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -395,6 +395,7 @@ if get_option('with_mysql')
endif
libssl = []
+libx509 = []
libcrypto = []
if get_option('with_openssl')
# manual search:
@@ -420,6 +421,17 @@ if get_option('with_wolfssl') != 'false'
libcrypto += libwolfssl_includes_dep
conf_data.set('HAVE_WOLFSSL_SSL_H', true)
endif
+if get_option('with_mbedtls')
+ # manual search:
+ # header: mbedtls/ssl.h
+ # function: mbedtls_cipher_info_from_type (-lmbedtls)
+ # function: mbedtls_x509_get_name (-lmbedx509)
+ # function: mbedtls_base64_encode (-lmbedcrypto)
+ libssl = [ dependency('libmbedtls') ]
+ libx509 = [ dependency('libmbedx509') ]
+ libcrypto = [ dependency('libmbedcrypto') ]
+ conf_data.set('HAVE_LIBMBEDCRYPTO', true)
+endif
if get_option('with_nettle') != 'false'
# manual search:
# header: nettle/nettle-types.h
@@ -973,6 +985,12 @@ if get_option('with_wolfssl') != 'false'
]
endif
+if get_option('with_mbedtls') != 'false'
+ modules += [
+ [ 'mod_mbedtls', [ 'mod_mbedtls.c' ], libssl + libx509 + libcrypto ],
+ ]
+endif
+
if get_option('with_pam')
modules += [
[ 'mod_authn_pam', [ 'mod_authn_pam.c' ], libpam ],
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 172a6a49..7a3fceef 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -37,6 +37,22 @@ SHA512_256_Update(SHA512_CTX *ctx, const void *data, size_t length)
sha512_256_update(ctx, length, data);
}
+#elif defined(USE_MBEDTLS_CRYPTO)
+
+#include <mbedtls/sha256.h>
+#ifdef MBEDTLS_SHA256_C
+typedef struct mbedtls_sha256_context SHA256_CTX;
+#define SHA256_Init(ctx) \
+ (mbedtls_sha256_init(ctx), mbedtls_sha256_starts_ret((ctx),0))
+#define SHA256_Final(digest, ctx) \
+ (mbedtls_sha256_finish_ret((ctx),(digest)), mbedtls_sha256_free(ctx))
+static void
+SHA256_Update(SHA256_CTX *ctx, const void *data, size_t length)
+{
+ mbedtls_sha256_update_ret(ctx, data, length);
+}
+#endif
+
#elif defined(USE_OPENSSL_CRYPTO)
#include <openssl/sha.h>
diff --git a/src/mod_authn_file.c b/src/mod_authn_file.c
index 571178b2..7d8de7b2 100644
--- a/src/mod_authn_file.c
+++ b/src/mod_authn_file.c
@@ -58,6 +58,38 @@ SHA512_256_Update(SHA512_CTX *ctx, const void *data, size_t length)
sha512_256_update(ctx, length, data);
}
+#elif defined(USE_MBEDTLS_CRYPTO)
+
+#include <mbedtls/md4.h>
+#ifdef MBEDTLS_MD4_C
+typedef struct mbedtls_md4_context MD4_CTX;
+#define MD4_Init(ctx) \
+ (mbedtls_md4_init(ctx), mbedtls_md4_starts_ret(ctx))
+#define MD4_Final(digest, ctx) \
+ (mbedtls_md4_finish_ret((ctx),(digest)), mbedtls_md4_free(ctx))
+static void
+MD4_Update(MD4_CTX *ctx, const void *data, size_t length)
+{
+ mbedtls_md4_update_ret(ctx, data, length);
+}
+#else /*(mbedTLS built without MD4)*/
+#define NO_MD4
+#endif
+
+#include <mbedtls/sha256.h>
+#ifdef MBEDTLS_SHA256_C
+typedef struct mbedtls_sha256_context SHA256_CTX;
+#define SHA256_Init(ctx) \
+ (mbedtls_sha256_init(ctx), mbedtls_sha256_starts_ret((ctx),0))
+#define SHA256_Final(digest, ctx) \
+ (mbedtls_sha256_finish_ret((ctx),(digest)), mbedtls_sha256_free(ctx))
+static void
+SHA256_Update(SHA256_CTX *ctx, const void *data, size_t length)
+{
+ mbedtls_sha256_update_ret(ctx, data, length);
+}
+#endif
+
#elif defined(USE_OPENSSL_CRYPTO)
#include <openssl/md4.h>
diff --git a/src/mod_mbedtls.c b/src/mod_mbedtls.c
new file mode 100644
index 00000000..48bfa870
--- /dev/null
+++ b/src/mod_mbedtls.c
@@ -0,0 +1,3478 @@
+/*
+ * mod_mbedtls - mbedTLS support for lighttpd
+ *
+ * Copyright(c) 2020 Glenn Strauss gstrauss()gluelogic.com All rights reserved
+ * License: BSD 3-clause (same as lighttpd)
+ */
+/*
+ * reference:
+ * https://tls.mbed.org/high-level-design
+ * https://tls.mbed.org/tech-updates/blog/mbedtls-2.0-defaults-best-practices
+ * mbedTLS header files (mbedtls/ssl.h and others) are extremely well-documented
+ * https://tls.mbed.org/api/ (generated from mbedTLS headers and code)
+ *
+ * mbedTLS limitations:
+ * - mbedTLS does not currently support TLSv1.3
+ * - mbedTLS does not currently support OCSP
+ * https://tls.mbed.org/discussions/feature-request/ocsp-stapling
+ * TLS/DTLS: OCSP Stapling support #880
+ * https://github.com/ARMmbed/mbedtls/issues/880
+ * Add support for writing OCSP requests and parsing OCSP responses #1197
+ * https://github.com/ARMmbed/mbedtls/issues/1197
+ *
+ * future possible enhancements to lighttpd mod_mbedtls:
+ * - session cache (though session tickets are implemented)
+ * sample code in mbedtls:programs/ssl/ssl_server2.c
+ *
+ * Note: session tickets are disabled by default
+ * If enabled, mbedtls rotates the session ticket key according to 2x timeout
+ * set with mbedtls_ssl_ticket_setup() (currently 43200 sec in mod_mbedtls).
+ * This is fine for use with a single lighttpd instance, but with multiple
+ * lighttpd workers, no coordinated STEK (server ticket encryption key)
+ * rotation occurs other than by (some external job) restarting lighttpd.
+ * Restarting lighttpd generates a new key that is shared by lighttpd workers
+ * for the lifetime of the new key. If the rotation period expires and
+ * lighttpd has not been restarted, lighttpd workers will generate new
+ * independent keys, making session tickets less effective for session
+ * resumption, since clients have a lower chance for future connections to
+ * reach the same lighttpd worker. However, things will still work, and a new
+ * session will be created if session resumption fails. Admins should plan to
+ * restart lighttpd at least every 24 hours if session tickets are enabled and
+ * multiple lighttpd workers are configured.
+ */
+#include "first.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h> /* vsnprintf() */
+#include <string.h>
+#include <unistd.h>
+
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/dhm.h>
+#include <mbedtls/error.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/pem.h>
+#include <mbedtls/ssl.h>
+#include <mbedtls/ssl_internal.h> /* struct mbedtls_ssl_transform */
+#include <mbedtls/x509.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/version.h>
+
+#if MBEDTLS_VERSION_NUMBER >= 0x02040000 /* mbedtls 2.04.0 */
+#include <mbedtls/net_sockets.h>
+#else
+#include <mbedtls/net.h>
+#endif
+
+#if defined(MBEDTLS_SSL_TICKET_C)
+#include <mbedtls/ssl_ticket.h>
+#endif
+
+#ifndef MBEDTLS_X509_CRT_PARSE_C
+#error "lighttpd requires that mbedtls be built with MBEDTLS_X509_CRT_PARSE_C"
+#endif
+
+#include "base.h"
+#include "http_header.h"
+#include "log.h"
+#include "plugin.h"
+
+typedef struct {
+ /* SNI per host: with COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */
+ mbedtls_pk_context ssl_pemfile_pkey;/* parsed private key structure */
+ mbedtls_x509_crt ssl_pemfile_x509; /* parsed public key structure */
+ const buffer *ssl_pemfile;
+ const buffer *ssl_privkey;
+ int8_t need_chain;
+} plugin_cert;
+
+typedef struct {
+ mbedtls_ssl_config *ssl_ctx; /* context shared between mbedtls_ssl_CONTEXT structures */
+ int *ciphersuites;
+ mbedtls_ecp_group_id *curves;
+} plugin_ssl_ctx;
+
+typedef struct {
+ mbedtls_ssl_config *ssl_ctx; /* output from network_init_ssl() */
+ int *ciphersuites; /* output from network_init_ssl() */
+ mbedtls_ecp_group_id *curves; /* output from network_init_ssl() */
+
+ /*(used only during startup; not patched)*/
+ unsigned char ssl_enabled; /* only interesting for setting up listening sockets. don't use at runtime */
+ unsigned char ssl_honor_cipher_order; /* determine SSL cipher in server-preferred order, not client-order */
+ unsigned char ssl_empty_fragments;
+ unsigned char ssl_use_sslv2;
+ unsigned char ssl_use_sslv3;
+ const buffer *ssl_cipher_list;
+ const buffer *ssl_dh_file;
+ const buffer *ssl_ec_curve;
+ const buffer *ssl_acme_tls_1;
+ array *ssl_conf_cmd;
+
+ /*(copied from plugin_data for socket ssl_ctx config)*/
+ plugin_cert *pc;
+ mbedtls_pk_context *ssl_pemfile_pkey; /* parsed private key structure */
+ mbedtls_x509_crt *ssl_pemfile_x509; /* parsed public key structure */
+ mbedtls_x509_crt *ssl_ca_file;
+ const buffer *ssl_pemfile;
+ const buffer *ssl_privkey;
+ unsigned char ssl_session_ticket;
+ unsigned char ssl_verifyclient;
+ unsigned char ssl_verifyclient_enforce;
+ unsigned char ssl_verifyclient_depth;
+} plugin_config_socket; /*(used at startup during configuration)*/
+
+typedef struct {
+ /* SNI per host: w/ COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */
+ plugin_cert *pc;
+ mbedtls_pk_context *ssl_pemfile_pkey; /* parsed private key structure */
+ mbedtls_x509_crt *ssl_pemfile_x509; /* parsed public key structure */
+ const buffer *ssl_pemfile;
+ mbedtls_x509_crt *ssl_ca_file;
+ mbedtls_x509_crt *ssl_ca_dn_file;
+ mbedtls_x509_crl *ssl_ca_crl_file;
+
+ unsigned char ssl_verifyclient;
+ unsigned char ssl_verifyclient_enforce;
+ unsigned char ssl_verifyclient_depth;
+ unsigned char ssl_verifyclient_export_cert;
+ unsigned char ssl_read_ahead;
+ unsigned char ssl_log_noise;
+ unsigned char ssl_disable_client_renegotiation;
+ const buffer *ssl_verifyclient_username;
+ const buffer *ssl_acme_tls_1;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ plugin_ssl_ctx *ssl_ctxs;
+ plugin_config defaults;
+ server *srv;
+ /* NIST counter-mode deterministic random byte generator */
+ mbedtls_ctr_drbg_context ctr_drbg;
+ /* entropy collection and state management */
+ mbedtls_entropy_context entropy;
+ #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_ticket_context ticket_ctx;
+ #endif
+} plugin_data;
+
+static int ssl_is_init;
+/* need assigned p->id for deep access of module handler_ctx for connection
+ * i.e. handler_ctx *hctx = r->plugin_ctx[plugin_data_singleton->id]; */
+static plugin_data *plugin_data_singleton;
+#define LOCAL_SEND_BUFSIZE MBEDTLS_SSL_MAX_CONTENT_LEN
+static char *local_send_buffer;
+
+typedef struct {
+ mbedtls_ssl_context ssl; /* mbedtls request/connection context */
+ request_st *r;
+ connection *con;
+ int8_t request_env_patched;
+ int8_t close_notify;
+ unsigned short alpn;
+ int handshake_done;
+ size_t pending_write;
+ plugin_config conf;
+ buffer *tmp_buf;
+ mbedtls_pk_context *acme_tls_1_pkey;
+ mbedtls_x509_crt *acme_tls_1_x509;
+} handler_ctx;
+
+
+static handler_ctx *
+handler_ctx_init (void)
+{
+ handler_ctx *hctx = calloc(1, sizeof(*hctx));
+ force_assert(hctx);
+ return hctx;
+}
+
+
+static void
+handler_ctx_free (handler_ctx *hctx)
+{
+ mbedtls_ssl_free(&hctx->ssl);
+ if (hctx->acme_tls_1_pkey) {
+ mbedtls_pk_free(hctx->acme_tls_1_pkey);
+ free(hctx->acme_tls_1_pkey);
+ }
+ if (hctx->acme_tls_1_x509) {
+ mbedtls_x509_crt_free(hctx->acme_tls_1_x509);
+ free(hctx->acme_tls_1_x509);
+ }
+ free(hctx);
+}
+
+
+#ifdef MBEDTLS_ERROR_C
+__attribute_cold__
+static void elog(log_error_st * const errh,
+ const char * const file, const int line,
+ const int rc, const char * const msg)
+{
+ /* error logging convenience function that decodes mbedtls result codes */
+ char buf[256];
+ mbedtls_strerror(rc, buf, sizeof(buf));
+ log_error(errh, file, line, "MTLS: %s: %s (-0x%04x)", msg, buf, -rc);
+}
+#else
+#define elog(errh, file, line, rc, msg) \
+ log_error((errh), (file), (line), "MTLS: %s: (-0x%04x)", (msg), -(rc))
+#endif
+
+
+__attribute_cold__
+__attribute_format__((__printf__, 5, 6))
+static void elogf(log_error_st * const errh,
+ const char * const file, const int line,
+ const int rc, const char * const fmt, ...)
+{
+ char msg[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ elog(errh, file, line, rc, msg);
+}
+
+
+INIT_FUNC(mod_mbedtls_init)
+{
+ plugin_data_singleton = (plugin_data *)calloc(1, sizeof(plugin_data));
+ #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_ticket_init(&plugin_data_singleton->ticket_ctx);
+ #endif
+ return plugin_data_singleton;
+}
+
+
+static int mod_mbedtls_init_once_mbedtls (server *srv)
+{
+ if (ssl_is_init) return 1;
+ ssl_is_init = 1;
+
+ plugin_data * const p = plugin_data_singleton;
+ mbedtls_ctr_drbg_init(&p->ctr_drbg); /* init empty NSIT random num gen */
+ mbedtls_entropy_init(&p->entropy); /* init empty entropy collection struct
+ .. could add sources here too */
+
+ int rc = /* init RNG */
+ mbedtls_ctr_drbg_seed(&p->ctr_drbg, /* random number generator */
+ mbedtls_entropy_func, /* default entropy func */
+ &p->entropy, /* entropy context */
+ NULL, 0); /* no personalization data */
+ if (0 != rc) {
+ elog(srv->errh, __FILE__,__LINE__, rc,
+ "Init of random number generator failed");
+ return 0;
+ }
+
+ local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
+ force_assert(NULL != local_send_buffer);
+
+ return 1;
+}
+
+
+static void mod_mbedtls_free_mbedtls (void)
+{
+ if (!ssl_is_init) return;
+
+ plugin_data * const p = plugin_data_singleton;
+ mbedtls_ctr_drbg_free(&p->ctr_drbg);
+ mbedtls_entropy_free(&p->entropy);
+ #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_ticket_free(&p->ticket_ctx);
+ #endif
+
+ free(local_send_buffer);
+ ssl_is_init = 0;
+}
+
+
+static void
+mod_mbedtls_free_config (server *srv, plugin_data * const p)
+{
+ if (NULL != p->ssl_ctxs) {
+ mbedtls_ssl_config * const ssl_ctx_global_scope = p->ssl_ctxs->ssl_ctx;
+ /* free ssl_ctx from $SERVER["socket"] (if not copy of global scope) */
+ for (uint32_t i = 1; i < srv->config_context->used; ++i) {
+ plugin_ssl_ctx * const s = p->ssl_ctxs + i;
+ if (s->ssl_ctx && s->ssl_ctx != ssl_ctx_global_scope) {
+ mbedtls_ssl_config_free(s->ssl_ctx);
+ free(s->ciphersuites);
+ free(s->curves);
+ }
+ }
+ /* free ssl_ctx from global scope */
+ if (ssl_ctx_global_scope) {
+ mbedtls_ssl_config_free(ssl_ctx_global_scope);
+ free(p->ssl_ctxs[0].ciphersuites);
+ free(p->ssl_ctxs[0].curves);
+ }
+ free(p->ssl_ctxs);
+ }
+
+ if (NULL == p->cvlist) return;
+ /* (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* ssl.pemfile */
+ if (cpv->vtype == T_CONFIG_LOCAL) {
+ plugin_cert *pc = cpv->v.v;
+ mbedtls_pk_free(&pc->ssl_pemfile_pkey);
+ mbedtls_x509_crt_free(&pc->ssl_pemfile_x509);
+ }
+ break;
+ case 2: /* ssl.ca-file */
+ case 3: /* ssl.ca-dn-file */
+ if (cpv->vtype == T_CONFIG_LOCAL) {
+ mbedtls_x509_crt *cacert = cpv->v.v;
+ mbedtls_x509_crt_free(cacert);
+ free(cacert);
+ }
+ break;
+ case 4: /* ssl.ca-dn-file */
+ if (cpv->vtype == T_CONFIG_LOCAL) {
+ mbedtls_x509_crl *crl = cpv->v.v;
+ mbedtls_x509_crl_free(crl);
+ free(crl);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+FREE_FUNC(mod_mbedtls_free)
+{
+ plugin_data *p = p_d;
+ if (NULL == p->srv) return;
+ mod_mbedtls_free_config(p->srv, p);
+ mod_mbedtls_free_mbedtls();
+}
+
+
+static void
+mod_mbedtls_merge_config_cpv (plugin_config * const pconf, const config_plugin_value_t * const cpv)
+{
+ switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
+ case 0: /* ssl.pemfile */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->pc = cpv->v.v;
+ break;
+ case 1: /* ssl.privkey */
+ break;
+ case 2: /* ssl.ca-file */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->ssl_ca_file = cpv->v.v;
+ break;
+ case 3: /* ssl.ca-dn-file */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->ssl_ca_dn_file = cpv->v.v;
+ break;
+ case 4: /* ssl.ca-crl-file */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ pconf->ssl_ca_dn_file = cpv->v.v;
+ break;
+ case 5: /* ssl.read-ahead */
+ pconf->ssl_read_ahead = (0 != cpv->v.u);
+ break;
+ case 6: /* ssl.disable-client-renegotiation */
+ pconf->ssl_disable_client_renegotiation = (0 != cpv->v.u);
+ break;
+ case 7: /* ssl.verifyclient.activate */
+ pconf->ssl_verifyclient = (0 != cpv->v.u);
+ break;
+ case 8: /* ssl.verifyclient.enforce */
+ pconf->ssl_verifyclient_enforce = (0 != cpv->v.u);
+ break;
+ case 9: /* ssl.verifyclient.depth */
+ pconf->ssl_verifyclient_depth = (unsigned char)cpv->v.shrt;
+ break;
+ case 10:/* ssl.verifyclient.username */
+ pconf->ssl_verifyclient_username = cpv->v.b;
+ break;
+ case 11:/* ssl.verifyclient.exportcert */
+ pconf->ssl_verifyclient_export_cert = (0 != cpv->v.u);
+ break;
+ case 12:/* ssl.acme-tls-1 */
+ pconf->ssl_acme_tls_1 = cpv->v.b;
+ break;
+ case 13:/* debug.log-ssl-noise */
+ pconf->ssl_log_noise = (unsigned char)cpv->v.shrt;
+ break;
+ default:/* should not happen */
+ return;
+ }
+}
+
+
+static void
+mod_mbedtls_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv)
+{
+ do {
+ mod_mbedtls_merge_config_cpv(pconf, cpv);
+ } while ((++cpv)->k_id != -1);
+}
+
+
+static void
+mod_mbedtls_patch_config (request_st * const r, plugin_config * const pconf)
+{
+ plugin_data * const p = plugin_data_singleton;
+ memcpy(pconf, &p->defaults, sizeof(plugin_config));
+ for (int i = 1, used = p->nconfig; i < used; ++i) {
+ if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
+ mod_mbedtls_merge_config(pconf, p->cvlist + p->cvlist[i].v.u2[0]);
+ }
+}
+
+
+__attribute_pure__
+static int
+mod_mbedtls_crt_is_self_issued (const mbedtls_x509_crt * const crt)
+{
+ const mbedtls_x509_buf * const issuer = &crt->issuer_raw;
+ const mbedtls_x509_buf * const subject = &crt->subject_raw;
+ return subject->len == issuer->len
+ && 0 == memcmp(issuer->p, subject->p, subject->len);
+}
+
+
+static int
+mod_mbedtls_construct_crt_chain (mbedtls_x509_crt *leaf, mbedtls_x509_crt *store, log_error_st *errh)
+{
+ /* Historically, openssl will use the cert chain in (SSL_CTX *) if a cert
+ * does not have a chain configured in (SSL *). While similar behavior
+ * could be achieved with mbedtls_x509_crt_parse_file(crt, ssl_ca_file->ptr)
+ * instead attempt to do better and build a proper, ordered cert chain. */
+
+ if (leaf->next) return 0; /*(presume chain has already been provided)*/
+ if (store == NULL) return 0;/*(unable to proceed; chain may be incomplete)*/
+
+ /* attempt to construct certificate chain from certificate store */
+ for (mbedtls_x509_crt *crt = leaf; crt; ) {
+ const mbedtls_x509_buf * const issuer = &crt->issuer_raw;
+
+ /*(walk entire store in case certs are not properly sorted)*/
+ for (crt = store; crt; crt = crt->next) {
+ /* The raw issuer/subject data (DER) is used for quick comparison */
+ /* (see comments in mod_mbedtls_verify_cb())*/
+ const mbedtls_x509_buf * const subject = &crt->subject_raw;
+ if (issuer->len != subject->len
+ || 0 != memcmp(subject->p, issuer->p, issuer->len)) continue;
+
+ /* root cert is end condition; omit from chain of intermediates */
+ if (mod_mbedtls_crt_is_self_issued(crt))
+ return 0;
+
+ int rc =
+ #if MBEDTLS_VERSION_NUMBER >= 0x02110000 /* mbedtls 2.17.0 */
+ /* save memory by eliding copy of already-loaded raw DER */
+ mbedtls_x509_crt_parse_der_nocopy(leaf, crt->raw.p, crt->raw.len);
+ #else
+ mbedtls_x509_crt_parse_der(leaf, crt->raw.p, crt->raw.len);
+ #endif
+ if (0 != rc) { /*(failure not unexpected since already parsed)*/
+ elog(errh, __FILE__, __LINE__, rc, "cert copy failed");
+ return rc;
+ }
+ break;
+ }
+ }
+
+ return 0; /*(no error, though cert chain may or may not be complete)*/
+}
+
+
+static int
+mod_mbedtls_verify_cb (void *arg, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
+{
+ handler_ctx * const hctx = (handler_ctx *)arg;
+
+ if (depth > hctx->conf.ssl_verifyclient_depth) {
+ log_error(hctx->r->conf.errh, __FILE__, __LINE__,
+ "MTLS: client cert chain too long");
+ *flags |= MBEDTLS_X509_BADCERT_OTHER; /* cert chain too long */
+ }
+ else if (0 == depth && NULL != hctx->conf.ssl_ca_dn_file) {
+ /* verify that client cert is issued by CA in ssl.ca-dn-file
+ * if both ssl.ca-dn-file and ssl.ca-file were configured */
+ /* The raw issuer/subject data (DER) is used for quick comparison. */
+ const size_t len = crt->issuer_raw.len;
+ mbedtls_x509_crt *chain = hctx->conf.ssl_ca_dn_file;
+ do {
+ #if 0 /* x509_name_cmp() is not a public func in mbedtls */
+ if (0 == x509_name_cmp(&crt->issuer, &chain->subject))
+ break;
+ #else
+ if (len == chain->subject_raw.len
+ && 0 == memcmp(chain->subject_raw.p, crt->issuer_raw.p, len))
+ break;
+ #endif
+ } while ((chain = chain->next));
+
+ if (NULL == chain)
+ *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;
+ }
+ if (*flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
+ log_error(hctx->r->conf.errh, __FILE__, __LINE__,
+ "MTLS: client cert not trusted");
+ }
+
+ return 0;
+}
+
+
+#ifdef MBEDTLS_SSL_SERVER_NAME_INDICATION
+static int
+mod_mbedtls_SNI (void *arg, mbedtls_ssl_context *ssl, const unsigned char *servername, size_t len)
+{
+ handler_ctx * const hctx = (handler_ctx *) arg;
+ buffer_copy_string(&hctx->r->uri.scheme, "https");
+
+ request_st * const r = hctx->r;
+ if (len >= 1024) { /*(expecting < 256; TLSEXT_MAXLEN_host_name is 255)*/
+ log_error(r->conf.errh, __FILE__, __LINE__,
+ "MTLS: SNI name too long %.*s", (int)len, servername);
+ return MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO;
+ }
+
+ /* use SNI to patch mod_mbedtls config and then reset COMP_HTTP_HOST */
+ buffer_copy_string_len(&r->uri.authority, (const char *)servername, len);
+ buffer_to_lower(&r->uri.authority);
+ #if 0
+ /*(r->uri.authority used below for configuration before request read;
+ * revisit for h2)*/
+ if (0 != http_request_host_policy(&r->uri.authority,
+ r->conf.http_parseopts, 443))
+ return MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO;
+ #endif
+
+ const buffer * const ssl_pemfile = hctx->conf.pc->ssl_pemfile;
+
+ r->conditional_is_valid |= (1 << COMP_HTTP_SCHEME)
+ | (1 << COMP_HTTP_HOST);
+
+ mod_mbedtls_patch_config(r, &hctx->conf);
+ /* reset COMP_HTTP_HOST so that conditions re-run after request hdrs read */
+ /*(done in configfile-glue.c:config_cond_cache_reset() after request hdrs read)*/
+ /*config_cond_cache_reset_item(r, COMP_HTTP_HOST);*/
+ /*buffer_clear(&r->uri.authority);*/
+
+ /*(compare strings as ssl.pemfile might repeat same file in lighttpd.conf
+ * and mod_mbedtls does not attempt to de-dup)*/
+ if (!buffer_is_equal(hctx->conf.pc->ssl_pemfile, ssl_pemfile)) {
+ /* if needed, attempt to construct certificate chain for server cert */
+ if (hctx->conf.pc->need_chain) {
+ hctx->conf.pc->need_chain = 0; /*(attempt once to complete chain)*/
+ mbedtls_x509_crt *ssl_cred = &hctx->conf.pc->ssl_pemfile_x509;
+ mbedtls_x509_crt *store = hctx->conf.ssl_ca_file;
+ if (!mod_mbedtls_construct_crt_chain(ssl_cred, store, r->conf.errh))
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+ }
+ /* reconfigure to use SNI-specific cert */
+ int rc =
+ mbedtls_ssl_set_hs_own_cert(ssl,
+ &hctx->conf.pc->ssl_pemfile_x509,
+ &hctx->conf.pc->ssl_pemfile_pkey);
+ if (0 != rc) {
+ elogf(r->conf.errh, __FILE__, __LINE__, rc,
+ "failed to set SNI certificate for TLS server name %s",
+ r->uri.authority.ptr);
+ return MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO;
+ }
+ }
+
+ return 0;
+}
+#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
+
+
+static int
+mod_mbedtls_conf_verify (handler_ctx *hctx, mbedtls_ssl_config *ssl_ctx)
+{
+ if (NULL == hctx->conf.ssl_ca_file) {
+ log_error(hctx->r->conf.errh, __FILE__, __LINE__,
+ "MTLS: can't verify client without ssl.ca-file "
+ "for TLS server name %s",
+ hctx->r->uri.authority.ptr);
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+ }
+
+ /* send ssl_ca_dn_file (if set) in client certificate request
+ * (later changed to ssl_ca_file before client certificate verification) */
+ mbedtls_x509_crt *ca_certs = hctx->conf.ssl_ca_dn_file
+ ? hctx->conf.ssl_ca_dn_file
+ : hctx->conf.ssl_ca_file;
+
+ mbedtls_ssl_context * const ssl = &hctx->ssl;
+ mbedtls_ssl_set_hs_ca_chain(ssl, ca_certs, hctx->conf.ssl_ca_crl_file);
+ #if MBEDTLS_VERSION_NUMBER >= 0x02120000 /* mbedtls 2.18.0 */
+ mbedtls_ssl_set_verify(ssl, mod_mbedtls_verify_cb, hctx);
+ #else
+ mbedtls_ssl_conf_verify(ssl_ctx, mod_mbedtls_verify_cb, hctx);
+ #endif
+ return 0;
+}
+
+
+static void *
+network_mbedtls_load_pemfile (server *srv, const buffer *pemfile, const buffer *privkey)
+{
+ mbedtls_x509_crt ssl_pemfile_x509; /* parsed public key structure */
+ mbedtls_pk_context ssl_pemfile_pkey; /* parsed private key structure */
+ int rc;
+
+ mbedtls_x509_crt_init(&ssl_pemfile_x509); /* init cert structure */
+ rc = mbedtls_x509_crt_parse_file(&ssl_pemfile_x509, pemfile->ptr);
+ if (0 != rc) {
+ elogf(srv->errh, __FILE__, __LINE__, rc,
+ "PEM file cert read failed (%s)", pemfile->ptr);
+ return NULL;
+ }
+
+ mbedtls_pk_init(&ssl_pemfile_pkey); /* init private key context */
+ rc = mbedtls_pk_parse_keyfile(&ssl_pemfile_pkey, privkey->ptr, NULL);
+ if (0 != rc) {
+ elogf(srv->errh, __FILE__, __LINE__, rc,
+ "PEM file private key read failed %s", privkey->ptr);
+ mbedtls_x509_crt_free(&ssl_pemfile_x509);
+ return NULL;
+ }
+
+ rc = mbedtls_pk_check_pair(&ssl_pemfile_x509.pk, &ssl_pemfile_pkey);
+ if (0 != rc) {
+ elogf(srv->errh, __FILE__, __LINE__, rc,
+ "PEM cert and private key did not verify (%s) (%s)",
+ pemfile->ptr, privkey->ptr);
+ mbedtls_pk_free(&ssl_pemfile_pkey);
+ mbedtls_x509_crt_free(&ssl_pemfile_x509);
+ return NULL;
+ }
+
+ plugin_cert *pc = malloc(sizeof(plugin_cert));
+ force_assert(pc);
+ pc->ssl_pemfile_pkey = ssl_pemfile_pkey;
+ pc->ssl_pemfile_x509 = ssl_pemfile_x509;
+ pc->ssl_pemfile = pemfile;
+ pc->ssl_privkey = privkey;
+ pc->need_chain = (ssl_pemfile_x509.next == NULL
+ && !mod_mbedtls_crt_is_self_issued(&ssl_pemfile_x509));
+ mbedtls_platform_zeroize(&ssl_pemfile_pkey, sizeof(ssl_pemfile_pkey));
+ return pc;
+}
+
+
+#ifdef MBEDTLS_SSL_ALPN
+
+static int
+mod_mbedtls_acme_tls_1 (handler_ctx *hctx)
+{
+ buffer * const b = hctx->tmp_buf;
+ const buffer * const name = &hctx->r->uri.authority;
+ log_error_st * const errh = hctx->r->conf.errh;
+ mbedtls_x509_crt *ssl_pemfile_x509 = NULL;
+ mbedtls_pk_context *ssl_pemfile_pkey = NULL;
+ size_t len;
+ int rc = MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO;
+
+ /* check if acme-tls/1 protocol is enabled (path to dir of cert(s) is set)*/
+ if (buffer_string_is_empty(hctx->conf.ssl_acme_tls_1))
+ return 0; /*(should not happen)*/
+ buffer_copy_buffer(b, hctx->conf.ssl_acme_tls_1);
+ buffer_append_slash(b);
+
+ /* check if SNI set server name (required for acme-tls/1 protocol)
+ * and perform simple path checks for no '/'
+ * and no leading '.' (e.g. ignore "." or ".." or anything beginning '.') */
+ if (buffer_string_is_empty(name)) return rc;
+ if (NULL != strchr(name->ptr, '/')) return rc;
+ if (name->ptr[0] == '.') return rc;
+ #if 0
+ if (0 != http_request_host_policy(name,hctx->r->conf.http_parseopts,443))
+ return rc;
+ #endif
+ buffer_append_string_buffer(b, name);
+ len = buffer_string_length(b);
+
+ do {
+ buffer_append_string_len(b, CONST_STR_LEN(".crt.pem"));
+ ssl_pemfile_x509 = malloc(sizeof(*ssl_pemfile_x509));
+ force_assert(ssl_pemfile_x509);
+ mbedtls_x509_crt_init(ssl_pemfile_x509); /* init cert structure */
+ rc = mbedtls_x509_crt_parse_file(ssl_pemfile_x509, b->ptr);
+ if (0 != rc) {
+ elogf(errh, __FILE__, __LINE__, rc,
+ "Failed to load acme-tls/1 pemfile: %s", b->ptr);
+ break;
+ }
+
+ buffer_string_set_length(b, len); /*(remove ".crt.pem")*/
+ buffer_append_string_len(b, CONST_STR_LEN(".key.pem"));
+ ssl_pemfile_pkey = malloc(sizeof(*ssl_pemfile_pkey));
+ force_assert(ssl_pemfile_pkey);
+ mbedtls_pk_init(ssl_pemfile_pkey); /* init private key context */
+ rc = mbedtls_pk_parse_keyfile(ssl_pemfile_pkey, b->ptr, NULL);
+ if (0 != rc) {
+ elogf(errh, __FILE__, __LINE__, rc,
+ "Failed to load acme-tls/1 pemfile: %s", b->ptr);
+ break;
+ }
+
+ rc = mbedtls_ssl_set_hs_own_cert(&hctx->ssl,
+ ssl_pemfile_x509, ssl_pemfile_pkey);
+ if (0 != rc) {
+ elogf(errh, __FILE__, __LINE__, rc,
+ "failed to set acme-tls/1 certificate for TLS server "
+ "name %s", name->ptr);
+ break;
+ }
+
+ hctx->acme_tls_1_pkey = ssl_pemfile_pkey; /* save ptr and free later */
+ hctx->acme_tls_1_x509 = ssl_pemfile_x509; /* save ptr and free later */
+ return 0;
+
+ } while (0);
+
+ if (ssl_pemfile_pkey) {
+ mbedtls_pk_free(ssl_pemfile_pkey);
+ free(ssl_pemfile_pkey);
+ }
+ if (ssl_pemfile_x509) {
+ mbedtls_x509_crt_free(ssl_pemfile_x509);
+ free(ssl_pemfile_x509);
+ }
+
+ return rc;
+}
+
+
+enum {
+ MOD_MBEDTLS_ALPN_HTTP11 = 1
+ ,MOD_MBEDTLS_ALPN_HTTP10 = 2
+ ,MOD_MBEDTLS_ALPN_H2 = 3
+ ,MOD_MBEDTLS_ALPN_ACME_TLS_1 = 4
+};
+
+
+static int
+mod_mbedtls_alpn_select_cb (handler_ctx *hctx, const char *in)
+{
+ const int n = (int)strlen(in);
+ const int i = 0;
+ unsigned short proto;
+
+ switch (n) {
+ #if 0
+ case 2: /* "h2" */
+ if (in[i] == 'h' && in[i+1] == '2') {
+ proto = MOD_MBEDTLS_ALPN_H2;
+ break;
+ }
+ return 0;
+ #endif
+ case 8: /* "http/1.1" "http/1.0" */
+ if (0 == memcmp(in+i, "http/1.", 7)) {
+ if (in[i+7] == '1') {
+ proto = MOD_MBEDTLS_ALPN_HTTP11;
+ break;
+ }
+ if (in[i+7] == '0') {
+ proto = MOD_MBEDTLS_ALPN_HTTP10;
+ break;
+ }
+ }
+ return 0;
+ case 10: /* "acme-tls/1" */
+ if (0 == memcmp(in+i, "acme-tls/1", 10)) {
+ int rc = mod_mbedtls_acme_tls_1(hctx);
+ if (0 == rc) {
+ proto = MOD_MBEDTLS_ALPN_ACME_TLS_1;
+ break;
+ }
+ return rc;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+
+ hctx->alpn = proto;
+ return 0;
+}
+
+#endif /* MBEDTLS_SSL_ALPN */
+
+
+static int
+mod_mbedtls_ssl_conf_ciphersuites (server *srv, plugin_config_socket *s, buffer *ciphersuites, const buffer *cipherstring);
+
+
+static int
+mod_mbedtls_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *curvelist);
+
+
+static void
+mod_mbedtls_ssl_conf_proto (server *srv, plugin_config_socket *s, const buffer *b, int max);
+
+
+static int
+mod_mbedtls_ssl_conf_cmd (server *srv, plugin_config_socket *s)
+{
+ /* reference:
+ * https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html */
+ int rc = 0;
+ buffer *cipherstring = NULL;
+ buffer *ciphersuites = NULL;
+
+ for (size_t i = 0; i < s->ssl_conf_cmd->used; ++i) {
+ data_string *ds = (data_string *)s->ssl_conf_cmd->data[i];
+ if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("CipherString")))
+ cipherstring = &ds->value;
+ else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Ciphersuites")))
+ ciphersuites = &ds->value;
+ else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Curves"))
+ || buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Groups"))) {
+ if (!mod_mbedtls_ssl_conf_curves(srv, s, &ds->value))
+ rc = -1;
+ }
+ else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("MaxProtocol")))
+ mod_mbedtls_ssl_conf_proto(srv, s, &ds->value, 1); /* max */
+ else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("MinProtocol")))
+ mod_mbedtls_ssl_conf_proto(srv, s, &ds->value, 0); /* min */
+ else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Protocol"))) {
+ /* openssl config for Protocol=... is complex and deprecated */
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ssl.openssl.ssl-conf-cmd %s ignored; "
+ "use MinProtocol=... and MaxProtocol=... instead",
+ ds->key.ptr);
+ }
+ else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("Options"))) {
+ for (char *v = ds->value.ptr, *e; *v; v = e) {
+ while (*v == ' ' || *v == '\t' || *v == ',') ++v;
+ int flag = 1;
+ if (*v == '-') {
+ flag = 0;
+ ++v;
+ }
+ for (e = v; light_isalpha(*e); ++e) ;
+ switch ((int)(e-v)) {
+ case 11:
+ if (buffer_eq_icase_ssn(v, "Compression", 11)) {
+ /* mbedtls defaults to no record compression unless
+ * mbedtls is built with MBEDTLS_ZLIB_SUPPORT, which
+ * is deprecated and slated for removal*/
+ if (!flag) continue;
+ }
+ break;
+ case 13:
+ if (buffer_eq_icase_ssn(v, "SessionTicket", 13)) {
+ s->ssl_session_ticket = flag;
+ continue;
+ }
+ break;
+ case 16:
+ if (buffer_eq_icase_ssn(v, "ServerPreference", 16)) {
+ /* Note: The server uses its own preferences
+ * over the preference of the client unless
+ * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE defined! */
+ s->ssl_honor_cipher_order = flag;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ /* warn if not explicitly handled or ignored above */
+ if (!flag) --v;
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ssl.openssl.ssl-conf-cmd Options %.*s ignored",
+ (int)(e-v), v);
+ }
+ }
+ #if 0
+ else if (buffer_eq_icase_slen(&ds->key, CONST_STR_LEN("..."))) {
+ }
+ #endif
+ else {
+ /* warn if not explicitly handled or ignored above */
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ssl.openssl.ssl-conf-cmd %s ignored",
+ ds->key.ptr);
+ }
+ }
+
+ if (!mod_mbedtls_ssl_conf_ciphersuites(srv, s, ciphersuites, cipherstring))
+ rc = -1;
+
+ return rc;
+}
+
+
+static int
+network_init_ssl (server *srv, plugin_config_socket *s, plugin_data *p)
+{
+ int rc;
+
+ s->ssl_ctx = malloc(sizeof(mbedtls_ssl_config));
+ force_assert(s->ssl_ctx);
+ mbedtls_ssl_config_init(s->ssl_ctx);
+
+ /* set the RNG in the ssl config context, using the default random func */
+ mbedtls_ssl_conf_rng(s->ssl_ctx, mbedtls_ctr_drbg_random, &p->ctr_drbg);
+
+ /* mbedtls defaults to disable client renegotiation
+ * mbedtls defaults to no record compression unless mbedtls is built
+ * with MBEDTLS_ZLIB_SUPPORT, which is deprecated and slated for removal
+ * MBEDTLS_SSL_PRESET_SUITEB is stricter than MBEDTLS_SSL_PRESET_DEFAULT
+ * (and is attempted to be supported in mod_mbedtls_ssl_conf_ciphersuites())
+ * explanation: https://github.com/ARMmbed/mbedtls/issues/1591
+ * reference: RFC 6460 */
+ rc = mbedtls_ssl_config_defaults(s->ssl_ctx,
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT);
+ if (0 != rc) {
+ elog(srv->errh, __FILE__,__LINE__, rc,
+ "Init of ssl config context defaults failed");
+ return -1;
+ }
+
+ /* mbedtls defaults minimum accepted SSL/TLS protocol version TLS v1.0
+ * use of SSL v3 should be avoided, and SSL v2 is not supported */
+ if (s->ssl_use_sslv3)
+ mbedtls_ssl_conf_min_version(s->ssl_ctx, MBEDTLS_SSL_MAJOR_VERSION_3,
+ MBEDTLS_SSL_MINOR_VERSION_0);
+
+ if (!buffer_string_is_empty(s->ssl_cipher_list)) {
+ if (!mod_mbedtls_ssl_conf_ciphersuites(srv,s,NULL,s->ssl_cipher_list))
+ return -1;
+ }
+
+ if (!buffer_string_is_empty(s->ssl_dh_file)) {
+ mbedtls_dhm_context dhm;
+ mbedtls_dhm_init(&dhm);
+ rc = mbedtls_dhm_parse_dhmfile(&dhm, s->ssl_dh_file->ptr);
+ if (0 != rc)
+ elogf(srv->errh, __FILE__,__LINE__, rc,
+ "mbedtls_dhm_parse_dhmfile() %s", s->ssl_dh_file->ptr);
+ else {
+ rc = mbedtls_ssl_conf_dh_param_ctx(s->ssl_ctx, &dhm);
+ if (0 != rc)
+ elogf(srv->errh, __FILE__,__LINE__, rc,
+ "mbedtls_ssl_conf_dh_param_ctx() %s", s->ssl_dh_file->ptr);
+ }
+ mbedtls_dhm_free(&dhm);
+ if (0 != rc)
+ return -1;
+ }
+
+ if (!buffer_string_is_empty(s->ssl_ec_curve)) {
+ if (!mod_mbedtls_ssl_conf_curves(srv, s, s->ssl_ec_curve))
+ return -1;
+ }
+
+ /* if needed, attempt to construct certificate chain for server cert */
+ if (s->pc->need_chain) {
+ s->pc->need_chain = 0; /*(attempt once to complete chain)*/
+ if (!mod_mbedtls_construct_crt_chain(s->ssl_pemfile_x509,
+ s->ssl_ca_file, srv->errh))
+ return -1;
+ }
+
+ rc = mbedtls_ssl_conf_own_cert(s->ssl_ctx,
+ s->ssl_pemfile_x509, s->ssl_pemfile_pkey);
+ if (0 != rc) {
+ elogf(srv->errh, __FILE__, __LINE__, rc,
+ "PEM cert and private key did not verify (%s) (%s)",
+ s->ssl_pemfile->ptr, s->ssl_privkey->ptr);
+ return -1;
+ }
+
+ #ifdef MBEDTLS_SSL_ALPN
+ /* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */
+ static const char *alpn_protos_http_acme[] = {
+ "http/1.1"
+ ,"http/1.0"
+ ,"acme-tls/1"
+ ,NULL
+ };
+ static const char *alpn_protos_http[] = {
+ "http/1.1"
+ ,"http/1.0"
+ ,NULL
+ };
+ const char **alpn_protos = (!buffer_string_is_empty(s->ssl_acme_tls_1))
+ ? alpn_protos_http_acme
+ : alpn_protos_http;
+ rc = mbedtls_ssl_conf_alpn_protocols(s->ssl_ctx, alpn_protos);
+ if (0 != rc) {
+ elog(srv->errh, __FILE__, __LINE__, rc, "error setting ALPN protocols");
+ return -1;
+ }
+ #endif
+
+ if (!s->ssl_use_sslv3 && !s->ssl_use_sslv2)
+ mod_mbedtls_ssl_conf_proto(srv, s, NULL, 0); /* min */
+
+ if (s->ssl_conf_cmd && s->ssl_conf_cmd->used) {
+ if (0 != mod_mbedtls_ssl_conf_cmd(srv, s)) return -1;
+ }
+
+ /* server preference is used (default) unless mbedtls is built with
+ * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE defined (not default) */
+ #ifndef MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
+ if (!s->ssl_honor_cipher_order)
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: "
+ "ignoring ssl.honor-cipher-order; mbedtls uses server preference "
+ "unless mbedtls built MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE");
+ #else
+ if (s->ssl_honor_cipher_order)
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: "
+ "ignoring ssl.honor-cipher-order; mbedtls uses client preference "
+ "since mbedtls built MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE");
+ #endif
+
+ #if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ if (s->ssl_session_ticket && !p->ticket_ctx.ticket_lifetime) { /*init once*/
+ rc = mbedtls_ssl_ticket_setup(&p->ticket_ctx, mbedtls_ctr_drbg_random,
+ &p->ctr_drbg, MBEDTLS_CIPHER_AES_256_GCM,
+ 43200); /* ticket timeout: 12 hours */
+ if (0 != rc) {
+ elog(srv->errh, __FILE__,__LINE__, rc,
+ "mbedtls_ssl_ticket_setup()");
+ return -1;
+ }
+ }
+
+ #if defined(MBEDTLS_SSL_TICKET_C)
+ if (s->ssl_session_ticket)
+ mbedtls_ssl_conf_session_tickets_cb(s->ssl_ctx,
+ mbedtls_ssl_ticket_write,
+ mbedtls_ssl_ticket_parse,
+ &p->ticket_ctx);
+ #endif
+ #endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+ return 0;
+}
+
+
+static int
+mod_mbedtls_set_defaults_sockets(server *srv, plugin_data *p)
+{
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("ssl.engine"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.cipher-list"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.honor-cipher-order"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.dh-file"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.ec-curve"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.openssl.ssl-conf-cmd"),
+ T_CONFIG_ARRAY_KVSTRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.pemfile"), /* included to process global scope */
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.empty-fragments"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.use-sslv2"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.use-sslv3"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+ static const buffer default_ssl_cipher_list = { CONST_STR_LEN("HIGH"), 0 };
+
+ p->ssl_ctxs = calloc(srv->config_context->used, sizeof(plugin_ssl_ctx));
+ force_assert(p->ssl_ctxs);
+
+ int rc = HANDLER_GO_ON;
+ plugin_data_base srvplug;
+ memset(&srvplug, 0, sizeof(srvplug));
+ plugin_data_base * const ps = &srvplug;
+ if (!config_plugin_values_init(srv, ps, cpk, "mod_mbedtls"))
+ return HANDLER_ERROR;
+
+ plugin_config_socket defaults;
+ memset(&defaults, 0, sizeof(defaults));
+ #ifndef MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
+ defaults.ssl_honor_cipher_order = 1;
+ #endif
+ defaults.ssl_session_ticket = 0; /* disabled by default */
+ defaults.ssl_cipher_list = &default_ssl_cipher_list;
+
+ /* process and validate config directives for global and $SERVER["socket"]
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !ps->cvlist[0].v.u2[1]; i < ps->nconfig; ++i) {
+ config_cond_info cfginfo;
+ config_get_config_cond_info(&cfginfo, (uint32_t)ps->cvlist[i].k_id);
+ int is_socket_scope = (0 == i || cfginfo.comp == COMP_SERVER_SOCKET);
+ int count_not_engine = 0;
+
+ plugin_config_socket conf;
+ memcpy(&conf, &defaults, sizeof(conf));
+
+ /*(preserve prior behavior; not inherited)*/
+ /*(forcing inheritance might break existing configs where SSL is enabled
+ * by default in the global scope, but not $SERVER["socket"]=="*:80") */
+ conf.ssl_enabled = 0;
+
+ config_plugin_value_t *cpv = ps->cvlist + ps->cvlist[i].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ /* ignore ssl.pemfile (k_id=10); included to process global scope */
+ if (!is_socket_scope && cpv->k_id != 10) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: %s is valid only in global scope or "
+ "$SERVER[\"socket\"] condition", cpk[cpv->k_id].k);
+ continue;
+ }
+ ++count_not_engine;
+ switch (cpv->k_id) {
+ case 0: /* ssl.engine */
+ conf.ssl_enabled = (0 != cpv->v.u);
+ --count_not_engine;
+ break;
+ case 1: /* ssl.cipher-list */
+ conf.ssl_cipher_list = cpv->v.b;
+ break;
+ case 2: /* ssl.honor-cipher-order */
+ conf.ssl_honor_cipher_order = (0 != cpv->v.u);
+ break;
+ case 3: /* ssl.dh-file */
+ conf.ssl_dh_file = cpv->v.b;
+ break;
+ case 4: /* ssl.ec-curve */
+ conf.ssl_ec_curve = cpv->v.b;
+ break;
+ case 5: /* ssl.openssl.ssl-conf-cmd */
+ *(const array **)&conf.ssl_conf_cmd = cpv->v.a;
+ break;
+ case 6: /* ssl.pemfile */
+ /* ignore here; included to process global scope when
+ * ssl.pemfile is set, but ssl.engine is not "enable" */
+ break;
+ case 7: /* ssl.empty-fragments */
+ conf.ssl_empty_fragments = (0 != cpv->v.u);
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ignoring ssl.empty-fragments; openssl-specific "
+ "counter-measure against a SSL 3.0/TLS 1.0 protocol "
+ "vulnerability affecting CBC ciphers, which cannot be handled"
+ " by some broken (Microsoft) SSL implementations.");
+ break;
+ case 8: /* ssl.use-sslv2 */
+ conf.ssl_use_sslv2 = (0 != cpv->v.u);
+ log_error(srv->errh, __FILE__, __LINE__, "MTLS: "
+ "ssl.use-sslv2 is deprecated and will soon be removed. "
+ "Many modern TLS libraries no longer support SSLv2.");
+ break;
+ case 9: /* ssl.use-sslv3 */
+ conf.ssl_use_sslv3 = (0 != cpv->v.u);
+ log_error(srv->errh, __FILE__, __LINE__, "MTLS: "
+ "ssl.use-sslv3 is deprecated and will soon be removed. "
+ "Many modern TLS libraries no longer support SSLv3. "
+ "If needed, use: "
+ "ssl.openssl.ssl-conf-cmd = (\"MinProtocol\" => \"SSLv3\")");
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+ if (HANDLER_GO_ON != rc) break;
+ if (0 == i) memcpy(&defaults, &conf, sizeof(conf));
+
+ if (0 != i && !conf.ssl_enabled) continue;
+
+ /* fill plugin_config_socket with global context then $SERVER["socket"]
+ * only for directives directly in current $SERVER["socket"] condition*/
+
+ /*conf.ssl_pemfile_pkey = p->defaults.ssl_pemfile_pkey;*/
+ /*conf.ssl_pemfile_x509 = p->defaults.ssl_pemfile_x509;*/
+ conf.ssl_verifyclient = p->defaults.ssl_verifyclient;
+ conf.ssl_verifyclient_enforce = p->defaults.ssl_verifyclient_enforce;
+ conf.ssl_verifyclient_depth = p->defaults.ssl_verifyclient_depth;
+ conf.ssl_acme_tls_1 = p->defaults.ssl_acme_tls_1;
+
+ int sidx = ps->cvlist[i].k_id;
+ for (int j = !p->cvlist[0].v.u2[1]; j < p->nconfig; ++j) {
+ if (p->cvlist[j].k_id != sidx) continue;
+ /*if (0 == sidx) break;*//*(repeat to get ssl_pemfile,ssl_privkey)*/
+ cpv = p->cvlist + p->cvlist[j].v.u2[0];
+ for (; -1 != cpv->k_id; ++cpv) {
+ ++count_not_engine;
+ switch (cpv->k_id) {
+ case 0: /* ssl.pemfile */
+ if (cpv->vtype == T_CONFIG_LOCAL) {
+ plugin_cert *pc = cpv->v.v;
+ conf.pc = pc;
+ conf.ssl_pemfile_pkey = &pc->ssl_pemfile_pkey;
+ conf.ssl_pemfile_x509 = &pc->ssl_pemfile_x509;
+ conf.ssl_pemfile = pc->ssl_pemfile;
+ conf.ssl_privkey = pc->ssl_privkey;
+ }
+ break;
+ case 2: /* ssl.ca-file */
+ if (cpv->vtype == T_CONFIG_LOCAL)
+ conf.ssl_ca_file = cpv->v.v;
+ break;
+ case 7: /* ssl.verifyclient.activate */
+ conf.ssl_verifyclient = (0 != cpv->v.u);
+ break;
+ case 8: /* ssl.verifyclient.enforce */
+ conf.ssl_verifyclient_enforce = (0 != cpv->v.u);
+ break;
+ case 9: /* ssl.verifyclient.depth */
+ conf.ssl_verifyclient_depth = (unsigned char)cpv->v.shrt;
+ break;
+ case 13:/* ssl.acme-tls-1 */
+ conf.ssl_acme_tls_1 = cpv->v.b;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ if (NULL == conf.ssl_pemfile_x509) {
+ if (0 == i && !conf.ssl_enabled) continue;
+ if (0 != i) {
+ /* inherit ssl settings from global scope
+ * (if only ssl.engine = "enable" and no other ssl.* settings)
+ * (This is for convenience when defining both IPv4 and IPv6
+ * and desiring to inherit the ssl config from global context
+ * without having to duplicate the directives)*/
+ if (count_not_engine) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ssl.pemfile has to be set in same "
+ "$SERVER[\"socket\"] scope as other ssl.* directives, "
+ "unless only ssl.engine is set, inheriting ssl.* from "
+ "global scope");
+ rc = HANDLER_ERROR;
+ continue;
+ }
+ plugin_ssl_ctx * const s = p->ssl_ctxs + sidx;
+ *s = *p->ssl_ctxs;/*(copy struct of ssl_ctx from global scope)*/
+ continue;
+ }
+ /* PEM file is required */
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ssl.pemfile has to be set when ssl.engine = \"enable\"");
+ rc = HANDLER_ERROR;
+ continue;
+ }
+
+ /* (initialize once if module enabled) */
+ if (!mod_mbedtls_init_once_mbedtls(srv)) {
+ rc = HANDLER_ERROR;
+ break;
+ }
+
+ /* configure ssl_ctx for socket */
+
+ /*conf.ssl_ctx = NULL;*//*(filled by network_init_ssl() even on error)*/
+ if (0 == network_init_ssl(srv, &conf, p)) {
+ plugin_ssl_ctx * const s = p->ssl_ctxs + sidx;
+ s->ssl_ctx = conf.ssl_ctx;
+ s->ciphersuites = conf.ciphersuites;
+ s->curves = conf.curves;
+ }
+ else {
+ mbedtls_ssl_config_free(conf.ssl_ctx);
+ free(conf.ciphersuites);
+ free(conf.curves);
+ rc = HANDLER_ERROR;
+ }
+ }
+
+ free(srvplug.cvlist);
+ return rc;
+}
+
+
+SETDEFAULTS_FUNC(mod_mbedtls_set_defaults)
+{
+ static const config_plugin_keys_t cpk[] = {
+ { CONST_STR_LEN("ssl.pemfile"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.privkey"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.ca-file"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.ca-dn-file"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.ca-crl-file"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.read-ahead"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.disable-client-renegotiation"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.verifyclient.activate"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.verifyclient.enforce"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.verifyclient.depth"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.verifyclient.username"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.verifyclient.exportcert"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("ssl.acme-tls-1"),
+ T_CONFIG_STRING,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ CONST_STR_LEN("debug.log-ssl-noise"),
+ T_CONFIG_SHORT,
+ T_CONFIG_SCOPE_CONNECTION }
+ ,{ NULL, 0,
+ T_CONFIG_UNSET,
+ T_CONFIG_SCOPE_UNSET }
+ };
+
+ plugin_data * const p = p_d;
+ p->srv = srv;
+ if (!config_plugin_values_init(srv, p, cpk, "mod_mbedtls"))
+ return HANDLER_ERROR;
+
+ /* process and validate config directives
+ * (init i to 0 if global context; to 1 to skip empty global context) */
+ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) {
+ config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0];
+ config_plugin_value_t *pemfile = NULL;
+ config_plugin_value_t *privkey = NULL;
+ for (; -1 != cpv->k_id; ++cpv) {
+ switch (cpv->k_id) {
+ case 0: /* ssl.pemfile */
+ if (!buffer_string_is_empty(cpv->v.b)) pemfile = cpv;
+ break;
+ case 1: /* ssl.privkey */
+ if (!buffer_string_is_empty(cpv->v.b)) privkey = cpv;
+ break;
+ case 2: /* ssl.ca-file */
+ case 3: /* ssl.ca-dn-file */
+ #if 0 /* defer; not necessary for pemfile parsing */
+ if (!mod_mbedtls_init_once_mbedtls(srv)) return HANDLER_ERROR;
+ #endif
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ mbedtls_x509_crt *cacert = calloc(1, sizeof(*cacert));
+ force_assert(cacert);
+ mbedtls_x509_crt_init(cacert);
+ int rc = mbedtls_x509_crt_parse_file(cacert, cpv->v.b->ptr);
+ if (0 == rc) {
+ cpv->vtype = T_CONFIG_LOCAL;
+ cpv->v.v = cacert;
+ }
+ else {
+ elogf(srv->errh, __FILE__, __LINE__, rc,
+ "%s = %s", cpk[cpv->k_id].k, cpv->v.b->ptr);
+ mbedtls_x509_crt_free(cacert);
+ free(cacert);
+ return HANDLER_ERROR;
+ }
+ }
+ break;
+ case 4: /* ssl.ca-crl-file */
+ if (!buffer_string_is_empty(cpv->v.b)) {
+ mbedtls_x509_crl *crl = malloc(sizeof(*crl));
+ force_assert(crl);
+ mbedtls_x509_crl_init(crl);
+ int rc = mbedtls_x509_crl_parse_file(crl, cpv->v.b->ptr);
+ if (0 == rc) {
+ cpv->vtype = T_CONFIG_LOCAL;
+ cpv->v.v = crl;
+ }
+ else {
+ elogf(srv->errh, __FILE__, __LINE__, rc,
+ "CRL file read failed (%s)", cpv->v.b->ptr);
+ free(crl);
+ return HANDLER_ERROR;
+ }
+ }
+ break;
+ case 5: /* ssl.read-ahead */
+ case 6: /* ssl.disable-client-renegotiation */
+ case 7: /* ssl.verifyclient.activate */
+ case 8: /* ssl.verifyclient.enforce */
+ break;
+ case 9: /* ssl.verifyclient.depth */
+ if (cpv->v.shrt > 255) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: %s is absurdly large (%hu); limiting to 255",
+ cpk[cpv->k_id].k, cpv->v.shrt);
+ cpv->v.shrt = 255;
+ }
+ break;
+ case 10:/* ssl.verifyclient.username */
+ case 11:/* ssl.verifyclient.exportcert */
+ case 12:/* ssl.acme-tls-1 */
+ case 13:/* debug.log-ssl-noise */
+ break;
+ default:/* should not happen */
+ break;
+ }
+ }
+
+ if (pemfile) {
+ if (NULL == privkey) privkey = pemfile;
+ pemfile->v.v =
+ network_mbedtls_load_pemfile(srv, pemfile->v.b, privkey->v.b);
+ if (pemfile->v.v)
+ pemfile->vtype = T_CONFIG_LOCAL;
+ else
+ return HANDLER_ERROR;
+ }
+ }
+
+ p->defaults.ssl_verifyclient = 0;
+ p->defaults.ssl_verifyclient_enforce = 1;
+ p->defaults.ssl_verifyclient_depth = 9;
+ p->defaults.ssl_verifyclient_export_cert = 0;
+ p->defaults.ssl_disable_client_renegotiation = 1;
+ p->defaults.ssl_read_ahead = 0;
+
+ /* initialize p->defaults from global config context */
+ if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
+ const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
+ if (-1 != cpv->k_id)
+ mod_mbedtls_merge_config(&p->defaults, cpv);
+ }
+
+ #ifndef MBEDTLS_ERROR_C
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: No error strings available. "
+ "Compile mbedtls with MBEDTLS_ERROR_C to enable.");
+ #endif
+
+ return mod_mbedtls_set_defaults_sockets(srv, p);
+}
+
+
+static int
+load_next_chunk (request_st * const r, chunkqueue * const cq, off_t max_bytes,
+ const char ** const data, size_t * const data_len)
+{
+ chunk *c = cq->first;
+
+ /* local_send_buffer is a static buffer of size (LOCAL_SEND_BUFSIZE)
+ *
+ * buffer is allocated once, is NOT realloced (note: not thread-safe)
+ * */
+
+ force_assert(NULL != c);
+
+ switch (c->type) {
+ case MEM_CHUNK:
+ *data = NULL;
+ *data_len = 0;
+ do {
+ size_t have;
+
+ force_assert(c->offset >= 0
+ && c->offset <= (off_t)buffer_string_length(c->mem));
+
+ have = buffer_string_length(c->mem) - c->offset;
+
+ /* copy small mem chunks into single large buffer
+ * before mbedtls_ssl_write() to reduce number times
+ * write() called underneath mbedtls_ssl_write() and
+ * potentially reduce number of packets generated if TCP_NODELAY */
+ if (*data_len) {
+ size_t space = LOCAL_SEND_BUFSIZE - *data_len;
+ if (have > space)
+ have = space;
+ if (have > (size_t)max_bytes - *data_len)
+ have = (size_t)max_bytes - *data_len;
+ if (*data != local_send_buffer) {
+ memcpy(local_send_buffer, *data, *data_len);
+ *data = local_send_buffer;
+ }
+ memcpy(local_send_buffer+*data_len,c->mem->ptr+c->offset,have);
+ *data_len += have;
+ continue;
+ }
+
+ if ((off_t) have > max_bytes) have = max_bytes;
+
+ *data = c->mem->ptr + c->offset;
+ *data_len = have;
+ } while ((c = c->next) && c->type == MEM_CHUNK
+ && *data_len < LOCAL_SEND_BUFSIZE
+ && (off_t) *data_len < max_bytes);
+ return 0;
+
+ case FILE_CHUNK:
+ if (0 != chunkqueue_open_file_chunk(cq, r->conf.errh)) return -1;
+
+ {
+ off_t offset, toSend;
+
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+
+ if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
+ if (toSend > max_bytes) toSend = max_bytes;
+
+ if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
+ log_perror(r->conf.errh, __FILE__, __LINE__, "lseek");
+ return -1;
+ }
+ if (-1 == (toSend = read(c->file.fd, local_send_buffer, toSend))) {
+ log_perror(r->conf.errh, __FILE__, __LINE__, "read");
+ return -1;
+ }
+
+ *data = local_send_buffer;
+ *data_len = toSend;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+
+__attribute_cold__
+static int
+mod_mbedtls_ssl_write_err(connection *con, handler_ctx *hctx, int wr, size_t wr_len)
+{
+ switch (wr) {
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ con->is_readable = -1;
+ break; /* try again later */
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ con->is_writable = -1;
+ break; /* try again later */
+ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
+ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+ break; /* try again later */
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ if (hctx->conf.ssl_log_noise)
+ elog(hctx->r->conf.errh, __FILE__, __LINE__, wr,
+ "peer closed connection");
+ return -1;
+ default:
+ elog(hctx->r->conf.errh, __FILE__, __LINE__, wr, __func__);
+ return -1;
+ }
+
+ if (0 != hctx->ssl.out_left) /* partial write; save attempted wr_len */
+ hctx->pending_write = wr_len;
+
+ return 0; /* try again later */
+}
+
+
+static int
+mod_mbedtls_close_notify(handler_ctx *hctx);
+
+
+static int
+connection_write_cq_ssl (connection *con, chunkqueue *cq, off_t max_bytes)
+{
+ request_st * const r = &con->request;
+ handler_ctx *hctx = r->plugin_ctx[plugin_data_singleton->id];
+ mbedtls_ssl_context * const ssl = &hctx->ssl;
+
+ if (hctx->pending_write) {
+ int wr = (int)hctx->pending_write;
+ if (0 != ssl->out_left) {
+ /*(would prefer mbedtls_ssl_flush_output() from ssl_internal.h)*/
+ size_t data_len = hctx->pending_write;
+ wr = mbedtls_ssl_write(ssl, NULL, data_len);
+ if (wr <= 0)
+ return mod_mbedtls_ssl_write_err(con, hctx, wr, data_len);
+ max_bytes -= wr;
+ }
+ hctx->pending_write = 0;
+ chunkqueue_mark_written(cq, wr);
+ }
+
+ if (0 != hctx->close_notify) return mod_mbedtls_close_notify(hctx);
+
+ chunkqueue_remove_finished_chunks(cq);
+
+ const int lim = mbedtls_ssl_get_max_out_record_payload(ssl);
+ if (lim < 0) return mod_mbedtls_ssl_write_err(con, hctx, lim, 0);
+
+ while (max_bytes > 0 && NULL != cq->first) {
+ const char *data;
+ size_t data_len;
+ int wr;
+
+ if (0 != load_next_chunk(r, cq, max_bytes, &data, &data_len)) return -1;
+
+ /* mbedtls_ssl_write() copies the data, up to max record size, but if
+ * (temporarily) unable to write the entire record, it is documented
+ * that the caller must call mbedtls_ssl_write() again, later, with the
+ * same arguments. This appears to be because mbedtls_ssl_context does
+ * not keep track of the original size of the caller data that
+ * mbedtls_ssl_write() attempted to write (and may have transformed to
+ * a different size). The func may return MBEDTLS_ERR_SSL_WANT_READ or
+ * MBEDTLS_ERR_SSL_WANT_WRITE to indicate that the caller should wait
+ * for the fd to be readable/writable before calling the func again,
+ * which is why those (temporary) errors are returned instead of telling
+ * the caller that the data was successfully copied. When the record is
+ * written successfully, the return value is supposed to indicate the
+ * number of (originally submitted) bytes written, but since that value
+ * is unknown (not saved), the caller's len parameter is reflected back,
+ * which is why the caller must call the func again with the same args.
+ * Additionally, to be accurate, the size must fit into a record which
+ * is why we restrict ourselves to sending max out record payload each
+ * iteration.
+ */
+
+ int wr_total = 0;
+ do {
+ size_t wr_len = (data_len > (size_t)lim) ? (size_t)lim : data_len;
+ wr = mbedtls_ssl_write(ssl, (const unsigned char *)data, wr_len);
+ if (wr <= 0) {
+ if (wr_total) chunkqueue_mark_written(cq, wr_total);
+ return mod_mbedtls_ssl_write_err(con, hctx, wr, wr_len);
+ }
+ wr_total += wr;
+ data += wr;
+ } while ((data_len -= wr));
+ chunkqueue_mark_written(cq, wr_total);
+ max_bytes -= wr_total;
+ }
+
+ return 0;
+}
+
+
+static int
+mod_mbedtls_ssl_handshake (handler_ctx *hctx)
+{
+ int rc = 0;
+
+ /* overwrite callback with hctx each time we enter here, before handshake
+ * (Some callbacks are on mbedtls_ssl_config, not mbedtls_ssl_context)
+ * (Not thread-safe if config (mbedtls_ssl_config *ssl_ctx) is shared)
+ * (XXX: there is probably a better way to do this...) */
+ /* (alternative: save ssl_ctx in hctx in mod_mbedtls_handle_con_accept()) */
+ mbedtls_ssl_config *ssl_ctx;
+ *(const mbedtls_ssl_config **)&ssl_ctx = hctx->ssl.conf;
+ #ifdef MBEDTLS_SSL_SERVER_NAME_INDICATION
+ mbedtls_ssl_conf_sni(ssl_ctx, mod_mbedtls_SNI, hctx);
+ #endif
+
+ if (hctx->ssl.state < MBEDTLS_SSL_SERVER_HELLO) {
+ while (hctx->ssl.state != MBEDTLS_SSL_SERVER_HELLO
+ && hctx->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
+ rc = mbedtls_ssl_handshake_step(&hctx->ssl);
+ if (0 != rc) break;
+ }
+ if (0 == rc && hctx->ssl.state == MBEDTLS_SSL_SERVER_HELLO) {
+ #ifdef MBEDTLS_SSL_ALPN
+ if (!buffer_string_is_empty(hctx->conf.ssl_acme_tls_1)) {
+ const char *alpn = mbedtls_ssl_get_alpn_protocol(&hctx->ssl);
+ if (NULL != alpn)
+ rc = mod_mbedtls_alpn_select_cb(hctx, alpn);
+ }
+ #endif
+ }
+ }
+
+ /* overwrite callback with hctx each time we enter here, before handshake
+ * (Some callbacks are on mbedtls_ssl_config, not mbedtls_ssl_context)
+ * (Not thread-safe if config (mbedtls_ssl_config *ssl_ctx) is shared)
+ * (XXX: there is probably a better way to do this...) */
+ if (0 == rc && hctx->conf.ssl_verifyclient
+ && hctx->ssl.state >= MBEDTLS_SSL_SERVER_HELLO /*(after SNI and ALPN)*/
+ && hctx->ssl.state <= MBEDTLS_SSL_SERVER_HELLO_DONE
+ && hctx->alpn != MOD_MBEDTLS_ALPN_ACME_TLS_1) { /*(not "acme-tls/1")*/
+ int mode = (hctx->conf.ssl_verifyclient_enforce)
+ ? MBEDTLS_SSL_VERIFY_REQUIRED
+ : MBEDTLS_SSL_VERIFY_OPTIONAL;
+ mbedtls_ssl_set_hs_authmode(&hctx->ssl, mode);
+ while (hctx->ssl.state != MBEDTLS_SSL_CERTIFICATE_REQUEST
+ && hctx->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
+ rc = mbedtls_ssl_handshake_step(&hctx->ssl);
+ if (0 != rc) break;
+ }
+ if (0 == rc && hctx->ssl.state == MBEDTLS_SSL_CERTIFICATE_REQUEST) {
+ rc = mod_mbedtls_conf_verify(hctx, ssl_ctx);
+ if (0 == rc)
+ rc = mbedtls_ssl_handshake_step(&hctx->ssl);
+ /* reconfigure CA trust chain after sending client certificate
+ * request (if ssl_ca_dn_file is set), before client certificate
+ * verification (MBEDTLS_SSL_CERTIFICATE_VERIFY) */
+ if (0 == rc && hctx->conf.ssl_ca_dn_file
+ && hctx->ssl.state == MBEDTLS_SSL_SERVER_HELLO_DONE) {
+ mbedtls_ssl_context * const ssl = &hctx->ssl;
+ mbedtls_x509_crt *ca_certs = hctx->conf.ssl_ca_file;
+ mbedtls_x509_crl *ca_crl = hctx->conf.ssl_ca_crl_file;
+ mbedtls_ssl_set_hs_ca_chain(ssl, ca_certs, ca_crl);
+ }
+ }
+ }
+
+ if (0 == rc && hctx->ssl.state != MBEDTLS_SSL_HANDSHAKE_OVER) {
+ rc = mbedtls_ssl_handshake(&hctx->ssl);
+ }
+
+ switch (rc) {
+ case 0:
+ hctx->handshake_done = 1;
+ #ifdef MBEDTLS_SSL_ALPN
+ if (hctx->alpn == MOD_MBEDTLS_ALPN_ACME_TLS_1) {
+ /* Once TLS handshake is complete, return -1 to result in
+ * CON_STATE_ERROR so that socket connection is quickly closed */
+ return -1;
+ }
+ hctx->alpn = 0;
+ #endif
+ return 1; /* continue reading */
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ hctx->con->is_writable = -1;
+ __attribute_fallthrough__
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ hctx->con->is_readable = 0;
+ return 0;
+ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
+ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+ return 0;
+ case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
+ return -1;
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ case MBEDTLS_ERR_SSL_CONN_EOF:
+ if (!hctx->conf.ssl_log_noise) return -1;
+ __attribute_fallthrough__
+ default:
+ elog(hctx->r->conf.errh, __FILE__, __LINE__, rc, __func__);
+ return -1;
+ }
+}
+
+
+static int
+connection_read_cq_ssl (connection *con, chunkqueue *cq, off_t max_bytes)
+{
+ request_st * const r = &con->request;
+ handler_ctx *hctx = r->plugin_ctx[plugin_data_singleton->id];
+ int len;
+ char *mem = NULL;
+ size_t mem_len = 0;
+
+ UNUSED(max_bytes);
+
+ if (0 != hctx->close_notify) return mod_mbedtls_close_notify(hctx);
+
+ if (!hctx->handshake_done) {
+ int rc = mod_mbedtls_ssl_handshake(hctx);
+ if (1 != rc) return rc; /* !hctx->handshake_done; not done, or error */
+ }
+
+ do {
+ len = mbedtls_ssl_get_bytes_avail(&hctx->ssl);
+ mem_len = len < 2048 ? 2048 : (size_t)len;
+ chunk * const ckpt = cq->last;
+ mem = chunkqueue_get_memory(cq, &mem_len);
+
+ len = mbedtls_ssl_read(&hctx->ssl, (unsigned char *)mem, mem_len);
+ if (len > 0) {
+ chunkqueue_use_memory(cq, ckpt, len);
+ con->bytes_read += len;
+ } else {
+ chunkqueue_use_memory(cq, ckpt, 0);
+ }
+ } while (len > 0
+ && mbedtls_ssl_check_pending(&hctx->ssl));
+
+ if (len < 0) {
+ int rc = len;
+ switch (rc) {
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ con->is_writable = -1;
+ __attribute_fallthrough__
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ con->is_readable = 0;
+ return 0;
+ case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
+ case MBEDTLS_ERR_SSL_CONN_EOF:
+ /* XXX: future: save state to avoid future read after response? */
+ con->is_readable = 0;
+ r->keep_alive = 0;
+ return -2;
+ case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
+ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+ return 0;
+ case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
+ return -1;
+ case MBEDTLS_ERR_NET_CONN_RESET:
+ if (!hctx->conf.ssl_log_noise) return -1;
+ __attribute_fallthrough__
+ default:
+ elog(r->conf.errh, __FILE__, __LINE__, rc, "Reading mbedtls");
+ return -1;
+ }
+ } else if (len == 0) {
+ con->is_readable = 0;
+ /* the other end closed the connection -> KEEP-ALIVE */
+
+ return -2;
+ } else {
+ return 0;
+ }
+}
+
+
+static void
+mod_mbedtls_debug_cb(void *ctx, int level,
+ const char *file, int line,
+ const char *str)
+{
+ if (level < (intptr_t)ctx) /* level */
+ log_error(plugin_data_singleton->srv->errh,file,line,"MTLS: %s",str);
+}
+
+
+CONNECTION_FUNC(mod_mbedtls_handle_con_accept)
+{
+ server_socket *srv_sock = con->srv_socket;
+ if (!srv_sock->is_ssl) return HANDLER_GO_ON;
+
+ plugin_data *p = p_d;
+ handler_ctx * const hctx = handler_ctx_init();
+ request_st * const r = &con->request;
+ hctx->r = r;
+ hctx->con = con;
+ hctx->tmp_buf = con->srv->tmp_buf;
+ r->plugin_ctx[p->id] = hctx;
+
+ plugin_ssl_ctx * const s = p->ssl_ctxs + srv_sock->sidx;
+ mbedtls_ssl_init(&hctx->ssl);
+ int rc = mbedtls_ssl_setup(&hctx->ssl, s->ssl_ctx);
+ if (0 == rc) {
+ con->network_read = connection_read_cq_ssl;
+ con->network_write = connection_write_cq_ssl;
+ con->proto_default_port = 443; /* "https" */
+ mod_mbedtls_patch_config(r, &hctx->conf);
+ }
+ else {
+ elog(r->conf.errh, __FILE__, __LINE__, rc, "ssl_setup() failed");
+ return HANDLER_ERROR;
+ }
+
+ mbedtls_ssl_set_bio(&hctx->ssl, (mbedtls_net_context *)&con->fd,
+ mbedtls_net_send, mbedtls_net_recv, NULL);
+
+ /* (mbedtls_ssl_config *) is shared across multiple connections, which may
+ * overlap, and so this debug setting is not reset upon connection close.
+ * Once enabled, debug hook will remain so for this mbedtls_ssl_config */
+ if (hctx->conf.ssl_log_noise) /* volume level for debug message callback */
+ mbedtls_ssl_conf_dbg(s->ssl_ctx, mod_mbedtls_debug_cb,
+ (void *)(intptr_t)hctx->conf.ssl_log_noise);
+
+ /* (mbedtls_ssl_config *) is shared across multiple connections, which may
+ * overlap, and so renegotiation setting is not reset upon connection close.
+ * Once enabled, renegotiation will remain so for this mbedtls_ssl_config.
+ * mbedtls defaults to disable client renegotiation
+ * (MBEDTLS_SSL_RENEGOTIATION_DISABLED)
+ * and it is recommended to leave it disabled (lighttpd mbedtls default) */
+ if (!hctx->conf.ssl_disable_client_renegotiation)
+ mbedtls_ssl_conf_renegotiation(s->ssl_ctx,
+ MBEDTLS_SSL_RENEGOTIATION_ENABLED);
+
+ return HANDLER_GO_ON;
+}
+
+
+static void
+mod_mbedtls_detach(handler_ctx *hctx)
+{
+ /* step aside from further SSL processing
+ * (used after handle_connection_shut_wr hook) */
+ /* future: might restore prior network_read and network_write fn ptrs */
+ hctx->con->is_ssl_sock = 0;
+ /* if called after handle_connection_shut_wr hook, shutdown SHUT_WR */
+ if (-1 == hctx->close_notify) shutdown(hctx->con->fd, SHUT_WR);
+ hctx->close_notify = 1;
+}
+
+
+CONNECTION_FUNC(mod_mbedtls_handle_con_shut_wr)
+{
+ request_st * const r = &con->request;
+ plugin_data *p = p_d;
+ handler_ctx *hctx = r->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+
+ hctx->close_notify = -2;
+ if (hctx->handshake_done) {
+ mod_mbedtls_close_notify(hctx);
+ }
+ else {
+ mod_mbedtls_detach(hctx);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+static int
+mod_mbedtls_close_notify (handler_ctx *hctx)
+{
+ if (1 == hctx->close_notify) return -2;
+
+ int rc = mbedtls_ssl_close_notify(&hctx->ssl);
+ switch (rc) {
+ case 0:
+ mod_mbedtls_detach(hctx);
+ return -2;
+ case MBEDTLS_ERR_SSL_WANT_READ:
+ case MBEDTLS_ERR_SSL_WANT_WRITE:
+ return 0;
+ default:
+ elog(hctx->r->conf.errh, __FILE__, __LINE__, rc,
+ "mbedtls_ssl_close_notify()");
+ mbedtls_ssl_session_reset(&hctx->ssl);
+ mod_mbedtls_detach(hctx);
+ return -1;
+ }
+}
+
+
+CONNECTION_FUNC(mod_mbedtls_handle_con_close)
+{
+ request_st * const r = &con->request;
+ plugin_data *p = p_d;
+ handler_ctx *hctx = r->plugin_ctx[p->id];
+ if (NULL != hctx) {
+ if (1 != hctx->close_notify)
+ mod_mbedtls_close_notify(hctx); /*(one final try)*/
+ handler_ctx_free(hctx);
+ r->plugin_ctx[p->id] = NULL;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+#if defined(MBEDTLS_PEM_WRITE_C)
+__attribute_noinline__
+static void
+https_add_ssl_client_cert (request_st * const r, const mbedtls_x509_crt * const peer)
+{
+ #define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
+ #define PEM_END_CRT "-----END CERTIFICATE-----\n"
+ unsigned char buf[4096];
+ size_t olen;
+ if (0 == mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT,
+ peer->raw.p, peer->raw.len,
+ buf, sizeof(buf), &olen))
+ http_header_env_set(r,
+ CONST_STR_LEN("SSL_CLIENT_CERT"),
+ (char *)buf, olen);
+}
+#endif
+
+
+static void
+https_add_ssl_client_entries (request_st * const r, handler_ctx * const hctx)
+{
+ /* Note: starting with mbedtls-2.17.0, peer cert is not available here if
+ * MBEDTLS_SSL_KEEP_PEER_CERTIFICATE *is not* defined at compile time,
+ * though default behavior is to have it defined. However, since earlier
+ * versions do keep the cert, but not set this define, attempt to retrieve
+ * the peer cert and check for NULL before using it. */
+ const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&hctx->ssl);
+ buffer * const tb = r->tmp_buf;
+ char buf[512];
+ int n;
+
+ uint32_t rc = (NULL != crt)
+ ? mbedtls_ssl_get_verify_result(&hctx->ssl)
+ : 0xFFFFFFFF;
+ if (0xFFFFFFFF == rc) { /*(e.g. no cert, or verify result not available)*/
+ http_header_env_set(r,
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"),
+ CONST_STR_LEN("NONE"));
+ return;
+ }
+ else if (0 != rc) {
+ /* get failure string and translate newline to ':', removing last one */
+ n = mbedtls_x509_crt_verify_info(buf, sizeof(buf), "", rc);
+ buffer_copy_string_len(tb, CONST_STR_LEN("FAILED:"));
+ if (n > 0) {
+ for (char *nl = buf; NULL != (nl = strchr(nl, '\n')); ++nl)
+ nl[0] = ('\0' == nl[1] ? (--n, '\0') : ':');
+ buffer_append_string_len(tb, buf, n);
+ }
+ http_header_env_set(r,
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"),
+ CONST_BUF_LEN(tb));
+ return;
+ }
+ else {
+ http_header_env_set(r,
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"),
+ CONST_STR_LEN("SUCCESS"));
+ }
+
+ n = mbedtls_x509_dn_gets(buf, sizeof(buf), &crt->subject);
+ if (n > 0 && n < (int)sizeof(buf)) {
+ http_header_env_set(r,
+ CONST_STR_LEN("SSL_CLIENT_S_DN"),
+ buf, n);
+ }
+
+ /* add components of client Subject DN */
+ /* code block is similar to mbedtls_x509_dn_gets() */
+ /*(reuse buf; sizeof(buf) > MBEDTLS_X509_MAX_DN_NAME_SIZE, which is 256)*/
+ buffer_copy_string_len(tb, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
+ const mbedtls_x509_name *name = &crt->subject;
+ while (name != NULL) {
+ if (!name->oid.p) {
+ name = name->next;
+ continue;
+ }
+
+ const char *short_name = NULL;
+ if (0 != mbedtls_oid_get_attr_short_name(&name->oid, &short_name))
+ continue;
+ buffer_string_set_length(tb, sizeof("SSL_CLIENT_S_DN_")-1);
+ buffer_append_string(tb, short_name);
+
+ const mbedtls_x509_name *nm = name;
+ n = 0;
+ do {
+ if (nm != name && n < (int)sizeof(buf)-1)
+ buf[n++] = ',';
+ for (size_t i = 0; i < nm->val.len && n < (int)sizeof(buf)-1; ++n) {
+ unsigned char c = nm->val.p[i];
+ buf[n] = (c < 32 || c == 127 || (c > 128 && c < 160)) ? '?' : c;
+ }
+ buf[n] = '\0';
+ } while (nm->next_merged && nm->next && (nm = nm->next));
+ if (n == sizeof(buf)-1)
+ while (nm->next_merged && nm->next) nm = nm->next;
+ name = nm->next;
+
+ http_header_env_set(r,
+ CONST_BUF_LEN(tb),
+ buf, n);
+ }
+
+ n = mbedtls_x509_serial_gets(buf, sizeof(buf), &crt->serial);
+ if (n > 0 && n < (int)sizeof(buf)) {
+ http_header_env_set(r,
+ CONST_STR_LEN("SSL_CLIENT_M_SERIAL"),
+ buf, n);
+ }
+
+ if (!buffer_string_is_empty(hctx->conf.ssl_verifyclient_username)) {
+ /* pick one of the exported values as "REMOTE_USER", for example
+ * ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID"
+ * or
+ * ssl.verifyclient.username = "SSL_CLIENT_S_DN_emailAddress"
+ */
+ const buffer *varname = hctx->conf.ssl_verifyclient_username;
+ const buffer *vb = http_header_env_get(r, CONST_BUF_LEN(varname));
+ if (vb) { /* same as http_auth.c:http_auth_setenv() */
+ http_header_env_set(r,
+ CONST_STR_LEN("REMOTE_USER"),
+ CONST_BUF_LEN(vb));
+ http_header_env_set(r,
+ CONST_STR_LEN("AUTH_TYPE"),
+ CONST_STR_LEN("SSL_CLIENT_VERIFY"));
+ }
+ }
+
+ #if defined(MBEDTLS_PEM_WRITE_C)
+ /* if (NULL != crt) (e.g. not PSK-based ciphersuite) */
+ if (hctx->conf.ssl_verifyclient_export_cert && NULL != crt)
+ https_add_ssl_client_cert(r, crt);
+ #endif
+}
+
+
+static void
+http_cgi_ssl_env (request_st * const r, handler_ctx * const hctx)
+{
+ #if 1
+ /* XXX: reaching into ssl_internal.h here for mbedtls_ssl_transform */
+ const mbedtls_cipher_info_t *cipher_info =
+ hctx->ssl.transform->cipher_ctx_enc.cipher_info;
+ #else
+ const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
+ mbedtls_ssl_ciphersuite_from_id(hctx->ssl.session->ciphersuite);
+ const mbedtls_cipher_info_t *cipher_info =
+ mbedtls_cipher_info_from_type(ciphersuite_info->cipher);
+ #endif
+ const char *s;
+
+ s = mbedtls_ssl_get_version(&hctx->ssl);
+ http_header_env_set(r, CONST_STR_LEN("SSL_PROTOCOL"), s, strlen(s));
+
+ /*s = ciphersuite_info->name;*/ /*mbedtls_ssl_get_ciphersuite(&hctx->ssl);*/
+ s = cipher_info->name;
+ http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER"), s, strlen(s));
+
+ if (cipher_info != NULL) {
+ /* SSL_CIPHER_ALGKEYSIZE - Number of cipher bits (possible) */
+ /* SSL_CIPHER_USEKEYSIZE - Number of cipher bits (actually used) */
+ /* XXX: is usekeysize correct? XXX: reaching into ssl_internal.h here */
+ int usekeysize = hctx->ssl.transform->cipher_ctx_enc.key_bitlen;
+ unsigned int algkeysize = cipher_info->key_bitlen;
+ char buf[LI_ITOSTRING_LENGTH];
+ http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_USEKEYSIZE"),
+ buf, li_itostrn(buf, sizeof(buf), usekeysize));
+ http_header_env_set(r, CONST_STR_LEN("SSL_CIPHER_ALGKEYSIZE"),
+ buf, li_utostrn(buf, sizeof(buf), algkeysize));
+ }
+}
+
+
+REQUEST_FUNC(mod_mbedtls_handle_request_env)
+{
+ plugin_data *p = p_d;
+ handler_ctx *hctx = r->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+ if (hctx->request_env_patched) return HANDLER_GO_ON;
+ hctx->request_env_patched = 1;
+
+ http_cgi_ssl_env(r, hctx);
+ if (hctx->conf.ssl_verifyclient) {
+ https_add_ssl_client_entries(r, hctx);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+REQUEST_FUNC(mod_mbedtls_handle_uri_raw)
+{
+ /* mod_mbedtls must be loaded prior to mod_auth
+ * if mod_mbedtls is configured to set REMOTE_USER based on client cert */
+ /* mod_mbedtls must be loaded after mod_extforward
+ * if mod_mbedtls config is based on lighttpd.conf remote IP conditional
+ * using remote IP address set by mod_extforward, *unless* PROXY protocol
+ * is enabled with extforward.hap-PROXY = "enable", in which case the
+ * reverse is true: mod_extforward must be loaded after mod_mbedtls */
+ plugin_data *p = p_d;
+ handler_ctx *hctx = r->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+
+ mod_mbedtls_patch_config(r, &hctx->conf);
+ if (hctx->conf.ssl_verifyclient) {
+ mod_mbedtls_handle_request_env(r, p);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+REQUEST_FUNC(mod_mbedtls_handle_request_reset)
+{
+ plugin_data *p = p_d;
+ handler_ctx *hctx = r->plugin_ctx[p->id];
+ if (NULL == hctx) return HANDLER_GO_ON;
+
+ hctx->request_env_patched = 0;
+ return HANDLER_GO_ON;
+}
+
+
+int mod_mbedtls_plugin_init (plugin *p);
+int mod_mbedtls_plugin_init (plugin *p)
+{
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = "mbedtls";
+ p->init = mod_mbedtls_init;
+ p->cleanup = mod_mbedtls_free;
+ p->priv_defaults= mod_mbedtls_set_defaults;
+
+ p->handle_connection_accept = mod_mbedtls_handle_con_accept;
+ p->handle_connection_shut_wr = mod_mbedtls_handle_con_shut_wr;
+ p->handle_connection_close = mod_mbedtls_handle_con_close;
+ p->handle_uri_raw = mod_mbedtls_handle_uri_raw;
+ p->handle_request_env = mod_mbedtls_handle_request_env;
+ p->connection_reset = mod_mbedtls_handle_request_reset;
+
+ return 0;
+}
+
+
+/* cipher suites (taken from mbedtls/ssl_ciphersuites.[ch]) */
+
+static const int suite_CHACHAPOLY_ephemeral[] = {
+ /* Chacha-Poly ephemeral suites */
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+};
+
+static const int suite_AES_256_ephemeral[] = {
+ /* All AES-256 ephemeral suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8
+};
+
+static const int suite_CAMELLIA_256_ephemeral[] = {
+ /* All CAMELLIA-256 ephemeral suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+};
+
+static const int suite_ARIA_256_ephemeral[] = {
+ /* All ARIA-256 ephemeral suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384
+};
+
+static const int suite_AES_128_ephemeral[] = {
+ /* All AES-128 ephemeral suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8
+};
+
+static const int suite_CAMELLIA_128_ephemeral[] = {
+ /* All CAMELLIA-128 ephemeral suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+};
+
+static const int suite_ARIA_128_ephemeral[] = {
+ /* All ARIA-128 ephemeral suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256
+};
+
+static const int suite_PSK_ephemeral[] = {
+ /* The PSK ephemeral suites */
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384,
+
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256
+};
+
+#if 0
+static const int suite_ECJPAKE[] = {
+ /* The ECJPAKE suite */
+ MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
+};
+#endif
+
+static const int suite_AES_256[] = {
+ /* All AES-256 suites */
+ MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8
+};
+
+static const int suite_CAMELLIA_256[] = {
+ /* All CAMELLIA-256 suites */
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+};
+
+static const int suite_ARIA_256[] = {
+ /* All ARIA-256 suites */
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384
+};
+
+static const int suite_AES_128[] = {
+ /* All AES-128 suites */
+ MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8
+};
+
+static const int suite_CAMELLIA_128[] = {
+ /* All CAMELLIA-128 suites */
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+};
+
+static const int suite_ARIA_128[] = {
+ /* All ARIA-128 suites */
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256
+};
+
+static const int suite_RSA_PSK[] = {
+ /* The RSA PSK suites */
+ MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384,
+
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256
+};
+
+static const int suite_PSK[] = {
+ /* The PSK suites */
+ MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CCM,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384,
+
+ MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CCM,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256
+};
+
+static const int suite_3DES[] = {
+ /* 3DES suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA
+};
+
+static const int suite_RC4[] = {
+ /* RC4 suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_RSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_RSA_WITH_RC4_128_MD5,
+ MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_PSK_WITH_RC4_128_SHA
+};
+
+static const int suite_weak[] = {
+ /* Weak suites */
+ MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA
+};
+
+static const int suite_null[] = {
+ /* NULL suites */
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA,
+
+ MBEDTLS_TLS_RSA_WITH_NULL_SHA256,
+ MBEDTLS_TLS_RSA_WITH_NULL_SHA,
+ MBEDTLS_TLS_RSA_WITH_NULL_MD5,
+ MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA,
+ MBEDTLS_TLS_PSK_WITH_NULL_SHA384,
+ MBEDTLS_TLS_PSK_WITH_NULL_SHA256,
+ MBEDTLS_TLS_PSK_WITH_NULL_SHA
+};
+
+/* TLSv1.2 cipher list (supported in mbedtls)
+ * marked with minimum version MBEDTLS_SSL_MINOR_VERSION_3 in
+ * ciphersuite_definitions[] and then sorted by ciphersuite_preference[]
+ * from mbedtls library/ssl_ciphersuites.c */
+static const int suite_TLSv12[] = {
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256,
+ MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CCM,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CCM,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256
+};
+
+/* TLSv1.0 cipher list (supported in mbedtls)
+ * marked with minimum version MBEDTLS_SSL_MINOR_VERSION_1 in
+ * ciphersuite_definitions[] and then sorted by ciphersuite_preference[]
+ * from mbedtls library/ssl_ciphersuites.c */
+/* XXX: intentionally not including overlapping eNULL ciphers */
+static const int suite_TLSv10[] = {
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA
+};
+
+/* SSLv3 cipher list (supported in mbedtls)
+ * marked with minimum version MBEDTLS_SSL_MINOR_VERSION_0 in
+ * ciphersuite_definitions[] and then sorted by ciphersuite_preference[]
+ * from mbedtls library/ssl_ciphersuites.c */
+/* XXX: intentionally not including overlapping eNULL ciphers */
+static const int suite_SSLv3[] = {
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_RSA_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_RSA_WITH_RC4_128_MD5,
+ MBEDTLS_TLS_PSK_WITH_RC4_128_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA
+};
+
+/* HIGH cipher list (mapped from openssl list to mbedtls) */
+static const int suite_HIGH[] = {
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CCM,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CCM,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
+ MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
+ MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CCM,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8,
+ MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
+ MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CCM,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA,
+ MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
+ MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8,
+ MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
+};
+
+
+/* true if RC4 or weak or NULL cipher suite
+ * (These ciphersuites are excluded from openssl "DEFAULT")
+ * This is a subset of ciphers excluded for mod_openssl "!aNULL:!eNULL:!EXP" */
+static int
+mod_mbedtls_ssl_is_weak_ciphersuite (int id)
+{
+ for (uint32_t i = 0; i < sizeof(suite_RC4)/sizeof(suite_RC4[0]); ++i) {
+ if (id == suite_RC4[i]) return 1;
+ }
+ for (uint32_t i = 0; i < sizeof(suite_weak)/sizeof(suite_weak[0]); ++i) {
+ if (id == suite_weak[i]) return 1;
+ }
+ for (uint32_t i = 0; i < sizeof(suite_null)/sizeof(suite_null[0]); ++i) {
+ if (id == suite_null[i]) return 1;
+ }
+ return 0;
+}
+
+
+static int
+mod_mbedtls_ssl_DEFAULT_ciphersuite (server *srv, int *ids, int nids, int idsz)
+{
+ /* obtain default ciphersuite list and filter out weak or NULL */
+ const int *dids = mbedtls_ssl_list_ciphersuites();
+ int i = 0;
+ while (dids[i] != 0) ++i;
+
+ if (i >= idsz - (nids + 1)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: too many ciphersuites during list expand");
+ return -1;
+ }
+
+ for (i = 0; dids[i] != 0; ++i) {
+ if (!mod_mbedtls_ssl_is_weak_ciphersuite(dids[i]))
+ ids[++nids] = dids[i];
+ }
+
+ return nids;
+}
+
+
+static int
+mod_mbedtls_ssl_append_ciphersuite (server *srv, int *ids, int nids, int idsz, const int *x, int xsz)
+{
+ if (xsz >= idsz - (nids + 1)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: too many ciphersuites during list expand");
+ return -1;
+ }
+
+ for (int i = 0; i < xsz; ++i)
+ ids[++nids] = x[i];
+
+ return nids;
+}
+
+
+static int
+mod_mbedtls_ssl_conf_ciphersuites (server *srv, plugin_config_socket *s, buffer *ciphersuites, const buffer *cipherstring)
+{
+ /* reference: https://www.openssl.org/docs/man1.1.1/man1/ciphers.html
+ * Attempt to parse *some* keywords from Ciphersuites and CipherString
+ * !!! openssl uses a *different* naming scheme than does mbedTLS !!!
+ * Since Ciphersuites in openssl takes only TLSv1.3 suites, and mbedTLS
+ * does not currently support TLSv1.3, mapping of those names is not
+ * currently provided. Note that CipherString does allow cipher suites to
+ * be listed, and this code does not currently attempt to provide mapping */
+
+ char n[128]; /*(most ciphersuite names are about 40 chars)*/
+ int ids[512];
+ int nids = -1;
+ const int idsz = (int)(sizeof(ids)/sizeof(*ids)-1);
+ int crt_profile_default = 0;
+
+ if (ciphersuites) {
+ buffer *b = ciphersuites;
+ buffer_to_upper(b); /*(ciphersuites are all uppercase (currently))*/
+ for (const char *p, *e = b->ptr-1; e && (e = strchr((p = e+1),':')); ) {
+ size_t len = e ? (size_t)(e - p) : strlen(p);
+ if (len >= sizeof(n)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: skipped ciphersuite; too long: %.*s",
+ (int)len, p);
+ continue;
+ }
+ memcpy(n, p, len);
+ n[len] = '\0';
+
+ int id = mbedtls_ssl_get_ciphersuite_id(n);
+ if (0 == id) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: skipped ciphersuite; not recognized: %.*s",
+ (int)len, n);
+ continue;
+ }
+
+ /* allow any ciphersuite if explicitly listed, even weak or eNULL */
+ #if 0
+ if (mod_mbedtls_ssl_is_weak_ciphersuite(id)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: skipped ciphersuite; weak or NULL suite: %.*s",
+ (int)len, n);
+ continue;
+ }
+ #endif
+
+ if (nids >= idsz) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: skipped ciphersuite; too many listed: %.*s",
+ (int)len, n);
+ continue;
+ }
+
+ ids[++nids] = id;
+ }
+ }
+
+ /* XXX: openssl config for CipherString=... is excessively complex.
+ * If there is a need to enable specific ciphersuites, then that
+ * can be accomplished with mod_mbedtls by specifying the list in
+ * Ciphersuites=... in the ssl.openssl.ssl-conf-cmd directive.
+ * (Alternatively, build mbedtls with specific set of cipher suites
+ * or modify mod_mbedtls code to specify the precise list).
+ *
+ * The tokens parsed here are a quick attempt to handle a few cases
+ *
+ * XXX: not done: could make a list of ciphers with bitflag of attributes
+ * to make future combining easier */
+ if (cipherstring) {
+ const buffer *b = cipherstring;
+ const char *e = b->ptr;
+
+ /* XXX: not done: no checking for duplication of ciphersuites
+ * even if tokens overlap or are repeated */
+
+ /* XXX: not done: might walk string and build up exclude list of !xxxxx
+ * ciphersuites and walk string again, excluding as result list built */
+
+ /* manually handle first token, since one-offs apply */
+ /* (openssl syntax NOT fully supported) */
+ int default_suite = 0;
+ if (0 == strncmp(e, "!ALL", 4) || 0 == strncmp(e, "-ALL", 4)) {
+ /* "!ALL" excluding all ciphers does not make sense; ignore */
+ e += sizeof("!ALL")-1; /* same as sizeof("-ALL")-1 */
+ }
+ else if (0 == strncmp(e, CONST_STR_LEN("!DEFAULT"))
+ || 0 == strncmp(e, CONST_STR_LEN("-DEFAULT"))) {
+ /* "!DEFAULT" excluding default ciphers is empty list; no effect */
+ e += sizeof("!DEFAULT")-1; /* same as sizeof("-DEFAULT")-1 */
+ }
+ else if (0 == strncmp(e, CONST_STR_LEN("DEFAULT"))) {
+ e += sizeof("DEFAULT")-1;
+ default_suite = 1;
+ }
+ else if (0 == /* effectively the same as "DEFAULT" */
+ strncmp(e, CONST_STR_LEN("ALL:!COMPLEMENTOFDEFAULT:!eNULL"))) {
+ e += sizeof("ALL:!COMPLEMENTOFDEFAULT:!eNULL")-1;
+ default_suite = 1;
+ }
+ else if (0 == strncmp(e, CONST_STR_LEN("SUITEB128"))
+ || 0 == strncmp(e, CONST_STR_LEN("SUITEB128ONLY"))
+ || 0 == strncmp(e, CONST_STR_LEN("SUITEB192"))) {
+ mbedtls_ssl_conf_cert_profile(s->ssl_ctx,
+ &mbedtls_x509_crt_profile_suiteb);
+ /* re-initialize mbedtls_ssl_config defaults */
+ mbedtls_mpi_free(&s->ssl_ctx->dhm_P);
+ mbedtls_mpi_free(&s->ssl_ctx->dhm_G);
+ int rc = mbedtls_ssl_config_defaults(s->ssl_ctx,
+ MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_SUITEB);
+ if (0 != rc) {
+ elog(srv->errh, __FILE__,__LINE__, rc,
+ "Init of ssl config context SUITEB defaults failed");
+ return 0;
+ }
+ e += (0 == strncmp(e, CONST_STR_LEN("SUITEB128ONLY")))
+ ? sizeof("SUITEB128ONLY")-1
+ : sizeof("SUITEB128")-1;
+ if (*e)
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ignoring cipher string after SUITEB: %s", e);
+ return 1;
+ }
+
+ if (e != b->ptr && *e != ':' && *e != '\0') {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: missing support for cipher list: %s", b->ptr);
+ return 0;
+ }
+
+ if (default_suite) {
+ crt_profile_default = 1;
+ nids =
+ mod_mbedtls_ssl_DEFAULT_ciphersuite(srv, ids, nids, idsz);
+ if (-1 == nids) return 0;
+ }
+
+ /* not handled: "ALL" is "DEFAULT" and "RC4" */
+ /* not handled: "COMPLEMENTOFALL" is "eNULL" */
+
+ int rc = 1;
+ if (e == b->ptr || *e == '\0') --e; /*initial condition for loop below*/
+ for (const char *p; e && (e = strchr((p = e+1),':')); ) {
+ size_t len = e ? (size_t)(e - p) : strlen(p);
+ if (len >= sizeof(n)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: skipped ciphersuite; too long: %.*s",
+ (int)len, p);
+ continue;
+ }
+ char c = (*p == '!' || *p == '-' || *p == '+') ? *p : 0;
+ size_t nlen = c ? len-1 : len;
+ memcpy(n, c ? p+1 : p, nlen);
+ n[nlen] = '\0';
+
+ /* not handled: !xxxxx -xxxxx and most +xxxxx */
+ if (c) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: missing support for cipher list: %s", b->ptr);
+ }
+
+ /* ignore @STRENGTH sorting and ignore @SECLEVEL=n */
+ char *a = strchr(n, '@');
+ if (a) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ignored %s in %.*s", a, (int)len, p);
+ *a = '\0';
+ nlen = (size_t)(a - n);
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("TLSv1.2"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_TLSv12,
+ (int)(sizeof(suite_TLSv12)/sizeof(*suite_TLSv12)));
+ if (-1 == nids) return 0;
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("TLSv1.0"))) {
+ crt_profile_default = 1;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_TLSv10,
+ (int)(sizeof(suite_TLSv10)/sizeof(*suite_TLSv10)));
+ if (-1 == nids) return 0;
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("SSLv3"))) {
+ crt_profile_default = 1;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_SSLv3,
+ (int)(sizeof(suite_SSLv3)/sizeof(*suite_SSLv3)));
+ if (-1 == nids) return 0;
+ continue;
+ }
+
+ /* handle a popular recommendations
+ * ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM"
+ * ssl.cipher-list = "AES256+EECDH:AES256+EDH"
+ * which uses AES hardware acceleration built into popular CPUs */
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("ECDHE+AESGCM"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("EECDH+AESGCM"))) {
+ if (nids + 4 >= idsz) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: too many ciphersuites during list expand");
+ return 0;
+ }
+ ids[++nids] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+ continue;
+ }
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("DHE+AESGCM"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("EDH+AESGCM"))) {
+ if (nids + 2 >= idsz) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: too many ciphersuites during list expand");
+ return 0;
+ }
+ ids[++nids] = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
+ ids[++nids] = MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
+ continue;
+ }
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256+EECDH"))) {
+ if (nids + 8 >= idsz) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: too many ciphersuites during list expand");
+ return 0;
+ }
+ ids[++nids] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+ ids[++nids] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8;
+ continue;
+ }
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256+EDH"))) {
+ if (nids + 5 >= idsz) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: too many ciphersuites during list expand");
+ return 0;
+ }
+ ids[++nids] = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
+ ids[++nids] = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM;
+ ids[++nids] = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+ ids[++nids] = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+ ids[++nids] = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8;
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("HIGH"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_HIGH,
+ (int)(sizeof(suite_HIGH)/sizeof(*suite_HIGH)));
+ if (-1 == nids) return 0;
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES256"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_AES_256_ephemeral,
+ (int)(sizeof(suite_AES_256_ephemeral)
+ /sizeof(*suite_AES_256_ephemeral)));
+ if (-1 == nids) return 0;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_AES_256,
+ (int)(sizeof(suite_AES_256)/sizeof(*suite_AES_256)));
+ if (-1 == nids) return 0;
+ /* XXX: not done: AES256 PSK suites */
+ if (nlen == sizeof("AES256")-1) continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES128"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("AES"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_AES_128_ephemeral,
+ (int)(sizeof(suite_AES_128_ephemeral)
+ /sizeof(*suite_AES_128_ephemeral)));
+ if (-1 == nids) return 0;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_AES_128,
+ (int)(sizeof(suite_AES_128)/sizeof(*suite_AES_128)));
+ if (-1 == nids) return 0;
+ /* XXX: not done: AES128 PSK suites */
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA256"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_CAMELLIA_256_ephemeral,
+ (int)(sizeof(suite_CAMELLIA_256_ephemeral)
+ /sizeof(*suite_CAMELLIA_256_ephemeral)));
+ if (-1 == nids) return 0;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_CAMELLIA_256,
+ (int)(sizeof(suite_CAMELLIA_256)
+ /sizeof(*suite_CAMELLIA_256)));
+ if (-1 == nids) return 0;
+ /* XXX: not done: CAMELLIA256 PSK suites */
+ if (nlen == sizeof("CAMELLIA256")-1) continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA128"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CAMELLIA"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_CAMELLIA_128_ephemeral,
+ (int)(sizeof(suite_CAMELLIA_128_ephemeral)
+ /sizeof(*suite_CAMELLIA_128_ephemeral)));
+ if (-1 == nids) return 0;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_CAMELLIA_128,
+ (int)(sizeof(suite_CAMELLIA_128)
+ /sizeof(*suite_CAMELLIA_128)));
+ if (-1 == nids) return 0;
+ /* XXX: not done: CAMELLIA128 PSK suites */
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("ARIA256"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("ARIA"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_ARIA_256_ephemeral,
+ (int)(sizeof(suite_ARIA_256_ephemeral)
+ /sizeof(*suite_ARIA_256_ephemeral)));
+ if (-1 == nids) return 0;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_ARIA_256,
+ (int)(sizeof(suite_ARIA_256)/sizeof(*suite_ARIA_256)));
+ if (-1 == nids) return 0;
+ /* XXX: not done: ARIA256 PSK suites */
+ if (nlen == sizeof("ARIA256")-1) continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("ARIA128"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("ARIA"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_ARIA_128_ephemeral,
+ (int)(sizeof(suite_ARIA_128_ephemeral)
+ /sizeof(*suite_ARIA_128_ephemeral)));
+ if (-1 == nids) return 0;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_ARIA_128,
+ (int)(sizeof(suite_ARIA_128)/sizeof(*suite_ARIA_128)));
+ if (-1 == nids) return 0;
+ /* XXX: not done: ARIA128 PSK suites */
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("CHACHA20"))) {
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_CHACHAPOLY_ephemeral,
+ (int)(sizeof(suite_CHACHAPOLY_ephemeral)
+ /sizeof(*suite_CHACHAPOLY_ephemeral)));
+ if (-1 == nids) return 0;
+ /* XXX: not done: CHACHA20 PSK suites */
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("PSK"))) {
+ /* XXX: intentionally not including overlapping eNULL ciphers */
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_PSK_ephemeral,
+ (int)(sizeof(suite_PSK_ephemeral)
+ /sizeof(*suite_PSK_ephemeral)));
+ if (-1 == nids) return 0;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_RSA_PSK,
+ (int)(sizeof(suite_RSA_PSK)/sizeof(*suite_RSA_PSK)));
+ if (-1 == nids) return 0;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_PSK,
+ (int)(sizeof(suite_PSK)/sizeof(*suite_PSK)));
+ if (-1 == nids) return 0;
+ continue;
+ }
+
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("3DES"))) {
+ crt_profile_default = 1;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_3DES,
+ (int)(sizeof(suite_3DES)/sizeof(*suite_3DES)));
+ if (-1 == nids) return 0;
+ continue;
+ }
+
+ /* not recommended, but permitted if explicitly requested */
+ /* "RC4" is same as openssl "COMPLEMENTOFALL" */
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("RC4"))) {
+ crt_profile_default = 1;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_RC4,
+ (int)(sizeof(suite_RC4)/sizeof(*suite_RC4)));
+ if (-1 == nids) return 0;
+ continue;
+ }
+
+ /* not recommended, but permitted if explicitly requested */
+ if (buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("NULL"))
+ || buffer_eq_icase_ss(n, nlen, CONST_STR_LEN("eNULL"))) {
+ crt_profile_default = 1;
+ nids = mod_mbedtls_ssl_append_ciphersuite(srv, ids, nids, idsz,
+ suite_null,
+ (int)(sizeof(suite_null)/sizeof(*suite_null)));
+ if (-1 == nids) return 0;
+ continue;
+ }
+
+ if (*e != ':' && *e != '\0') {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: missing support for cipher list: %.*s",
+ (int)len, p);
+ rc = 0;
+ continue;
+ }
+ }
+ if (0 == rc) return 0;
+ }
+
+ if (-1 == nids) {
+ /* Do not set a default if ssl.cipher-list was set (and we are
+ * are processing ssl.openssl.ssl-conf-cmd, not ssl.cipher-list) */
+ if (cipherstring != s->ssl_cipher_list
+ && !buffer_string_is_empty(s->ssl_cipher_list))
+ return 1;
+
+ /* obtain default ciphersuite list and filter out RC4, weak, and NULL */
+ nids =
+ mod_mbedtls_ssl_DEFAULT_ciphersuite(srv, ids, nids,
+ sizeof(ids)/sizeof(*ids));
+ if (-1 == nids) return 0;
+ }
+
+ ids[++nids] = 0; /* terminate list */
+ ++nids;
+
+ if (!crt_profile_default)
+ mbedtls_ssl_conf_cert_profile(s->ssl_ctx,
+ &mbedtls_x509_crt_profile_next);
+
+ /* ciphersuites list must be persistent for lifetime of mbedtls_ssl_config*/
+ s->ciphersuites = malloc(nids * sizeof(int));
+ force_assert(s->ciphersuites);
+ memcpy(s->ciphersuites, ids, nids * sizeof(int));
+
+ mbedtls_ssl_conf_ciphersuites(s->ssl_ctx, s->ciphersuites);
+ return 1;
+}
+
+
+static int
+mod_mbedtls_ssl_append_curve (server *srv, mbedtls_ecp_group_id *ids, int nids, int idsz, const mbedtls_ecp_group_id id)
+{
+ if (1 >= idsz - (nids + 1)) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: error: too many curves during list expand");
+ return -1;
+ }
+
+ ids[++nids] = id;
+
+ return nids;
+}
+
+
+static int
+mod_mbedtls_ssl_conf_curves(server *srv, plugin_config_socket *s, const buffer *curvelist)
+{
+ mbedtls_ecp_group_id ids[512];
+ int nids = -1;
+ const int idsz = (int)(sizeof(ids)/sizeof(*ids)-1);
+ const mbedtls_ecp_curve_info * const curve_info = mbedtls_ecp_curve_list();
+
+ const buffer * const b = curvelist;
+ for (const char *n, *e = b->ptr-1; e && (e = strchr((n = e+1),':')); ) {
+ size_t len = e ? (size_t)(e - n) : strlen(n);
+ /* similar to mbedtls_ecp_curve_info_from_name() */
+ const mbedtls_ecp_curve_info *info;
+ for (info = curve_info; info->grp_id != MBEDTLS_ECP_DP_NONE; ++info) {
+ if (0 == strncmp(info->name, n, len) && info->name[len] == '\0')
+ break;
+ }
+ if (info->grp_id == MBEDTLS_ECP_DP_NONE) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: unrecognized curve: %.*s; ignored", (int)len, n);
+ continue;
+ }
+
+ nids = mod_mbedtls_ssl_append_curve(srv, ids, nids, idsz, info->grp_id);
+ if (-1 == nids) return 0;
+ }
+
+ /* XXX: mod_openssl configures "prime256v1" if curve list not specified,
+ * but mbedtls provides a list of supported curves if not explicitly set */
+ if (-1 == nids) return 1; /* empty list; no-op */
+
+ ids[++nids] = MBEDTLS_ECP_DP_NONE; /* terminate list */
+ ++nids;
+
+ /* curves list must be persistent for lifetime of mbedtls_ssl_config */
+ s->curves = malloc(nids * sizeof(mbedtls_ecp_group_id));
+ force_assert(s->curves);
+ memcpy(s->curves, ids, nids * sizeof(mbedtls_ecp_group_id));
+
+ mbedtls_ssl_conf_curves(s->ssl_ctx, s->curves);
+ return 1;
+}
+
+
+static void
+mod_mbedtls_ssl_conf_proto (server *srv, plugin_config_socket *s, const buffer *b, int max)
+{
+ int v = MBEDTLS_SSL_MINOR_VERSION_3; /* default: TLS v1.2 */
+ if (NULL == b) /* default: min TLSv1.2, max TLSv1.2 */
+ v = max ? MBEDTLS_SSL_MINOR_VERSION_3 : MBEDTLS_SSL_MINOR_VERSION_3;
+ else if (buffer_eq_icase_slen(b, CONST_STR_LEN("None"))) /*"disable" limit*/
+ v = max
+ ? MBEDTLS_SSL_MINOR_VERSION_3 /* TLS v1.2 */
+ : s->ssl_use_sslv3
+ ? MBEDTLS_SSL_MINOR_VERSION_0 /* SSL v3.0 */
+ : MBEDTLS_SSL_MINOR_VERSION_1; /* TLS v1.0 */
+ else if (buffer_eq_icase_slen(b, CONST_STR_LEN("SSLv3")))
+ v = MBEDTLS_SSL_MINOR_VERSION_0; /* SSL v3.0 */
+ else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.0")))
+ v = MBEDTLS_SSL_MINOR_VERSION_1; /* TLS v1.0 */
+ else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.1")))
+ v = MBEDTLS_SSL_MINOR_VERSION_2; /* TLS v1.1 */
+ else if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.2")))
+ v = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS v1.2 */
+ else {
+ if (buffer_eq_icase_slen(b, CONST_STR_LEN("TLSv1.3")))
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ssl.openssl.ssl-conf-cmd %s TLSv1.3 not supported "
+ "by mod_mbedtls; using TLSv1.2",
+ max ? "MaxProtocol" : "MinProtocol");
+ else if (buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1"))
+ || buffer_eq_icase_slen(b, CONST_STR_LEN("DTLSv1.2"))) {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ssl.openssl.ssl-conf-cmd %s %s ignored",
+ max ? "MaxProtocol" : "MinProtocol", b->ptr);
+ return;
+ }
+ else {
+ log_error(srv->errh, __FILE__, __LINE__,
+ "MTLS: ssl.openssl.ssl-conf-cmd %s %s invalid; ignored",
+ max ? "MaxProtocol" : "MinProtocol", b->ptr);
+ return;
+ }
+ }
+
+ max
+ ? mbedtls_ssl_conf_max_version(s->ssl_ctx,MBEDTLS_SSL_MAJOR_VERSION_3,v)
+ : mbedtls_ssl_conf_min_version(s->ssl_ctx,MBEDTLS_SSL_MAJOR_VERSION_3,v);
+}
diff --git a/src/mod_secdownload.c b/src/mod_secdownload.c
index ba816827..4b594e28 100644
--- a/src/mod_secdownload.c
+++ b/src/mod_secdownload.c
@@ -15,6 +15,8 @@
#ifdef USE_LIB_CRYPTO
#if defined(USE_NETTLE_CRYPTO)
#include <nettle/hmac.h>
+#elif defined(USE_MBEDTLS_CRYPTO)
+#include <mbedtls/md.h>
#elif defined(USE_OPENSSL_CRYPTO)
#include <openssl/evp.h>
#include <openssl/hmac.h>
@@ -180,8 +182,8 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c
return const_time_memeq((char *)HA1, (char *)md5bin, sizeof(md5bin));
}
+ #ifdef USE_LIB_CRYPTO
case SECDL_HMAC_SHA1:
-#ifdef USE_LIB_CRYPTO
{
unsigned char digest[20];
char base64_digest[27];
@@ -191,6 +193,18 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c
hmac_sha1_set_key(&ctx, buffer_string_length(config->secret), (const uint8_t *)config->secret->ptr);
hmac_sha1_update(&ctx, strlen(protected_path), (const uint8_t *)protected_path);
hmac_sha1_digest(&ctx, sizeof(digest), (uint8_t *)digest);
+ #elif defined(USE_MBEDTLS_CRYPTO) && defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA1_C)
+ int rc =
+ mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1),
+ (const unsigned char *)config->secret->ptr,
+ buffer_string_length(config->secret),
+ (const unsigned char *)protected_path,
+ strlen(protected_path), digest);
+ if (0 != rc) {
+ log_error(errh, __FILE__, __LINE__,
+ "hmac-sha1: HMAC() failed");
+ return 0;
+ }
#elif defined(USE_OPENSSL_CRYPTO)
if (NULL == HMAC(
EVP_sha1(),
@@ -209,10 +223,8 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c
return (27 == maclen) && const_time_memeq(mac, base64_digest, 27);
}
-#endif
break;
case SECDL_HMAC_SHA256:
-#ifdef USE_LIB_CRYPTO
{
unsigned char digest[32];
char base64_digest[43];
@@ -222,6 +234,18 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c
hmac_sha256_set_key(&ctx, buffer_string_length(config->secret), (const uint8_t *)config->secret->ptr);
hmac_sha256_update(&ctx, strlen(protected_path), (const uint8_t *)protected_path);
hmac_sha256_digest(&ctx, sizeof(digest), (uint8_t *)digest);
+ #elif defined(USE_MBEDTLS_CRYPTO) && defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA256_C)
+ int rc =
+ mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
+ (const unsigned char *)config->secret->ptr,
+ buffer_string_length(config->secret),
+ (const unsigned char *)protected_path,
+ strlen(protected_path), digest);
+ if (0 != rc) {
+ log_error(errh, __FILE__, __LINE__,
+ "hmac-sha256: HMAC() failed");
+ return 0;
+ }
#elif defined(USE_OPENSSL_CRYPTO)
if (NULL == HMAC(
EVP_sha256(),
@@ -240,7 +264,9 @@ static int secdl_verify_mac(plugin_config *config, const char* protected_path, c
return (43 == maclen) && const_time_memeq(mac, base64_digest, 43);
}
-#endif
+ break;
+ #endif
+ default:
break;
}
diff --git a/src/network.c b/src/network.c
index 05d1f074..432a0011 100644
--- a/src/network.c
+++ b/src/network.c
@@ -142,6 +142,7 @@ typedef struct {
/* global or per-socket config; not patched per connection */
int listen_backlog;
unsigned char ssl_enabled;
+ unsigned char mbedtls_enabled; /* TODO: more integration needed ... */
unsigned char use_ipv6;
unsigned char set_v6only; /* set_v6only is only a temporary option */
unsigned char defer_accept;
@@ -264,7 +265,7 @@ static int network_server_init(server *srv, network_socket_config *s, buffer *ho
memcpy(&srv_socket->addr, &addr, addr_len);
srv_socket->fd = -1;
srv_socket->sidx = sidx;
- srv_socket->is_ssl = s->ssl_enabled;
+ srv_socket->is_ssl = (s->ssl_enabled || s->mbedtls_enabled);
srv_socket->srv = srv;
srv_socket->srv_token = buffer_init_buffer(host_token);
@@ -383,7 +384,7 @@ static int network_server_init(server *srv, network_socket_config *s, buffer *ho
return -1;
}
- if (s->ssl_enabled) {
+ if (s->ssl_enabled || s->mbedtls_enabled) {
#ifdef TCP_DEFER_ACCEPT
} else if (s->defer_accept) {
int v = s->defer_accept;
@@ -514,6 +515,11 @@ int network_init(server *srv, int stdin_fd) {
,{ CONST_STR_LEN("server.set-v6only"),
T_CONFIG_BOOL,
T_CONFIG_SCOPE_CONNECTION }
+ #if 0 /* TODO: more integration needed ... */
+ ,{ CONST_STR_LEN("mbedtls.engine"),
+ T_CONFIG_BOOL,
+ T_CONFIG_SCOPE_CONNECTION }
+ #endif
,{ NULL, 0,
T_CONFIG_UNSET,
T_CONFIG_SCOPE_UNSET }
diff --git a/src/rand.c b/src/rand.c
index d8a9b427..ffdd15f0 100644
--- a/src/rand.c
+++ b/src/rand.c
@@ -1,6 +1,7 @@
#include "first.h"
#include "rand.h"
+#include "buffer.h"
#include "fdevent.h"
#include "safe_memclear.h"
@@ -15,11 +16,17 @@
#include "sys-crypto.h" /* USE_LIB_CRYPTO */
#ifdef USE_NETTLE_CRYPTO
+#undef USE_MBEDTLS_CRYPTO
#undef USE_OPENSSL_CRYPTO
#include <nettle/knuth-lfib.h>
#include <nettle/arcfour.h>
#include <nettle/yarrow.h>
#endif
+#ifdef USE_MBEDTLS_CRYPTO
+#undef USE_OPENSSL_CRYPTO
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
+#endif
#ifdef USE_OPENSSL_CRYPTO
#include <openssl/opensslv.h> /* OPENSSL_VERSION_NUMBER */
#include <openssl/rand.h>
@@ -132,6 +139,14 @@ static int li_rand_device_bytes (unsigned char *buf, int num)
static int li_rand_inited;
static unsigned short xsubi[3];
+#ifdef USE_MBEDTLS_CRYPTO
+#ifdef MBEDTLS_ENTROPY_C
+static mbedtls_entropy_context entropy;
+#ifdef MBEDTLS_CTR_DRBG_C
+static mbedtls_ctr_drbg_context ctr_drbg;
+#endif
+#endif
+#endif
#ifdef USE_NETTLE_CRYPTO
static struct knuth_lfib_ctx knuth_lfib_ctx;
static struct arcfour_ctx arcfour_ctx;
@@ -206,10 +221,33 @@ static void li_rand_init (void)
RAND_poll();
RAND_seed(xsubi, (int)sizeof(xsubi));
#endif
+ #ifdef USE_MBEDTLS_CRYPTO
+ #ifdef MBEDTLS_ENTROPY_C
+ mbedtls_entropy_init(&entropy);
+ #ifdef MBEDTLS_CTR_DRBG_C
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ int rc =
+ mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
+ (unsigned char *)xsubi, sizeof(xsubi));
+ if (0 != rc) /*(not expecting built-in entropy function to fail)*/
+ log_failed_assert(__FILE__, __LINE__, "mbedtls_ctr_drbg_seed() failed");
+ #endif
+ #endif
+ #endif
}
void li_rand_reseed (void)
{
+ #ifdef USE_MBEDTLS_CRYPTO
+ if (li_rand_inited) {
+ #ifdef MBEDTLS_ENTROPY_C
+ #ifdef MBEDTLS_CTR_DRBG_C
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ #endif
+ mbedtls_entropy_free(&entropy);
+ #endif
+ }
+ #endif
if (li_rand_inited) li_rand_init();
}
@@ -229,6 +267,13 @@ int li_rand_pseudo (void)
nettle_arcfour_crypt(&arcfour_ctx, sizeof(i), (uint8_t *)&i, (uint8_t *)&i);
if (i) return i; /*(cond to avoid compiler warning for code after return)*/
#endif
+ #ifdef USE_MBEDTLS_CRYPTO
+ #ifdef MBEDTLS_CTR_DRBG_C
+ int i;
+ if (0 == mbedtls_ctr_drbg_random(&ctr_drbg, (unsigned char *)&i, sizeof(i)))
+ return i;
+ #endif
+ #endif
#ifdef HAVE_ARC4RANDOM_BUF
return (int)arc4random();
#elif defined(HAVE_SRANDOM)
@@ -246,6 +291,11 @@ int li_rand_pseudo (void)
void li_rand_pseudo_bytes (unsigned char *buf, int num)
{
+ #ifdef USE_MBEDTLS_CRYPTO
+ #ifdef MBEDTLS_CTR_DRBG_C
+ if (0 == mbedtls_ctr_drbg_random(&ctr_drbg, buf, (size_t)num)) return;
+ #endif
+ #endif
for (int i = 0; i < num; ++i)
buf[i] = li_rand_pseudo() & 0xFF;
}
@@ -273,6 +323,15 @@ int li_rand_bytes (unsigned char *buf, int num)
return rc;
}
#endif
+ #ifdef USE_MBEDTLS_CRYPTO
+ #ifdef MBEDTLS_ENTROPY_C
+ /*(each call <= MBEDTLS_ENTROPY_BLOCK_SIZE; could implement loop here)*/
+ if (num <= MBEDTLS_ENTROPY_BLOCK_SIZE
+ && 0 == mbedtls_entropy_func(&entropy, buf, (size_t)num)) {
+ return 1;
+ }
+ #endif
+ #endif
if (1 == li_rand_device_bytes(buf, num)) {
return 1;
}
@@ -291,5 +350,13 @@ void li_rand_cleanup (void)
RAND_cleanup();
#endif
#endif
+ #ifdef USE_MBEDTLS_CRYPTO
+ #ifdef MBEDTLS_ENTROPY_C
+ #ifdef MBEDTLS_CTR_DRBG_C
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ #endif
+ mbedtls_entropy_free(&entropy);
+ #endif
+ #endif
safe_memclear(xsubi, sizeof(xsubi));
}
diff --git a/src/server.c b/src/server.c
index 410f5b2f..0c74a1c7 100644
--- a/src/server.c
+++ b/src/server.c
@@ -71,8 +71,8 @@ static const buffer default_server_tag = { CONST_STR_LEN(PACKAGE_DESC), 0 };
#endif
#include "sys-crypto.h"
-#ifdef USE_OPENSSL_CRYPTO
-#define USE_SSL
+#if defined(USE_OPENSSL_CRYPTO) \
+ || defined(USE_MBEDTLS_CRYPTO)
#define TEXT_SSL " (ssl)"
#else
#define TEXT_SSL
@@ -430,10 +430,15 @@ static void show_features (void) {
#else
"\t- crypt support\n"
#endif
-#ifdef USE_SSL
- "\t+ SSL support\n"
+#ifdef USE_OPENSSL_CRYPTO
+ "\t+ OpenSSL support\n"
+#else
+ "\t- OpenSSL support\n"
+#endif
+#ifdef USE_MBEDTLS_CRYPTO
+ "\t+ mbedTLS support\n"
#else
- "\t- SSL support\n"
+ "\t- mbedTLS support\n"
#endif
#ifdef HAVE_LIBPCRE
"\t+ PCRE support\n"
diff --git a/src/sys-crypto.h b/src/sys-crypto.h
index 5d15533c..ec321cc4 100644
--- a/src/sys-crypto.h
+++ b/src/sys-crypto.h
@@ -18,6 +18,12 @@
#include <wolfssl/options.h>
#endif
+#ifdef HAVE_LIBMBEDCRYPTO
+#define USE_LIB_CRYPTO
+#define USE_MBEDTLS_CRYPTO
+#include <mbedtls/config.h>
+#endif
+
#ifdef HAVE_NETTLE_NETTLE_TYPES_H
#define USE_LIB_CRYPTO
#define USE_NETTLE_CRYPTO