From 89cb55ea589fe6b600939c2c9a660be95a2f8d46 Mon Sep 17 00:00:00 2001
From: Andy Green <andy@warmcat.com>
Date: Wed, 18 Oct 2017 09:41:44 +0800
Subject: [PATCH] tls: split out common, openssl and mbedtls code

 - introduce lib/tls/mbedtls lib/tls/openssl
 - move wrapper into lib/tls/mbedtls/wrapper
 - introduce private helpers to hide backend

This patch doesn't replace or remove the wrapper, it moves it
to lib/tls/mbedtls/wrapper.

But it should be now that the ONLY functions directly consuming
wrapper apis are isolated in

  - lib/tls/mbedtls/client.c (180 lines)
  - lib/tls/mbedtls/server.c (317 lines)
  - lib/tls/mbedtls/ssl.c    (325 lines)

In particular there are no uses of openssl or mbedtls-related
constants outside of ./lib/tls any more.
---
 CMakeLists.txt                                |  87 +-
 cmake/lws_config.h.in                         |   1 +
 lib/client/client.c                           |   6 +-
 lib/client/ssl-client.c                       | 557 +---------
 lib/libwebsockets.c                           |  42 +-
 lib/libwebsockets.h                           |  13 +-
 lib/private-libwebsockets.h                   | 116 ++-
 lib/server/ssl-server.c                       | 562 ++++------
 lib/service.c                                 |  40 +-
 lib/ssl.c                                     | 976 ------------------
 lib/tls/mbedtls/client.c                      | 180 ++++
 lib/tls/mbedtls/server.c                      | 317 ++++++
 lib/tls/mbedtls/ssl.c                         | 325 ++++++
 .../mbedtls/wrapper}/include/internal/ssl3.h  |   0
 .../wrapper}/include/internal/ssl_cert.h      |   0
 .../wrapper}/include/internal/ssl_code.h      |   0
 .../wrapper}/include/internal/ssl_dbg.h       |   0
 .../wrapper}/include/internal/ssl_lib.h       |   0
 .../wrapper}/include/internal/ssl_methods.h   |   0
 .../wrapper}/include/internal/ssl_pkey.h      |   0
 .../wrapper}/include/internal/ssl_stack.h     |   0
 .../wrapper}/include/internal/ssl_types.h     |   0
 .../wrapper}/include/internal/ssl_x509.h      |   0
 .../mbedtls/wrapper}/include/internal/tls1.h  |   0
 .../wrapper}/include/internal/x509_vfy.h      |   0
 .../mbedtls/wrapper}/include/openssl/ssl.h    |   0
 .../wrapper}/include/platform/ssl_pm.h        |   0
 .../wrapper}/include/platform/ssl_port.h      |   0
 .../mbedtls/wrapper}/library/ssl_cert.c       |   0
 .../mbedtls/wrapper}/library/ssl_lib.c        |   0
 .../mbedtls/wrapper}/library/ssl_methods.c    |   0
 .../mbedtls/wrapper}/library/ssl_pkey.c       |   0
 .../mbedtls/wrapper}/library/ssl_stack.c      |   0
 .../mbedtls/wrapper}/library/ssl_x509.c       |   0
 .../mbedtls/wrapper}/platform/ssl_pm.c        |   0
 .../mbedtls/wrapper}/platform/ssl_port.c      |   0
 lib/tls/openssl/client.c                      | 384 +++++++
 lib/tls/openssl/server.c                      | 417 ++++++++
 lib/tls/openssl/ssl.c                         | 486 +++++++++
 lib/tls/tls.c                                 | 122 +++
 .../protocol_generic_sessions.c               |   1 +
 .../protocol_lws_messageboard.c               |   1 +
 plugins/generic-sessions/utils.c              |   1 +
 .../generic-table/protocol_table_dirlisting.c |   1 +
 plugins/protocol_lws_sshd_demo.c              |   3 +-
 plugins/protocol_post_demo.c                  |   1 +
 plugins/ssh-base/crypto/chacha.c              |   1 +
 plugins/ssh-base/sshd.c                       |   1 +
 test-apps/test-server-http.c                  |   2 +-
 test-apps/test-server-v2.0.c                  |   3 +-
 50 files changed, 2670 insertions(+), 1976 deletions(-)
 delete mode 100644 lib/ssl.c
 create mode 100644 lib/tls/mbedtls/client.c
 create mode 100644 lib/tls/mbedtls/server.c
 create mode 100644 lib/tls/mbedtls/ssl.c
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl3.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_cert.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_code.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_dbg.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_lib.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_methods.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_pkey.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_stack.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_types.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/ssl_x509.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/tls1.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/internal/x509_vfy.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/openssl/ssl.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/platform/ssl_pm.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/include/platform/ssl_port.h (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/library/ssl_cert.c (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/library/ssl_lib.c (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/library/ssl_methods.c (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/library/ssl_pkey.c (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/library/ssl_stack.c (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/library/ssl_x509.c (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/platform/ssl_pm.c (100%)
 rename lib/{mbedtls_wrapper => tls/mbedtls/wrapper}/platform/ssl_port.c (100%)
 create mode 100644 lib/tls/openssl/client.c
 create mode 100644 lib/tls/openssl/server.c
 create mode 100644 lib/tls/openssl/ssl.c
 create mode 100644 lib/tls/tls.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c7eb7e9d..f5c641fe 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -646,58 +646,81 @@ endif()
 
 if (LWS_WITH_MBEDTLS)
  	set(LWS_WITH_SSL ON)
-
+ 	
 	list(APPEND HDR_PRIVATE
-		lib/mbedtls_wrapper/include/internal/ssl3.h
-		lib/mbedtls_wrapper/include/internal/ssl_cert.h
-		lib/mbedtls_wrapper/include/internal/ssl_code.h
-		lib/mbedtls_wrapper/include/internal/ssl_dbg.h
-		lib/mbedtls_wrapper/include/internal/ssl_lib.h
-		lib/mbedtls_wrapper/include/internal/ssl_methods.h
-		lib/mbedtls_wrapper/include/internal/ssl_pkey.h
-		lib/mbedtls_wrapper/include/internal/ssl_stack.h
-		lib/mbedtls_wrapper/include/internal/ssl_types.h
-		lib/mbedtls_wrapper/include/internal/ssl_x509.h
-		lib/mbedtls_wrapper/include/internal/tls1.h
-		lib/mbedtls_wrapper/include/internal/x509_vfy.h)
+		lib/tls/mbedtls/wrapper/include/internal/ssl3.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_cert.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_code.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_dbg.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_lib.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_methods.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_pkey.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_stack.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_types.h
+		lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h
+		lib/tls/mbedtls/wrapper/include/internal/tls1.h
+		lib/tls/mbedtls/wrapper/include/internal/x509_vfy.h)
 
 	list(APPEND HDR_PRIVATE
-		lib/mbedtls_wrapper/include/openssl/ssl.h)
+		lib/tls/mbedtls/wrapper/include/openssl/ssl.h)
 
 	list(APPEND HDR_PRIVATE
-		lib/mbedtls_wrapper/include/platform/ssl_pm.h
-		lib/mbedtls_wrapper/include/platform/ssl_port.h)
+		lib/tls/mbedtls/wrapper/include/platform/ssl_pm.h
+		lib/tls/mbedtls/wrapper/include/platform/ssl_port.h)
 
-	include_directories(lib/mbedtls_wrapper/include)
-	include_directories(lib/mbedtls_wrapper/include/platform)
-	include_directories(lib/mbedtls_wrapper/include/internal)
-	include_directories(lib/mbedtls_wrapper/include/openssl)
+	include_directories(lib/tls/mbedtls/wrapper/include)
+	include_directories(lib/tls/mbedtls/wrapper/include/platform)
+	include_directories(lib/tls/mbedtls/wrapper/include/internal)
+	include_directories(lib/tls/mbedtls/wrapper/include/openssl)
 
 	list(APPEND SOURCES
-		lib/mbedtls_wrapper/library/ssl_cert.c
-		lib/mbedtls_wrapper/library/ssl_lib.c
-		lib/mbedtls_wrapper/library/ssl_methods.c
-		lib/mbedtls_wrapper/library/ssl_pkey.c
-		lib/mbedtls_wrapper/library/ssl_stack.c
-		lib/mbedtls_wrapper/library/ssl_x509.c)
+		lib/tls/mbedtls/wrapper/library/ssl_cert.c
+		lib/tls/mbedtls/wrapper/library/ssl_lib.c
+		lib/tls/mbedtls/wrapper/library/ssl_methods.c
+		lib/tls/mbedtls/wrapper/library/ssl_pkey.c
+		lib/tls/mbedtls/wrapper/library/ssl_stack.c
+		lib/tls/mbedtls/wrapper/library/ssl_x509.c)
 
 	list(APPEND SOURCES
-		lib/mbedtls_wrapper/platform/ssl_pm.c
-		lib/mbedtls_wrapper/platform/ssl_port.c)
+		lib/tls/mbedtls/wrapper/platform/ssl_pm.c
+		lib/tls/mbedtls/wrapper/platform/ssl_port.c)
 endif()
 
 if (LWS_WITH_SSL)
 	list(APPEND SOURCES
-		lib/ssl.c
+		lib/tls/tls.c
 		lib/misc/lws-genhash.c)
 		
+		if (LWS_WITH_MBEDTLS)
+			list(APPEND SOURCES
+				lib/tls/mbedtls/ssl.c)
+		else()
+			list(APPEND SOURCES
+				lib/tls/openssl/ssl.c)
+		endif()
+		
 	if (NOT LWS_WITHOUT_SERVER)
 		list(APPEND SOURCES
-		lib/server/ssl-server.c)
+			lib/server/ssl-server.c)
+		if (LWS_WITH_MBEDTLS)
+			list(APPEND SOURCES
+				lib/tls/mbedtls/server.c)
+		else()
+			list(APPEND SOURCES
+				lib/tls/openssl/server.c)
+		endif()
 	endif()
 	if (NOT LWS_WITHOUT_CLIENT)
 		list(APPEND SOURCES
 		lib/client/ssl-client.c)
+		if (LWS_WITH_MBEDTLS)
+			list(APPEND SOURCES
+				lib/tls/mbedtls/client.c)
+		else()
+			list(APPEND SOURCES
+				lib/tls/openssl/client.c)
+		endif()
+		
 	endif()
 endif()
 
@@ -1173,7 +1196,9 @@ CHECK_FUNCTION_EXISTS(SSL_CTX_set1_param LWS_HAVE_SSL_CTX_set1_param)
 CHECK_FUNCTION_EXISTS(SSL_set_info_callback LWS_HAVE_SSL_SET_INFO_CALLBACK)
 CHECK_FUNCTION_EXISTS(X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set1_host)
 CHECK_FUNCTION_EXISTS(RSA_set0_key LWS_HAVE_RSA_SET0_KEY)
-
+if (LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS)
+CHECK_SYMBOL_EXISTS(SSL_CTX_get_extra_chain_certs_only openssl/ssl.h LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
+endif()
 if (LWS_WITH_MBEDTLS)
 	set(LWS_HAVE_TLS_CLIENT_METHOD 1)
 	if (NOT LWS_WITH_ESP32)
diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in
index 0da150f5..2c429e0b 100644
--- a/cmake/lws_config.h.in
+++ b/cmake/lws_config.h.in
@@ -150,6 +150,7 @@
 #cmakedefine LWS_HAVE_TLS_CLIENT_METHOD
 #cmakedefine LWS_HAVE_TLSV1_2_CLIENT_METHOD
 #cmakedefine LWS_HAVE_SSL_SET_INFO_CALLBACK
+#cmakedefine LWS_HAVE_SSL_EXTRA_CHAIN_CERTS
 
 #cmakedefine LWS_HAS_INTPTR_T
 
diff --git a/lib/client/client.c b/lib/client/client.c
index 20450aa9..f7fa4c76 100644
--- a/lib/client/client.c
+++ b/lib/client/client.c
@@ -258,10 +258,8 @@ start_ws_handshake:
 #ifdef LWS_OPENSSL_SUPPORT
 		/* we can retry this... just cook the SSL BIO the first time */
 
-		if (wsi->use_ssl && !wsi->ssl) {
-			if (lws_ssl_client_bio_create(wsi))
-				return -1;
-		}
+		if (wsi->use_ssl && !wsi->ssl && lws_ssl_client_bio_create(wsi))
+			return -1;
 
 		if (wsi->use_ssl) {
 			n = lws_ssl_client_connect1(wsi);
diff --git a/lib/client/ssl-client.c b/lib/client/ssl-client.c
index b69fd2da..50f5dd04 100644
--- a/lib/client/ssl-client.c
+++ b/lib/client/ssl-client.c
@@ -1,5 +1,5 @@
 /*
- * libwebsockets - small server side websockets and web server implementation
+ * libwebsockets - client-related ssl code independent of backend
  *
  * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
  *
@@ -21,224 +21,6 @@
 
 #include "private-libwebsockets.h"
 
-extern int openssl_websocket_private_data_index,
-    openssl_SSL_CTX_private_data_index;
-
-extern void
-lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);
-
-extern int lws_ssl_get_error(struct lws *wsi, int n);
-
-#if defined(USE_WOLFSSL)
-#else
-
-static int
-OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
-{
-#if defined(LWS_WITH_MBEDTLS)
-	lwsl_notice("%s\n", __func__);
-
-	return 0;
-#else
-	SSL *ssl;
-	int n;
-	struct lws *wsi;
-
-	/* keep old behaviour accepting self-signed server certs */
-	if (!preverify_ok) {
-		int err = X509_STORE_CTX_get_error(x509_ctx);
-
-		if (err != X509_V_OK) {
-			ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-			wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
-
-			if ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
-					err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
-					wsi->use_ssl & LCCSCF_ALLOW_SELFSIGNED) {
-				lwsl_notice("accepting self-signed certificate (verify_callback)\n");
-				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
-				return 1;	// ok
-			} else if ((err == X509_V_ERR_CERT_NOT_YET_VALID ||
-					err == X509_V_ERR_CERT_HAS_EXPIRED) &&
-					wsi->use_ssl & LCCSCF_ALLOW_EXPIRED) {
-				if (err == X509_V_ERR_CERT_NOT_YET_VALID)
-					lwsl_notice("accepting not yet valid certificate (verify_callback)\n");
-				else if (err == X509_V_ERR_CERT_HAS_EXPIRED)
-					lwsl_notice("accepting expired certificate (verify_callback)\n");
-				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
-				return 1;	// ok
-			}
-		}
-	}
-
-	ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-	wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
-
-	n = lws_get_context_protocol(wsi->context, 0).callback(wsi,
-			LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION,
-			x509_ctx, ssl, preverify_ok);
-
-	/* keep old behaviour if something wrong with server certs */
-	/* if ssl error is overruled in callback and cert is ok,
-	 * X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); must be set and
-	 * return value is 0 from callback */
-	if (!preverify_ok) {
-		int err = X509_STORE_CTX_get_error(x509_ctx);
-
-		if (err != X509_V_OK) {	/* cert validation error was not handled in callback */
-			int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
-			const char* msg = X509_verify_cert_error_string(err);
-			lwsl_err("SSL error: %s (preverify_ok=%d;err=%d;depth=%d)\n", msg, preverify_ok, err, depth);
-			return preverify_ok;	// not ok
-		}
-	}
-	/* convert callback return code from 0 = OK to verify callback return value 1 = OK */
-	return !n;
-#endif
-}
-#endif
-
-int
-lws_ssl_client_bio_create(struct lws *wsi)
-{
-	char hostname[128], *p;
-
-	if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
-			 _WSI_TOKEN_CLIENT_HOST) <= 0) {
-		lwsl_err("%s: Unable to get hostname\n", __func__);
-
-		return -1;
-	}
-
-	/*
-	 * remove any :port part on the hostname... necessary for network
-	 * connection but typical certificates do not contain it
-	 */
-	p = hostname;
-	while (*p) {
-		if (*p == ':') {
-			*p = '\0';
-			break;
-		}
-		p++;
-	}
-
-	wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx);
-	if (!wsi->ssl) {
-		lwsl_err("SSL_new failed: %s\n",
-		         ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
-		lws_ssl_elaborate_error();
-		return -1;
-	}
-
-#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
-	if (wsi->vhost->ssl_info_event_mask)
-		SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
-#endif
-
-#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
-	X509_VERIFY_PARAM *param;
-	(void)param;
-
-	if (!(wsi->use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
-		param = SSL_get0_param(wsi->ssl);
-		/* Enable automatic hostname checks */
-		X509_VERIFY_PARAM_set_hostflags(param,
-						X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
-		X509_VERIFY_PARAM_set1_host(param, hostname, 0);
-	}
-
-#endif
-
-#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_MBEDTLS)
-#ifndef USE_OLD_CYASSL
-	/* OpenSSL_client_verify_callback will be called @ SSL_connect() */
-	SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);
-#endif
-#endif
-
-#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_MBEDTLS)
-	SSL_set_mode(wsi->ssl,  SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-#endif
-	/*
-	 * use server name indication (SNI), if supported,
-	 * when establishing connection
-	 */
-#ifdef USE_WOLFSSL
-#ifdef USE_OLD_CYASSL
-#ifdef CYASSL_SNI_HOST_NAME
-	CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname));
-#endif
-#else
-#ifdef WOLFSSL_SNI_HOST_NAME
-	wolfSSL_UseSNI(wsi->ssl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname));
-#endif
-#endif
-#else
-#if defined(LWS_WITH_MBEDTLS)
-	if (wsi->vhost->x509_client_CA)
-		SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);
-	else
-		SSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, OpenSSL_client_verify_callback);
-
-#else
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-	SSL_set_tlsext_host_name(wsi->ssl, hostname);
-#endif
-#endif
-#endif
-
-#ifdef USE_WOLFSSL
-	/*
-	 * wolfSSL/CyaSSL does certificate verification differently
-	 * from OpenSSL.
-	 * If we should ignore the certificate, we need to set
-	 * this before SSL_new and SSL_connect is called.
-	 * Otherwise the connect will simply fail with error code -155
-	 */
-#ifdef USE_OLD_CYASSL
-	if (wsi->use_ssl == 2)
-		CyaSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL);
-#else
-	if (wsi->use_ssl == 2)
-		wolfSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL);
-#endif
-#endif /* USE_WOLFSSL */
-
-#if !defined(LWS_WITH_MBEDTLS)
-	wsi->client_bio = BIO_new_socket(wsi->desc.sockfd, BIO_NOCLOSE);
-	SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
-#else
-	SSL_set_fd(wsi->ssl, wsi->desc.sockfd);
-#endif
-
-#ifdef USE_WOLFSSL
-#ifdef USE_OLD_CYASSL
-	CyaSSL_set_using_nonblock(wsi->ssl, 1);
-#else
-	wolfSSL_set_using_nonblock(wsi->ssl, 1);
-#endif
-#else
-#if !defined(LWS_WITH_MBEDTLS)
-	BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
-#endif
-#endif
-
-#if !defined(LWS_WITH_MBEDTLS)
-	SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index,
-			wsi);
-#endif
-
-	return 0;
-}
-
-#if defined(LWS_WITH_MBEDTLS)
-int ERR_get_error(void)
-{
-	return 0;
-}
-#endif
-
 int
 lws_ssl_client_connect1(struct lws *wsi)
 {
@@ -246,187 +28,59 @@ lws_ssl_client_connect1(struct lws *wsi)
 	int n = 0;
 
 	lws_latency_pre(context, wsi);
-
-	n = SSL_connect(wsi->ssl);
-
+	n = lws_tls_client_connect(wsi);
 	lws_latency(context, wsi,
 	  "SSL_connect LWSCM_WSCL_ISSUE_HANDSHAKE", n, n > 0);
 
-	if (n < 0) {
-		n = lws_ssl_get_error(wsi, n);
-
-		if (n == SSL_ERROR_WANT_READ)
-			goto some_wait;
-
-		if (n == SSL_ERROR_WANT_WRITE) {
-			/*
-			 * wants us to retry connect due to
-			 * state of the underlying ssl layer...
-			 * but since it may be stalled on
-			 * blocked write, no incoming data may
-			 * arrive to trigger the retry.
-			 * Force (possibly many times if the SSL
-			 * state persists in returning the
-			 * condition code, but other sockets
-			 * are getting serviced inbetweentimes)
-			 * us to get called back when writable.
-			 */
-			lwsl_info("%s: WANT_WRITE... retrying\n", __func__);
-			lws_callback_on_writable(wsi);
-some_wait:
-			wsi->mode = LWSCM_WSCL_WAITING_SSL;
-
-			return 0; /* no error */
-		}
-
-		{
-			struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-			char *p = (char *)&pt->serv_buf[0];
-			char *sb = p;
-
-			lwsl_err("ssl hs1 error, X509_V_ERR = %d: %s\n",
-				 n, ERR_error_string(n, sb));
-			lws_ssl_elaborate_error();
-		}
-
-		n = -1;
-	}
-
-	if (n <= 0) {
-		/*
-		 * retry if new data comes until we
-		 * run into the connection timeout or win
-		 */
-
-		unsigned long error = ERR_get_error();
-
-		if (error != SSL_ERROR_NONE) {
-			struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-			char *p = (char *)&pt->serv_buf[0];
-			char *sb = p;
-			lwsl_err("SSL connect error %lu: %s\n",
-				error, ERR_error_string(error, sb));
-			return -1;
-		}
-
-		return 0;
-	}
-
-	return 1;
+	switch (n) {
+	case LWS_SSL_CAPABLE_ERROR:
+		return -1;
+	case LWS_SSL_CAPABLE_DONE:
+		return 1; /* connected */
+	case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
+		lws_callback_on_writable(wsi);
+		/* fallthru */
+	case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
+		wsi->mode = LWSCM_WSCL_WAITING_SSL;
+		break;
+	case LWS_SSL_CAPABLE_MORE_SERVICE:
+		break;
+	}
+
+	return 0; /* retry */
 }
 
 int
 lws_ssl_client_connect2(struct lws *wsi)
 {
-	struct lws_context *context = wsi->context;
-	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-	char *p = (char *)&pt->serv_buf[0];
-	char *sb = p;
 	int n = 0;
 
 	if (wsi->mode == LWSCM_WSCL_WAITING_SSL) {
-		lws_latency_pre(context, wsi);
-		n = SSL_connect(wsi->ssl);
-		lwsl_debug("%s: SSL_connect says %d\n", __func__, n);
+		lws_latency_pre(wsi->context, wsi);
 
-		lws_latency(context, wsi,
+		n = lws_tls_client_connect(wsi);
+		lwsl_debug("%s: SSL_connect says %d\n", __func__, n);
+		lws_latency(wsi->context, wsi,
 			    "SSL_connect LWSCM_WSCL_WAITING_SSL", n, n > 0);
 
-		if (n < 0) {
-			n = lws_ssl_get_error(wsi, n);
-
-			if (n == SSL_ERROR_WANT_READ) {
-				lwsl_info("SSL_connect WANT_READ... retrying\n");
-
-				wsi->mode = LWSCM_WSCL_WAITING_SSL;
-
-				return 0; /* no error */
-			}
-
-			if (n == SSL_ERROR_WANT_WRITE) {
-				/*
-				 * wants us to retry connect due to
-				 * state of the underlying ssl layer...
-				 * but since it may be stalled on
-				 * blocked write, no incoming data may
-				 * arrive to trigger the retry.
-				 * Force (possibly many times if the SSL
-				 * state persists in returning the
-				 * condition code, but other sockets
-				 * are getting serviced inbetweentimes)
-				 * us to get called back when writable.
-				 */
-				lwsl_info("SSL_connect WANT_WRITE... retrying\n");
-				lws_callback_on_writable(wsi);
-
-				wsi->mode = LWSCM_WSCL_WAITING_SSL;
-
-				return 0; /* no error */
-			}
-
-			n = -1;
-		}
-
-		if (n <= 0) {
-			/*
-			 * retry if new data comes until we
-			 * run into the connection timeout or win
-			 */
-			unsigned long error = ERR_get_error();
-			if (error != SSL_ERROR_NONE) {
-				lwsl_err("SSL connect error %lu: %s\n",
-					 error, ERR_error_string(error, sb));
-				return -1;
-			}
-		}
-	}
-
-#if defined(LWS_WITH_MBEDTLS)
-	{
-		X509 *peer = SSL_get_peer_certificate(wsi->ssl);
-
-		if (!peer) {
-			lwsl_notice("peer did not provide cert\n");
-
-			return -1;
-		}
-		lwsl_notice("peer provided cert\n");
-	}
-#endif
-
-#ifndef USE_WOLFSSL
-	/*
-	 * See comment above about wolfSSL certificate
-	 * verification
-	 */
-	lws_latency_pre(context, wsi);
-	n = SSL_get_verify_result(wsi->ssl);
-	lws_latency(context, wsi,
-		"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);
-
-	lwsl_debug("get_verify says %d\n", n);
-
-	if (n != X509_V_OK) {
-		if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
-		     n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
-		     (wsi->use_ssl & LCCSCF_ALLOW_SELFSIGNED)) {
-			lwsl_notice("accepting self-signed certificate\n");
-		} else if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
-		            n == X509_V_ERR_CERT_HAS_EXPIRED) &&
-		     (wsi->use_ssl & LCCSCF_ALLOW_EXPIRED)) {
-			lwsl_notice("accepting expired certificate\n");
-		} else if (n == X509_V_ERR_CERT_NOT_YET_VALID) {
-			lwsl_notice("Cert is from the future... "
-				    "probably our clock... accepting...\n");
-		} else {
-			lwsl_err("server's cert didn't look good, X509_V_ERR = %d: %s\n",
-				 n, ERR_error_string(n, sb));
-			lws_ssl_elaborate_error();
+		switch (n) {
+		case LWS_SSL_CAPABLE_ERROR:
 			return -1;
+		case LWS_SSL_CAPABLE_DONE:
+			break; /* connected */
+		case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
+			lws_callback_on_writable(wsi);
+			/* fallthru */
+		case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
+			wsi->mode = LWSCM_WSCL_WAITING_SSL;
+			/* fallthru */
+		case LWS_SSL_CAPABLE_MORE_SERVICE:
+			return 0;
 		}
 	}
 
-#endif /* USE_WOLFSSL */
+	if (lws_tls_client_confirm_peer_cert(wsi))
+		return -1;
 
 	return 1;
 }
@@ -435,15 +89,11 @@ lws_ssl_client_connect2(struct lws *wsi)
 int lws_context_init_client_ssl(struct lws_context_creation_info *info,
 				struct lws_vhost *vhost)
 {
-	SSL_METHOD *method = NULL;
-	struct lws wsi;
-	unsigned long error;
 	const char *ca_filepath = info->ssl_ca_filepath;
-#if !defined(LWS_WITH_MBEDTLS)
 	const char *cipher_list = info->ssl_cipher_list;
 	const char *private_key_filepath = info->ssl_private_key_filepath;
 	const char *cert_filepath = info->ssl_cert_filepath;
-	int n;
+	struct lws wsi;
 
 	if (vhost->options & LWS_SERVER_OPTION_ONLY_RAW)
 		return 0;
@@ -458,7 +108,7 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
 		cert_filepath = info->client_ssl_cert_filepath;
 	if (info->client_ssl_private_key_filepath)
 		private_key_filepath = info->client_ssl_private_key_filepath;
-#endif
+
 	if (info->client_ssl_ca_filepath)
 		ca_filepath = info->client_ssl_ca_filepath;
 
@@ -477,138 +127,13 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info,
 		return 0;
 	}
 
-	/* basic openssl init already happened in context init */
-
-	/* choose the most recent spin of the api */
-#if defined(LWS_HAVE_TLS_CLIENT_METHOD)
-	method = (SSL_METHOD *)TLS_client_method();
-#elif defined(LWS_HAVE_TLSV1_2_CLIENT_METHOD)
-	method = (SSL_METHOD *)TLSv1_2_client_method();
-#else
-	method = (SSL_METHOD *)SSLv23_client_method();
-#endif
-	if (!method) {
-		error = ERR_get_error();
-		lwsl_err("problem creating ssl method %lu: %s\n",
-			error, ERR_error_string(error,
-				      (char *)vhost->context->pt[0].serv_buf));
-		return 1;
-	}
-	/* create context */
-	vhost->ssl_client_ctx = SSL_CTX_new(method);
-	if (!vhost->ssl_client_ctx) {
-		error = ERR_get_error();
-		lwsl_err("problem creating ssl context %lu: %s\n",
-			error, ERR_error_string(error,
-				      (char *)vhost->context->pt[0].serv_buf));
+	if (lws_tls_client_create_vhost_context(vhost, info, cipher_list,
+						ca_filepath, cert_filepath,
+						private_key_filepath))
 		return 1;
-	}
 
 	lwsl_notice("created client ssl context for %s\n", vhost->name);
 
-#ifdef SSL_OP_NO_COMPRESSION
-	SSL_CTX_set_options(vhost->ssl_client_ctx, SSL_OP_NO_COMPRESSION);
-#endif
-
-#if defined(LWS_WITH_MBEDTLS)
-	if (ca_filepath) {
-		lws_filepos_t len;
-		uint8_t *buf;
-		/*
-		 * prototype this here, the shim does not export it in the
-		 * header, and we need to use the shim unchanged for ESP32 case
-		 */
-		X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);
-
-		if (alloc_file(vhost->context, ca_filepath, &buf, &len)) {
-			lwsl_err("Load CA cert file %s failed\n", ca_filepath);
-			return 1;
-		}
-
-		vhost->x509_client_CA = d2i_X509(NULL, buf, len);
-		free(buf);
-		if (!vhost->x509_client_CA) {
-			lwsl_err("client CA: x509 parse failed\n");
-			return 1;
-		}
-
-		SSL_CTX_add_client_CA(vhost->ssl_client_ctx,
-				      vhost->x509_client_CA);
-
-		lwsl_notice("client loaded CA for verification %s\n", ca_filepath);
-	}
-#else
-	SSL_CTX_set_options(vhost->ssl_client_ctx,
-			    SSL_OP_CIPHER_SERVER_PREFERENCE);
-
-	if (cipher_list)
-		SSL_CTX_set_cipher_list(vhost->ssl_client_ctx, cipher_list);
-
-#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS
-	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
-		/* loads OS default CA certs */
-		SSL_CTX_set_default_verify_paths(vhost->ssl_client_ctx);
-#endif
-
-	/* openssl init for cert verification (for client sockets) */
-	if (!ca_filepath) {
-		if (!SSL_CTX_load_verify_locations(
-			vhost->ssl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS))
-			lwsl_err("Unable to load SSL Client certs from %s "
-			    "(set by LWS_OPENSSL_CLIENT_CERTS) -- "
-			    "client ssl isn't going to work\n",
-			    LWS_OPENSSL_CLIENT_CERTS);
-	} else
-		if (!SSL_CTX_load_verify_locations(
-			vhost->ssl_client_ctx, ca_filepath, NULL)) {
-			lwsl_err(
-				"Unable to load SSL Client certs "
-				"file from %s -- client ssl isn't "
-				"going to work\n", info->client_ssl_ca_filepath);
-			lws_ssl_elaborate_error();
-		}
-		else
-			lwsl_info("loaded ssl_ca_filepath\n");
-
-	/*
-	 * callback allowing user code to load extra verification certs
-	 * helping the client to verify server identity
-	 */
-
-	/* support for client-side certificate authentication */
-	if (cert_filepath) {
-		lwsl_notice("%s: doing cert filepath\n", __func__);
-		n = SSL_CTX_use_certificate_chain_file(vhost->ssl_client_ctx,
-						       cert_filepath);
-		if (n < 1) {
-			lwsl_err("problem %d getting cert '%s'\n", n,
-				 cert_filepath);
-			lws_ssl_elaborate_error();
-			return 1;
-		}
-		lwsl_notice("Loaded client cert %s\n", cert_filepath);
-	}
-	if (private_key_filepath) {
-		lwsl_notice("%s: doing private key filepath\n", __func__);
-		lws_ssl_bind_passphrase(vhost->ssl_client_ctx, info);
-		/* set the private key from KeyFile */
-		if (SSL_CTX_use_PrivateKey_file(vhost->ssl_client_ctx,
-		    private_key_filepath, SSL_FILETYPE_PEM) != 1) {
-			lwsl_err("use_PrivateKey_file '%s'\n",
-				 private_key_filepath);
-			lws_ssl_elaborate_error();
-			return 1;
-		}
-		lwsl_notice("Loaded client cert private key %s\n",
-			    private_key_filepath);
-
-		/* verify private key */
-		if (!SSL_CTX_check_private_key(vhost->ssl_client_ctx)) {
-			lwsl_err("Private SSL key doesn't match cert\n");
-			return 1;
-		}
-	}
-#endif
 	/*
 	 * give him a fake wsi with context set, so he can use
 	 * lws_get_context() in the callback
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 669f4edf..55d15611 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -621,35 +621,19 @@ just_kill_connection:
 	    wsi->state != LWSS_CLIENT_UNCONNECTED &&
 	    reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY &&
 	    !wsi->socket_is_permanently_unusable) {
+
 #ifdef LWS_OPENSSL_SUPPORT
-		if (lws_is_ssl(wsi) && wsi->ssl) {
-			n = SSL_shutdown(wsi->ssl);
-			/*
-			 * If finished the SSL shutdown, then do socket
-			 * shutdown, else need to retry SSL shutdown
-			 */
-			switch (n) {
-			case 0:
-				lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
-				break;
-			case 1:
-				n = shutdown(wsi->desc.sockfd, SHUT_WR);
-				break;
-			default:
-				if (SSL_want_read(wsi->ssl)) {
-					lws_change_pollfd(wsi, 0, LWS_POLLIN);
-					n = 0;
-					break;
-				}
-				if (SSL_want_write(wsi->ssl)) {
-					lws_change_pollfd(wsi, 0, LWS_POLLOUT);
-					n = 0;
-					break;
-				}
-				n = shutdown(wsi->desc.sockfd, SHUT_WR);
-				break;
-			}
-		} else
+	if (lws_is_ssl(wsi) && wsi->ssl) {
+		n = 0;
+		switch (lws_tls_shutdown(wsi)) {
+		case LWS_SSL_CAPABLE_DONE:
+		case LWS_SSL_CAPABLE_ERROR:
+		case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
+		case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
+		case LWS_SSL_CAPABLE_MORE_SERVICE:
+			break;
+		}
+	} else
 #endif
 		{
 			lwsl_info("%s: shutdown conn: %p (sock %d, state %d)\n",
@@ -1858,7 +1842,7 @@ lws_is_ssl(struct lws *wsi)
 }
 
 #ifdef LWS_OPENSSL_SUPPORT
-LWS_VISIBLE SSL*
+LWS_VISIBLE lws_tls_conn*
 lws_get_ssl(struct lws *wsi)
 {
 	return wsi->ssl;
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index e1d5110a..f78560b6 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -210,11 +210,12 @@ typedef unsigned long long lws_intptr_t;
 #define MBEDTLS_CONFIG_FILE <mbedtls/esp_config.h>
 #endif
 #include <mbedtls/ssl.h>
-#endif
+#else
 #include <openssl/ssl.h>
 #if !defined(LWS_WITH_MBEDTLS)
 #include <openssl/err.h>
 #endif
+#endif
 #endif /* not USE_WOLFSSL */
 #endif
 
@@ -2191,12 +2192,12 @@ struct lws_context_creation_info {
 	int ka_interval;
 	/**< CONTEXT: if ka_time was nonzero, how long to wait before each ka_probes
 	 * attempt */
-#ifdef LWS_OPENSSL_SUPPORT
+#if defined(LWS_OPENSSL_SUPPORT) && !defined(LWS_WITH_MBEDTLS)
 	SSL_CTX *provided_client_ssl_ctx;
 	/**< CONTEXT: If non-null, swap out libwebsockets ssl
- *		implementation for the one provided by provided_ssl_ctx.
- *		Libwebsockets no longer is responsible for freeing the context
- *		if this option is selected. */
+	  * implementation for the one provided by provided_ssl_ctx.
+	  * Libwebsockets no longer is responsible for freeing the context
+	  * if this option is selected. */
 #else /* maintain structure layout either way */
 	void *provided_client_ssl_ctx; /**< dummy if ssl disabled */
 #endif
@@ -4995,7 +4996,7 @@ lws_is_ssl(struct lws *wsi);
 LWS_VISIBLE LWS_EXTERN int
 lws_is_cgi(struct lws *wsi);
 
-#ifdef LWS_OPENSSL_SUPPORT
+#if defined(LWS_OPENSSL_SUPPORT) && !defined(LWS_WITH_MBEDTLS)
 /**
  * lws_get_ssl() - Return wsi's SSL context structure
  * \param wsi:	websocket connection
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 74ce7c55..28b58923 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -283,6 +283,7 @@ lws_plat_get_peer_simple(struct lws *wsi, char *name, int namelen);
 #if defined(LWS_WITH_MBEDTLS)
 #include <mbedtls/ssl.h>
 #include <mbedtls/x509_crt.h>
+#include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */
 #else
 #include <openssl/ssl.h>
 #include <openssl/evp.h>
@@ -477,6 +478,53 @@ extern "C" {
 #define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
 #endif
 
+/*
+ * Choose the SSL backend
+ */
+
+#if defined(LWS_OPENSSL_SUPPORT)
+#if defined(LWS_WITH_MBEDTLS________)
+struct lws_tls_mbed_ctx {
+
+};
+struct lws_tls_mbed_conn {
+
+};
+struct lws_tls_mbed_bio {
+
+};
+struct lws_tls_mbed_x509 {
+
+};
+typedef struct lws_tls_mbed_conn lws_tls_conn;
+typedef struct lws_tls_mbed_ctx lws_tls_ctx;
+typedef struct lws_tls_mbed_bio lws_tls_bio;
+typedef struct lws_tls_mbed_x509 lws_tls_x509;
+#else
+typedef SSL lws_tls_conn;
+typedef SSL_CTX lws_tls_ctx;
+typedef BIO lws_tls_bio;
+typedef X509 lws_tls_x509;
+#endif
+#endif
+
+/*
+ * All lws_tls...() functions must return this type, converting the
+ * native backend result and doing the extra work to determine which one
+ * as needed.
+ *
+ * Native TLS backend return codes are NOT ALLOWED outside the backend.
+ *
+ * Non-SSL mode also uses these types.
+ */
+enum lws_ssl_capable_status {
+	LWS_SSL_CAPABLE_ERROR = -1,		 /* it failed */
+	LWS_SSL_CAPABLE_DONE = 0,		 /* it succeeded */
+	LWS_SSL_CAPABLE_MORE_SERVICE_READ = -2,	 /* retry WANT_READ */
+	LWS_SSL_CAPABLE_MORE_SERVICE_WRITE = -3,  /* retry WANT_WRITE */
+	LWS_SSL_CAPABLE_MORE_SERVICE = -4,	 /* general retry */
+};
+
 enum lws_websocket_opcodes_07 {
 	LWSWSOPC_CONTINUATION = 0,
 	LWSWSOPC_TEXT_FRAME = 1,
@@ -924,11 +972,11 @@ struct lws_vhost {
 	const struct lws_protocol_vhost_options *headers;
 	struct lws **same_vh_protocol_list;
 #ifdef LWS_OPENSSL_SUPPORT
-	SSL_CTX *ssl_ctx;
-	SSL_CTX *ssl_client_ctx;
+	lws_tls_ctx *ssl_ctx;
+	lws_tls_ctx *ssl_client_ctx;
 #endif
 #if defined(LWS_WITH_MBEDTLS)
-	X509 *x509_client_CA;
+	lws_tls_x509 *x509_client_CA;
 #endif
 #ifndef LWS_NO_EXTENSIONS
 	const struct lws_extension *extensions;
@@ -1879,8 +1927,8 @@ struct lws {
 	void *act_ext_user[LWS_MAX_EXTENSIONS_ACTIVE];
 #endif
 #ifdef LWS_OPENSSL_SUPPORT
-	SSL *ssl;
-	BIO *client_bio;
+	lws_tls_conn *ssl;
+	lws_tls_bio *client_bio;
 	struct lws *pending_read_list_prev, *pending_read_list_next;
 #if defined(LWS_WITH_STATS)
 	uint64_t accept_start_us;
@@ -2272,11 +2320,6 @@ interface_to_sa(struct lws_vhost *vh, const char *ifname,
 #endif
 LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
 
-enum lws_ssl_capable_status {
-	LWS_SSL_CAPABLE_ERROR = -1,
-	LWS_SSL_CAPABLE_MORE_SERVICE = -2,
-};
-
 #ifndef LWS_OPENSSL_SUPPORT
 #define LWS_SSL_ENABLED(context) (0)
 #define lws_context_init_server_ssl(_a, _b) (0)
@@ -2323,6 +2366,13 @@ LWS_EXTERN void
 lws_ssl_elaborate_error(void);
 LWS_EXTERN int
 lws_ssl_anybody_has_buffered_read_tsi(struct lws_context *context, int tsi);
+LWS_EXTERN int
+lws_gate_accepts(struct lws_context *context, int on);
+LWS_EXTERN void
+lws_ssl_bind_passphrase(lws_tls_ctx *ssl_ctx, struct lws_context_creation_info *info);
+LWS_EXTERN void
+lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
+
 #ifndef LWS_NO_SERVER
 LWS_EXTERN int
 lws_context_init_server_ssl(struct lws_context_creation_info *info,
@@ -2332,6 +2382,47 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
 #endif
 LWS_EXTERN void
 lws_ssl_destroy(struct lws_vhost *vhost);
+LWS_EXTERN char *
+lws_ssl_get_error_string(int status, int ret, char *buf, size_t len);
+
+/*
+ * lws_tls_ abstract backend implementations
+ */
+
+LWS_EXTERN int
+lws_tls_server_client_cert_verify_config(struct lws_context_creation_info *info,
+					 struct lws_vhost *vh);
+LWS_EXTERN int
+lws_tls_server_vhost_backend_init(struct lws_context_creation_info *info,
+				  struct lws_vhost *vhost, struct lws *wsi);
+LWS_EXTERN int
+lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd);
+
+LWS_EXTERN enum lws_ssl_capable_status
+lws_tls_server_accept(struct lws *wsi);
+
+LWS_EXTERN enum lws_ssl_capable_status
+lws_tls_server_abort_connection(struct lws *wsi);
+
+LWS_EXTERN enum lws_ssl_capable_status
+lws_tls_shutdown(struct lws *wsi);
+
+LWS_EXTERN enum lws_ssl_capable_status
+lws_tls_client_connect(struct lws *wsi);
+LWS_EXTERN int
+lws_tls_client_confirm_peer_cert(struct lws *wsi);
+LWS_EXTERN int
+lws_tls_client_create_vhost_context(struct lws_vhost *vh,
+				    struct lws_context_creation_info *info,
+				    const char *cipher_list,
+				    const char *ca_filepath,
+				    const char *cert_filepath,
+				    const char *private_key_filepath);
+LWS_EXTERN lws_tls_ctx *
+lws_tls_ctx_from_wsi(struct lws *wsi);
+LWS_EXTERN int
+lws_ssl_get_error(struct lws *wsi, int n);
+
 /* HTTP2-related */
 
 #ifdef LWS_WITH_HTTP2
@@ -2437,7 +2528,7 @@ lws_context_init_client_ssl(struct lws_context_creation_info *info,
 			    struct lws_vhost *vhost);
 
 LWS_EXTERN void
-lws_ssl_info_callback(const SSL *ssl, int where, int ret);
+lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
 
 #else
 	#define lws_context_init_client_ssl(_a, _b) (0)
@@ -2560,8 +2651,7 @@ LWS_EXTERN int LWS_WARN_UNUSED_RESULT
 lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len);
 LWS_EXTERN int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
 		                lws_filepos_t *amount);
-LWS_EXTERN int alloc_pem_to_der_file(struct lws_context *context, const char *filename, uint8_t **buf,
-	       lws_filepos_t *amount);
+
 
 LWS_EXTERN void
 lws_same_vh_protocol_remove(struct lws *wsi);
diff --git a/lib/server/ssl-server.c b/lib/server/ssl-server.c
index a9516f22..f5531e40 100644
--- a/lib/server/ssl-server.c
+++ b/lib/server/ssl-server.c
@@ -21,185 +21,17 @@
 
 #include "private-libwebsockets.h"
 
-extern int openssl_websocket_private_data_index,
-    openssl_SSL_CTX_private_data_index;
-
-extern void
-lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info);
-
-#if !defined(LWS_WITH_MBEDTLS)
-static int
-OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
-{
-	SSL *ssl;
-	int n;
-	struct lws *wsi;
-
-	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
-		SSL_get_ex_data_X509_STORE_CTX_idx());
-
-	/*
-	 * !!! nasty openssl requires the index to come as a library-scope
-	 * static
-	 */
-	wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
-
-	n = wsi->vhost->protocols[0].callback(wsi,
-			LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
-					   x509_ctx, ssl, preverify_ok);
-
-	/* convert return code from 0 = OK to 1 = OK */
-	return !n;
-}
-#endif
-
-static int
-lws_context_ssl_init_ecdh(struct lws_vhost *vhost)
-{
-#ifdef LWS_SSL_SERVER_WITH_ECDH_CERT
-	EC_KEY *EC_key = NULL;
-	EVP_PKEY *pkey;
-	int KeyType;
-	X509 *x;
-
-	if (!lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_SSL_ECDH))
-		return 0;
-
-	lwsl_notice(" Using ECDH certificate support\n");
-
-	/* Get X509 certificate from ssl context */
-	x = sk_X509_value(vhost->ssl_ctx->extra_certs, 0);
-	if (!x) {
-		lwsl_err("%s: x is NULL\n", __func__);
-		return 1;
-	}
-	/* Get the public key from certificate */
-	pkey = X509_get_pubkey(x);
-	if (!pkey) {
-		lwsl_err("%s: pkey is NULL\n", __func__);
-
-		return 1;
-	}
-	/* Get the key type */
-	KeyType = EVP_PKEY_type(pkey->type);
-
-	if (EVP_PKEY_EC != KeyType) {
-		lwsl_notice("Key type is not EC\n");
-		return 0;
-	}
-	/* Get the key */
-	EC_key = EVP_PKEY_get1_EC_KEY(pkey);
-	/* Set ECDH parameter */
-	if (!EC_key) {
-		lwsl_err("%s: ECDH key is NULL \n", __func__);
-		return 1;
-	}
-	SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, EC_key);
-	EC_KEY_free(EC_key);
-#endif
-	return 0;
-}
-
-static int
-lws_context_ssl_init_ecdh_curve(struct lws_context_creation_info *info,
-				struct lws_vhost *vhost)
-{
-#if defined(LWS_HAVE_OPENSSL_ECDH_H) && !defined(LWS_WITH_MBEDTLS)
-	EC_KEY *ecdh;
-	int ecdh_nid;
-	const char *ecdh_curve = "prime256v1";
-
-	if (info->ecdh_curve)
-		ecdh_curve = info->ecdh_curve;
-
-	ecdh_nid = OBJ_sn2nid(ecdh_curve);
-	if (NID_undef == ecdh_nid) {
-		lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve);
-		return 1;
-	}
-
-	ecdh = EC_KEY_new_by_curve_name(ecdh_nid);
-	if (NULL == ecdh) {
-		lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve);
-		return 1;
-	}
-	SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, ecdh);
-	EC_KEY_free(ecdh);
-
-	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
-
-	lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve);
-#else
-#if !defined(LWS_WITH_MBEDTLS)
-	lwsl_notice(" OpenSSL doesn't support ECDH\n");
-#endif
-#endif
-	return 0;
-}
-
-#if !defined(LWS_WITH_MBEDTLS) && defined(SSL_TLSEXT_ERR_NOACK) && !defined(OPENSSL_NO_TLSEXT)
-static int
-lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
-{
-	struct lws_context *context = (struct lws_context *)arg;
-	struct lws_vhost *vhost, *vh;
-	const char *servername;
-
-	if (!ssl)
-		return SSL_TLSEXT_ERR_NOACK;
-
-	/*
-	 * We can only get ssl accepted connections by using a vhost's ssl_ctx
-	 * find out which listening one took us and only match vhosts on the
-	 * same port.
-	 */
-	vh = context->vhost_list;
-	while (vh) {
-		if (!vh->being_destroyed && vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
-			break;
-		vh = vh->vhost_next;
-	}
-
-	if (!vh) {
-		assert(vh); /* can't match the incoming vh? */
-		return SSL_TLSEXT_ERR_OK;
-	}
-
-	servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
-	if (!servername) {
-		/* the client doesn't know what hostname it wants */
-		lwsl_info("SNI: Unknown ServerName: %s\n", servername);
-
-		return SSL_TLSEXT_ERR_OK;
-	}
-
-	vhost = lws_select_vhost(context, vh->listen_port, servername);
-	if (!vhost) {
-		lwsl_info("SNI: none: %s:%d\n", servername, vh->listen_port);
-
-		return SSL_TLSEXT_ERR_OK;
-	}
-
-	lwsl_info("SNI: Found: %s:%d\n", servername, vh->listen_port);
-
-	/* select the ssl ctx from the selected vhost for this conn */
-	SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
-
-	return SSL_TLSEXT_ERR_OK;
-}
-#endif
-
 LWS_VISIBLE int
 lws_context_init_server_ssl(struct lws_context_creation_info *info,
 			    struct lws_vhost *vhost)
 {
 	struct lws_context *context = vhost->context;
 	struct lws wsi;
-	unsigned long error;
-	int n;
 
-	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
+	if (!lws_check_opt(info->options,
+			   LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
 		vhost->use_ssl = 0;
+
 		return 0;
 	}
 
@@ -220,7 +52,8 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
 					LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX);
 
 		if (vhost->use_ssl && info->ssl_cipher_list)
-			lwsl_notice(" SSL ciphers: '%s'\n", info->ssl_cipher_list);
+			lwsl_notice(" SSL ciphers: '%s'\n",
+						info->ssl_cipher_list);
 
 		if (vhost->use_ssl)
 			lwsl_notice(" Using SSL mode\n");
@@ -236,109 +69,23 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
 	wsi.vhost = vhost;
 	wsi.context = context;
 
-	(void)n;
-	(void)error;
-
 	/*
-	 * Firefox insists on SSLv23 not SSLv3
-	 * Konq disables SSLv2 by default now, SSLv23 works
-	 *
-	 * SSLv23_server_method() is the openssl method for "allow all TLS
-	 * versions", compared to e.g. TLSv1_2_server_method() which only allows
-	 * tlsv1.2. Unwanted versions must be disabled using SSL_CTX_set_options()
+	 * as a server, if we are requiring clients to identify themselves
+	 * then set the backend up for it
 	 */
-#if !defined(LWS_WITH_MBEDTLS)
-	{
-		SSL_METHOD *method;
-
-		method = (SSL_METHOD *)SSLv23_server_method();
-		if (!method) {
-			error = ERR_get_error();
-			lwsl_err("problem creating ssl method %lu: %s\n",
-					error, ERR_error_string(error,
-					      (char *)context->pt[0].serv_buf));
-			return 1;
-		}
-		vhost->ssl_ctx = SSL_CTX_new(method);	/* create context */
-		if (!vhost->ssl_ctx) {
-			error = ERR_get_error();
-			lwsl_err("problem creating ssl context %lu: %s\n",
-					error, ERR_error_string(error,
-					      (char *)context->pt[0].serv_buf));
-			return 1;
-		}
-	}
-#else
-	{
-		const SSL_METHOD *method = TLSv1_2_server_method();
-
-		vhost->ssl_ctx = SSL_CTX_new(method);	/* create context */
-		if (!vhost->ssl_ctx) {
-			lwsl_err("problem creating ssl context\n");
-			return 1;
-		}
-
-	}
-#endif
-#if !defined(LWS_WITH_MBEDTLS)
-
-	/* associate the lws context with the SSL_CTX */
-
-	SSL_CTX_set_ex_data(vhost->ssl_ctx,
-			openssl_SSL_CTX_private_data_index, (char *)vhost->context);
-	/* Disable SSLv2 and SSLv3 */
-	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
-#ifdef SSL_OP_NO_COMPRESSION
-	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_COMPRESSION);
-#endif
-	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE);
-	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
-
-	if (info->ssl_cipher_list)
-		SSL_CTX_set_cipher_list(vhost->ssl_ctx,
-						info->ssl_cipher_list);
-#endif
-
-	/* as a server, are we requiring clients to identify themselves? */
+	lws_tls_server_client_cert_verify_config(info, vhost);
 
 	if (lws_check_opt(info->options,
-			  LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) {
-		int verify_options = SSL_VERIFY_PEER;
-
-		if (!lws_check_opt(info->options,
-				   LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
-			verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-
-#if !defined(LWS_WITH_MBEDTLS)
-		SSL_CTX_set_session_id_context(vhost->ssl_ctx,
-				(unsigned char *)context, sizeof(void *));
-
-		/* absolutely require the client cert */
-
-		SSL_CTX_set_verify(vhost->ssl_ctx,
-		       verify_options, OpenSSL_verify_callback);
-#endif
-	}
-
-#if !defined(LWS_WITH_MBEDTLS) && !defined(OPENSSL_NO_TLSEXT)
-	SSL_CTX_set_tlsext_servername_callback(vhost->ssl_ctx,
-					       lws_ssl_server_name_cb);
-	SSL_CTX_set_tlsext_servername_arg(vhost->ssl_ctx, context);
-#endif
+			  LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))
+		/* Normally SSL listener rejects non-ssl, optionally allow */
+		vhost->allow_non_ssl_on_ssl_port = 1;
 
 	/*
 	 * give user code a chance to load certs into the server
 	 * allowing it to verify incoming client certs
 	 */
-#if !defined(LWS_WITH_MBEDTLS)
-	if (info->ssl_ca_filepath &&
-	    !SSL_CTX_load_verify_locations(vhost->ssl_ctx,
-					   info->ssl_ca_filepath, NULL)) {
-		lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", __func__);
-	}
-#endif
 	if (vhost->use_ssl) {
-		if (lws_context_ssl_init_ecdh_curve(info, vhost))
+		if (lws_tls_server_vhost_backend_init(info, vhost, &wsi))
 			return -1;
 
 		vhost->protocols[0].callback(&wsi,
@@ -346,132 +93,213 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
 			vhost->ssl_ctx, NULL, 0);
 	}
 
-	if (lws_check_opt(info->options, LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT))
-		/* Normally SSL listener rejects non-ssl, optionally allow */
-		vhost->allow_non_ssl_on_ssl_port = 1;
+	if (vhost->use_ssl)
+		/*
+		 * SSL is happy and has a cert it's content with
+		 * If we're supporting HTTP2, initialize that
+		 */
+		lws_context_init_http2_ssl(vhost);
 
-	if (info->ssl_options_set)
-		SSL_CTX_set_options(vhost->ssl_ctx, info->ssl_options_set);
+	return 0;
+}
 
-/* SSL_clear_options introduced in 0.9.8m */
-#if !defined(LWS_WITH_MBEDTLS)
-#if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
-	if (info->ssl_options_clear)
-		SSL_CTX_clear_options(vhost->ssl_ctx, info->ssl_options_clear);
-#endif
-#endif
+LWS_VISIBLE int
+lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
+{
+	struct lws_context *context = wsi->context;
+	struct lws_vhost *vh;
+	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+	int n;
+        char buf[256];
 
-	lwsl_info(" SSL options 0x%lX\n", SSL_CTX_get_options(vhost->ssl_ctx));
+        (void)buf;
 
-	if (vhost->use_ssl && info->ssl_cert_filepath) {
-		/*
-		 * The user code can choose to either pass the cert and
-		 * key filepaths using the info members like this, or it can
-		 * leave them NULL; force the vhost SSL_CTX init using the info
-		 * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and
-		 * set up the cert himself using the user callback
-		 * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
-		 * happened just above and has the vhost SSL_CTX * in the user
-		 * parameter.
-		 */
-#if !defined(LWS_WITH_MBEDTLS)
-		/* set the local certificate from CertFile */
-		n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx,
-					info->ssl_cert_filepath);
-		if (n != 1) {
-			error = ERR_get_error();
-			lwsl_err("problem getting cert '%s' %lu: %s\n",
-				info->ssl_cert_filepath,
-				error,
-				ERR_error_string(error,
-					      (char *)context->pt[0].serv_buf));
+	if (!LWS_SSL_ENABLED(wsi->vhost))
+		return 0;
+
+	switch (wsi->mode) {
+	case LWSCM_SSL_INIT:
+	case LWSCM_SSL_INIT_RAW:
+		if (wsi->ssl)
+			lwsl_err("%s: leaking ssl\n", __func__);
+		if (accept_fd == LWS_SOCK_INVALID)
+			assert(0);
+		if (context->simultaneous_ssl_restriction &&
+		    context->simultaneous_ssl >= context->simultaneous_ssl_restriction) {
+			lwsl_notice("unable to deal with SSL connection\n");
 			return 1;
 		}
-		lws_ssl_bind_passphrase(vhost->ssl_ctx, info);
-#else
-		uint8_t *p;
-		lws_filepos_t flen;
-		int err;
 
-		if (alloc_pem_to_der_file(vhost->context, info->ssl_cert_filepath, &p,
-				                &flen)) {
-			lwsl_err("couldn't find cert file %s\n",
-				 info->ssl_cert_filepath);
+		if (lws_tls_server_new_nonblocking(wsi, accept_fd)) {
+			if (accept_fd != LWS_SOCK_INVALID)
+				compatible_close(accept_fd);
+			goto fail;
+		}
 
-			return 1;
+		if (context->simultaneous_ssl_restriction &&
+		    ++context->simultaneous_ssl == context->simultaneous_ssl_restriction)
+			/* that was the last allowed SSL connection */
+			lws_gate_accepts(context, 0);
+#if defined(LWS_WITH_STATS)
+	context->updated = 1;
+#endif
+		/*
+		 * we are not accepted yet, but we need to enter ourselves
+		 * as a live connection.  That way we can retry when more
+		 * pieces come if we're not sorted yet
+		 */
+		if (wsi->mode == LWSCM_SSL_INIT)
+			wsi->mode = LWSCM_SSL_ACK_PENDING;
+		else
+			wsi->mode = LWSCM_SSL_ACK_PENDING_RAW;
+
+		if (insert_wsi_socket_into_fds(context, wsi)) {
+			lwsl_err("%s: failed to insert into fds\n", __func__);
+			goto fail;
 		}
-		err = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx, flen, p);
-		if (!err) {
-			lwsl_err("Problem loading cert\n");
-			return 1;
+
+		lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
+				context->timeout_secs);
+
+		lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n");
+
+		/* fallthru */
+
+	case LWSCM_SSL_ACK_PENDING:
+	case LWSCM_SSL_ACK_PENDING_RAW:
+		if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
+			lwsl_err("%s: lws_change_pollfd failed\n", __func__);
+			goto fail;
 		}
-#if !defined(LWS_WITH_ESP32)
-		free(p);
-		p = NULL;
-#endif
 
-		if (info->ssl_private_key_filepath) {
-			if (alloc_pem_to_der_file(vhost->context,
-				       info->ssl_private_key_filepath, &p, &flen)) {
-				lwsl_err("couldn't find cert file %s\n",
-					 info->ssl_cert_filepath);
+		lws_latency_pre(context, wsi);
 
-				return 1;
-			}
-			err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, p, flen);
-			if (!err) {
-				lwsl_err("Problem loading key\n");
+		if (wsi->vhost->allow_non_ssl_on_ssl_port) {
+
+			n = recv(wsi->desc.sockfd, (char *)pt->serv_buf,
+				 context->pt_serv_buf_size, MSG_PEEK);
 
-				return 1;
+		/*
+		 * optionally allow non-SSL connect on SSL listening socket
+		 * This is disabled by default, if enabled it goes around any
+		 * SSL-level access control (eg, client-side certs) so leave
+		 * it disabled unless you know it's not a problem for you
+		 */
+
+			if (n >= 1 && pt->serv_buf[0] >= ' ') {
+				/*
+				* TLS content-type for Handshake is 0x16, and
+				* for ChangeCipherSpec Record, it's 0x14
+				*
+				* A non-ssl session will start with the HTTP
+				* method in ASCII.  If we see it's not a legit
+				* SSL handshake kill the SSL for this
+				* connection and try to handle as a HTTP
+				* connection upgrade directly.
+				*/
+				wsi->use_ssl = 0;
+
+				lws_tls_server_abort_connection(wsi);
+				wsi->ssl = NULL;
+				if (lws_check_opt(context->options,
+				    LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS))
+					wsi->redirect_to_https = 1;
+				goto accepted;
+			}
+			if (!n) /*
+				 * connection is gone, or nothing to read
+				 * if it's gone, we will timeout on
+				 * PENDING_TIMEOUT_SSL_ACCEPT
+				 */
+				break;
+			if (n < 0 && (LWS_ERRNO == LWS_EAGAIN ||
+				      LWS_ERRNO == LWS_EWOULDBLOCK)) {
+				/*
+				 * well, we get no way to know ssl or not
+				 * so go around again waiting for something
+				 * to come and give us a hint, or timeout the
+				 * connection.
+				 */
+				if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
+					lwsl_info("%s: WANT_READ change_pollfd failed\n",
+						  __func__);
+					return -1;
+				}
+
+				lwsl_info("SSL_ERROR_WANT_READ\n");
+				return 0;
 			}
 		}
 
-#if !defined(LWS_WITH_ESP32)
-		free(p);
-		p = NULL;
-#endif
+		/* normal SSL connection processing path */
+
+#if defined(LWS_WITH_STATS)
+		if (!wsi->accept_start_us)
+			wsi->accept_start_us = time_in_microseconds();
 #endif
-		if (info->ssl_private_key_filepath != NULL) {
-#if !defined(LWS_WITH_MBEDTLS)
-			/* set the private key from KeyFile */
-			if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx,
-				     info->ssl_private_key_filepath,
-						       SSL_FILETYPE_PEM) != 1) {
-				error = ERR_get_error();
-				lwsl_err("ssl problem getting key '%s' %lu: %s\n",
-					 info->ssl_private_key_filepath, error,
-					 ERR_error_string(error,
-					      (char *)context->pt[0].serv_buf));
-				return 1;
-			}
+		errno = 0;
+		lws_stats_atomic_bump(wsi->context, pt,
+				      LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN, 1);
+		n = lws_tls_server_accept(wsi);
+		lws_latency(context, wsi,
+			"SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1);
+		lwsl_info("SSL_accept says %d\n", n);
+		switch (n) {
+		case LWS_SSL_CAPABLE_DONE:
+			break;
+		case LWS_SSL_CAPABLE_ERROR:
+			lws_stats_atomic_bump(wsi->context, pt,
+					      LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1);
+	                lwsl_info("SSL_accept failed socket %u: %d\n",
+	                		wsi->desc.sockfd, n);
+			goto fail;
+
+		default: /* MORE_SERVICE */
+			return 0;
+		}
+
+		lws_stats_atomic_bump(wsi->context, pt,
+				      LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1);
+#if defined(LWS_WITH_STATS)
+		lws_stats_atomic_bump(wsi->context, pt,
+				      LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY,
+				      time_in_microseconds() - wsi->accept_start_us);
+		wsi->accept_start_us = time_in_microseconds();
 #endif
-		} else
-			if (vhost->protocols[0].callback(&wsi,
-				LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
-				vhost->ssl_ctx, NULL, 0)) {
-				lwsl_err("ssl private key not set\n");
 
-				return 1;
+accepted:
+
+		/* adapt our vhost to match the SNI SSL_CTX that was chosen */
+		vh = context->vhost_list;
+		while (vh) {
+			if (!vh->being_destroyed &&
+			    vh->ssl_ctx == lws_tls_ctx_from_wsi(wsi)) {
+				lwsl_info("setting wsi to vh %s\n", vh->name);
+				wsi->vhost = vh;
+				break;
 			}
-#if !defined(LWS_WITH_MBEDTLS)
-		/* verify private key */
-		if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) {
-			lwsl_err("Private SSL key doesn't match cert\n");
-			return 1;
+			vh = vh->vhost_next;
 		}
-#endif
-	}
-	if (vhost->use_ssl) {
-		if (lws_context_ssl_init_ecdh(vhost))
-			return 1;
 
-		/*
-		 * SSL is happy and has a cert it's content with
-		 * If we're supporting HTTP2, initialize that
-		 */
-		lws_context_init_http2_ssl(vhost);
+		/* OK, we are accepted... give him some time to negotiate */
+		lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
+				context->timeout_secs);
+
+		if (wsi->mode == LWSCM_SSL_ACK_PENDING_RAW)
+			wsi->mode = LWSCM_RAW;
+		else
+			wsi->mode = LWSCM_HTTP_SERVING;
+#if defined(LWS_WITH_HTTP2)
+		if (lws_h2_configure_if_upgraded(wsi))
+			goto fail;
+#endif
+		lwsl_debug("accepted new SSL conn\n");
+		break;
 	}
 
 	return 0;
+
+fail:
+	return 1;
 }
 
diff --git a/lib/service.c b/lib/service.c
index 49760f82..37366757 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -1190,46 +1190,24 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
 #endif
 
 	if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
-			(pollfd->revents & LWS_POLLHUP)) {
+	    (pollfd->revents & LWS_POLLHUP)) {
 		lwsl_debug("pollhup\n");
 		wsi->socket_is_permanently_unusable = 1;
 		goto close_and_handled;
 	}
 
 #ifdef LWS_OPENSSL_SUPPORT
-	if ((wsi->state == LWSS_SHUTDOWN) && lws_is_ssl(wsi) && wsi->ssl) {
-		n = SSL_shutdown(wsi->ssl);
-		lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
-		switch (n) {
-		case 1:
-			n = shutdown(wsi->desc.sockfd, SHUT_WR);
+	if (wsi->state == LWSS_SHUTDOWN && lws_is_ssl(wsi) && wsi->ssl) {
+		n = 0;
+		switch (lws_tls_shutdown(wsi)) {
+		case LWS_SSL_CAPABLE_DONE:
+		case LWS_SSL_CAPABLE_ERROR:
 			goto close_and_handled;
 
-		case 0:
-			lws_change_pollfd(wsi, 0, LWS_POLLIN);
-			n = 0;
+		case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
+		case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
+		case LWS_SSL_CAPABLE_MORE_SERVICE:
 			goto handled;
-
-		default:
-			n = SSL_get_error(wsi->ssl, n);
-			if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) {
-				if (SSL_want_read(wsi->ssl)) {
-					lwsl_debug("(wants read)\n");
-					lws_change_pollfd(wsi, 0, LWS_POLLIN);
-					n = 0;
-					goto handled;
-				}
-				if (SSL_want_write(wsi->ssl)) {
-					lwsl_debug("(wants write)\n");
-					lws_change_pollfd(wsi, 0, LWS_POLLOUT);
-					n = 0;
-					goto handled;
-				}
-			}
-
-			/* actual error occurred, just close the connection */
-			n = shutdown(wsi->desc.sockfd, SHUT_WR);
-			goto close_and_handled;
 		}
 	}
 #endif
diff --git a/lib/ssl.c b/lib/ssl.c
deleted file mode 100644
index 0a647b46..00000000
--- a/lib/ssl.c
+++ /dev/null
@@ -1,976 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#include "private-libwebsockets.h"
-
-/* workaround for mingw */
-#if !defined(ECONNABORTED)
-#define ECONNABORTED 103
-#endif
-
-int lws_alloc_vfs_file(struct lws_context *context, const char *filename, uint8_t **buf,
-		lws_filepos_t *amount)
-{
-	lws_filepos_t len;
-	lws_fop_flags_t	flags = LWS_O_RDONLY;
-	lws_fop_fd_t fops_fd = lws_vfs_file_open(
-				lws_get_fops(context), filename, &flags);
-	int ret = 1;
-
-	if (!fops_fd)
-		return 1;
-
-	len = lws_vfs_get_length(fops_fd);
-
-	*buf = lws_malloc((size_t)len, "lws_alloc_vfs_file");
-	if (!*buf)
-		goto bail;
-
-	if (lws_vfs_file_read(fops_fd, amount, *buf, len))
-		goto bail;
-
-	ret = 0;
-bail:
-	lws_vfs_file_close(&fops_fd);
-
-	return ret;
-}
-
-#if defined(LWS_WITH_MBEDTLS)
-#if defined(LWS_WITH_ESP32)
-int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
-	       lws_filepos_t *amount)
-{
-	nvs_handle nvh;
-	size_t s;
-	int n = 0;
-
-	ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
-	if (nvs_get_blob(nvh, filename, NULL, &s) != ESP_OK) {
-		n = 1;
-		goto bail;
-	}
-	*buf = lws_malloc(s, "alloc_file");
-	if (!*buf) {
-		n = 2;
-		goto bail;
-	}
-	if (nvs_get_blob(nvh, filename, (char *)*buf, &s) != ESP_OK) {
-		lws_free(*buf);
-		n = 1;
-		goto bail;
-	}
-
-	*amount = s;
-
-bail:
-	nvs_close(nvh);
-
-	return n;
-}
-#else
-int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
-		lws_filepos_t *amount)
-{
-	FILE *f;
-	size_t s;
-	int n = 0;
-
-	f = fopen(filename, "rb");
-	if (f == NULL) {
-		n = 1;
-		goto bail;
-	}
-
-	if (fseek(f, 0, SEEK_END) != 0) {
-		n = 1;
-		goto bail;
-	}
-
-	s = ftell(f);
-	if (s == -1) {
-		n = 1;
-		goto bail;
-	}
-
-	if (fseek(f, 0, SEEK_SET) != 0) {
-		n = 1;
-		goto bail;
-	}
-
-	*buf = lws_malloc(s, "alloc_file");
-	if (!*buf) {
-		n = 2;
-		goto bail;
-	}
-
-	if (fread(*buf, s, 1, f) != 1) {
-		lws_free(*buf);
-		n = 1;
-		goto bail;
-	}
-
-	*amount = s;
-
-bail:
-	if (f)
-		fclose(f);
-
-	return n;
-
-}
-#endif
-int alloc_pem_to_der_file(struct lws_context *context, const char *filename, uint8_t **buf,
-	       lws_filepos_t *amount)
-{
-	uint8_t *pem, *p, *q, *end;
-	lws_filepos_t len;
-	int n;
-
-	n = alloc_file(context, filename, &pem, &len);
-	if (n)
-		return n;
-
-	/* trim the first line */
-
-	p = pem;
-	end = p + len;
-	if (strncmp((char *)p, "-----", 5))
-		goto bail;
-	p += 5;
-	while (p < end && *p != '\n' && *p != '-')
-		p++;
-
-	if (*p != '-')
-		goto bail;
-
-	while (p < end && *p != '\n')
-		p++;
-
-	if (p >= end)
-		goto bail;
-
-	p++;
-
-	/* trim the last line */
-
-	q = end - 2;
-
-	while (q > pem && *q != '\n')
-		q--;
-
-	if (*q != '\n')
-		goto bail;
-
-	*q = '\0';
-
-	*amount = lws_b64_decode_string((char *)p, (char *)pem, len);
-	*buf = pem;
-
-	return 0;
-
-bail:
-	lws_free(pem);
-
-	return 4;
-}
-#endif
-
-int openssl_websocket_private_data_index,
-    openssl_SSL_CTX_private_data_index;
-
-int lws_ssl_get_error(struct lws *wsi, int n)
-{
-	int m;
-
-	if (!wsi->ssl)
-		return 99;
-
-	m = SSL_get_error(wsi->ssl, n);
-	lwsl_debug("%s: %p %d -> %d\n", __func__, wsi->ssl, n, m);
-
-	return m;
-}
-
-/* Copies a string describing the code returned by lws_ssl_get_error(),
- * which may also contain system error information in the case of SSL_ERROR_SYSCALL,
- * into buf up to len.
- * Returns a pointer to buf.
- *
- * Note: the lws_ssl_get_error() code is *not* an error code that can be passed
- * to ERR_error_string(),
- *
- * ret is the return value originally passed to lws_ssl_get_error(), needed to disambiguate
- * SYS_ERROR_SYSCALL.
- *
- * See man page for SSL_get_error().
- *
- * Not thread safe, uses strerror()
- */
-char* lws_ssl_get_error_string(int status, int ret, char *buf, size_t len) {
-	switch (status) {
-	case SSL_ERROR_NONE: return strncpy(buf, "SSL_ERROR_NONE", len);
-	case SSL_ERROR_ZERO_RETURN: return strncpy(buf, "SSL_ERROR_ZERO_RETURN", len);
-	case SSL_ERROR_WANT_READ: return strncpy(buf, "SSL_ERROR_WANT_READ", len);
-	case SSL_ERROR_WANT_WRITE: return strncpy(buf, "SSL_ERROR_WANT_WRITE", len);
-	case SSL_ERROR_WANT_CONNECT: return strncpy(buf, "SSL_ERROR_WANT_CONNECT", len);
-	case SSL_ERROR_WANT_ACCEPT: return strncpy(buf, "SSL_ERROR_WANT_ACCEPT", len);
-	case SSL_ERROR_WANT_X509_LOOKUP: return strncpy(buf, "SSL_ERROR_WANT_X509_LOOKUP", len);
-	case SSL_ERROR_SYSCALL:
-		switch (ret) {
-                case 0:
-                        lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: EOF");
-                        return buf;
-                case -1:
-#ifndef LWS_PLAT_OPTEE
-			lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %s", strerror(errno));
-#else
-			lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %d", errno);
-#endif
-			return buf;
-                default:
-                        return strncpy(buf, "SSL_ERROR_SYSCALL", len);
-	}
-	case SSL_ERROR_SSL: return "SSL_ERROR_SSL";
-	default: return "SSL_ERROR_UNKNOWN";
-	}
-}
-
-void
-lws_ssl_elaborate_error(void)
-{
-#if defined(LWS_WITH_MBEDTLS)
-#else
-	char buf[256];
-	u_long err;
-
-	while ((err = ERR_get_error()) != 0) {
-		ERR_error_string_n(err, buf, sizeof(buf));
-		lwsl_info("*** %s\n", buf);
-	}
-#endif
-}
-
-#if !defined(LWS_WITH_MBEDTLS)
-
-static int
-lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag, void *userdata)
-{
-	struct lws_context_creation_info * info =
-			(struct lws_context_creation_info *)userdata;
-
-	strncpy(buf, info->ssl_private_key_password, size);
-	buf[size - 1] = '\0';
-
-	return strlen(buf);
-}
-
-void
-lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info)
-{
-	if (!info->ssl_private_key_password)
-		return;
-	/*
-	 * password provided, set ssl callback and user data
-	 * for checking password which will be trigered during
-	 * SSL_CTX_use_PrivateKey_file function
-	 */
-	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info);
-	SSL_CTX_set_default_passwd_cb(ssl_ctx, lws_context_init_ssl_pem_passwd_cb);
-}
-#endif
-
-int
-lws_context_init_ssl_library(struct lws_context_creation_info *info)
-{
-#ifdef USE_WOLFSSL
-#ifdef USE_OLD_CYASSL
-	lwsl_info(" Compiled with CyaSSL support\n");
-#else
-	lwsl_info(" Compiled with wolfSSL support\n");
-#endif
-#else
-#if defined(LWS_WITH_BORINGSSL)
-	lwsl_info(" Compiled with BoringSSL support\n");
-#else
-#if defined(LWS_WITH_MBEDTLS)
-	lwsl_info(" Compiled with MbedTLS support\n");
-#else
-	lwsl_info(" Compiled with OpenSSL support\n");
-#endif
-#endif
-#endif
-	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
-		lwsl_info(" SSL disabled: no LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
-		return 0;
-	}
-
-	/* basic openssl init */
-
-	lwsl_info("Doing SSL library init\n");
-
-#if !defined(LWS_WITH_MBEDTLS)
-	SSL_library_init();
-	OpenSSL_add_all_algorithms();
-	SSL_load_error_strings();
-
-	openssl_websocket_private_data_index =
-		SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL);
-
-	openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0,
-			NULL, NULL, NULL, NULL);
-#endif
-
-	return 0;
-}
-
-LWS_VISIBLE void
-lws_ssl_destroy(struct lws_vhost *vhost)
-{
-	if (!lws_check_opt(vhost->context->options,
-			   LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
-		return;
-
-	if (vhost->ssl_ctx)
-		SSL_CTX_free(vhost->ssl_ctx);
-	if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
-		SSL_CTX_free(vhost->ssl_client_ctx);
-
-#if defined(LWS_WITH_MBEDTLS)
-	if (vhost->x509_client_CA)
-		X509_free(vhost->x509_client_CA);
-#else
-// after 1.1.0 no need
-#if (OPENSSL_VERSION_NUMBER <  0x10100000)
-// <= 1.0.1f = old api, 1.0.1g+ = new api
-#if (OPENSSL_VERSION_NUMBER <= 0x1000106f) || defined(USE_WOLFSSL)
-	ERR_remove_state(0);
-#else
-#if OPENSSL_VERSION_NUMBER >= 0x1010005f && \
-    !defined(LIBRESSL_VERSION_NUMBER) && \
-    !defined(OPENSSL_IS_BORINGSSL)
-	ERR_remove_thread_state();
-#else
-	ERR_remove_thread_state(NULL);
-#endif
-#endif
-	// after 1.1.0 no need
-#if  (OPENSSL_VERSION_NUMBER >= 0x10002000) && (OPENSSL_VERSION_NUMBER <= 0x10100000)
-	SSL_COMP_free_compression_methods();
-#endif
-	ERR_free_strings();
-	EVP_cleanup();
-	CRYPTO_cleanup_all_ex_data();
-#endif
-#endif
-}
-
-int
-lws_ssl_anybody_has_buffered_read_tsi(struct lws_context *context, int tsi)
-{
-	struct lws_context_per_thread *pt = &context->pt[tsi];
-	struct lws *wsi, *wsi_next;
-
-	wsi = pt->pending_read_list;
-	while (wsi) {
-		wsi_next = wsi->pending_read_list_next;
-		pt->fds[wsi->position_in_fds_table].revents |=
-			pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
-		if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN)
-			return 1;
-
-		wsi = wsi_next;
-	}
-
-	return 0;
-}
-
-LWS_VISIBLE void
-lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
-{
-	struct lws_context *context = wsi->context;
-	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-
-	if (!wsi->pending_read_list_prev &&
-	    !wsi->pending_read_list_next &&
-	    pt->pending_read_list != wsi)
-		/* we are not on the list */
-		return;
-
-	/* point previous guy's next to our next */
-	if (!wsi->pending_read_list_prev)
-		pt->pending_read_list = wsi->pending_read_list_next;
-	else
-		wsi->pending_read_list_prev->pending_read_list_next =
-			wsi->pending_read_list_next;
-
-	/* point next guy's previous to our previous */
-	if (wsi->pending_read_list_next)
-		wsi->pending_read_list_next->pending_read_list_prev =
-			wsi->pending_read_list_prev;
-
-	wsi->pending_read_list_prev = NULL;
-	wsi->pending_read_list_next = NULL;
-}
-
-LWS_VISIBLE int
-lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
-{
-	struct lws_context *context = wsi->context;
-	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-	int n = 0, m;
-
-	if (!wsi->ssl)
-		return lws_ssl_capable_read_no_ssl(wsi, buf, len);
-
-	lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
-
-	errno = 0;
-	n = SSL_read(wsi->ssl, buf, len);
-#if defined(LWS_WITH_ESP32)
-	if (!n && errno == ENOTCONN) {
-		lwsl_debug("%p: SSL_read ENOTCONN\n", wsi);
-		return LWS_SSL_CAPABLE_ERROR;
-	}
-#endif
-#if defined(LWS_WITH_STATS)
-	if (!wsi->seen_rx) {
-                lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_RX_DELAY,
-				time_in_microseconds() - wsi->accept_start_us);
-                lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1);
-		wsi->seen_rx = 1;
-	}
-#endif
-
-
-	lwsl_debug("%p: SSL_read says %d\n", wsi, n);
-	/* manpage: returning 0 means connection shut down */
-	if (!n) {
-		wsi->socket_is_permanently_unusable = 1;
-
-		return LWS_SSL_CAPABLE_ERROR;
-	}
-
-	if (n < 0) {
-		m = lws_ssl_get_error(wsi, n);
-		lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno);
-		if (m == SSL_ERROR_ZERO_RETURN ||
-		    m == SSL_ERROR_SYSCALL)
-			return LWS_SSL_CAPABLE_ERROR;
-
-		if (SSL_want_read(wsi->ssl)) {
-			lwsl_debug("%s: WANT_READ\n", __func__);
-			lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
-			return LWS_SSL_CAPABLE_MORE_SERVICE;
-		}
-		if (SSL_want_write(wsi->ssl)) {
-			lwsl_debug("%s: WANT_WRITE\n", __func__);
-			lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
-			return LWS_SSL_CAPABLE_MORE_SERVICE;
-		}
-		wsi->socket_is_permanently_unusable = 1;
-
-		return LWS_SSL_CAPABLE_ERROR;
-	}
-
-	lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
-
-	if (wsi->vhost)
-		wsi->vhost->conn_stats.rx += n;
-
-	lws_restart_ws_ping_pong_timer(wsi);
-
-	/*
-	 * if it was our buffer that limited what we read,
-	 * check if SSL has additional data pending inside SSL buffers.
-	 *
-	 * Because these won't signal at the network layer with POLLIN
-	 * and if we don't realize, this data will sit there forever
-	 */
-	if (n != len)
-		goto bail;
-	if (!wsi->ssl)
-		goto bail;
-
-	if (!SSL_pending(wsi->ssl))
-		goto bail;
-
-	if (wsi->pending_read_list_next)
-		return n;
-	if (wsi->pending_read_list_prev)
-		return n;
-	if (pt->pending_read_list == wsi)
-		return n;
-
-	/* add us to the linked list of guys with pending ssl */
-	if (pt->pending_read_list)
-		pt->pending_read_list->pending_read_list_prev = wsi;
-
-	wsi->pending_read_list_next = pt->pending_read_list;
-	wsi->pending_read_list_prev = NULL;
-	pt->pending_read_list = wsi;
-
-	return n;
-bail:
-	lws_ssl_remove_wsi_from_buffered_list(wsi);
-
-	return n;
-}
-
-LWS_VISIBLE int
-lws_ssl_pending(struct lws *wsi)
-{
-	if (!wsi->ssl)
-		return 0;
-
-	return SSL_pending(wsi->ssl);
-}
-
-LWS_VISIBLE int
-lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
-{
-	int n, m;
-
-	if (!wsi->ssl)
-		return lws_ssl_capable_write_no_ssl(wsi, buf, len);
-
-	n = SSL_write(wsi->ssl, buf, len);
-	if (n > 0)
-		return n;
-
-	m = lws_ssl_get_error(wsi, n);
-	if (m != SSL_ERROR_SYSCALL) {
-
-		if (SSL_want_read(wsi->ssl)) {
-			lwsl_notice("%s: want read\n", __func__);
-
-			return LWS_SSL_CAPABLE_MORE_SERVICE;
-		}
-
-		if (SSL_want_write(wsi->ssl)) {
-			lws_set_blocking_send(wsi);
-
-			lwsl_notice("%s: want write\n", __func__);
-
-			return LWS_SSL_CAPABLE_MORE_SERVICE;
-		}
-	}
-
-	lwsl_debug("%s failed: %s\n",__func__, ERR_error_string(m, NULL));
-	lws_ssl_elaborate_error();
-
-	wsi->socket_is_permanently_unusable = 1;
-
-	return LWS_SSL_CAPABLE_ERROR;
-}
-
-static int
-lws_gate_accepts(struct lws_context *context, int on)
-{
-	struct lws_vhost *v = context->vhost_list;
-
-	lwsl_info("gating accepts %d\n", on);
-	context->ssl_gate_accepts = !on;
-#if defined(LWS_WITH_STATS)
-	context->updated = 1;
-#endif
-
-	while (v) {
-		if (v->use_ssl &&  v->lserv_wsi) /* gate ability to accept incoming connections */
-			if (lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
-					      (LWS_POLLIN) * on))
-				lwsl_info("Unable to set accept POLLIN %d\n", on);
-
-		v = v->vhost_next;
-	}
-
-	return 0;
-}
-
-void
-lws_ssl_info_callback(const SSL *ssl, int where, int ret)
-{
-	struct lws *wsi;
-	struct lws_context *context;
-	struct lws_ssl_info si;
-
-	context = (struct lws_context *)SSL_CTX_get_ex_data(
-					SSL_get_SSL_CTX(ssl),
-					openssl_SSL_CTX_private_data_index);
-	if (!context)
-		return;
-	wsi = wsi_from_fd(context, SSL_get_fd(ssl));
-	if (!wsi)
-		return;
-
-	if (!(where & wsi->vhost->ssl_info_event_mask))
-		return;
-
-	si.where = where;
-	si.ret = ret;
-
-	if (user_callback_handle_rxflow(wsi->protocol->callback,
-						   wsi, LWS_CALLBACK_SSL_INFO,
-						   wsi->user_space, &si, 0))
-		lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
-}
-
-
-LWS_VISIBLE int
-lws_ssl_close(struct lws *wsi)
-{
-	lws_sockfd_type n;
-
-	if (!wsi->ssl)
-		return 0; /* not handled */
-
-#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
-	/* kill ssl callbacks, becausse we will remove the fd from the
-	 * table linking it to the wsi
-	 */
-	if (wsi->vhost->ssl_info_event_mask)
-		SSL_set_info_callback(wsi->ssl, NULL);
-#endif
-
-	n = SSL_get_fd(wsi->ssl);
-	if (!wsi->socket_is_permanently_unusable)
-		SSL_shutdown(wsi->ssl);
-	compatible_close(n);
-	SSL_free(wsi->ssl);
-	wsi->ssl = NULL;
-
-	if (wsi->context->simultaneous_ssl_restriction &&
-	    wsi->context->simultaneous_ssl-- ==
-			    wsi->context->simultaneous_ssl_restriction)
-		/* we made space and can do an accept */
-		lws_gate_accepts(wsi->context, 1);
-#if defined(LWS_WITH_STATS)
-	wsi->context->updated = 1;
-#endif
-
-	return 1; /* handled */
-}
-
-/* leave all wsi close processing to the caller */
-
-LWS_VISIBLE int
-lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
-{
-	struct lws_context *context = wsi->context;
-	struct lws_vhost *vh;
-	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
-	int n, m;
-#if !defined(USE_WOLFSSL) && !defined(LWS_WITH_MBEDTLS)
-	BIO *bio;
-#endif
-        char buf[256];
-
-        (void)buf;
-
-	if (!LWS_SSL_ENABLED(wsi->vhost))
-		return 0;
-
-	switch (wsi->mode) {
-	case LWSCM_SSL_INIT:
-	case LWSCM_SSL_INIT_RAW:
-		if (wsi->ssl)
-			lwsl_err("%s: leaking ssl\n", __func__);
-		if (accept_fd == LWS_SOCK_INVALID)
-			assert(0);
-		if (context->simultaneous_ssl_restriction &&
-		    context->simultaneous_ssl >= context->simultaneous_ssl_restriction) {
-			lwsl_notice("unable to deal with SSL connection\n");
-			return 1;
-		}
-		errno = 0;
-		wsi->ssl = SSL_new(wsi->vhost->ssl_ctx);
-		if (wsi->ssl == NULL) {
-			lwsl_err("SSL_new failed: %d (errno %d)\n",
-				 lws_ssl_get_error(wsi, 0), errno);
-
-			lws_ssl_elaborate_error();
-			if (accept_fd != LWS_SOCK_INVALID)
-				compatible_close(accept_fd);
-			goto fail;
-		}
-#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
-		if (wsi->vhost->ssl_info_event_mask)
-			SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
-#endif
-		if (context->simultaneous_ssl_restriction &&
-		    ++context->simultaneous_ssl == context->simultaneous_ssl_restriction)
-			/* that was the last allowed SSL connection */
-			lws_gate_accepts(context, 0);
-#if defined(LWS_WITH_STATS)
-	context->updated = 1;
-#endif
-
-#if !defined(LWS_WITH_MBEDTLS)
-		SSL_set_ex_data(wsi->ssl,
-			openssl_websocket_private_data_index, wsi);
-#endif
-		SSL_set_fd(wsi->ssl, accept_fd);
-
-#ifdef USE_WOLFSSL
-#ifdef USE_OLD_CYASSL
-		CyaSSL_set_using_nonblock(wsi->ssl, 1);
-#else
-		wolfSSL_set_using_nonblock(wsi->ssl, 1);
-#endif
-#else
-#if defined(LWS_WITH_MBEDTLS)
-		lws_plat_set_socket_options(wsi->vhost, accept_fd);
-#else
-		SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-		bio = SSL_get_rbio(wsi->ssl);
-		if (bio)
-			BIO_set_nbio(bio, 1); /* nonblocking */
-		else
-			lwsl_notice("NULL rbio\n");
-		bio = SSL_get_wbio(wsi->ssl);
-		if (bio)
-			BIO_set_nbio(bio, 1); /* nonblocking */
-		else
-			lwsl_notice("NULL rbio\n");
-#endif
-#endif
-
-		/*
-		 * we are not accepted yet, but we need to enter ourselves
-		 * as a live connection.  That way we can retry when more
-		 * pieces come if we're not sorted yet
-		 */
-
-		if (wsi->mode == LWSCM_SSL_INIT)
-			wsi->mode = LWSCM_SSL_ACK_PENDING;
-		else
-			wsi->mode = LWSCM_SSL_ACK_PENDING_RAW;
-
-		if (insert_wsi_socket_into_fds(context, wsi)) {
-			lwsl_err("%s: failed to insert into fds\n", __func__);
-			goto fail;
-		}
-
-		lws_set_timeout(wsi, PENDING_TIMEOUT_SSL_ACCEPT,
-				context->timeout_secs);
-
-		lwsl_debug("inserted SSL accept into fds, trying SSL_accept\n");
-
-		/* fallthru */
-
-	case LWSCM_SSL_ACK_PENDING:
-	case LWSCM_SSL_ACK_PENDING_RAW:
-		if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
-			lwsl_err("%s: lws_change_pollfd failed\n", __func__);
-			goto fail;
-		}
-
-		lws_latency_pre(context, wsi);
-
-		if (wsi->vhost->allow_non_ssl_on_ssl_port) {
-
-			n = recv(wsi->desc.sockfd, (char *)pt->serv_buf,
-				 context->pt_serv_buf_size, MSG_PEEK);
-
-		/*
-		 * optionally allow non-SSL connect on SSL listening socket
-		 * This is disabled by default, if enabled it goes around any
-		 * SSL-level access control (eg, client-side certs) so leave
-		 * it disabled unless you know it's not a problem for you
-		 */
-
-			if (n >= 1 && pt->serv_buf[0] >= ' ') {
-				/*
-				* TLS content-type for Handshake is 0x16, and
-				* for ChangeCipherSpec Record, it's 0x14
-				*
-				* A non-ssl session will start with the HTTP
-				* method in ASCII.  If we see it's not a legit
-				* SSL handshake kill the SSL for this
-				* connection and try to handle as a HTTP
-				* connection upgrade directly.
-				*/
-				wsi->use_ssl = 0;
-
-				SSL_shutdown(wsi->ssl);
-				SSL_free(wsi->ssl);
-				wsi->ssl = NULL;
-				if (lws_check_opt(context->options,
-				    LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS))
-					wsi->redirect_to_https = 1;
-				goto accepted;
-			}
-			if (!n) /*
-				 * connection is gone, or nothing to read
-				 * if it's gone, we will timeout on
-				 * PENDING_TIMEOUT_SSL_ACCEPT
-				 */
-				break;
-			if (n < 0 && (LWS_ERRNO == LWS_EAGAIN ||
-				      LWS_ERRNO == LWS_EWOULDBLOCK)) {
-				/*
-				 * well, we get no way to know ssl or not
-				 * so go around again waiting for something
-				 * to come and give us a hint, or timeout the
-				 * connection.
-				 */
-				m = SSL_ERROR_WANT_READ;
-				goto go_again;
-			}
-		}
-
-		/* normal SSL connection processing path */
-
-#if defined(LWS_WITH_STATS)
-		if (!wsi->accept_start_us)
-			wsi->accept_start_us = time_in_microseconds();
-#endif
-		errno = 0;
-		lws_stats_atomic_bump(wsi->context, pt,
-				      LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN, 1);
-		n = SSL_accept(wsi->ssl);
-		lws_latency(context, wsi,
-			"SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1);
-		lwsl_info("SSL_accept says %d\n", n);
-		if (n == 1)
-			goto accepted;
-
-		m = lws_ssl_get_error(wsi, n);
-
-#if defined(LWS_WITH_MBEDTLS)
-		if (m == SSL_ERROR_SYSCALL && errno == 11)
-			m = SSL_ERROR_WANT_READ;
-#endif
-		if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL)
-			goto failed;
-
-go_again:
-		if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) {
-			if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
-				lwsl_info("%s: WANT_READ change_pollfd failed\n", __func__);
-				goto fail;
-			}
-
-			lwsl_info("SSL_ERROR_WANT_READ\n");
-			break;
-		}
-		if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) {
-			lwsl_debug("%s: WANT_WRITE\n", __func__);
-
-			if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
-				lwsl_info("%s: WANT_WRITE change_pollfd failed\n", __func__);
-				goto fail;
-			}
-
-			break;
-		}
-failed:
-		lws_stats_atomic_bump(wsi->context, pt,
-				      LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1);
-                lwsl_info("SSL_accept failed socket %u: %s\n", wsi->desc.sockfd,
-                         lws_ssl_get_error_string(m, n, buf, sizeof(buf)));
-		lws_ssl_elaborate_error();
-		goto fail;
-
-accepted:
-		lws_stats_atomic_bump(wsi->context, pt,
-				      LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1);
-#if defined(LWS_WITH_STATS)
-		lws_stats_atomic_bump(wsi->context, pt,
-				      LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY,
-				      time_in_microseconds() - wsi->accept_start_us);
-		wsi->accept_start_us = time_in_microseconds();
-#endif
-
-		/* adapt our vhost to match the SNI SSL_CTX that was chosen */
-		vh = context->vhost_list;
-		while (vh) {
-			if (!vh->being_destroyed &&
-			    vh->ssl_ctx == SSL_get_SSL_CTX(wsi->ssl)) {
-				lwsl_info("setting wsi to vh %s\n", vh->name);
-				wsi->vhost = vh;
-				break;
-			}
-			vh = vh->vhost_next;
-		}
-
-		/* OK, we are accepted... give him some time to negotiate */
-		lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
-				context->timeout_secs);
-
-		if (wsi->mode == LWSCM_SSL_ACK_PENDING_RAW)
-			wsi->mode = LWSCM_RAW;
-		else
-			wsi->mode = LWSCM_HTTP_SERVING;
-#if defined(LWS_WITH_HTTP2)
-		if (lws_h2_configure_if_upgraded(wsi))
-			goto fail;
-#endif
-		lwsl_debug("accepted new SSL conn\n");
-		break;
-	}
-
-	return 0;
-
-fail:
-	return 1;
-}
-
-void
-lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
-{
-	if (vhost->ssl_ctx)
-		SSL_CTX_free(vhost->ssl_ctx);
-
-	if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
-		SSL_CTX_free(vhost->ssl_client_ctx);
-}
-
-void
-lws_ssl_context_destroy(struct lws_context *context)
-{
-
-#if !defined(LWS_WITH_MBEDTLS)
-
-// after 1.1.0 no need
-#if (OPENSSL_VERSION_NUMBER <  0x10100000)
-// <= 1.0.1f = old api, 1.0.1g+ = new api
-#if (OPENSSL_VERSION_NUMBER <= 0x1000106f) || defined(USE_WOLFSSL)
-	ERR_remove_state(0);
-#else
-#if OPENSSL_VERSION_NUMBER >= 0x1010005f && \
-    !defined(LIBRESSL_VERSION_NUMBER) && \
-    !defined(OPENSSL_IS_BORINGSSL)
-	ERR_remove_thread_state();
-#else
-	ERR_remove_thread_state(NULL);
-#endif
-#endif
-	// after 1.1.0 no need
-#if  (OPENSSL_VERSION_NUMBER >= 0x10002000) && (OPENSSL_VERSION_NUMBER <= 0x10100000)
-	SSL_COMP_free_compression_methods();
-#endif
-	ERR_free_strings();
-	EVP_cleanup();
-	CRYPTO_cleanup_all_ex_data();
-#endif
-#endif
-}
diff --git a/lib/tls/mbedtls/client.c b/lib/tls/mbedtls/client.c
new file mode 100644
index 00000000..5e971e04
--- /dev/null
+++ b/lib/tls/mbedtls/client.c
@@ -0,0 +1,180 @@
+/*
+ * libwebsockets - mbedtls-specific client TLS code
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+static int
+OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+	return 0;
+}
+
+int
+lws_ssl_client_bio_create(struct lws *wsi)
+{
+	X509_VERIFY_PARAM *param;
+	char hostname[128], *p;
+
+	if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
+			 _WSI_TOKEN_CLIENT_HOST) <= 0) {
+		lwsl_err("%s: Unable to get hostname\n", __func__);
+
+		return -1;
+	}
+
+	/*
+	 * remove any :port part on the hostname... necessary for network
+	 * connection but typical certificates do not contain it
+	 */
+	p = hostname;
+	while (*p) {
+		if (*p == ':') {
+			*p = '\0';
+			break;
+		}
+		p++;
+	}
+
+	wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx);
+	if (!wsi->ssl)
+		return -1;
+
+	if (wsi->vhost->ssl_info_event_mask)
+		SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
+
+	if (!(wsi->use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
+		param = SSL_get0_param(wsi->ssl);
+		/* Enable automatic hostname checks */
+	//	X509_VERIFY_PARAM_set_hostflags(param,
+	//				X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+		X509_VERIFY_PARAM_set1_host(param, hostname, 0);
+	}
+
+	/*
+	 * use server name indication (SNI), if supported,
+	 * when establishing connection
+	 */
+	if (wsi->vhost->x509_client_CA)
+		SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER,
+			       OpenSSL_client_verify_callback);
+	else
+		SSL_set_verify(wsi->ssl, SSL_VERIFY_NONE,
+			       OpenSSL_client_verify_callback);
+
+	SSL_set_fd(wsi->ssl, wsi->desc.sockfd);
+
+	return 0;
+}
+
+int ERR_get_error(void)
+{
+	return 0;
+}
+
+enum lws_ssl_capable_status
+lws_tls_client_connect(struct lws *wsi)
+{
+	int m, n = SSL_connect(wsi->ssl);
+
+	if (n == 1)
+		return LWS_SSL_CAPABLE_DONE;
+
+	m = SSL_get_error(wsi->ssl, n);
+
+	if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl))
+		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+
+	if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl))
+		return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
+
+	if (!n) /* we don't know what he wants, but he says to retry */
+		return LWS_SSL_CAPABLE_MORE_SERVICE;
+
+	return LWS_SSL_CAPABLE_ERROR;
+}
+
+int
+lws_tls_client_confirm_peer_cert(struct lws *wsi)
+{
+	X509 *peer = SSL_get_peer_certificate(wsi->ssl);
+
+	if (!peer) {
+		lwsl_info("peer did not provide cert\n");
+
+		return -1;
+	}
+	lwsl_info("peer provided cert\n");
+
+	return 0;
+}
+
+int
+lws_tls_client_create_vhost_context(struct lws_vhost *vh,
+				    struct lws_context_creation_info *info,
+				    const char *cipher_list,
+				    const char *ca_filepath,
+				    const char *cert_filepath,
+				    const char *private_key_filepath)
+{
+	X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len);
+	SSL_METHOD *method = (SSL_METHOD *)TLS_client_method();
+	unsigned long error;
+	lws_filepos_t len;
+	uint8_t *buf;
+
+	if (!method) {
+		error = ERR_get_error();
+		lwsl_err("problem creating ssl method %lu: %s\n",
+			error, ERR_error_string(error,
+				      (char *)vh->context->pt[0].serv_buf));
+		return 1;
+	}
+	/* create context */
+	vh->ssl_client_ctx = SSL_CTX_new(method);
+	if (!vh->ssl_client_ctx) {
+		error = ERR_get_error();
+		lwsl_err("problem creating ssl context %lu: %s\n",
+			error, ERR_error_string(error,
+				      (char *)vh->context->pt[0].serv_buf));
+		return 1;
+	}
+
+	if (!ca_filepath)
+		return 0;
+
+	if (alloc_file(vh->context, ca_filepath, &buf, &len)) {
+		lwsl_err("Load CA cert file %s failed\n", ca_filepath);
+		return 1;
+	}
+
+	vh->x509_client_CA = d2i_X509(NULL, buf, len);
+	free(buf);
+	if (!vh->x509_client_CA) {
+		lwsl_err("client CA: x509 parse failed\n");
+		return 1;
+	}
+
+	SSL_CTX_add_client_CA(vh->ssl_client_ctx, vh->x509_client_CA);
+
+	lwsl_notice("client loaded CA for verification %s\n", ca_filepath);
+
+	return 0;
+}
diff --git a/lib/tls/mbedtls/server.c b/lib/tls/mbedtls/server.c
new file mode 100644
index 00000000..e137b73d
--- /dev/null
+++ b/lib/tls/mbedtls/server.c
@@ -0,0 +1,317 @@
+/*
+ * libwebsockets - mbedTLS-specific server functions
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+int
+lws_tls_server_client_cert_verify_config(struct lws_context_creation_info *info,
+					 struct lws_vhost *vh)
+{
+	return 0;
+}
+
+#if defined(LWS_WITH_ESP32)
+int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
+	       lws_filepos_t *amount)
+{
+	nvs_handle nvh;
+	size_t s;
+	int n = 0;
+
+	ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
+	if (nvs_get_blob(nvh, filename, NULL, &s) != ESP_OK) {
+		n = 1;
+		goto bail;
+	}
+	*buf = lws_malloc(s, "alloc_file");
+	if (!*buf) {
+		n = 2;
+		goto bail;
+	}
+	if (nvs_get_blob(nvh, filename, (char *)*buf, &s) != ESP_OK) {
+		lws_free(*buf);
+		n = 1;
+		goto bail;
+	}
+
+	*amount = s;
+
+bail:
+	nvs_close(nvh);
+
+	return n;
+}
+#else
+int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
+		lws_filepos_t *amount)
+{
+	FILE *f;
+	size_t s;
+	int n = 0;
+
+	f = fopen(filename, "rb");
+	if (f == NULL) {
+		n = 1;
+		goto bail;
+	}
+
+	if (fseek(f, 0, SEEK_END) != 0) {
+		n = 1;
+		goto bail;
+	}
+
+	s = ftell(f);
+	if (s == -1) {
+		n = 1;
+		goto bail;
+	}
+
+	if (fseek(f, 0, SEEK_SET) != 0) {
+		n = 1;
+		goto bail;
+	}
+
+	*buf = lws_malloc(s, "alloc_file");
+	if (!*buf) {
+		n = 2;
+		goto bail;
+	}
+
+	if (fread(*buf, s, 1, f) != 1) {
+		lws_free(*buf);
+		n = 1;
+		goto bail;
+	}
+
+	*amount = s;
+
+bail:
+	if (f)
+		fclose(f);
+
+	return n;
+
+}
+#endif
+
+static int
+alloc_pem_to_der_file(struct lws_context *context, const char *filename,
+		      uint8_t **buf, lws_filepos_t *amount)
+{
+	uint8_t *pem, *p, *q, *end;
+	lws_filepos_t len;
+	int n;
+
+	n = alloc_file(context, filename, &pem, &len);
+	if (n)
+		return n;
+
+	/* trim the first line */
+
+	p = pem;
+	end = p + len;
+	if (strncmp((char *)p, "-----", 5))
+		goto bail;
+	p += 5;
+	while (p < end && *p != '\n' && *p != '-')
+		p++;
+
+	if (*p != '-')
+		goto bail;
+
+	while (p < end && *p != '\n')
+		p++;
+
+	if (p >= end)
+		goto bail;
+
+	p++;
+
+	/* trim the last line */
+
+	q = end - 2;
+
+	while (q > pem && *q != '\n')
+		q--;
+
+	if (*q != '\n')
+		goto bail;
+
+	*q = '\0';
+
+	*amount = lws_b64_decode_string((char *)p, (char *)pem, len);
+	*buf = pem;
+
+	return 0;
+
+bail:
+	lws_free(pem);
+
+	return 4;
+}
+
+int
+lws_tls_server_vhost_backend_init(struct lws_context_creation_info *info,
+				  struct lws_vhost *vhost, struct lws *wsi)
+{
+	const SSL_METHOD *method = TLS_server_method();
+	uint8_t *p;
+	lws_filepos_t flen;
+	int err;
+
+	vhost->ssl_ctx = SSL_CTX_new(method);	/* create context */
+	if (!vhost->ssl_ctx) {
+		lwsl_err("problem creating ssl context\n");
+		return 1;
+	}
+
+	if (!vhost->use_ssl || !info->ssl_cert_filepath)
+		return 0;
+
+	/*
+	 * The user code can choose to either pass the cert and
+	 * key filepaths using the info members like this, or it can
+	 * leave them NULL; force the vhost SSL_CTX init using the info
+	 * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and
+	 * set up the cert himself using the user callback
+	 * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
+	 * happened just above and has the vhost SSL_CTX * in the user
+	 * parameter.
+	 */
+	if (alloc_pem_to_der_file(vhost->context, info->ssl_cert_filepath, &p,
+					&flen)) {
+		lwsl_err("couldn't find cert file %s\n",
+			 info->ssl_cert_filepath);
+
+		return 1;
+	}
+	err = SSL_CTX_use_certificate_ASN1(vhost->ssl_ctx, flen, p);
+	if (!err) {
+		lwsl_err("Problem loading cert\n");
+		return 1;
+	}
+#if !defined(LWS_WITH_ESP32)
+	free(p);
+	p = NULL;
+#endif
+
+	if (info->ssl_private_key_filepath) {
+		if (alloc_pem_to_der_file(vhost->context,
+					  info->ssl_private_key_filepath,
+					  &p, &flen)) {
+			lwsl_err("couldn't find cert file %s\n",
+				 info->ssl_cert_filepath);
+
+			return 1;
+		}
+		err = SSL_CTX_use_PrivateKey_ASN1(0, vhost->ssl_ctx, p, flen);
+		if (!err) {
+			lwsl_err("Problem loading key\n");
+
+			return 1;
+		}
+	}
+
+#if !defined(LWS_WITH_ESP32)
+	free(p);
+	p = NULL;
+#endif
+
+	if (!info->ssl_private_key_filepath && vhost->protocols[0].callback(wsi,
+			LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
+			vhost->ssl_ctx, NULL, 0)) {
+		lwsl_err("ssl private key not set\n");
+
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
+{
+	errno = 0;
+	wsi->ssl = SSL_new(wsi->vhost->ssl_ctx);
+	if (wsi->ssl == NULL) {
+		lwsl_err("SSL_new failed: errno %d\n", errno);
+
+		lws_ssl_elaborate_error();
+		return 1;
+	}
+
+	SSL_set_fd(wsi->ssl, accept_fd);
+
+	if (wsi->vhost->ssl_info_event_mask)
+		SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
+
+	return 0;
+}
+
+int
+lws_tls_server_abort_connection(struct lws *wsi)
+{
+	lws_tls_shutdown(wsi);
+	SSL_free(wsi->ssl);
+
+	return 0;
+}
+
+enum lws_ssl_capable_status
+lws_tls_server_accept(struct lws *wsi)
+{
+	int m, n = SSL_accept(wsi->ssl);
+
+	if (n == 1)
+		return LWS_SSL_CAPABLE_DONE;
+
+	m = SSL_get_error(wsi->ssl, n);
+
+	// mbedtls wrapper only
+	if (m == SSL_ERROR_SYSCALL && errno == 11)
+		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+
+	if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL)
+		return LWS_SSL_CAPABLE_ERROR;
+
+	if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) {
+		if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
+			lwsl_info("%s: WANT_READ change_pollfd failed\n", __func__);
+			return LWS_SSL_CAPABLE_ERROR;
+		}
+
+		lwsl_info("SSL_ERROR_WANT_READ\n");
+		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+	}
+	if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) {
+		lwsl_debug("%s: WANT_WRITE\n", __func__);
+
+		if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
+			lwsl_info("%s: WANT_WRITE change_pollfd failed\n", __func__);
+			return LWS_SSL_CAPABLE_ERROR;
+		}
+		return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
+	}
+
+	return LWS_SSL_CAPABLE_ERROR;
+}
+
+
diff --git a/lib/tls/mbedtls/ssl.c b/lib/tls/mbedtls/ssl.c
new file mode 100644
index 00000000..a9d019ce
--- /dev/null
+++ b/lib/tls/mbedtls/ssl.c
@@ -0,0 +1,325 @@
+/*
+ * libwebsockets - mbedTLS-specific lws apis
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+void
+lws_ssl_elaborate_error(void)
+{
+}
+
+int
+lws_context_init_ssl_library(struct lws_context_creation_info *info)
+{
+	lwsl_info(" Compiled with MbedTLS support\n");
+
+	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
+		lwsl_info(" SSL disabled: no LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
+
+	return 0;
+}
+
+LWS_VISIBLE void
+lws_ssl_destroy(struct lws_vhost *vhost)
+{
+	if (!lws_check_opt(vhost->context->options,
+			   LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
+		return;
+
+	if (vhost->ssl_ctx)
+		SSL_CTX_free(vhost->ssl_ctx);
+	if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
+		SSL_CTX_free(vhost->ssl_client_ctx);
+
+	if (vhost->x509_client_CA)
+		X509_free(vhost->x509_client_CA);
+}
+
+LWS_VISIBLE int
+lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
+{
+	struct lws_context *context = wsi->context;
+	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+	int n = 0, m;
+
+	if (!wsi->ssl)
+		return lws_ssl_capable_read_no_ssl(wsi, buf, len);
+
+	lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
+
+	errno = 0;
+	n = SSL_read(wsi->ssl, buf, len);
+#if defined(LWS_WITH_ESP32)
+	if (!n && errno == ENOTCONN) {
+		lwsl_debug("%p: SSL_read ENOTCONN\n", wsi);
+		return LWS_SSL_CAPABLE_ERROR;
+	}
+#endif
+#if defined(LWS_WITH_STATS)
+	if (!wsi->seen_rx) {
+                lws_stats_atomic_bump(wsi->context, pt,
+                		      LWSSTATS_MS_SSL_RX_DELAY,
+				time_in_microseconds() - wsi->accept_start_us);
+                lws_stats_atomic_bump(wsi->context, pt,
+                		      LWSSTATS_C_SSL_CONNS_HAD_RX, 1);
+		wsi->seen_rx = 1;
+	}
+#endif
+
+
+	lwsl_debug("%p: SSL_read says %d\n", wsi, n);
+	/* manpage: returning 0 means connection shut down */
+	if (!n) {
+		wsi->socket_is_permanently_unusable = 1;
+
+		return LWS_SSL_CAPABLE_ERROR;
+	}
+
+	if (n < 0) {
+		m = SSL_get_error(wsi->ssl, n);
+		lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno);
+		if (m == SSL_ERROR_ZERO_RETURN ||
+		    m == SSL_ERROR_SYSCALL)
+			return LWS_SSL_CAPABLE_ERROR;
+
+		if (SSL_want_read(wsi->ssl)) {
+			lwsl_debug("%s: WANT_READ\n", __func__);
+			lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
+			return LWS_SSL_CAPABLE_MORE_SERVICE;
+		}
+		if (SSL_want_write(wsi->ssl)) {
+			lwsl_debug("%s: WANT_WRITE\n", __func__);
+			lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
+			return LWS_SSL_CAPABLE_MORE_SERVICE;
+		}
+		wsi->socket_is_permanently_unusable = 1;
+
+		return LWS_SSL_CAPABLE_ERROR;
+	}
+
+	lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
+
+	if (wsi->vhost)
+		wsi->vhost->conn_stats.rx += n;
+
+	lws_restart_ws_ping_pong_timer(wsi);
+
+	/*
+	 * if it was our buffer that limited what we read,
+	 * check if SSL has additional data pending inside SSL buffers.
+	 *
+	 * Because these won't signal at the network layer with POLLIN
+	 * and if we don't realize, this data will sit there forever
+	 */
+	if (n != len)
+		goto bail;
+	if (!wsi->ssl)
+		goto bail;
+
+	if (!SSL_pending(wsi->ssl))
+		goto bail;
+
+	if (wsi->pending_read_list_next)
+		return n;
+	if (wsi->pending_read_list_prev)
+		return n;
+	if (pt->pending_read_list == wsi)
+		return n;
+
+	/* add us to the linked list of guys with pending ssl */
+	if (pt->pending_read_list)
+		pt->pending_read_list->pending_read_list_prev = wsi;
+
+	wsi->pending_read_list_next = pt->pending_read_list;
+	wsi->pending_read_list_prev = NULL;
+	pt->pending_read_list = wsi;
+
+	return n;
+bail:
+	lws_ssl_remove_wsi_from_buffered_list(wsi);
+
+	return n;
+}
+
+LWS_VISIBLE int
+lws_ssl_pending(struct lws *wsi)
+{
+	if (!wsi->ssl)
+		return 0;
+
+	return SSL_pending(wsi->ssl);
+}
+
+LWS_VISIBLE int
+lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
+{
+	int n, m;
+
+	if (!wsi->ssl)
+		return lws_ssl_capable_write_no_ssl(wsi, buf, len);
+
+	n = SSL_write(wsi->ssl, buf, len);
+	if (n > 0)
+		return n;
+
+	m = SSL_get_error(wsi->ssl, n);
+	if (m != SSL_ERROR_SYSCALL) {
+		if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) {
+			lwsl_notice("%s: want read\n", __func__);
+
+			return LWS_SSL_CAPABLE_MORE_SERVICE;
+		}
+
+		if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) {
+			lws_set_blocking_send(wsi);
+
+			lwsl_notice("%s: want write\n", __func__);
+
+			return LWS_SSL_CAPABLE_MORE_SERVICE;
+		}
+	}
+
+	lwsl_debug("%s failed: %d\n",__func__, m);
+	wsi->socket_is_permanently_unusable = 1;
+
+	return LWS_SSL_CAPABLE_ERROR;
+}
+
+int openssl_SSL_CTX_private_data_index;
+
+void
+lws_ssl_info_callback(const SSL *ssl, int where, int ret)
+{
+	struct lws *wsi;
+	struct lws_context *context;
+	struct lws_ssl_info si;
+
+	context = (struct lws_context *)SSL_CTX_get_ex_data(
+					SSL_get_SSL_CTX(ssl),
+					openssl_SSL_CTX_private_data_index);
+	if (!context)
+		return;
+	wsi = wsi_from_fd(context, SSL_get_fd(ssl));
+	if (!wsi)
+		return;
+
+	if (!(where & wsi->vhost->ssl_info_event_mask))
+		return;
+
+	si.where = where;
+	si.ret = ret;
+
+	if (user_callback_handle_rxflow(wsi->protocol->callback,
+					wsi, LWS_CALLBACK_SSL_INFO,
+					wsi->user_space, &si, 0))
+		lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
+}
+
+
+LWS_VISIBLE int
+lws_ssl_close(struct lws *wsi)
+{
+	lws_sockfd_type n;
+
+	if (!wsi->ssl)
+		return 0; /* not handled */
+
+#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
+	/* kill ssl callbacks, becausse we will remove the fd from the
+	 * table linking it to the wsi
+	 */
+	if (wsi->vhost->ssl_info_event_mask)
+		SSL_set_info_callback(wsi->ssl, NULL);
+#endif
+
+	n = SSL_get_fd(wsi->ssl);
+	if (!wsi->socket_is_permanently_unusable)
+		SSL_shutdown(wsi->ssl);
+	compatible_close(n);
+	SSL_free(wsi->ssl);
+	wsi->ssl = NULL;
+
+	if (wsi->context->simultaneous_ssl_restriction &&
+	    wsi->context->simultaneous_ssl-- ==
+			    wsi->context->simultaneous_ssl_restriction)
+		/* we made space and can do an accept */
+		lws_gate_accepts(wsi->context, 1);
+#if defined(LWS_WITH_STATS)
+	wsi->context->updated = 1;
+#endif
+
+	return 1; /* handled */
+}
+
+void
+lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
+{
+	if (vhost->ssl_ctx)
+		SSL_CTX_free(vhost->ssl_ctx);
+
+	if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
+		SSL_CTX_free(vhost->ssl_client_ctx);
+}
+
+void
+lws_ssl_context_destroy(struct lws_context *context)
+{
+}
+
+lws_tls_ctx *
+lws_tls_ctx_from_wsi(struct lws *wsi)
+{
+	return SSL_get_SSL_CTX(wsi->ssl);
+}
+
+enum lws_ssl_capable_status
+lws_tls_shutdown(struct lws *wsi)
+{
+	int n = SSL_shutdown(wsi->ssl);
+
+	lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
+
+	switch (n) {
+	case 1: /* successful completion */
+		n = shutdown(wsi->desc.sockfd, SHUT_WR);
+		return LWS_SSL_CAPABLE_DONE;
+
+	case 0: /* needs a retry */
+		lws_change_pollfd(wsi, 0, LWS_POLLIN);
+		return LWS_SSL_CAPABLE_MORE_SERVICE;
+
+	default: /* fatal error, or WANT */
+		n = SSL_get_error(wsi->ssl, n);
+		if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) {
+			if (SSL_want_read(wsi->ssl)) {
+				lwsl_debug("(wants read)\n");
+				lws_change_pollfd(wsi, 0, LWS_POLLIN);
+				return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+			}
+			if (SSL_want_write(wsi->ssl)) {
+				lwsl_debug("(wants write)\n");
+				lws_change_pollfd(wsi, 0, LWS_POLLOUT);
+				return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
+			}
+		}
+		return LWS_SSL_CAPABLE_ERROR;
+	}
+}
diff --git a/lib/mbedtls_wrapper/include/internal/ssl3.h b/lib/tls/mbedtls/wrapper/include/internal/ssl3.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl3.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl3.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_cert.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_cert.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_cert.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_cert.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_code.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_code.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_code.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_code.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_dbg.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_dbg.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_dbg.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_dbg.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_lib.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_lib.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_lib.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_lib.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_methods.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_methods.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_methods.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_methods.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_pkey.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_pkey.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_pkey.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_pkey.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_stack.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_stack.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_stack.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_stack.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_types.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_types.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_types.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_types.h
diff --git a/lib/mbedtls_wrapper/include/internal/ssl_x509.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/ssl_x509.h
rename to lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h
diff --git a/lib/mbedtls_wrapper/include/internal/tls1.h b/lib/tls/mbedtls/wrapper/include/internal/tls1.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/tls1.h
rename to lib/tls/mbedtls/wrapper/include/internal/tls1.h
diff --git a/lib/mbedtls_wrapper/include/internal/x509_vfy.h b/lib/tls/mbedtls/wrapper/include/internal/x509_vfy.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/internal/x509_vfy.h
rename to lib/tls/mbedtls/wrapper/include/internal/x509_vfy.h
diff --git a/lib/mbedtls_wrapper/include/openssl/ssl.h b/lib/tls/mbedtls/wrapper/include/openssl/ssl.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/openssl/ssl.h
rename to lib/tls/mbedtls/wrapper/include/openssl/ssl.h
diff --git a/lib/mbedtls_wrapper/include/platform/ssl_pm.h b/lib/tls/mbedtls/wrapper/include/platform/ssl_pm.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/platform/ssl_pm.h
rename to lib/tls/mbedtls/wrapper/include/platform/ssl_pm.h
diff --git a/lib/mbedtls_wrapper/include/platform/ssl_port.h b/lib/tls/mbedtls/wrapper/include/platform/ssl_port.h
similarity index 100%
rename from lib/mbedtls_wrapper/include/platform/ssl_port.h
rename to lib/tls/mbedtls/wrapper/include/platform/ssl_port.h
diff --git a/lib/mbedtls_wrapper/library/ssl_cert.c b/lib/tls/mbedtls/wrapper/library/ssl_cert.c
similarity index 100%
rename from lib/mbedtls_wrapper/library/ssl_cert.c
rename to lib/tls/mbedtls/wrapper/library/ssl_cert.c
diff --git a/lib/mbedtls_wrapper/library/ssl_lib.c b/lib/tls/mbedtls/wrapper/library/ssl_lib.c
similarity index 100%
rename from lib/mbedtls_wrapper/library/ssl_lib.c
rename to lib/tls/mbedtls/wrapper/library/ssl_lib.c
diff --git a/lib/mbedtls_wrapper/library/ssl_methods.c b/lib/tls/mbedtls/wrapper/library/ssl_methods.c
similarity index 100%
rename from lib/mbedtls_wrapper/library/ssl_methods.c
rename to lib/tls/mbedtls/wrapper/library/ssl_methods.c
diff --git a/lib/mbedtls_wrapper/library/ssl_pkey.c b/lib/tls/mbedtls/wrapper/library/ssl_pkey.c
similarity index 100%
rename from lib/mbedtls_wrapper/library/ssl_pkey.c
rename to lib/tls/mbedtls/wrapper/library/ssl_pkey.c
diff --git a/lib/mbedtls_wrapper/library/ssl_stack.c b/lib/tls/mbedtls/wrapper/library/ssl_stack.c
similarity index 100%
rename from lib/mbedtls_wrapper/library/ssl_stack.c
rename to lib/tls/mbedtls/wrapper/library/ssl_stack.c
diff --git a/lib/mbedtls_wrapper/library/ssl_x509.c b/lib/tls/mbedtls/wrapper/library/ssl_x509.c
similarity index 100%
rename from lib/mbedtls_wrapper/library/ssl_x509.c
rename to lib/tls/mbedtls/wrapper/library/ssl_x509.c
diff --git a/lib/mbedtls_wrapper/platform/ssl_pm.c b/lib/tls/mbedtls/wrapper/platform/ssl_pm.c
similarity index 100%
rename from lib/mbedtls_wrapper/platform/ssl_pm.c
rename to lib/tls/mbedtls/wrapper/platform/ssl_pm.c
diff --git a/lib/mbedtls_wrapper/platform/ssl_port.c b/lib/tls/mbedtls/wrapper/platform/ssl_port.c
similarity index 100%
rename from lib/mbedtls_wrapper/platform/ssl_port.c
rename to lib/tls/mbedtls/wrapper/platform/ssl_port.c
diff --git a/lib/tls/openssl/client.c b/lib/tls/openssl/client.c
new file mode 100644
index 00000000..1eb9f19b
--- /dev/null
+++ b/lib/tls/openssl/client.c
@@ -0,0 +1,384 @@
+/*
+ * libwebsockets - openSSL-specific client tls code
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+extern int openssl_websocket_private_data_index,
+    openssl_SSL_CTX_private_data_index;
+
+#if !defined(USE_WOLFSSL)
+
+static int
+OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+	SSL *ssl;
+	int n;
+	struct lws *wsi;
+
+	/* keep old behaviour accepting self-signed server certs */
+	if (!preverify_ok) {
+		int err = X509_STORE_CTX_get_error(x509_ctx);
+
+		if (err != X509_V_OK) {
+			ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+			wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
+
+			if ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
+					err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
+					wsi->use_ssl & LCCSCF_ALLOW_SELFSIGNED) {
+				lwsl_notice("accepting self-signed certificate (verify_callback)\n");
+				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
+				return 1;	// ok
+			} else if ((err == X509_V_ERR_CERT_NOT_YET_VALID ||
+					err == X509_V_ERR_CERT_HAS_EXPIRED) &&
+					wsi->use_ssl & LCCSCF_ALLOW_EXPIRED) {
+				if (err == X509_V_ERR_CERT_NOT_YET_VALID)
+					lwsl_notice("accepting not yet valid certificate (verify_callback)\n");
+				else if (err == X509_V_ERR_CERT_HAS_EXPIRED)
+					lwsl_notice("accepting expired certificate (verify_callback)\n");
+				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
+				return 1;	// ok
+			}
+		}
+	}
+
+	ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+	wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
+
+	n = lws_get_context_protocol(wsi->context, 0).callback(wsi,
+			LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION,
+			x509_ctx, ssl, preverify_ok);
+
+	/* keep old behaviour if something wrong with server certs */
+	/* if ssl error is overruled in callback and cert is ok,
+	 * X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); must be set and
+	 * return value is 0 from callback */
+	if (!preverify_ok) {
+		int err = X509_STORE_CTX_get_error(x509_ctx);
+
+		if (err != X509_V_OK) {	/* cert validation error was not handled in callback */
+			int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+			const char* msg = X509_verify_cert_error_string(err);
+			lwsl_err("SSL error: %s (preverify_ok=%d;err=%d;depth=%d)\n", msg, preverify_ok, err, depth);
+			return preverify_ok;	// not ok
+		}
+	}
+	/* convert callback return code from 0 = OK to verify callback return value 1 = OK */
+	return !n;
+}
+#endif
+
+int
+lws_ssl_client_bio_create(struct lws *wsi)
+{
+#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
+	X509_VERIFY_PARAM *param;
+#endif
+	char hostname[128], *p;
+
+	if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
+			 _WSI_TOKEN_CLIENT_HOST) <= 0) {
+		lwsl_err("%s: Unable to get hostname\n", __func__);
+
+		return -1;
+	}
+
+	/*
+	 * remove any :port part on the hostname... necessary for network
+	 * connection but typical certificates do not contain it
+	 */
+	p = hostname;
+	while (*p) {
+		if (*p == ':') {
+			*p = '\0';
+			break;
+		}
+		p++;
+	}
+
+	wsi->ssl = SSL_new(wsi->vhost->ssl_client_ctx);
+	if (!wsi->ssl) {
+		lwsl_err("SSL_new failed: %s\n",
+		         ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
+		lws_ssl_elaborate_error();
+		return -1;
+	}
+
+#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
+	if (wsi->vhost->ssl_info_event_mask)
+		SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
+#endif
+
+#if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
+	if (!(wsi->use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
+		param = SSL_get0_param(wsi->ssl);
+		/* Enable automatic hostname checks */
+		X509_VERIFY_PARAM_set_hostflags(param,
+						X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+		X509_VERIFY_PARAM_set1_host(param, hostname, 0);
+	}
+#endif
+
+#if !defined(USE_WOLFSSL)
+#ifndef USE_OLD_CYASSL
+	/* OpenSSL_client_verify_callback will be called @ SSL_connect() */
+	SSL_set_verify(wsi->ssl, SSL_VERIFY_PEER, OpenSSL_client_verify_callback);
+#endif
+#endif
+
+#if !defined(USE_WOLFSSL)
+	SSL_set_mode(wsi->ssl,  SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+#endif
+	/*
+	 * use server name indication (SNI), if supported,
+	 * when establishing connection
+	 */
+#ifdef USE_WOLFSSL
+#ifdef USE_OLD_CYASSL
+#ifdef CYASSL_SNI_HOST_NAME
+	CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME, hostname, strlen(hostname));
+#endif
+#else
+#ifdef WOLFSSL_SNI_HOST_NAME
+	wolfSSL_UseSNI(wsi->ssl, WOLFSSL_SNI_HOST_NAME, hostname, strlen(hostname));
+#endif
+#endif
+#else
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+	SSL_set_tlsext_host_name(wsi->ssl, hostname);
+#endif
+#endif
+
+#ifdef USE_WOLFSSL
+	/*
+	 * wolfSSL/CyaSSL does certificate verification differently
+	 * from OpenSSL.
+	 * If we should ignore the certificate, we need to set
+	 * this before SSL_new and SSL_connect is called.
+	 * Otherwise the connect will simply fail with error code -155
+	 */
+#ifdef USE_OLD_CYASSL
+	if (wsi->use_ssl == 2)
+		CyaSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL);
+#else
+	if (wsi->use_ssl == 2)
+		wolfSSL_set_verify(wsi->ssl, SSL_VERIFY_NONE, NULL);
+#endif
+#endif /* USE_WOLFSSL */
+
+	wsi->client_bio = BIO_new_socket(wsi->desc.sockfd, BIO_NOCLOSE);
+	SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
+
+#ifdef USE_WOLFSSL
+#ifdef USE_OLD_CYASSL
+	CyaSSL_set_using_nonblock(wsi->ssl, 1);
+#else
+	wolfSSL_set_using_nonblock(wsi->ssl, 1);
+#endif
+#else
+	BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
+#endif
+
+	SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, wsi);
+
+	return 0;
+}
+
+enum lws_ssl_capable_status
+lws_tls_client_connect(struct lws *wsi)
+{
+	int m, n = SSL_connect(wsi->ssl);
+
+	if (n == 1)
+		return LWS_SSL_CAPABLE_DONE;
+
+	m = lws_ssl_get_error(wsi, n);
+
+	if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl))
+		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+
+	if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl))
+		return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
+
+	if (!n) /* we don't know what he wants, but he says to retry */
+		return LWS_SSL_CAPABLE_MORE_SERVICE;
+
+	return LWS_SSL_CAPABLE_ERROR;
+}
+
+int
+lws_tls_client_confirm_peer_cert(struct lws *wsi)
+{
+#ifndef USE_WOLFSSL
+	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
+	char *p = (char *)&pt->serv_buf[0];
+	char *sb = p;
+	int n;
+
+	lws_latency_pre(wsi->context, wsi);
+	n = SSL_get_verify_result(wsi->ssl);
+	lws_latency(wsi->context, wsi,
+		"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);
+
+	lwsl_debug("get_verify says %d\n", n);
+
+	if (n != X509_V_OK) {
+		if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
+		     n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
+		     (wsi->use_ssl & LCCSCF_ALLOW_SELFSIGNED)) {
+			lwsl_notice("accepting self-signed certificate\n");
+		} else if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
+		            n == X509_V_ERR_CERT_HAS_EXPIRED) &&
+		     (wsi->use_ssl & LCCSCF_ALLOW_EXPIRED)) {
+			lwsl_notice("accepting expired certificate\n");
+		} else if (n == X509_V_ERR_CERT_NOT_YET_VALID) {
+			lwsl_notice("Cert is from the future... "
+				    "probably our clock... accepting...\n");
+		} else {
+			lwsl_err("server's cert didn't look good, X509_V_ERR = %d: %s\n",
+				 n, ERR_error_string(n, sb));
+			lws_ssl_elaborate_error();
+			return -1;
+		}
+	}
+#endif /* USE_WOLFSSL */
+
+	return 0;
+}
+
+int
+lws_tls_client_create_vhost_context(struct lws_vhost *vh,
+				    struct lws_context_creation_info *info,
+				    const char *cipher_list,
+				    const char *ca_filepath,
+				    const char *cert_filepath,
+				    const char *private_key_filepath)
+{
+	SSL_METHOD *method;
+	unsigned long error;
+	int n;
+
+	/* basic openssl init already happened in context init */
+
+	/* choose the most recent spin of the api */
+#if defined(LWS_HAVE_TLS_CLIENT_METHOD)
+	method = (SSL_METHOD *)TLS_client_method();
+#elif defined(LWS_HAVE_TLSV1_2_CLIENT_METHOD)
+	method = (SSL_METHOD *)TLSv1_2_client_method();
+#else
+	method = (SSL_METHOD *)SSLv23_client_method();
+#endif
+
+	if (!method) {
+		error = ERR_get_error();
+		lwsl_err("problem creating ssl method %lu: %s\n",
+			error, ERR_error_string(error,
+				      (char *)vh->context->pt[0].serv_buf));
+		return 1;
+	}
+	/* create context */
+	vh->ssl_client_ctx = SSL_CTX_new(method);
+	if (!vh->ssl_client_ctx) {
+		error = ERR_get_error();
+		lwsl_err("problem creating ssl context %lu: %s\n",
+			error, ERR_error_string(error,
+				      (char *)vh->context->pt[0].serv_buf));
+		return 1;
+	}
+
+#ifdef SSL_OP_NO_COMPRESSION
+	SSL_CTX_set_options(vh->ssl_client_ctx, SSL_OP_NO_COMPRESSION);
+#endif
+
+	SSL_CTX_set_options(vh->ssl_client_ctx,
+			    SSL_OP_CIPHER_SERVER_PREFERENCE);
+
+	if (cipher_list)
+		SSL_CTX_set_cipher_list(vh->ssl_client_ctx, cipher_list);
+
+#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS
+	if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
+		/* loads OS default CA certs */
+		SSL_CTX_set_default_verify_paths(vh->ssl_client_ctx);
+#endif
+
+	/* openssl init for cert verification (for client sockets) */
+	if (!ca_filepath) {
+		if (!SSL_CTX_load_verify_locations(
+			vh->ssl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS))
+			lwsl_err("Unable to load SSL Client certs from %s "
+			    "(set by LWS_OPENSSL_CLIENT_CERTS) -- "
+			    "client ssl isn't going to work\n",
+			    LWS_OPENSSL_CLIENT_CERTS);
+	} else
+		if (!SSL_CTX_load_verify_locations(
+			vh->ssl_client_ctx, ca_filepath, NULL)) {
+			lwsl_err(
+				"Unable to load SSL Client certs "
+				"file from %s -- client ssl isn't "
+				"going to work\n", ca_filepath);
+			lws_ssl_elaborate_error();
+		}
+		else
+			lwsl_info("loaded ssl_ca_filepath\n");
+
+	/*
+	 * callback allowing user code to load extra verification certs
+	 * helping the client to verify server identity
+	 */
+
+	/* support for client-side certificate authentication */
+	if (cert_filepath) {
+		lwsl_notice("%s: doing cert filepath\n", __func__);
+		n = SSL_CTX_use_certificate_chain_file(vh->ssl_client_ctx,
+						       cert_filepath);
+		if (n < 1) {
+			lwsl_err("problem %d getting cert '%s'\n", n,
+				 cert_filepath);
+			lws_ssl_elaborate_error();
+			return 1;
+		}
+		lwsl_notice("Loaded client cert %s\n", cert_filepath);
+	}
+	if (private_key_filepath) {
+		lwsl_notice("%s: doing private key filepath\n", __func__);
+		lws_ssl_bind_passphrase(vh->ssl_client_ctx, info);
+		/* set the private key from KeyFile */
+		if (SSL_CTX_use_PrivateKey_file(vh->ssl_client_ctx,
+		    private_key_filepath, SSL_FILETYPE_PEM) != 1) {
+			lwsl_err("use_PrivateKey_file '%s'\n",
+				 private_key_filepath);
+			lws_ssl_elaborate_error();
+			return 1;
+		}
+		lwsl_notice("Loaded client cert private key %s\n",
+			    private_key_filepath);
+
+		/* verify private key */
+		if (!SSL_CTX_check_private_key(vh->ssl_client_ctx)) {
+			lwsl_err("Private SSL key doesn't match cert\n");
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
diff --git a/lib/tls/openssl/server.c b/lib/tls/openssl/server.c
new file mode 100644
index 00000000..2a5032fa
--- /dev/null
+++ b/lib/tls/openssl/server.c
@@ -0,0 +1,417 @@
+/*
+ * libwebsockets - OpenSSL-specific server functions
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+extern int openssl_websocket_private_data_index,
+	   openssl_SSL_CTX_private_data_index;
+
+static int
+OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+	SSL *ssl;
+	int n;
+	struct lws *wsi;
+
+	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+		SSL_get_ex_data_X509_STORE_CTX_idx());
+
+	/*
+	 * !!! nasty openssl requires the index to come as a library-scope
+	 * static
+	 */
+	wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
+
+	n = wsi->vhost->protocols[0].callback(wsi,
+			LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
+					   x509_ctx, ssl, preverify_ok);
+
+	/* convert return code from 0 = OK to 1 = OK */
+	return !n;
+}
+
+int
+lws_tls_server_client_cert_verify_config(struct lws_context_creation_info *info,
+					 struct lws_vhost *vh)
+{
+	int verify_options = SSL_VERIFY_PEER;
+
+	/* as a server, are we requiring clients to identify themselves? */
+
+	if (!lws_check_opt(info->options,
+			  LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT))
+		return 0;
+
+	if (!lws_check_opt(info->options,
+			   LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED))
+		verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+
+	SSL_CTX_set_session_id_context(vh->ssl_ctx, (uint8_t *)vh->context,
+				       sizeof(void *));
+
+	/* absolutely require the client cert */
+	SSL_CTX_set_verify(vh->ssl_ctx, verify_options, OpenSSL_verify_callback);
+
+	return 0;
+}
+
+#if defined(SSL_TLSEXT_ERR_NOACK) && !defined(OPENSSL_NO_TLSEXT)
+static int
+lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
+{
+	struct lws_context *context = (struct lws_context *)arg;
+	struct lws_vhost *vhost, *vh;
+	const char *servername;
+
+	if (!ssl)
+		return SSL_TLSEXT_ERR_NOACK;
+
+	/*
+	 * We can only get ssl accepted connections by using a vhost's ssl_ctx
+	 * find out which listening one took us and only match vhosts on the
+	 * same port.
+	 */
+	vh = context->vhost_list;
+	while (vh) {
+		if (!vh->being_destroyed && vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
+			break;
+		vh = vh->vhost_next;
+	}
+
+	if (!vh) {
+		assert(vh); /* can't match the incoming vh? */
+		return SSL_TLSEXT_ERR_OK;
+	}
+
+	servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+	if (!servername) {
+		/* the client doesn't know what hostname it wants */
+		lwsl_info("SNI: Unknown ServerName: %s\n", servername);
+
+		return SSL_TLSEXT_ERR_OK;
+	}
+
+	vhost = lws_select_vhost(context, vh->listen_port, servername);
+	if (!vhost) {
+		lwsl_info("SNI: none: %s:%d\n", servername, vh->listen_port);
+
+		return SSL_TLSEXT_ERR_OK;
+	}
+
+	lwsl_info("SNI: Found: %s:%d\n", servername, vh->listen_port);
+
+	/* select the ssl ctx from the selected vhost for this conn */
+	SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
+
+	return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
+int
+lws_tls_server_vhost_backend_init(struct lws_context_creation_info *info,
+				  struct lws_vhost *vhost,
+				  struct lws *wsi)
+{
+#if defined(LWS_HAVE_OPENSSL_ECDH_H)
+	const char *ecdh_curve = "prime256v1";
+	EC_KEY *ecdh, *EC_key = NULL;
+	EVP_PKEY *pkey;
+	X509 *x = NULL;
+	int ecdh_nid;
+	int KeyType;
+#if defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
+	STACK_OF(X509) *extra_certs = NULL;
+#endif
+#endif
+	SSL_METHOD *method = (SSL_METHOD *)SSLv23_server_method();
+	unsigned long error;
+	int n;
+
+	if (!method) {
+		error = ERR_get_error();
+		lwsl_err("problem creating ssl method %lu: %s\n",
+				error, ERR_error_string(error,
+				      (char *)vhost->context->pt[0].serv_buf));
+		return 1;
+	}
+	vhost->ssl_ctx = SSL_CTX_new(method);	/* create context */
+	if (!vhost->ssl_ctx) {
+		error = ERR_get_error();
+		lwsl_err("problem creating ssl context %lu: %s\n",
+				error, ERR_error_string(error,
+				      (char *)vhost->context->pt[0].serv_buf));
+		return 1;
+	}
+
+	SSL_CTX_set_ex_data(vhost->ssl_ctx, openssl_SSL_CTX_private_data_index,
+			    (char *)vhost->context);
+	/* Disable SSLv2 and SSLv3 */
+	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+#ifdef SSL_OP_NO_COMPRESSION
+	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_NO_COMPRESSION);
+#endif
+	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_DH_USE);
+	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+
+	if (info->ssl_cipher_list)
+		SSL_CTX_set_cipher_list(vhost->ssl_ctx, info->ssl_cipher_list);
+
+#if !defined(LWS_WITH_MBEDTLS) && !defined(OPENSSL_NO_TLSEXT)
+	SSL_CTX_set_tlsext_servername_callback(vhost->ssl_ctx,
+					       lws_ssl_server_name_cb);
+	SSL_CTX_set_tlsext_servername_arg(vhost->ssl_ctx, vhost->context);
+#endif
+
+	if (info->ssl_ca_filepath &&
+	    !SSL_CTX_load_verify_locations(vhost->ssl_ctx,
+					   info->ssl_ca_filepath, NULL)) {
+		lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n",
+			 __func__);
+	}
+
+	if (info->ssl_options_set)
+		SSL_CTX_set_options(vhost->ssl_ctx, info->ssl_options_set);
+
+/* SSL_clear_options introduced in 0.9.8m */
+#if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
+	if (info->ssl_options_clear)
+		SSL_CTX_clear_options(vhost->ssl_ctx, info->ssl_options_clear);
+#endif
+
+	lwsl_info(" SSL options 0x%lX\n", SSL_CTX_get_options(vhost->ssl_ctx));
+	if (!vhost->use_ssl || !info->ssl_cert_filepath)
+		return 0;
+
+	/*
+	 * The user code can choose to either pass the cert and
+	 * key filepaths using the info members like this, or it can
+	 * leave them NULL; force the vhost SSL_CTX init using the info
+	 * options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and
+	 * set up the cert himself using the user callback
+	 * LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
+	 * happened just above and has the vhost SSL_CTX * in the user
+	 * parameter.
+	 */
+	/* set the local certificate from CertFile */
+	n = SSL_CTX_use_certificate_chain_file(vhost->ssl_ctx,
+					       info->ssl_cert_filepath);
+	if (n != 1) {
+		error = ERR_get_error();
+		lwsl_err("problem getting cert '%s' %lu: %s\n",
+			 info->ssl_cert_filepath, error, ERR_error_string(error,
+			       (char *)vhost->context->pt[0].serv_buf));
+
+		return 1;
+	}
+	lws_ssl_bind_passphrase(vhost->ssl_ctx, info);
+
+	if (info->ssl_private_key_filepath != NULL) {
+		/* set the private key from KeyFile */
+		if (SSL_CTX_use_PrivateKey_file(vhost->ssl_ctx,
+						info->ssl_private_key_filepath,
+					        SSL_FILETYPE_PEM) != 1) {
+			error = ERR_get_error();
+			lwsl_err("ssl problem getting key '%s' %lu: %s\n",
+				 info->ssl_private_key_filepath, error,
+				 ERR_error_string(error,
+				      (char *)vhost->context->pt[0].serv_buf));
+			return 1;
+		}
+	} else
+		if (vhost->protocols[0].callback(wsi,
+			LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY,
+			vhost->ssl_ctx, NULL, 0)) {
+			lwsl_err("ssl private key not set\n");
+
+			return 1;
+		}
+
+	/* verify private key */
+	if (!SSL_CTX_check_private_key(vhost->ssl_ctx)) {
+		lwsl_err("Private SSL key doesn't match cert\n");
+
+		return 1;
+	}
+
+#if defined(LWS_HAVE_OPENSSL_ECDH_H)
+	if (info->ecdh_curve)
+		ecdh_curve = info->ecdh_curve;
+
+	ecdh_nid = OBJ_sn2nid(ecdh_curve);
+	if (NID_undef == ecdh_nid) {
+		lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve);
+		return 1;
+	}
+
+	ecdh = EC_KEY_new_by_curve_name(ecdh_nid);
+	if (NULL == ecdh) {
+		lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve);
+		return 1;
+	}
+	SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, ecdh);
+	EC_KEY_free(ecdh);
+
+	SSL_CTX_set_options(vhost->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
+
+	lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve);
+
+	if (lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_SSL_ECDH))
+		lwsl_notice(" Using ECDH certificate support\n");
+
+	/* Get X509 certificate from ssl context */
+#if !defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
+	x = sk_X509_value(vhost->ssl_ctx->extra_certs, 0);
+#else
+	SSL_CTX_get_extra_chain_certs_only(vhost->ssl_ctx, &extra_certs);
+	if (extra_certs)
+		x = sk_X509_value(extra_certs, 0);
+	else
+		lwsl_err("%s: no extra certs\n", __func__);
+#endif
+	if (!x) {
+		lwsl_err("%s: x is NULL\n", __func__);
+		return 0; // !!!
+	}
+	/* Get the public key from certificate */
+	pkey = X509_get_pubkey(x);
+	if (!pkey) {
+		lwsl_err("%s: pkey is NULL\n", __func__);
+
+		return 1;
+	}
+	/* Get the key type */
+	KeyType = EVP_PKEY_type(EVP_PKEY_id(pkey));
+
+	if (EVP_PKEY_EC != KeyType) {
+		lwsl_notice("Key type is not EC\n");
+		return 0;
+	}
+	/* Get the key */
+	EC_key = EVP_PKEY_get1_EC_KEY(pkey);
+	/* Set ECDH parameter */
+	if (!EC_key) {
+		lwsl_err("%s: ECDH key is NULL \n", __func__);
+		return 1;
+	}
+	SSL_CTX_set_tmp_ecdh(vhost->ssl_ctx, EC_key);
+
+	EC_KEY_free(EC_key);
+#else
+	lwsl_notice(" OpenSSL doesn't support ECDH\n");
+#endif
+
+
+	return 0;
+}
+
+int
+lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
+{
+#if !defined(USE_WOLFSSL)
+	BIO *bio;
+#endif
+
+	errno = 0;
+	wsi->ssl = SSL_new(wsi->vhost->ssl_ctx);
+	if (wsi->ssl == NULL) {
+		lwsl_err("SSL_new failed: %d (errno %d)\n",
+			 lws_ssl_get_error(wsi, 0), errno);
+
+		lws_ssl_elaborate_error();
+		return 1;
+	}
+
+	SSL_set_ex_data(wsi->ssl, openssl_websocket_private_data_index, wsi);
+	SSL_set_fd(wsi->ssl, accept_fd);
+
+#ifdef USE_WOLFSSL
+#ifdef USE_OLD_CYASSL
+	CyaSSL_set_using_nonblock(wsi->ssl, 1);
+#else
+	wolfSSL_set_using_nonblock(wsi->ssl, 1);
+#endif
+#else
+
+	SSL_set_mode(wsi->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+	bio = SSL_get_rbio(wsi->ssl);
+	if (bio)
+		BIO_set_nbio(bio, 1); /* nonblocking */
+	else
+		lwsl_notice("NULL rbio\n");
+	bio = SSL_get_wbio(wsi->ssl);
+	if (bio)
+		BIO_set_nbio(bio, 1); /* nonblocking */
+	else
+		lwsl_notice("NULL rbio\n");
+#endif
+
+#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
+		if (wsi->vhost->ssl_info_event_mask)
+			SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
+#endif
+
+	return 0;
+}
+
+int
+lws_tls_server_abort_connection(struct lws *wsi)
+{
+	SSL_shutdown(wsi->ssl);
+	SSL_free(wsi->ssl);
+
+	return 0;
+}
+
+enum lws_ssl_capable_status
+lws_tls_server_accept(struct lws *wsi)
+{
+	int m, n = SSL_accept(wsi->ssl);
+
+	if (n == 1)
+		return LWS_SSL_CAPABLE_DONE;
+
+	m = lws_ssl_get_error(wsi, n);
+
+	if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL)
+		return LWS_SSL_CAPABLE_ERROR;
+
+	if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) {
+		if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
+			lwsl_info("%s: WANT_READ change_pollfd failed\n", __func__);
+			return LWS_SSL_CAPABLE_ERROR;
+		}
+
+		lwsl_info("SSL_ERROR_WANT_READ\n");
+		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+	}
+	if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) {
+		lwsl_debug("%s: WANT_WRITE\n", __func__);
+
+		if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
+			lwsl_info("%s: WANT_WRITE change_pollfd failed\n", __func__);
+			return LWS_SSL_CAPABLE_ERROR;
+		}
+		return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
+	}
+
+	return LWS_SSL_CAPABLE_ERROR;
+}
+
diff --git a/lib/tls/openssl/ssl.c b/lib/tls/openssl/ssl.c
new file mode 100644
index 00000000..5b46809d
--- /dev/null
+++ b/lib/tls/openssl/ssl.c
@@ -0,0 +1,486 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+/* workaround for mingw */
+#if !defined(ECONNABORTED)
+#define ECONNABORTED 103
+#endif
+
+int openssl_websocket_private_data_index,
+	   openssl_SSL_CTX_private_data_index;
+
+int lws_ssl_get_error(struct lws *wsi, int n)
+{
+	int m;
+
+	if (!wsi->ssl)
+		return 99;
+
+	m = SSL_get_error(wsi->ssl, n);
+	lwsl_debug("%s: %p %d -> %d\n", __func__, wsi->ssl, n, m);
+
+	return m;
+}
+
+char* lws_ssl_get_error_string(int status, int ret, char *buf, size_t len) {
+	switch (status) {
+	case SSL_ERROR_NONE:
+		return strncpy(buf, "SSL_ERROR_NONE", len);
+	case SSL_ERROR_ZERO_RETURN:
+		return strncpy(buf, "SSL_ERROR_ZERO_RETURN", len);
+	case SSL_ERROR_WANT_READ:
+		return strncpy(buf, "SSL_ERROR_WANT_READ", len);
+	case SSL_ERROR_WANT_WRITE:
+		return strncpy(buf, "SSL_ERROR_WANT_WRITE", len);
+	case SSL_ERROR_WANT_CONNECT:
+		return strncpy(buf, "SSL_ERROR_WANT_CONNECT", len);
+	case SSL_ERROR_WANT_ACCEPT:
+		return strncpy(buf, "SSL_ERROR_WANT_ACCEPT", len);
+	case SSL_ERROR_WANT_X509_LOOKUP:
+		return strncpy(buf, "SSL_ERROR_WANT_X509_LOOKUP", len);
+	case SSL_ERROR_SYSCALL:
+		switch (ret) {
+                case 0:
+                        lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: EOF");
+                        return buf;
+                case -1:
+#ifndef LWS_PLAT_OPTEE
+			lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %s",
+				     strerror(errno));
+#else
+			lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %d", errno);
+#endif
+			return buf;
+                default:
+                        return strncpy(buf, "SSL_ERROR_SYSCALL", len);
+	}
+	case SSL_ERROR_SSL:
+		return "SSL_ERROR_SSL";
+	default:
+		return "SSL_ERROR_UNKNOWN";
+	}
+}
+
+void
+lws_ssl_elaborate_error(void)
+{
+	char buf[256];
+	u_long err;
+
+	while ((err = ERR_get_error()) != 0) {
+		ERR_error_string_n(err, buf, sizeof(buf));
+		lwsl_info("*** %s\n", buf);
+	}
+}
+
+static int
+lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag,
+				   void *userdata)
+{
+	struct lws_context_creation_info * info =
+			(struct lws_context_creation_info *)userdata;
+
+	strncpy(buf, info->ssl_private_key_password, size);
+	buf[size - 1] = '\0';
+
+	return strlen(buf);
+}
+
+void
+lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx, struct lws_context_creation_info *info)
+{
+	if (!info->ssl_private_key_password)
+		return;
+	/*
+	 * password provided, set ssl callback and user data
+	 * for checking password which will be trigered during
+	 * SSL_CTX_use_PrivateKey_file function
+	 */
+	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)info);
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, lws_context_init_ssl_pem_passwd_cb);
+}
+
+int
+lws_context_init_ssl_library(struct lws_context_creation_info *info)
+{
+#ifdef USE_WOLFSSL
+#ifdef USE_OLD_CYASSL
+	lwsl_info(" Compiled with CyaSSL support\n");
+#else
+	lwsl_info(" Compiled with wolfSSL support\n");
+#endif
+#else
+#if defined(LWS_WITH_BORINGSSL)
+	lwsl_info(" Compiled with BoringSSL support\n");
+#else
+	lwsl_info(" Compiled with OpenSSL support\n");
+#endif
+#endif
+	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
+		lwsl_info(" SSL disabled: no LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
+		return 0;
+	}
+
+	/* basic openssl init */
+
+	lwsl_info("Doing SSL library init\n");
+
+	SSL_library_init();
+	OpenSSL_add_all_algorithms();
+	SSL_load_error_strings();
+
+	openssl_websocket_private_data_index =
+		SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL);
+
+	openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0,
+			NULL, NULL, NULL, NULL);
+
+	return 0;
+}
+
+LWS_VISIBLE void
+lws_ssl_destroy(struct lws_vhost *vhost)
+{
+	if (!lws_check_opt(vhost->context->options,
+			   LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
+		return;
+
+	if (vhost->ssl_ctx)
+		SSL_CTX_free(vhost->ssl_ctx);
+	if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
+		SSL_CTX_free(vhost->ssl_client_ctx);
+
+// after 1.1.0 no need
+#if (OPENSSL_VERSION_NUMBER <  0x10100000)
+// <= 1.0.1f = old api, 1.0.1g+ = new api
+#if (OPENSSL_VERSION_NUMBER <= 0x1000106f) || defined(USE_WOLFSSL)
+	ERR_remove_state(0);
+#else
+#if OPENSSL_VERSION_NUMBER >= 0x1010005f && \
+    !defined(LIBRESSL_VERSION_NUMBER) && \
+    !defined(OPENSSL_IS_BORINGSSL)
+	ERR_remove_thread_state();
+#else
+	ERR_remove_thread_state(NULL);
+#endif
+#endif
+	// after 1.1.0 no need
+#if  (OPENSSL_VERSION_NUMBER >= 0x10002000) && (OPENSSL_VERSION_NUMBER <= 0x10100000)
+	SSL_COMP_free_compression_methods();
+#endif
+	ERR_free_strings();
+	EVP_cleanup();
+	CRYPTO_cleanup_all_ex_data();
+#endif
+}
+
+LWS_VISIBLE int
+lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
+{
+	struct lws_context *context = wsi->context;
+	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+	int n = 0, m;
+
+	if (!wsi->ssl)
+		return lws_ssl_capable_read_no_ssl(wsi, buf, len);
+
+	lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
+
+	errno = 0;
+	n = SSL_read(wsi->ssl, buf, len);
+#if defined(LWS_WITH_ESP32)
+	if (!n && errno == ENOTCONN) {
+		lwsl_debug("%p: SSL_read ENOTCONN\n", wsi);
+		return LWS_SSL_CAPABLE_ERROR;
+	}
+#endif
+#if defined(LWS_WITH_STATS)
+	if (!wsi->seen_rx) {
+                lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_RX_DELAY,
+				time_in_microseconds() - wsi->accept_start_us);
+                lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNS_HAD_RX, 1);
+		wsi->seen_rx = 1;
+	}
+#endif
+
+
+	lwsl_debug("%p: SSL_read says %d\n", wsi, n);
+	/* manpage: returning 0 means connection shut down */
+	if (!n) {
+		wsi->socket_is_permanently_unusable = 1;
+
+		return LWS_SSL_CAPABLE_ERROR;
+	}
+
+	if (n < 0) {
+		m = lws_ssl_get_error(wsi, n);
+		lwsl_debug("%p: ssl err %d errno %d\n", wsi, m, errno);
+		if (m == SSL_ERROR_ZERO_RETURN ||
+		    m == SSL_ERROR_SYSCALL)
+			return LWS_SSL_CAPABLE_ERROR;
+
+		if (SSL_want_read(wsi->ssl)) {
+			lwsl_debug("%s: WANT_READ\n", __func__);
+			lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
+			return LWS_SSL_CAPABLE_MORE_SERVICE;
+		}
+		if (SSL_want_write(wsi->ssl)) {
+			lwsl_debug("%s: WANT_WRITE\n", __func__);
+			lwsl_debug("%p: LWS_SSL_CAPABLE_MORE_SERVICE\n", wsi);
+			return LWS_SSL_CAPABLE_MORE_SERVICE;
+		}
+		wsi->socket_is_permanently_unusable = 1;
+
+		return LWS_SSL_CAPABLE_ERROR;
+	}
+
+	lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
+
+	if (wsi->vhost)
+		wsi->vhost->conn_stats.rx += n;
+
+	lws_restart_ws_ping_pong_timer(wsi);
+
+	/*
+	 * if it was our buffer that limited what we read,
+	 * check if SSL has additional data pending inside SSL buffers.
+	 *
+	 * Because these won't signal at the network layer with POLLIN
+	 * and if we don't realize, this data will sit there forever
+	 */
+	if (n != len)
+		goto bail;
+	if (!wsi->ssl)
+		goto bail;
+
+	if (!SSL_pending(wsi->ssl))
+		goto bail;
+
+	if (wsi->pending_read_list_next)
+		return n;
+	if (wsi->pending_read_list_prev)
+		return n;
+	if (pt->pending_read_list == wsi)
+		return n;
+
+	/* add us to the linked list of guys with pending ssl */
+	if (pt->pending_read_list)
+		pt->pending_read_list->pending_read_list_prev = wsi;
+
+	wsi->pending_read_list_next = pt->pending_read_list;
+	wsi->pending_read_list_prev = NULL;
+	pt->pending_read_list = wsi;
+
+	return n;
+bail:
+	lws_ssl_remove_wsi_from_buffered_list(wsi);
+
+	return n;
+}
+
+LWS_VISIBLE int
+lws_ssl_pending(struct lws *wsi)
+{
+	if (!wsi->ssl)
+		return 0;
+
+	return SSL_pending(wsi->ssl);
+}
+
+LWS_VISIBLE int
+lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len)
+{
+	int n, m;
+
+	if (!wsi->ssl)
+		return lws_ssl_capable_write_no_ssl(wsi, buf, len);
+
+	n = SSL_write(wsi->ssl, buf, len);
+	if (n > 0)
+		return n;
+
+	m = lws_ssl_get_error(wsi, n);
+	if (m != SSL_ERROR_SYSCALL) {
+		if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->ssl)) {
+			lwsl_notice("%s: want read\n", __func__);
+
+			return LWS_SSL_CAPABLE_MORE_SERVICE;
+		}
+
+		if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->ssl)) {
+			lws_set_blocking_send(wsi);
+
+			lwsl_notice("%s: want write\n", __func__);
+
+			return LWS_SSL_CAPABLE_MORE_SERVICE;
+		}
+	}
+
+	lwsl_debug("%s failed: %s\n",__func__, ERR_error_string(m, NULL));
+	lws_ssl_elaborate_error();
+
+	wsi->socket_is_permanently_unusable = 1;
+
+	return LWS_SSL_CAPABLE_ERROR;
+}
+
+void
+lws_ssl_info_callback(const SSL *ssl, int where, int ret)
+{
+	struct lws *wsi;
+	struct lws_context *context;
+	struct lws_ssl_info si;
+
+	context = (struct lws_context *)SSL_CTX_get_ex_data(
+					SSL_get_SSL_CTX(ssl),
+					openssl_SSL_CTX_private_data_index);
+	if (!context)
+		return;
+	wsi = wsi_from_fd(context, SSL_get_fd(ssl));
+	if (!wsi)
+		return;
+
+	if (!(where & wsi->vhost->ssl_info_event_mask))
+		return;
+
+	si.where = where;
+	si.ret = ret;
+
+	if (user_callback_handle_rxflow(wsi->protocol->callback,
+						   wsi, LWS_CALLBACK_SSL_INFO,
+						   wsi->user_space, &si, 0))
+		lws_set_timeout(wsi, PENDING_TIMEOUT_KILLED_BY_SSL_INFO, -1);
+}
+
+
+LWS_VISIBLE int
+lws_ssl_close(struct lws *wsi)
+{
+	lws_sockfd_type n;
+
+	if (!wsi->ssl)
+		return 0; /* not handled */
+
+#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
+	/* kill ssl callbacks, becausse we will remove the fd from the
+	 * table linking it to the wsi
+	 */
+	if (wsi->vhost->ssl_info_event_mask)
+		SSL_set_info_callback(wsi->ssl, NULL);
+#endif
+
+	n = SSL_get_fd(wsi->ssl);
+	if (!wsi->socket_is_permanently_unusable)
+		SSL_shutdown(wsi->ssl);
+	compatible_close(n);
+	SSL_free(wsi->ssl);
+	wsi->ssl = NULL;
+
+	if (wsi->context->simultaneous_ssl_restriction &&
+	    wsi->context->simultaneous_ssl-- ==
+			    wsi->context->simultaneous_ssl_restriction)
+		/* we made space and can do an accept */
+		lws_gate_accepts(wsi->context, 1);
+#if defined(LWS_WITH_STATS)
+	wsi->context->updated = 1;
+#endif
+
+	return 1; /* handled */
+}
+
+void
+lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
+{
+	if (vhost->ssl_ctx)
+		SSL_CTX_free(vhost->ssl_ctx);
+
+	if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
+		SSL_CTX_free(vhost->ssl_client_ctx);
+}
+
+void
+lws_ssl_context_destroy(struct lws_context *context)
+{
+// after 1.1.0 no need
+#if (OPENSSL_VERSION_NUMBER <  0x10100000)
+// <= 1.0.1f = old api, 1.0.1g+ = new api
+#if (OPENSSL_VERSION_NUMBER <= 0x1000106f) || defined(USE_WOLFSSL)
+	ERR_remove_state(0);
+#else
+#if OPENSSL_VERSION_NUMBER >= 0x1010005f && \
+    !defined(LIBRESSL_VERSION_NUMBER) && \
+    !defined(OPENSSL_IS_BORINGSSL)
+	ERR_remove_thread_state();
+#else
+	ERR_remove_thread_state(NULL);
+#endif
+#endif
+	// after 1.1.0 no need
+#if  (OPENSSL_VERSION_NUMBER >= 0x10002000) && (OPENSSL_VERSION_NUMBER <= 0x10100000)
+	SSL_COMP_free_compression_methods();
+#endif
+	ERR_free_strings();
+	EVP_cleanup();
+	CRYPTO_cleanup_all_ex_data();
+#endif
+}
+
+lws_tls_ctx *
+lws_tls_ctx_from_wsi(struct lws *wsi)
+{
+	return SSL_get_SSL_CTX(wsi->ssl);
+}
+
+enum lws_ssl_capable_status
+lws_tls_shutdown(struct lws *wsi)
+{
+	int n;
+
+	n = SSL_shutdown(wsi->ssl);
+	lwsl_debug("SSL_shutdown=%d for fd %d\n", n, wsi->desc.sockfd);
+	switch (n) {
+	case 1: /* successful completion */
+		n = shutdown(wsi->desc.sockfd, SHUT_WR);
+		return LWS_SSL_CAPABLE_DONE;
+
+	case 0: /* needs a retry */
+		lws_change_pollfd(wsi, 0, LWS_POLLIN);
+		return LWS_SSL_CAPABLE_MORE_SERVICE;
+
+	default: /* fatal error, or WANT */
+		n = SSL_get_error(wsi->ssl, n);
+		if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) {
+			if (SSL_want_read(wsi->ssl)) {
+				lwsl_debug("(wants read)\n");
+				lws_change_pollfd(wsi, 0, LWS_POLLIN);
+				return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
+			}
+			if (SSL_want_write(wsi->ssl)) {
+				lwsl_debug("(wants write)\n");
+				lws_change_pollfd(wsi, 0, LWS_POLLOUT);
+				return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
+			}
+		}
+		return LWS_SSL_CAPABLE_ERROR;
+	}
+}
diff --git a/lib/tls/tls.c b/lib/tls/tls.c
new file mode 100644
index 00000000..e804fb06
--- /dev/null
+++ b/lib/tls/tls.c
@@ -0,0 +1,122 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+int lws_alloc_vfs_file(struct lws_context *context, const char *filename, uint8_t **buf,
+		lws_filepos_t *amount)
+{
+	lws_filepos_t len;
+	lws_fop_flags_t	flags = LWS_O_RDONLY;
+	lws_fop_fd_t fops_fd = lws_vfs_file_open(
+				lws_get_fops(context), filename, &flags);
+	int ret = 1;
+
+	if (!fops_fd)
+		return 1;
+
+	len = lws_vfs_get_length(fops_fd);
+
+	*buf = lws_malloc((size_t)len, "lws_alloc_vfs_file");
+	if (!*buf)
+		goto bail;
+
+	if (lws_vfs_file_read(fops_fd, amount, *buf, len))
+		goto bail;
+
+	ret = 0;
+bail:
+	lws_vfs_file_close(&fops_fd);
+
+	return ret;
+}
+
+int
+lws_ssl_anybody_has_buffered_read_tsi(struct lws_context *context, int tsi)
+{
+	struct lws_context_per_thread *pt = &context->pt[tsi];
+	struct lws *wsi, *wsi_next;
+
+	wsi = pt->pending_read_list;
+	while (wsi) {
+		wsi_next = wsi->pending_read_list_next;
+		pt->fds[wsi->position_in_fds_table].revents |=
+			pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
+		if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN)
+			return 1;
+
+		wsi = wsi_next;
+	}
+
+	return 0;
+}
+
+LWS_VISIBLE void
+lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
+{
+	struct lws_context *context = wsi->context;
+	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+
+	if (!wsi->pending_read_list_prev &&
+	    !wsi->pending_read_list_next &&
+	    pt->pending_read_list != wsi)
+		/* we are not on the list */
+		return;
+
+	/* point previous guy's next to our next */
+	if (!wsi->pending_read_list_prev)
+		pt->pending_read_list = wsi->pending_read_list_next;
+	else
+		wsi->pending_read_list_prev->pending_read_list_next =
+			wsi->pending_read_list_next;
+
+	/* point next guy's previous to our previous */
+	if (wsi->pending_read_list_next)
+		wsi->pending_read_list_next->pending_read_list_prev =
+			wsi->pending_read_list_prev;
+
+	wsi->pending_read_list_prev = NULL;
+	wsi->pending_read_list_next = NULL;
+}
+
+
+int
+lws_gate_accepts(struct lws_context *context, int on)
+{
+	struct lws_vhost *v = context->vhost_list;
+
+	lwsl_info("gating accepts %d\n", on);
+	context->ssl_gate_accepts = !on;
+#if defined(LWS_WITH_STATS)
+	context->updated = 1;
+#endif
+
+	while (v) {
+		if (v->use_ssl &&  v->lserv_wsi) /* gate ability to accept incoming connections */
+			if (lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
+					      (LWS_POLLIN) * on))
+				lwsl_info("Unable to set accept POLLIN %d\n", on);
+
+		v = v->vhost_next;
+	}
+
+	return 0;
+}
diff --git a/plugins/generic-sessions/protocol_generic_sessions.c b/plugins/generic-sessions/protocol_generic_sessions.c
index 521b5398..31c41fc1 100644
--- a/plugins/generic-sessions/protocol_generic_sessions.c
+++ b/plugins/generic-sessions/protocol_generic_sessions.c
@@ -20,6 +20,7 @@
  */
 
 #include "private-lwsgs.h"
+#include <stdlib.h>
 
 /* keep changes in sync with the enum in lwsgs.h */
 static const char * const param_names[] = {
diff --git a/plugins/generic-sessions/protocol_lws_messageboard.c b/plugins/generic-sessions/protocol_lws_messageboard.c
index 8e66cd5b..19b9f2a0 100644
--- a/plugins/generic-sessions/protocol_lws_messageboard.c
+++ b/plugins/generic-sessions/protocol_lws_messageboard.c
@@ -25,6 +25,7 @@
 
 #include <sqlite3.h>
 #include <string.h>
+#include <stdlib.h>
 
 struct per_vhost_data__gs_mb {
 	struct lws_vhost *vh;
diff --git a/plugins/generic-sessions/utils.c b/plugins/generic-sessions/utils.c
index c90b91d1..c6adc5e1 100644
--- a/plugins/generic-sessions/utils.c
+++ b/plugins/generic-sessions/utils.c
@@ -20,6 +20,7 @@
  */
 
 #include "private-lwsgs.h"
+#include <stdlib.h>
 
 void
 sha1_to_lwsgw_hash(unsigned char *hash, lwsgw_hash *shash)
diff --git a/plugins/generic-table/protocol_table_dirlisting.c b/plugins/generic-table/protocol_table_dirlisting.c
index 49a2bb48..0734a14b 100644
--- a/plugins/generic-table/protocol_table_dirlisting.c
+++ b/plugins/generic-table/protocol_table_dirlisting.c
@@ -24,6 +24,7 @@
 #include "../lib/libwebsockets.h"
 
 #include <string.h>
+#include <stdlib.h>
 #include <uv.h>
 
 struct fobj {
diff --git a/plugins/protocol_lws_sshd_demo.c b/plugins/protocol_lws_sshd_demo.c
index db8164ac..47f7471e 100644
--- a/plugins/protocol_lws_sshd_demo.c
+++ b/plugins/protocol_lws_sshd_demo.c
@@ -27,6 +27,7 @@
 #include <lws-ssh.h>
 
 #include <string.h>
+#include <stdlib.h>
 
 #define TEST_SERVER_KEY_PATH "/etc/lws-test-sshd-server-key"
 
@@ -160,7 +161,7 @@ ssh_ops_tx(void *_priv, int stdch, uint8_t *buf, size_t len)
 	if (stdch != LWS_STDOUT)
 		return 0;
 
-	if (priv->len - priv->pos < chunk)
+	if ((size_t)(priv->len - priv->pos) < chunk)
 		chunk = priv->len - priv->pos;
 
 	if (!chunk)
diff --git a/plugins/protocol_post_demo.c b/plugins/protocol_post_demo.c
index 8880fe2e..6be73fbd 100644
--- a/plugins/protocol_post_demo.c
+++ b/plugins/protocol_post_demo.c
@@ -32,6 +32,7 @@
 #include <io.h>
 #endif
 #include <stdio.h>
+#include <stdlib.h>
 
 struct per_session_data__post_demo {
 	struct lws_spa *spa;
diff --git a/plugins/ssh-base/crypto/chacha.c b/plugins/ssh-base/crypto/chacha.c
index 46d46cb8..741991ac 100644
--- a/plugins/ssh-base/crypto/chacha.c
+++ b/plugins/ssh-base/crypto/chacha.c
@@ -8,6 +8,7 @@ Public domain.
 #include "lws-ssh.h"
 
 #include <string.h>
+#include <stdlib.h>
 
 struct chacha_ctx {
 	u_int input[16];
diff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c
index 345e1b85..c4b0e0ff 100644
--- a/plugins/ssh-base/sshd.c
+++ b/plugins/ssh-base/sshd.c
@@ -23,6 +23,7 @@
 #include "lws-ssh.h"
 
 #include <string.h>
+#include <stdlib.h>
 
 void *sshd_zalloc(size_t s)
 {
diff --git a/test-apps/test-server-http.c b/test-apps/test-server-http.c
index 155e493e..2e8126b4 100644
--- a/test-apps/test-server-http.c
+++ b/test-apps/test-server-http.c
@@ -764,7 +764,7 @@ bail:
 
 		break;
 
-#if defined(LWS_OPENSSL_SUPPORT)
+#if defined(LWS_OPENSSL_SUPPORT) && !defined(LWS_WITH_MBEDTLS)
 	case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION:
 		/* Verify the client certificate */
 		if (!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)) {
diff --git a/test-apps/test-server-v2.0.c b/test-apps/test-server-v2.0.c
index d26e2b2a..8c45ae95 100644
--- a/test-apps/test-server-v2.0.c
+++ b/test-apps/test-server-v2.0.c
@@ -24,6 +24,7 @@
 #ifndef WIN32
 #include <syslog.h>
 #endif
+#include <stdlib.h>
 
 /* windows has no SIGUSR1 */
 #if !defined(WIN32) && !defined(_WIN32)
@@ -365,7 +366,7 @@ int main(int argc, char **argv)
 			use_ssl = 1;
 			break;
 		case 'S':
-#if defined(LWS_OPENSSL_SUPPORT)
+#if defined(LWS_OPENSSL_SUPPORT) && !defined(LWS_WITH_MBEDTLS)
 			info.ssl_info_event_mask |= SSL_CB_ALERT;
 #endif
 			break;
-- 
GitLab