diff --git a/Makefile b/Makefile
index f7ebab39..914f1b31 100644
--- a/Makefile
+++ b/Makefile
@@ -125,7 +125,7 @@ mongoose.c: Makefile $(wildcard src/*)
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
mongoose.h: $(HDRS) Makefile
- (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/config.h src/arch.h src/arch_*.h src/str.h src/log.h src/timer.h src/util.h src/fs.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
+ (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/config.h src/arch.h src/arch_*.h src/str.h src/log.h src/timer.h src/util.h src/fs.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h | sed -e 's,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
clean:
rm -rf $(PROG) *.o *.dSYM unit_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack
diff --git a/docs/README.md b/docs/README.md
index bc1ba893..95f5071a 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -234,6 +234,7 @@ Here is a list of build constants and their default values:
|MG_ENABLE_SOCKET | 1 | Use BSD socket low-level API |
|MG_ENABLE_MBEDTLS | 0 | Enable mbedTLS library |
|MG_ENABLE_OPENSSL | 0 | Enable OpenSSL library |
+|MG_ENABLE_CUSTOM_TLS | 0 | Enable custom TLS library |
|MG_ENABLE_IPV6 | 0 | Enable IPv6 |
|MG_ENABLE_LOG | 1 | Enable `LOG()` macro |
|MG_ENABLE_MD5 | 0 | Use native MD5 implementation |
@@ -244,6 +245,7 @@ Here is a list of build constants and their default values:
|MG_IO_SIZE | 2048 | Granularity of the send/recv IO buffer growth |
|MG_MAX_RECV_BUF_SIZE | (3 * 1024 * 1024) | Maximum recv buffer size |
|MG_MAX_HTTP_HEADERS | 40 | Maximum number of HTTP headers |
+|MG_HTTP_INDEX | "index.html" | Index file for HTML directory |
|MG_ENABLE_LINES | undefined | If defined, show source file names in logs |
NOTE: the `MG_IO_SIZE` constant also sets
diff --git a/examples/http-restful-server/Makefile b/examples/http-restful-server/Makefile
index d92c128d..421f9142 100644
--- a/examples/http-restful-server/Makefile
+++ b/examples/http-restful-server/Makefile
@@ -1,5 +1,6 @@
PROG ?= example
+CFLAGS ?= -W -Wall -DMG_ENABLE_LINES=1
ifneq ($(MBEDTLS_DIR),)
CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include
CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509
@@ -12,7 +13,7 @@ all: $(PROG)
$(DEBUGGER) ./$(PROG) $(ARGS)
$(PROG): main.c
- $(CC) ../../mongoose.c -I../.. -W -Wall -DMG_ENABLE_LINES=1 $(CFLAGS) -o $(PROG) main.c
+ $(CC) ../../mongoose.c -I../.. $(CFLAGS) $(EFLAGS) -o $(PROG) main.c
clean:
rm -rf $(PROG) *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb
diff --git a/mongoose.c b/mongoose.c
index fc746ae6..86326a58 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -3694,38 +3694,35 @@ void mg_timer_poll(unsigned long now_ms) {
}
#ifdef MG_ENABLE_LINES
-#line 1 "src/tls.c"
+#line 1 "src/tls_dummy.c"
#endif
-#if MG_ENABLE_MBEDTLS ///////////////////////////////////////// MBEDTLS
-
-
-
-
-#include
-#include
-
-#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
-#define RNG , rng_get, NULL
-#else
-#define RNG
+#if !MG_ENABLE_MBEDTLS && !MG_ENABLE_OPENSSL && !MG_ENABLE_CUSTOM_TLS
+void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
+ (void) opts;
+ mg_error(c, "TLS is not enabled");
+}
+void mg_tls_handshake(struct mg_connection *c) {
+ (void) c;
+}
+void mg_tls_free(struct mg_connection *c) {
+ (void) c;
+}
+long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
+ return c == NULL || buf == NULL || len == 0 ? 0 : -1;
+}
+long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
+ return c == NULL || buf == NULL || len == 0 ? 0 : -1;
+}
#endif
-// Different versions have those in different files, so declare here
-EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t);
-EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t);
+#ifdef MG_ENABLE_LINES
+#line 1 "src/tls_mbed.c"
+#endif
-struct mg_tls {
- char *cafile; // CA certificate path
- mbedtls_x509_crt ca; // Parsed CA certificate
- mbedtls_x509_crl crl; // Parsed Certificate Revocation List
- mbedtls_x509_crt cert; // Parsed certificate
- mbedtls_ssl_context ssl; // SSL/TLS context
- mbedtls_ssl_config conf; // SSL-TLS config
- mbedtls_pk_context pk; // Private key context
-};
+#if MG_ENABLE_MBEDTLS
void mg_tls_handshake(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls;
int rc;
@@ -3913,16 +3910,14 @@ void mg_tls_free(struct mg_connection *c) {
free(tls);
c->tls = NULL;
}
-#elif MG_ENABLE_OPENSSL ///////////////////////////////////////// OPENSSL
+#endif
-#include
-#include
+#ifdef MG_ENABLE_LINES
+#line 1 "src/tls_openssl.c"
+#endif
-struct mg_tls {
- SSL_CTX *ctx;
- SSL *ssl;
-};
+#if MG_ENABLE_OPENSSL
static int mg_tls_err(struct mg_tls *tls, int res) {
int err = SSL_get_error(tls->ssl, res);
// We've just fetched the last error from the queue.
@@ -4066,26 +4061,6 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
int n = SSL_write(tls->ssl, buf, (int) len);
return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
}
-
-#else ////////////////////////////////////////// NO TLS
-
-void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
- (void) opts;
- mg_error(c, "TLS is not enabled");
-}
-void mg_tls_handshake(struct mg_connection *c) {
- (void) c;
-}
-void mg_tls_free(struct mg_connection *c) {
- (void) c;
-}
-long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
- return c == NULL || buf == NULL || len == 0 ? 0 : -1;
-}
-long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
- return c == NULL || buf == NULL || len == 0 ? 0 : -1;
-}
-
#endif
#ifdef MG_ENABLE_LINES
diff --git a/mongoose.h b/mongoose.h
index 6044fce1..7599767e 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -37,6 +37,10 @@ extern "C" {
#define MG_ENABLE_OPENSSL 0
#endif
+#ifndef MG_ENABLE_CUSTOM_TLS
+#define MG_ENABLE_CUSTOM_TLS 0
+#endif
+
#ifndef MG_ENABLE_SSI
#define MG_ENABLE_SSI 1
#endif
@@ -84,6 +88,10 @@ extern "C" {
#define MG_MAX_HTTP_HEADERS 40
#endif
+#ifndef MG_HTTP_INDEX
+#define MG_HTTP_INDEX "index.html"
+#endif
+
#ifndef MG_PATH_MAX
#define MG_PATH_MAX PATH_MAX
#endif
@@ -912,6 +920,9 @@ void mg_http_serve_ssi(struct mg_connection *c, const char *root,
+
+
+
struct mg_tls_opts {
const char *ca; // CA certificate file. For both listeners and clients
const char *crl; // Certificate Revocation List. For clients
@@ -928,6 +939,48 @@ long mg_tls_recv(struct mg_connection *, void *buf, size_t len);
void mg_tls_handshake(struct mg_connection *);
+#if MG_ENABLE_MBEDTLS
+
+
+
+
+#include
+#include
+
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+#define RNG , rng_get, NULL
+#else
+#define RNG
+#endif
+
+// Different versions have those in different files, so declare here
+EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t);
+EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t);
+
+struct mg_tls {
+ char *cafile; // CA certificate path
+ mbedtls_x509_crt ca; // Parsed CA certificate
+ mbedtls_x509_crl crl; // Parsed Certificate Revocation List
+ mbedtls_x509_crt cert; // Parsed certificate
+ mbedtls_ssl_context ssl; // SSL/TLS context
+ mbedtls_ssl_config conf; // SSL-TLS config
+ mbedtls_pk_context pk; // Private key context
+};
+#endif
+
+
+#if MG_ENABLE_OPENSSL
+
+#include
+#include
+
+struct mg_tls {
+ SSL_CTX *ctx;
+ SSL *ssl;
+};
+#endif
+
+
#define WEBSOCKET_OP_CONTINUE 0
#define WEBSOCKET_OP_TEXT 1
#define WEBSOCKET_OP_BINARY 2
diff --git a/src/config.h b/src/config.h
index 645dea42..153fbd74 100644
--- a/src/config.h
+++ b/src/config.h
@@ -12,6 +12,10 @@
#define MG_ENABLE_OPENSSL 0
#endif
+#ifndef MG_ENABLE_CUSTOM_TLS
+#define MG_ENABLE_CUSTOM_TLS 0
+#endif
+
#ifndef MG_ENABLE_SSI
#define MG_ENABLE_SSI 1
#endif
@@ -59,6 +63,10 @@
#define MG_MAX_HTTP_HEADERS 40
#endif
+#ifndef MG_HTTP_INDEX
+#define MG_HTTP_INDEX "index.html"
+#endif
+
#ifndef MG_PATH_MAX
#define MG_PATH_MAX PATH_MAX
#endif
diff --git a/src/tls.c b/src/tls.c
deleted file mode 100644
index 459077e0..00000000
--- a/src/tls.c
+++ /dev/null
@@ -1,391 +0,0 @@
-#include "tls.h"
-
-#if MG_ENABLE_MBEDTLS ///////////////////////////////////////// MBEDTLS
-#include "log.h"
-#include "url.h"
-#include "util.h"
-
-#include
-#include
-
-#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
-#define RNG , rng_get, NULL
-#else
-#define RNG
-#endif
-
-// Different versions have those in different files, so declare here
-EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t);
-EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t);
-
-struct mg_tls {
- char *cafile; // CA certificate path
- mbedtls_x509_crt ca; // Parsed CA certificate
- mbedtls_x509_crl crl; // Parsed Certificate Revocation List
- mbedtls_x509_crt cert; // Parsed certificate
- mbedtls_ssl_context ssl; // SSL/TLS context
- mbedtls_ssl_config conf; // SSL-TLS config
- mbedtls_pk_context pk; // Private key context
-};
-
-void mg_tls_handshake(struct mg_connection *c) {
- struct mg_tls *tls = (struct mg_tls *) c->tls;
- int rc;
- mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0);
- rc = mbedtls_ssl_handshake(&tls->ssl);
- if (rc == 0) { // Success
- LOG(LL_DEBUG, ("%lu success", c->id));
- c->is_tls_hs = 0;
- } else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
- rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
- LOG(LL_VERBOSE_DEBUG, ("%lu pending, %d%d %d (-%#x)", c->id,
- c->is_connecting, c->is_tls_hs, rc, -rc));
- } else {
- mg_error(c, "TLS handshake: -%#x", -rc); // Error
- }
-}
-
-static int mbed_rng(void *ctx, unsigned char *buf, size_t len) {
- mg_random(buf, len);
- (void) ctx;
- return 0;
-}
-
-static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
- n = (int) strlen(s2) - 1;
- LOG(LL_VERBOSE_DEBUG, ("%p %.*s", ((struct mg_connection *) c)->fd, n, s2));
- (void) s;
- (void) c;
- (void) lev;
-}
-
-#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
-static int rng_get(void *p_rng, unsigned char *buf, size_t len) {
- (void) p_rng;
- mg_random(buf, len);
- return 0;
-}
-#endif
-
-void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
- struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
- int rc = 0;
- const char *ca = opts->ca == NULL ? "-"
- : opts->ca[0] == '-' ? "(emb)"
- : opts->ca;
- const char *crl = opts->crl == NULL ? "-"
- : opts->crl[0] == '-' ? "(emb)"
- : opts->crl;
- const char *cert = opts->cert == NULL ? "-"
- : opts->cert[0] == '-' ? "(emb)"
- : opts->cert;
- const char *certkey = opts->certkey == NULL ? "-"
- : opts->certkey[0] == '-' ? "(emb)"
- : opts->certkey;
- if (tls == NULL) {
- mg_error(c, "TLS OOM");
- goto fail;
- }
- LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, CRL: %s, cert: %s, key: %s", c->id,
- ca, crl, cert, certkey));
- mbedtls_ssl_init(&tls->ssl);
- mbedtls_ssl_config_init(&tls->conf);
- mbedtls_x509_crt_init(&tls->ca);
- mbedtls_x509_crl_init(&tls->crl);
- mbedtls_x509_crt_init(&tls->cert);
- mbedtls_pk_init(&tls->pk);
- mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
- //#if !defined(ESP_PLATFORM)
- // mbedtls_debug_set_threshold(5);
- //#endif
- if ((rc = mbedtls_ssl_config_defaults(
- &tls->conf,
- c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
- MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
- mg_error(c, "tls defaults %#x", -rc);
- goto fail;
- }
- mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c);
- if (opts->ca == NULL || strcmp(opts->ca, "*") == 0) {
- mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
- }
- if (opts->ca != NULL && opts->ca[0] != '\0') {
- if (opts->crl != NULL && opts->crl[0] != '\0') {
- rc = opts->crl[0] == '-'
- ? mbedtls_x509_crl_parse(&tls->crl, (uint8_t *) opts->crl,
- strlen(opts->crl) + 1)
- : mbedtls_x509_crl_parse_file(&tls->crl, opts->crl);
- if (rc != 0) {
- mg_error(c, "parse(%s) err %#x", crl, -rc);
- goto fail;
- }
- }
-#if defined(MBEDTLS_X509_CA_CHAIN_ON_DISK)
- tls->cafile = strdup(opts->ca);
- rc = mbedtls_ssl_conf_ca_chain_file(&tls->conf, tls->cafile, &tls->crl);
- if (rc != 0) {
- mg_error(c, "parse on-disk chain(%s) err %#x", ca, -rc);
- goto fail;
- }
-#else
- rc = opts->ca[0] == '-'
- ? mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) opts->ca,
- strlen(opts->ca) + 1)
- : mbedtls_x509_crt_parse_file(&tls->ca, opts->ca);
- if (rc != 0) {
- mg_error(c, "parse(%s) err %#x", ca, -rc);
- goto fail;
- }
- mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, &tls->crl);
-#endif
- if (opts->srvname.len > 0) {
- char mem[128], *buf = mem;
- mg_asprintf(&buf, sizeof(mem), "%.*s", (int) opts->srvname.len,
- opts->srvname.ptr);
- mbedtls_ssl_set_hostname(&tls->ssl, buf);
- if (buf != mem) free(buf);
- }
- mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
- }
- if (opts->cert != NULL && opts->cert[0] != '\0') {
- const char *key = opts->certkey;
- if (key == NULL) {
- key = opts->cert;
- certkey = cert;
- }
- rc = opts->cert[0] == '-'
- ? mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) opts->cert,
- strlen(opts->cert) + 1)
- : mbedtls_x509_crt_parse_file(&tls->cert, opts->cert);
- if (rc != 0) {
- mg_error(c, "parse(%s) err %#x", cert, -rc);
- goto fail;
- }
- rc = key[0] == '-' ? mbedtls_pk_parse_key(&tls->pk, (uint8_t *) key,
- strlen(key) + 1, NULL, 0 RNG)
- : mbedtls_pk_parse_keyfile(&tls->pk, key, NULL RNG);
- if (rc != 0) {
- mg_error(c, "tls key(%s) %#x", certkey, -rc);
- goto fail;
- }
- rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk);
- if (rc != 0) {
- mg_error(c, "own cert %#x", -rc);
- goto fail;
- }
- }
- if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
- mg_error(c, "setup err %#x", -rc);
- goto fail;
- }
- c->tls = tls;
- c->is_tls = 1;
- c->is_tls_hs = 1;
- if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
- mg_tls_handshake(c);
- }
- return;
-fail:
- c->is_closing = 1;
- free(tls);
-}
-
-long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
- struct mg_tls *tls = (struct mg_tls *) c->tls;
- long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
- return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_READ ? 0 : n;
-}
-
-long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
- struct mg_tls *tls = (struct mg_tls *) c->tls;
- long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len);
- return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_WRITE ? 0 : n;
-}
-
-void mg_tls_free(struct mg_connection *c) {
- struct mg_tls *tls = (struct mg_tls *) c->tls;
- if (tls == NULL) return;
- free(tls->cafile);
- mbedtls_ssl_free(&tls->ssl);
- mbedtls_pk_free(&tls->pk);
- mbedtls_x509_crt_free(&tls->ca);
- mbedtls_x509_crl_free(&tls->crl);
- mbedtls_x509_crt_free(&tls->cert);
- mbedtls_ssl_config_free(&tls->conf);
- free(tls);
- c->tls = NULL;
-}
-#elif MG_ENABLE_OPENSSL ///////////////////////////////////////// OPENSSL
-
-#include
-#include
-
-struct mg_tls {
- SSL_CTX *ctx;
- SSL *ssl;
-};
-
-static int mg_tls_err(struct mg_tls *tls, int res) {
- int err = SSL_get_error(tls->ssl, res);
- // We've just fetched the last error from the queue.
- // Now we need to clear the error queue. If we do not, then the following
- // can happen (actually reported):
- // - A new connection is accept()-ed with cert error (e.g. self-signed cert)
- // - Since all accept()-ed connections share listener's context,
- // - *ALL* SSL accepted connection report read error on the next poll cycle.
- // Thus a single errored connection can close all the rest, unrelated ones.
- // Clearing the error keeps the shared SSL_CTX in an OK state.
-
- if (err != 0) ERR_print_errors_fp(stderr);
- ERR_clear_error();
- if (err == SSL_ERROR_WANT_READ) return 0;
- if (err == SSL_ERROR_WANT_WRITE) return 0;
- return err;
-}
-
-void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
- struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
- const char *id = "mongoose";
- static unsigned char s_initialised = 0;
- int rc;
-
- if (tls == NULL) {
- mg_error(c, "TLS OOM");
- goto fail;
- }
-
- if (!s_initialised) {
- SSL_library_init();
- s_initialised++;
- }
- LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id,
- opts->ca == NULL ? "null" : opts->ca,
- opts->cert == NULL ? "null" : opts->cert,
- opts->certkey == NULL ? "null" : opts->certkey));
- tls->ctx = c->is_client ? SSL_CTX_new(SSLv23_client_method())
- : SSL_CTX_new(SSLv23_server_method());
- if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
- mg_error(c, "SSL_new");
- goto fail;
- }
- SSL_set_session_id_context(tls->ssl, (const uint8_t *) id,
- (unsigned) strlen(id));
- // Disable deprecated protocols
- SSL_set_options(tls->ssl, SSL_OP_NO_SSLv2);
- SSL_set_options(tls->ssl, SSL_OP_NO_SSLv3);
- SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1);
- SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1_1);
-#ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
- SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
-#endif
-#ifdef MG_ENABLE_OPENSSL_CIPHER_SERVER_PREFERENCE
- SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
-#endif
-
- if (opts->ca != NULL && opts->ca[0] != '\0') {
- SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
- NULL);
- if ((rc = SSL_CTX_load_verify_locations(tls->ctx, opts->ca, NULL)) != 1) {
- mg_error(c, "parse(%s): err %d", opts->ca, mg_tls_err(tls, rc));
- goto fail;
- }
- }
- if (opts->cert != NULL && opts->cert[0] != '\0') {
- const char *key = opts->certkey;
- if (key == NULL) key = opts->cert;
- if ((rc = SSL_use_certificate_file(tls->ssl, opts->cert, 1)) != 1) {
- mg_error(c, "Invalid SSL cert, err %d", mg_tls_err(tls, rc));
- goto fail;
- } else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) {
- mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc));
- goto fail;
-#if OPENSSL_VERSION_NUMBER > 0x10100000L
- } else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) !=
- 1) {
- mg_error(c, "Invalid CA, err %d", mg_tls_err(tls, rc));
- goto fail;
-#endif
- } else {
- SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-#if OPENSSL_VERSION_NUMBER > 0x10002000L
- SSL_set_ecdh_auto(tls->ssl, 1);
-#endif
- }
- }
- if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers);
- if (opts->srvname.len > 0) {
- char mem[128], *buf = mem;
- mg_asprintf(&buf, sizeof(mem), "%.*s", (int) opts->srvname.len,
- opts->srvname.ptr);
- SSL_set_tlsext_host_name(tls->ssl, buf);
- if (buf != mem) free(buf);
- }
- c->tls = tls;
- c->is_tls = 1;
- c->is_tls_hs = 1;
- if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
- mg_tls_handshake(c);
- }
- c->is_hexdumping = 1;
- LOG(LL_DEBUG, ("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
- return;
-fail:
- c->is_closing = 1;
- free(tls);
-}
-
-void mg_tls_handshake(struct mg_connection *c) {
- struct mg_tls *tls = (struct mg_tls *) c->tls;
- int rc;
- SSL_set_fd(tls->ssl, (int) (size_t) c->fd);
- rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
- if (rc == 1) {
- LOG(LL_DEBUG, ("%lu success", c->id));
- c->is_tls_hs = 0;
- } else {
- int code = mg_tls_err(tls, rc);
- if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
- }
-}
-
-void mg_tls_free(struct mg_connection *c) {
- struct mg_tls *tls = (struct mg_tls *) c->tls;
- if (tls == NULL) return;
- SSL_free(tls->ssl);
- SSL_CTX_free(tls->ctx);
- free(tls);
- c->tls = NULL;
-}
-
-long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
- struct mg_tls *tls = (struct mg_tls *) c->tls;
- int n = SSL_read(tls->ssl, buf, (int) len);
- return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
-}
-
-long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
- struct mg_tls *tls = (struct mg_tls *) c->tls;
- int n = SSL_write(tls->ssl, buf, (int) len);
- return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
-}
-
-#else ////////////////////////////////////////// NO TLS
-
-void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
- (void) opts;
- mg_error(c, "TLS is not enabled");
-}
-void mg_tls_handshake(struct mg_connection *c) {
- (void) c;
-}
-void mg_tls_free(struct mg_connection *c) {
- (void) c;
-}
-long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
- return c == NULL || buf == NULL || len == 0 ? 0 : -1;
-}
-long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
- return c == NULL || buf == NULL || len == 0 ? 0 : -1;
-}
-
-#endif
diff --git a/src/tls.h b/src/tls.h
index f04de0fb..704c366e 100644
--- a/src/tls.h
+++ b/src/tls.h
@@ -1,5 +1,8 @@
#pragma once
+
#include "net.h"
+#include "tls_mbed.h"
+#include "tls_openssl.h"
struct mg_tls_opts {
const char *ca; // CA certificate file. For both listeners and clients
diff --git a/src/tls_dummy.c b/src/tls_dummy.c
new file mode 100644
index 00000000..4f1238ad
--- /dev/null
+++ b/src/tls_dummy.c
@@ -0,0 +1,20 @@
+#include "tls.h"
+
+#if !MG_ENABLE_MBEDTLS && !MG_ENABLE_OPENSSL && !MG_ENABLE_CUSTOM_TLS
+void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
+ (void) opts;
+ mg_error(c, "TLS is not enabled");
+}
+void mg_tls_handshake(struct mg_connection *c) {
+ (void) c;
+}
+void mg_tls_free(struct mg_connection *c) {
+ (void) c;
+}
+long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
+ return c == NULL || buf == NULL || len == 0 ? 0 : -1;
+}
+long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
+ return c == NULL || buf == NULL || len == 0 ? 0 : -1;
+}
+#endif
diff --git a/src/tls_mbed.c b/src/tls_mbed.c
new file mode 100644
index 00000000..f1dc8b3c
--- /dev/null
+++ b/src/tls_mbed.c
@@ -0,0 +1,191 @@
+#include "tls.h"
+
+#if MG_ENABLE_MBEDTLS
+void mg_tls_handshake(struct mg_connection *c) {
+ struct mg_tls *tls = (struct mg_tls *) c->tls;
+ int rc;
+ mbedtls_ssl_set_bio(&tls->ssl, &c->fd, mbedtls_net_send, mbedtls_net_recv, 0);
+ rc = mbedtls_ssl_handshake(&tls->ssl);
+ if (rc == 0) { // Success
+ LOG(LL_DEBUG, ("%lu success", c->id));
+ c->is_tls_hs = 0;
+ } else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
+ rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
+ LOG(LL_VERBOSE_DEBUG, ("%lu pending, %d%d %d (-%#x)", c->id,
+ c->is_connecting, c->is_tls_hs, rc, -rc));
+ } else {
+ mg_error(c, "TLS handshake: -%#x", -rc); // Error
+ }
+}
+
+static int mbed_rng(void *ctx, unsigned char *buf, size_t len) {
+ mg_random(buf, len);
+ (void) ctx;
+ return 0;
+}
+
+static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
+ n = (int) strlen(s2) - 1;
+ LOG(LL_VERBOSE_DEBUG, ("%p %.*s", ((struct mg_connection *) c)->fd, n, s2));
+ (void) s;
+ (void) c;
+ (void) lev;
+}
+
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+static int rng_get(void *p_rng, unsigned char *buf, size_t len) {
+ (void) p_rng;
+ mg_random(buf, len);
+ return 0;
+}
+#endif
+
+void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
+ struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
+ int rc = 0;
+ const char *ca = opts->ca == NULL ? "-"
+ : opts->ca[0] == '-' ? "(emb)"
+ : opts->ca;
+ const char *crl = opts->crl == NULL ? "-"
+ : opts->crl[0] == '-' ? "(emb)"
+ : opts->crl;
+ const char *cert = opts->cert == NULL ? "-"
+ : opts->cert[0] == '-' ? "(emb)"
+ : opts->cert;
+ const char *certkey = opts->certkey == NULL ? "-"
+ : opts->certkey[0] == '-' ? "(emb)"
+ : opts->certkey;
+ if (tls == NULL) {
+ mg_error(c, "TLS OOM");
+ goto fail;
+ }
+ LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, CRL: %s, cert: %s, key: %s", c->id,
+ ca, crl, cert, certkey));
+ mbedtls_ssl_init(&tls->ssl);
+ mbedtls_ssl_config_init(&tls->conf);
+ mbedtls_x509_crt_init(&tls->ca);
+ mbedtls_x509_crl_init(&tls->crl);
+ mbedtls_x509_crt_init(&tls->cert);
+ mbedtls_pk_init(&tls->pk);
+ mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
+ //#if !defined(ESP_PLATFORM)
+ // mbedtls_debug_set_threshold(5);
+ //#endif
+ if ((rc = mbedtls_ssl_config_defaults(
+ &tls->conf,
+ c->is_client ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
+ MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
+ mg_error(c, "tls defaults %#x", -rc);
+ goto fail;
+ }
+ mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c);
+ if (opts->ca == NULL || strcmp(opts->ca, "*") == 0) {
+ mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
+ }
+ if (opts->ca != NULL && opts->ca[0] != '\0') {
+ if (opts->crl != NULL && opts->crl[0] != '\0') {
+ rc = opts->crl[0] == '-'
+ ? mbedtls_x509_crl_parse(&tls->crl, (uint8_t *) opts->crl,
+ strlen(opts->crl) + 1)
+ : mbedtls_x509_crl_parse_file(&tls->crl, opts->crl);
+ if (rc != 0) {
+ mg_error(c, "parse(%s) err %#x", crl, -rc);
+ goto fail;
+ }
+ }
+#if defined(MBEDTLS_X509_CA_CHAIN_ON_DISK)
+ tls->cafile = strdup(opts->ca);
+ rc = mbedtls_ssl_conf_ca_chain_file(&tls->conf, tls->cafile, &tls->crl);
+ if (rc != 0) {
+ mg_error(c, "parse on-disk chain(%s) err %#x", ca, -rc);
+ goto fail;
+ }
+#else
+ rc = opts->ca[0] == '-'
+ ? mbedtls_x509_crt_parse(&tls->ca, (uint8_t *) opts->ca,
+ strlen(opts->ca) + 1)
+ : mbedtls_x509_crt_parse_file(&tls->ca, opts->ca);
+ if (rc != 0) {
+ mg_error(c, "parse(%s) err %#x", ca, -rc);
+ goto fail;
+ }
+ mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, &tls->crl);
+#endif
+ if (opts->srvname.len > 0) {
+ char mem[128], *buf = mem;
+ mg_asprintf(&buf, sizeof(mem), "%.*s", (int) opts->srvname.len,
+ opts->srvname.ptr);
+ mbedtls_ssl_set_hostname(&tls->ssl, buf);
+ if (buf != mem) free(buf);
+ }
+ mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+ }
+ if (opts->cert != NULL && opts->cert[0] != '\0') {
+ const char *key = opts->certkey;
+ if (key == NULL) {
+ key = opts->cert;
+ certkey = cert;
+ }
+ rc = opts->cert[0] == '-'
+ ? mbedtls_x509_crt_parse(&tls->cert, (uint8_t *) opts->cert,
+ strlen(opts->cert) + 1)
+ : mbedtls_x509_crt_parse_file(&tls->cert, opts->cert);
+ if (rc != 0) {
+ mg_error(c, "parse(%s) err %#x", cert, -rc);
+ goto fail;
+ }
+ rc = key[0] == '-' ? mbedtls_pk_parse_key(&tls->pk, (uint8_t *) key,
+ strlen(key) + 1, NULL, 0 RNG)
+ : mbedtls_pk_parse_keyfile(&tls->pk, key, NULL RNG);
+ if (rc != 0) {
+ mg_error(c, "tls key(%s) %#x", certkey, -rc);
+ goto fail;
+ }
+ rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk);
+ if (rc != 0) {
+ mg_error(c, "own cert %#x", -rc);
+ goto fail;
+ }
+ }
+ if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
+ mg_error(c, "setup err %#x", -rc);
+ goto fail;
+ }
+ c->tls = tls;
+ c->is_tls = 1;
+ c->is_tls_hs = 1;
+ if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
+ mg_tls_handshake(c);
+ }
+ return;
+fail:
+ c->is_closing = 1;
+ free(tls);
+}
+
+long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
+ struct mg_tls *tls = (struct mg_tls *) c->tls;
+ long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
+ return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_READ ? 0 : n;
+}
+
+long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
+ struct mg_tls *tls = (struct mg_tls *) c->tls;
+ long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len);
+ return n == 0 ? -1 : n == MBEDTLS_ERR_SSL_WANT_WRITE ? 0 : n;
+}
+
+void mg_tls_free(struct mg_connection *c) {
+ struct mg_tls *tls = (struct mg_tls *) c->tls;
+ if (tls == NULL) return;
+ free(tls->cafile);
+ mbedtls_ssl_free(&tls->ssl);
+ mbedtls_pk_free(&tls->pk);
+ mbedtls_x509_crt_free(&tls->ca);
+ mbedtls_x509_crl_free(&tls->crl);
+ mbedtls_x509_crt_free(&tls->cert);
+ mbedtls_ssl_config_free(&tls->conf);
+ free(tls);
+ c->tls = NULL;
+}
+#endif
diff --git a/src/tls_mbed.h b/src/tls_mbed.h
new file mode 100644
index 00000000..f1e7a228
--- /dev/null
+++ b/src/tls_mbed.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#if MG_ENABLE_MBEDTLS
+#include "log.h"
+#include "url.h"
+#include "util.h"
+
+#include
+#include
+
+#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
+#define RNG , rng_get, NULL
+#else
+#define RNG
+#endif
+
+// Different versions have those in different files, so declare here
+EXTERN_C int mbedtls_net_recv(void *, unsigned char *, size_t);
+EXTERN_C int mbedtls_net_send(void *, const unsigned char *, size_t);
+
+struct mg_tls {
+ char *cafile; // CA certificate path
+ mbedtls_x509_crt ca; // Parsed CA certificate
+ mbedtls_x509_crl crl; // Parsed Certificate Revocation List
+ mbedtls_x509_crt cert; // Parsed certificate
+ mbedtls_ssl_context ssl; // SSL/TLS context
+ mbedtls_ssl_config conf; // SSL-TLS config
+ mbedtls_pk_context pk; // Private key context
+};
+#endif
diff --git a/src/tls_openssl.c b/src/tls_openssl.c
new file mode 100644
index 00000000..0772f7ff
--- /dev/null
+++ b/src/tls_openssl.c
@@ -0,0 +1,147 @@
+#include "tls.h"
+
+#if MG_ENABLE_OPENSSL
+static int mg_tls_err(struct mg_tls *tls, int res) {
+ int err = SSL_get_error(tls->ssl, res);
+ // We've just fetched the last error from the queue.
+ // Now we need to clear the error queue. If we do not, then the following
+ // can happen (actually reported):
+ // - A new connection is accept()-ed with cert error (e.g. self-signed cert)
+ // - Since all accept()-ed connections share listener's context,
+ // - *ALL* SSL accepted connection report read error on the next poll cycle.
+ // Thus a single errored connection can close all the rest, unrelated ones.
+ // Clearing the error keeps the shared SSL_CTX in an OK state.
+
+ if (err != 0) ERR_print_errors_fp(stderr);
+ ERR_clear_error();
+ if (err == SSL_ERROR_WANT_READ) return 0;
+ if (err == SSL_ERROR_WANT_WRITE) return 0;
+ return err;
+}
+
+void mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) {
+ struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
+ const char *id = "mongoose";
+ static unsigned char s_initialised = 0;
+ int rc;
+
+ if (tls == NULL) {
+ mg_error(c, "TLS OOM");
+ goto fail;
+ }
+
+ if (!s_initialised) {
+ SSL_library_init();
+ s_initialised++;
+ }
+ LOG(LL_DEBUG, ("%lu Setting TLS, CA: %s, cert: %s, key: %s", c->id,
+ opts->ca == NULL ? "null" : opts->ca,
+ opts->cert == NULL ? "null" : opts->cert,
+ opts->certkey == NULL ? "null" : opts->certkey));
+ tls->ctx = c->is_client ? SSL_CTX_new(SSLv23_client_method())
+ : SSL_CTX_new(SSLv23_server_method());
+ if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
+ mg_error(c, "SSL_new");
+ goto fail;
+ }
+ SSL_set_session_id_context(tls->ssl, (const uint8_t *) id,
+ (unsigned) strlen(id));
+ // Disable deprecated protocols
+ SSL_set_options(tls->ssl, SSL_OP_NO_SSLv2);
+ SSL_set_options(tls->ssl, SSL_OP_NO_SSLv3);
+ SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1);
+ SSL_set_options(tls->ssl, SSL_OP_NO_TLSv1_1);
+#ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
+ SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
+#endif
+#ifdef MG_ENABLE_OPENSSL_CIPHER_SERVER_PREFERENCE
+ SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
+#endif
+
+ if (opts->ca != NULL && opts->ca[0] != '\0') {
+ SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ NULL);
+ if ((rc = SSL_CTX_load_verify_locations(tls->ctx, opts->ca, NULL)) != 1) {
+ mg_error(c, "parse(%s): err %d", opts->ca, mg_tls_err(tls, rc));
+ goto fail;
+ }
+ }
+ if (opts->cert != NULL && opts->cert[0] != '\0') {
+ const char *key = opts->certkey;
+ if (key == NULL) key = opts->cert;
+ if ((rc = SSL_use_certificate_file(tls->ssl, opts->cert, 1)) != 1) {
+ mg_error(c, "Invalid SSL cert, err %d", mg_tls_err(tls, rc));
+ goto fail;
+ } else if ((rc = SSL_use_PrivateKey_file(tls->ssl, key, 1)) != 1) {
+ mg_error(c, "Invalid SSL key, err %d", mg_tls_err(tls, rc));
+ goto fail;
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
+ } else if ((rc = SSL_use_certificate_chain_file(tls->ssl, opts->cert)) !=
+ 1) {
+ mg_error(c, "Invalid CA, err %d", mg_tls_err(tls, rc));
+ goto fail;
+#endif
+ } else {
+ SSL_set_mode(tls->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+#if OPENSSL_VERSION_NUMBER > 0x10002000L
+ SSL_set_ecdh_auto(tls->ssl, 1);
+#endif
+ }
+ }
+ if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers);
+ if (opts->srvname.len > 0) {
+ char mem[128], *buf = mem;
+ mg_asprintf(&buf, sizeof(mem), "%.*s", (int) opts->srvname.len,
+ opts->srvname.ptr);
+ SSL_set_tlsext_host_name(tls->ssl, buf);
+ if (buf != mem) free(buf);
+ }
+ c->tls = tls;
+ c->is_tls = 1;
+ c->is_tls_hs = 1;
+ if (c->is_client && c->is_resolving == 0 && c->is_connecting == 0) {
+ mg_tls_handshake(c);
+ }
+ c->is_hexdumping = 1;
+ LOG(LL_DEBUG, ("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
+ return;
+fail:
+ c->is_closing = 1;
+ free(tls);
+}
+
+void mg_tls_handshake(struct mg_connection *c) {
+ struct mg_tls *tls = (struct mg_tls *) c->tls;
+ int rc;
+ SSL_set_fd(tls->ssl, (int) (size_t) c->fd);
+ rc = c->is_client ? SSL_connect(tls->ssl) : SSL_accept(tls->ssl);
+ if (rc == 1) {
+ LOG(LL_DEBUG, ("%lu success", c->id));
+ c->is_tls_hs = 0;
+ } else {
+ int code = mg_tls_err(tls, rc);
+ if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
+ }
+}
+
+void mg_tls_free(struct mg_connection *c) {
+ struct mg_tls *tls = (struct mg_tls *) c->tls;
+ if (tls == NULL) return;
+ SSL_free(tls->ssl);
+ SSL_CTX_free(tls->ctx);
+ free(tls);
+ c->tls = NULL;
+}
+
+long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
+ struct mg_tls *tls = (struct mg_tls *) c->tls;
+ int n = SSL_read(tls->ssl, buf, (int) len);
+ return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
+}
+
+long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
+ struct mg_tls *tls = (struct mg_tls *) c->tls;
+ int n = SSL_write(tls->ssl, buf, (int) len);
+ return n == 0 ? -1 : n < 0 && mg_tls_err(tls, n) == 0 ? 0 : n;
+}
+#endif
diff --git a/src/tls_openssl.h b/src/tls_openssl.h
new file mode 100644
index 00000000..ed5bf3d5
--- /dev/null
+++ b/src/tls_openssl.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#if MG_ENABLE_OPENSSL
+
+#include
+#include
+
+struct mg_tls {
+ SSL_CTX *ctx;
+ SSL *ssl;
+};
+#endif