Merge pull request #2386 from cesanta/timer

Revert to the old TLS API, but keep certs as mg_str for DER
This commit is contained in:
Sergio R. Caprile 2023-09-19 12:17:56 -03:00 committed by GitHub
commit 33ab44430c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 535 additions and 785 deletions

View File

@ -15,7 +15,7 @@ jobs:
matrix: matrix:
cc: [gcc, clang, g++, clang++] cc: [gcc, clang, g++, clang++]
target: [test, mip_test] target: [test, mip_test]
ssl: ["", MBEDTLS] #ssl: ["", MBEDTLS, OPENSSL] ssl: ["", MBEDTLS, OPENSSL]
select: ["-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=1"] select: ["-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=1 -DMG_ENABLE_EPOLL=0", "-DMG_ENABLE_POLL=0 -DMG_ENABLE_EPOLL=1"]
exclude: exclude:
- ssl: MBEDTLS - ssl: MBEDTLS
@ -68,7 +68,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
ssl: ["", MBEDTLS] #ssl: ["", MBEDTLS, OPENSSL] ssl: ["", MBEDTLS, OPENSSL]
select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1] select: [-DMG_ENABLE_POLL=0, -DMG_ENABLE_POLL=1]
exclude: exclude:
- ssl: MBEDTLS - ssl: MBEDTLS

View File

@ -261,7 +261,14 @@ static void handle_sys_reset(struct mg_connection *c) {
// HTTP request handler function // HTTP request handler function
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_ACCEPT) {
if (fn_data != NULL) { // TLS listener!
struct mg_tls_opts opts = {0};
opts.cert = mg_unpacked("/certs/server_cert.pem");
opts.key = mg_unpacked("/certs/server_key.pem");
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct user *u = authenticate(hm); struct user *u = authenticate(hm);
@ -306,20 +313,12 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
hm->method.ptr, (int) hm->uri.len, hm->uri.ptr, (int) 3, hm->method.ptr, (int) hm->uri.len, hm->uri.ptr, (int) 3,
&c->send.buf[9])); &c->send.buf[9]));
} }
(void) fn_data;
} }
void web_init(struct mg_mgr *mgr) { void web_init(struct mg_mgr *mgr) {
struct mg_tls_opts opts = {0};
opts.server_cert = mg_unpacked("/certs/server_cert.pem");
opts.server_key = mg_unpacked("/certs/server_key.pem");
mg_tls_ctx_init(mgr, &opts);
s_settings.device_name = strdup("My Device"); s_settings.device_name = strdup("My Device");
mg_http_listen(mgr, HTTP_URL, fn, NULL); mg_http_listen(mgr, HTTP_URL, fn, NULL);
mg_http_listen(mgr, HTTPS_URL, fn, NULL); mg_http_listen(mgr, HTTPS_URL, fn, (void *) 1);
mg_timer_add(mgr, 3600 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT, mg_timer_add(mgr, 3600 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT,
timer_sntp_fn, mgr); timer_sntp_fn, mgr);
} }

View File

@ -28,6 +28,12 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
// Connected to server. Extract host name from URL // Connected to server. Extract host name from URL
struct mg_str host = mg_url_host(s_url); struct mg_str host = mg_url_host(s_url);
if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts);
}
// Send request // Send request
int content_length = s_post_data ? strlen(s_post_data) : 0; int content_length = s_post_data ? strlen(s_post_data) : 0;
mg_printf(c, mg_printf(c,
@ -59,8 +65,6 @@ int main(int argc, char *argv[]) {
if (argc > 1) s_url = argv[1]; // Use URL provided in the command line if (argc > 1) s_url = argv[1]; // Use URL provided in the command line
mg_log_set(atoi(log_level)); // Set to 0 to disable debug mg_log_set(atoi(log_level)); // Set to 0 to disable debug
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
struct mg_tls_opts opts = {.client_ca = mg_unpacked("/certs/client_ca.pem")};
mg_tls_ctx_init(&mgr, &opts);
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
while (!done) mg_mgr_poll(&mgr, 50); // Event manager loops until 'done' while (!done) mg_mgr_poll(&mgr, 50); // Event manager loops until 'done'
mg_mgr_free(&mgr); // Free resources mg_mgr_free(&mgr); // Free resources

View File

@ -2556,7 +2556,7 @@ static const struct packed_file {
size_t size; size_t size;
time_t mtime; time_t mtime;
} packed_files[] = { } packed_files[] = {
{"/certs/client_ca.pem", v1, sizeof(v1), 1694016785}, {"/certs/ca.pem", v1, sizeof(v1), 1694162397},
{NULL, NULL, 0, 0} {NULL, NULL, 0, 0}
}; };

View File

@ -7,7 +7,7 @@ CFLAGS = -W -Wall -Wextra -g -I. # Build options
# Mongoose build options. See https://mongoose.ws/documentation/#build-options # Mongoose build options. See https://mongoose.ws/documentation/#build-options
CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -DMG_ENABLE_PACKED_FS=1 CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1 -DMG_ENABLE_PACKED_FS=1
// see tutorial at https://mongoose.ws/tutorials/http-proxy-client/ # See tutorial at https://mongoose.ws/tutorials/http-proxy-client/
ARGS ?= 167.235.63.238:3128 http://info.cern.ch/ # default call arguments ARGS ?= 167.235.63.238:3128 http://info.cern.ch/ # default call arguments
ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD OUT=/Feprog.exe ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD OUT=/Feprog.exe

View File

@ -20,6 +20,13 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
} else if (ev == MG_EV_CONNECT) { } else if (ev == MG_EV_CONNECT) {
// Proxy TCP connection established. Send CONNECT request // Proxy TCP connection established. Send CONNECT request
struct mg_str host = mg_url_host(url); struct mg_str host = mg_url_host(url);
if (mg_url_is_ssl(url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = host};
mg_tls_init(c, &opts);
}
// c->is_hexdumping = 1; // c->is_hexdumping = 1;
mg_printf(c, "CONNECT %.*s:%hu HTTP/1.1\r\nHost: %.*s:%hu\r\n\r\n", mg_printf(c, "CONNECT %.*s:%hu HTTP/1.1\r\nHost: %.*s:%hu\r\n\r\n",
(int) host.len, host.ptr, mg_url_port(url), (int) host.len, (int) host.len, host.ptr, mg_url_port(url), (int) host.len,
@ -35,10 +42,11 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
("Connected to proxy, status: %.*s", (int) hm.uri.len, hm.uri.ptr)); ("Connected to proxy, status: %.*s", (int) hm.uri.len, hm.uri.ptr));
mg_iobuf_del(&c->recv, 0, n); mg_iobuf_del(&c->recv, 0, n);
// Send request to the target server // Send request to the target server
mg_printf(c, "GET %s HTTP/1.0\r\n" mg_printf(c,
"Host: %.*s\r\n" "GET %s HTTP/1.0\r\n"
"\r\n", "Host: %.*s\r\n"
mg_url_uri(url), (int) host.len, host.ptr); "\r\n",
mg_url_uri(url), (int) host.len, host.ptr);
} }
} }
} }
@ -52,8 +60,6 @@ int main(int argc, char *argv[]) {
} }
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
struct mg_tls_opts opts = {.client_ca = mg_unpacked("/certs/client_ca.pem")};
mg_tls_ctx_init(&mgr, &opts);
mg_http_connect(&mgr, argv[1], fn, argv[2]); // Connect to the proxy mg_http_connect(&mgr, argv[1], fn, argv[2]); // Connect to the proxy
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
mg_mgr_free(&mgr); mg_mgr_free(&mgr);

View File

@ -57,6 +57,15 @@ static const char *s_tls_key =
// We use the same event handler function for HTTP and HTTPS connections // We use the same event handler function for HTTP and HTTPS connections
// fn_data is NULL for plain HTTP, and non-NULL for HTTPS // fn_data is NULL for plain HTTP, and non-NULL for HTTPS
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_ACCEPT && fn_data != NULL) {
struct mg_tls_opts opts = {
#ifdef TLS_TWOWAY
.ca = mg_str(s_tls_ca),
#endif
.cert = mg_str(s_tls_cert),
.key = mg_str(s_tls_key)};
mg_tls_init(c, &opts);
}
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_http_match_uri(hm, "/api/stats")) { if (mg_http_match_uri(hm, "/api/stats")) {
@ -87,13 +96,6 @@ int main(void) {
struct mg_mgr mgr; // Event manager struct mg_mgr mgr; // Event manager
mg_log_set(MG_LL_DEBUG); // Set log level mg_log_set(MG_LL_DEBUG); // Set log level
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
struct mg_tls_opts opts = {
#ifdef TLS_TWOWAY
.client_ca = mg_str(s_tls_ca),
#endif
.server_cert = mg_str(s_tls_cert),
.server_key = mg_str(s_tls_key)};
mg_tls_ctx_init(&mgr, &opts);
mg_http_listen(&mgr, s_http_addr, fn, NULL); // Create HTTP listener mg_http_listen(&mgr, s_http_addr, fn, NULL); // Create HTTP listener
mg_http_listen(&mgr, s_https_addr, fn, (void *) 1); // HTTPS listener mg_http_listen(&mgr, s_https_addr, fn, (void *) 1); // HTTPS listener
for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop for (;;) mg_mgr_poll(&mgr, 1000); // Infinite event loop

View File

@ -37,7 +37,7 @@ static void forward_request(struct mg_http_message *hm,
} }
static void fn2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_connection *c2 = (struct mg_connection *)fn_data; struct mg_connection *c2 = (struct mg_connection *) fn_data;
if (ev == MG_EV_READ) { if (ev == MG_EV_READ) {
// All incoming data from the backend, forward to the client // All incoming data from the backend, forward to the client
if (c2 != NULL) mg_send(c2, c->recv.buf, c->recv.len); if (c2 != NULL) mg_send(c2, c->recv.buf, c->recv.len);
@ -58,9 +58,14 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (c2 == NULL) { if (c2 == NULL) {
mg_error(c, "Cannot create backend connection"); mg_error(c, "Cannot create backend connection");
} else { } else {
if (mg_url_is_ssl(s_backend_url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_backend_url)};
mg_tls_init(c2, &opts);
}
c->fn_data = c2; c->fn_data = c2;
forward_request(hm, c2); forward_request(hm, c2);
c->is_resp = 0; // process further msgs in keep-alive connection c->is_resp = 0; // process further msgs in keep-alive connection
c2->is_hexdumping = 1; c2->is_hexdumping = 1;
} }
} else if (ev == MG_EV_CLOSE) { } else if (ev == MG_EV_CLOSE) {
@ -74,8 +79,6 @@ int main(void) {
mg_log_set(MG_LL_DEBUG); // Set log level mg_log_set(MG_LL_DEBUG); // Set log level
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
struct mg_tls_opts opts = {.client_ca = mg_unpacked("/certs/client_ca.pem")};
mg_tls_ctx_init(&mgr, &opts);
mg_http_listen(&mgr, s_listen_url, fn, NULL); // Start proxy mg_http_listen(&mgr, s_listen_url, fn, NULL); // Start proxy
for (;;) mg_mgr_poll(&mgr, 1000); // Event loop for (;;) mg_mgr_poll(&mgr, 1000); // Event loop
mg_mgr_free(&mgr); mg_mgr_free(&mgr);

View File

@ -21,6 +21,13 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_CONNECT) { if (ev == MG_EV_CONNECT) {
// Connected to server. Extract host name from URL // Connected to server. Extract host name from URL
struct mg_str host = mg_url_host(s_url); struct mg_str host = mg_url_host(s_url);
if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = host};
mg_tls_init(c, &opts);
}
// Send request // Send request
mg_printf(c, mg_printf(c,
"GET %s HTTP/1.1\r\n" "GET %s HTTP/1.1\r\n"
@ -56,9 +63,6 @@ int main(int argc, char *argv[]) {
mg_log_set(atoi(log_level)); // Set to 0 to disable debug log mg_log_set(atoi(log_level)); // Set to 0 to disable debug log
if (argc > 1) s_url = argv[1]; // Use URL from command line if (argc > 1) s_url = argv[1]; // Use URL from command line
struct mg_tls_opts opts = {.client_ca = mg_unpacked("/certs/client_ca.pem")};
mg_tls_ctx_init(&mgr, &opts);
mg_http_connect(&mgr, s_url, fn, &done); // Create client connection mg_http_connect(&mgr, s_url, fn, &done); // Create client connection
while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop while (!done) mg_mgr_poll(&mgr, 1000); // Infinite event loop
mg_mgr_free(&mgr); // Free resources mg_mgr_free(&mgr); // Free resources

View File

@ -29,8 +29,8 @@ static const char *s_url =
// 3. From the dialog box that appears, download: // 3. From the dialog box that appears, download:
// xxx-certificate.pem.crt as cert.pem to the example directory // xxx-certificate.pem.crt as cert.pem to the example directory
// xxx-private.pem.key as key.pem to the example directory // xxx-private.pem.key as key.pem to the example directory
//static const char *s_cert = "cert.pem"; // static const char *s_cert = "cert.pem";
//static const char *s_key = "key.pem"; // static const char *s_key = "key.pem";
static const char *s_rx_topic = "d/rx"; static const char *s_rx_topic = "d/rx";
static const char *s_tx_topic = "d/tx"; static const char *s_tx_topic = "d/tx";
@ -41,6 +41,12 @@ static int s_qos = 1;
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_OPEN) { if (ev == MG_EV_OPEN) {
// c->is_hexdumping = 1; // c->is_hexdumping = 1;
} else if (ev == MG_EV_CONNECT) {
if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_ERROR) { } else if (ev == MG_EV_ERROR) {
// On error, log error message // On error, log error message
MG_ERROR(("%p %s", c->fd, (char *) ev_data)); MG_ERROR(("%p %s", c->fd, (char *) ev_data));
@ -87,9 +93,6 @@ int main(void) {
struct mg_mqtt_opts opts = {.clean = true}; struct mg_mqtt_opts opts = {.clean = true};
bool done = false; bool done = false;
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
struct mg_tls_opts topts = {.client_ca = mg_unpacked("/certs/client_ca.pem")};
//TODO() 2-way auth and certificate loading
mg_tls_ctx_init(&mgr, &topts);
MG_INFO(("Connecting to %s", s_url)); // Inform that we're starting MG_INFO(("Connecting to %s", s_url)); // Inform that we're starting
mg_mqtt_connect(&mgr, s_url, &opts, fn, &done); // Create client connection mg_mqtt_connect(&mgr, s_url, &opts, fn, &done); // Create client connection
while (!done) mg_mgr_poll(&mgr, 1000); // Loop until done while (!done) mg_mgr_poll(&mgr, 1000); // Loop until done

View File

@ -28,6 +28,12 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_OPEN) { if (ev == MG_EV_OPEN) {
MG_INFO(("%lu CREATED", c->id)); MG_INFO(("%lu CREATED", c->id));
// c->is_hexdumping = 1; // c->is_hexdumping = 1;
} else if (ev == MG_EV_CONNECT) {
if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_ERROR) { } else if (ev == MG_EV_ERROR) {
// On error, log error message // On error, log error message
MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data)); MG_ERROR(("%lu ERROR %s", c->id, (char *) ev_data));
@ -101,9 +107,6 @@ int main(int argc, char *argv[]) {
signal(SIGTERM, signal_handler); // manager loop on SIGINT and SIGTERM signal(SIGTERM, signal_handler); // manager loop on SIGINT and SIGTERM
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
struct mg_tls_opts opts = {.client_ca = mg_unpacked("/certs/client_ca.pem")};
mg_tls_ctx_init(&mgr, &opts);
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr); mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
while (s_signo == 0) mg_mgr_poll(&mgr, 1000); // Event loop, 1s timeout while (s_signo == 0) mg_mgr_poll(&mgr, 1000); // Event loop, 1s timeout
mg_mgr_free(&mgr); // Finished, cleanup mg_mgr_free(&mgr); // Finished, cleanup

View File

@ -11,11 +11,11 @@
#include "mongoose.h" #include "mongoose.h"
static const char *s_url = static const char *s_url =
#if MG_TLS #if MG_TLS
"wss://broker.hivemq.com:8884/mqtt"; "wss://broker.hivemq.com:8884/mqtt";
#else #else
"ws://broker.hivemq.com:8000/mqtt"; "ws://broker.hivemq.com:8000/mqtt";
#endif #endif
static const char *s_topic = "mg/test"; static const char *s_topic = "mg/test";
@ -24,12 +24,17 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_ERROR) { if (ev == MG_EV_ERROR) {
// On error, log error message // On error, log error message
MG_ERROR(("%p %s", c->fd, (char *) ev_data)); MG_ERROR(("%p %s", c->fd, (char *) ev_data));
} else if (ev == MG_EV_CONNECT) {
if (mg_url_is_ssl(s_url)) {
struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_WS_OPEN) { } else if (ev == MG_EV_WS_OPEN) {
// WS connection established. Perform MQTT login // WS connection established. Perform MQTT login
MG_INFO(("Connected to WS. Logging in to MQTT...")); MG_INFO(("Connected to WS. Logging in to MQTT..."));
struct mg_mqtt_opts opts = {.qos = 1, struct mg_mqtt_opts opts = {
.topic = mg_str(s_topic), .qos = 1, .topic = mg_str(s_topic), .message = mg_str("goodbye")};
.message = mg_str("goodbye")};
size_t len = c->send.len; size_t len = c->send.len;
mg_mqtt_login(c, &opts); mg_mqtt_login(c, &opts);
mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY); mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
@ -92,8 +97,6 @@ int main(void) {
struct mg_mgr mgr; // Event manager struct mg_mgr mgr; // Event manager
bool done = false; // Event handler flips it to true when done bool done = false; // Event handler flips it to true when done
mg_mgr_init(&mgr); // Initialise event manager mg_mgr_init(&mgr); // Initialise event manager
struct mg_tls_opts opts = {.client_ca = mg_unpacked("/certs/client_ca.pem")};
mg_tls_ctx_init(&mgr, &opts);
mg_log_set(MG_LL_DEBUG); // Set log level mg_log_set(MG_LL_DEBUG); // Set log level
mg_ws_connect(&mgr, s_url, fn, &done, NULL); // Create client connection mg_ws_connect(&mgr, s_url, fn, &done, NULL); // Create client connection
while (done == false) mg_mgr_poll(&mgr, 1000); // Event loop while (done == false) mg_mgr_poll(&mgr, 1000); // Event loop

View File

@ -28,8 +28,9 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
mg_printf(c, "STARTTLS\r\n"); mg_printf(c, "STARTTLS\r\n");
*state = STARTTLS_WAIT; *state = STARTTLS_WAIT;
} else if (*state == STARTTLS_WAIT) { } else if (*state == STARTTLS_WAIT) {
struct mg_str host = mg_url_host(server); struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
mg_tls_init(c, host); .name = mg_url_host(server)};
mg_tls_init(c, &opts);
*state = AUTH; *state = AUTH;
} else if (*state == AUTH) { } else if (*state == AUTH) {
char a[100], b[300] = ""; char a[100], b[300] = "";
@ -74,10 +75,6 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
int main(void) { int main(void) {
struct mg_mgr mgr; struct mg_mgr mgr;
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
struct mg_tls_opts opts = {.client_ca = mg_unpacked("/certs/client_ca.pem")};
mg_tls_ctx_init(&mgr, &opts);
mg_log_set(MG_LL_DEBUG); mg_log_set(MG_LL_DEBUG);
mg_connect(&mgr, server, fn, NULL); mg_connect(&mgr, server, fn, NULL);
while (s_quit == false) mg_mgr_poll(&mgr, 1000); while (s_quit == false) mg_mgr_poll(&mgr, 1000);

View File

@ -54,10 +54,12 @@ static void cfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
MG_INFO(("CLIENT has been initialized")); MG_INFO(("CLIENT has been initialized"));
} else if (ev == MG_EV_CONNECT) { } else if (ev == MG_EV_CONNECT) {
MG_INFO(("CLIENT connected")); MG_INFO(("CLIENT connected"));
#if MG_TLS if (mg_url_is_ssl(s_conn)) {
struct mg_str host = mg_url_host(s_conn); struct mg_tls_opts opts = {.ca = mg_str(s_tls_ca),
mg_tls_init(c, host); .cert = mg_str(s_tls_cert),
#endif .key = mg_str(s_tls_key)};
mg_tls_init(c, &opts);
}
*i = 1; // do something *i = 1; // do something
} else if (ev == MG_EV_READ) { } else if (ev == MG_EV_READ) {
struct mg_iobuf *r = &c->recv; struct mg_iobuf *r = &c->recv;
@ -89,9 +91,12 @@ static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
MG_INFO(("SERVER is listening")); MG_INFO(("SERVER is listening"));
} else if (ev == MG_EV_ACCEPT) { } else if (ev == MG_EV_ACCEPT) {
MG_INFO(("SERVER accepted a connection")); MG_INFO(("SERVER accepted a connection"));
#if MG_TLS if (mg_url_is_ssl(s_lsn)) {
mg_tls_init(c, mg_str("")); struct mg_tls_opts opts = {.ca = mg_str(s_tls_ca),
#endif .cert = mg_str(s_tls_cert),
.key = mg_str(s_tls_key)};
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_READ) { } else if (ev == MG_EV_READ) {
struct mg_iobuf *r = &c->recv; struct mg_iobuf *r = &c->recv;
MG_INFO(("SERVER got data: %.*s", r->len, r->buf)); MG_INFO(("SERVER got data: %.*s", r->len, r->buf));
@ -109,13 +114,9 @@ static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
static void timer_fn(void *arg) { static void timer_fn(void *arg) {
struct mg_mgr *mgr = (struct mg_mgr *) arg; struct mg_mgr *mgr = (struct mg_mgr *) arg;
if (c_res.c == NULL) { if (c_res.c == NULL) {
// connect
c_res.i = 0; c_res.i = 0;
c_res.c = mg_connect(mgr, s_conn, cfn, &c_res); c_res.c = mg_connect(mgr, s_conn, cfn, &c_res);
if (c_res.c == NULL) MG_INFO(("CLIENT %s", c_res.c ? "connecting" : "failed"));
MG_INFO(("CLIENT cant' open a connection"));
else
MG_INFO(("CLIENT is connecting"));
} }
} }
@ -126,11 +127,6 @@ int main(void) {
mg_log_set(MG_LL_INFO); // Set log level mg_log_set(MG_LL_INFO); // Set log level
mg_mgr_init(&mgr); // Initialize event manager mg_mgr_init(&mgr); // Initialize event manager
struct mg_tls_opts opts = {.client_ca = mg_str(s_tls_ca),
.server_cert = mg_str(s_tls_cert),
.server_key = mg_str(s_tls_key)};
mg_tls_ctx_init(&mgr, &opts);
mg_timer_add(&mgr, 15000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr); mg_timer_add(&mgr, 15000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
c = mg_listen(&mgr, s_lsn, sfn, NULL); // Create server connection c = mg_listen(&mgr, s_lsn, sfn, NULL); // Create server connection
if (c == NULL) { if (c == NULL) {

View File

@ -31,34 +31,29 @@ struct device {
char *last_seen; char *last_seen;
}; };
static struct device s_devices[] = { static struct device s_devices[] = {{.dev_name = "espressif",
{ .dev_name = "espressif", .mac = "02:11:22:33:44:55",
.mac = "02:11:22:33:44:55", .ip_addr = "192.168.1.1/24",
.ip_addr = "192.168.1.1/24", .speed = 1000,
.speed = 1000, .connected_to = "Ethernet",
.connected_to = "Ethernet", .lease_time_left = 1000,
.lease_time_left = 1000, .last_seen = "13h20m ago"},
.last_seen = "13h20m ago"
},
{ .dev_name = "windows11", {.dev_name = "windows11",
.mac = "01:22:11:44:33:55", .mac = "01:22:11:44:33:55",
.ip_addr = "192.168.1.2/24", .ip_addr = "192.168.1.2/24",
.speed = 200, .speed = 200,
.connected_to = "Wifi 2.4 GHz", .connected_to = "Wifi 2.4 GHz",
.lease_time_left = 4141, .lease_time_left = 4141,
.last_seen = "23s ago" .last_seen = "23s ago"},
},
{ .dev_name = "iRobot-2", {.dev_name = "iRobot-2",
.mac = "01:22:11:44:33:42", .mac = "01:22:11:44:33:42",
.ip_addr = "192.168.1.3/24", .ip_addr = "192.168.1.3/24",
.speed = 600, .speed = 600,
.connected_to = "Wifi 5GHz", .connected_to = "Wifi 5GHz",
.lease_time_left = 1141, .lease_time_left = 1141,
.last_seen = "20m ago" .last_seen = "20m ago"}};
}
};
// DHCP configuration // DHCP configuration
struct dhcp { struct dhcp {
@ -232,18 +227,19 @@ static void handle_devices_get(struct mg_connection *c) {
for (int i = 0; i < nr_devs; i++) { for (int i = 0; i < nr_devs; i++) {
size_t current_length = strlen(test_json); size_t current_length = strlen(test_json);
mg_snprintf(test_json + current_length, sizeof(test_json) - current_length, mg_snprintf(
test_json + current_length, sizeof(test_json) - current_length,
"{%m:\"%s\",%m:\"%s\", %m:\"%s\", %m:%d,%m:\"%s\",%m:%d,%m:\"%s\"}", // "{%m:\"%s\",%m:\"%s\", %m:\"%s\", %m:%d,%m:\"%s\",%m:%d,%m:\"%s\"}", //
MG_ESC("dev_name"), s_devices[i].dev_name, // MG_ESC("dev_name"), s_devices[i].dev_name, //
MG_ESC("mac"), s_devices[i].mac, // MG_ESC("mac"), s_devices[i].mac, //
MG_ESC("ip"), s_devices[i].ip_addr, // MG_ESC("ip"), s_devices[i].ip_addr, //
MG_ESC("speed"), s_devices[i].speed, // MG_ESC("speed"), s_devices[i].speed, //
MG_ESC("connected_to"), s_devices[i].connected_to, // MG_ESC("connected_to"), s_devices[i].connected_to, //
MG_ESC("lease_time_left"), s_devices[i].lease_time_left, // MG_ESC("lease_time_left"), s_devices[i].lease_time_left, //
MG_ESC("last_seen"), s_devices[i].last_seen); MG_ESC("last_seen"), s_devices[i].last_seen);
if (i < nr_devs - 1) { if (i < nr_devs - 1) {
strncat(test_json, ",", sizeof(test_json) - strlen(test_json) - 1); strncat(test_json, ",", sizeof(test_json) - strlen(test_json) - 1);
} }
} }
@ -261,7 +257,7 @@ static void handle_dhcp_set(struct mg_connection *c, struct mg_str body) {
s_dhcp = dhcp; // Save to the device flash, too s_dhcp = dhcp; // Save to the device flash, too
bool ok = true; bool ok = true;
mg_http_reply(c, 200, s_json_header, mg_http_reply(c, 200, s_json_header,
"{%m:%s,%m:%m}", // "{%m:%s,%m:%m}", //
MG_ESC("status"), ok ? "true" : "false", // MG_ESC("status"), ok ? "true" : "false", //
MG_ESC("message"), MG_ESC(ok ? "Success" : "Failed")); MG_ESC("message"), MG_ESC(ok ? "Success" : "Failed"));
} }
@ -276,7 +272,14 @@ static void handle_dhcp_get(struct mg_connection *c) {
// HTTP request handler function // HTTP request handler function
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_ACCEPT) {
if (fn_data != NULL) { // TLS
struct mg_tls_opts opts = {0};
opts.cert = mg_str(s_tls_cert);
opts.key = mg_str(s_tls_key);
mg_tls_init(c, &opts);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct user *u = authenticate(hm); struct user *u = authenticate(hm);
@ -317,12 +320,8 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
} }
void web_init(struct mg_mgr *mgr) { void web_init(struct mg_mgr *mgr) {
struct mg_tls_opts opts = {0};
opts.server_cert = mg_str(s_tls_cert);
opts.server_key = mg_str(s_tls_key);
mg_tls_ctx_init(mgr, &opts);
mg_http_listen(mgr, HTTP_URL, fn, NULL); mg_http_listen(mgr, HTTP_URL, fn, NULL);
mg_http_listen(mgr, HTTPS_URL, fn, NULL); mg_http_listen(mgr, HTTPS_URL, fn, (void *) 1);
// mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_mqtt_fn, c->mgr); // mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_mqtt_fn, c->mgr);
mg_timer_add(mgr, 3600 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT, mg_timer_add(mgr, 3600 * 1000, MG_TIMER_RUN_NOW | MG_TIMER_REPEAT,

View File

@ -405,7 +405,7 @@ void mg_error(struct mg_connection *c, const char *fmt, ...) {
va_start(ap, fmt); va_start(ap, fmt);
mg_vsnprintf(buf, sizeof(buf), fmt, &ap); mg_vsnprintf(buf, sizeof(buf), fmt, &ap);
va_end(ap); va_end(ap);
MG_ERROR(("%lu %p %s", c->id, c->fd, buf)); MG_ERROR(("%lu %ld %s", c->id, c->fd, buf));
c->is_closing = 1; // Set is_closing before sending MG_EV_CALL c->is_closing = 1; // Set is_closing before sending MG_EV_CALL
mg_call(c, MG_EV_ERROR, buf); // Let user handler to override it mg_call(c, MG_EV_ERROR, buf); // Let user handler to override it
} }
@ -3700,7 +3700,7 @@ void mg_close_conn(struct mg_connection *c) {
// Order of operations is important. `MG_EV_CLOSE` event must be fired // Order of operations is important. `MG_EV_CLOSE` event must be fired
// before we deallocate received data, see #1331 // before we deallocate received data, see #1331
mg_call(c, MG_EV_CLOSE, NULL); mg_call(c, MG_EV_CLOSE, NULL);
MG_DEBUG(("%lu %p closed", c->id, c->fd)); MG_DEBUG(("%lu %ld closed", c->id, c->fd));
mg_tls_free(c); mg_tls_free(c);
mg_iobuf_free(&c->recv); mg_iobuf_free(&c->recv);
@ -3723,13 +3723,9 @@ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
c->fn = fn; c->fn = fn;
c->is_client = true; c->is_client = true;
c->fn_data = fn_data; c->fn_data = fn_data;
MG_DEBUG(("%lu %p %s", c->id, c->fd, url)); MG_DEBUG(("%lu %ld %s", c->id, c->fd, url));
mg_call(c, MG_EV_OPEN, (void *) url); mg_call(c, MG_EV_OPEN, (void *) url);
mg_resolve(c, url); mg_resolve(c, url);
if (mg_url_is_ssl(url)) {
struct mg_str host = mg_url_host(url);
mg_tls_init(c, host);
}
} }
return c; return c;
} }
@ -3751,7 +3747,7 @@ struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
c->fn_data = fn_data; c->fn_data = fn_data;
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must
MG_DEBUG(("%lu %p %s", c->id, c->fd, url)); MG_DEBUG(("%lu %ld %s", c->id, c->fd, url));
} }
return c; return c;
} }
@ -3794,7 +3790,6 @@ void mg_mgr_free(struct mg_mgr *mgr) {
#if MG_ENABLE_EPOLL #if MG_ENABLE_EPOLL
if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1; if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1;
#endif #endif
mg_tls_ctx_free(mgr);
} }
void mg_mgr_init(struct mg_mgr *mgr) { void mg_mgr_init(struct mg_mgr *mgr) {
@ -4370,7 +4365,6 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
c->fn_data = lsn->fn_data; c->fn_data = lsn->fn_data;
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
mg_call(c, MG_EV_ACCEPT, NULL); mg_call(c, MG_EV_ACCEPT, NULL);
if (lsn->is_tls) mg_tls_init(c, mg_str(""));
return c; return c;
} }
@ -5993,7 +5987,7 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
bool mg_send(struct mg_connection *c, const void *buf, size_t len) { bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
if (c->is_udp) { if (c->is_udp) {
long n = mg_io_send(c, buf, len); long n = mg_io_send(c, buf, len);
MG_DEBUG(("%lu %p %d:%d %ld err %d", c->id, c->fd, (int) c->send.len, MG_DEBUG(("%lu %ld %d:%d %ld err %d", c->id, c->fd, (int) c->send.len,
(int) c->recv.len, n, MG_SOCK_ERR(n))); (int) c->recv.len, n, MG_SOCK_ERR(n)));
iolog(c, (char *) buf, n, false); iolog(c, (char *) buf, n, false);
return n > 0; return n > 0;
@ -6123,7 +6117,7 @@ static void read_conn(struct mg_connection *c) {
char *buf = (char *) &c->recv.buf[c->recv.len]; char *buf = (char *) &c->recv.buf[c->recv.len];
size_t len = c->recv.size - c->recv.len; size_t len = c->recv.size - c->recv.len;
n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_io_recv(c, buf, len); n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_io_recv(c, buf, len);
MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd, MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
(long) c->send.len, (long) c->send.size, (long) c->recv.len, (long) c->send.len, (long) c->send.size, (long) c->recv.len,
(long) c->recv.size, n, MG_SOCK_ERR(n))); (long) c->recv.size, n, MG_SOCK_ERR(n)));
iolog(c, buf, n, true); iolog(c, buf, n, true);
@ -6134,7 +6128,7 @@ static void write_conn(struct mg_connection *c) {
char *buf = (char *) c->send.buf; char *buf = (char *) c->send.buf;
size_t len = c->send.len; size_t len = c->send.len;
long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len); long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len);
MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd, MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
(long) c->send.len, (long) c->send.size, (long) c->recv.len, (long) c->send.len, (long) c->send.size, (long) c->recv.len,
(long) c->recv.size, n, MG_SOCK_ERR(n))); (long) c->recv.size, n, MG_SOCK_ERR(n)));
iolog(c, buf, n, false); iolog(c, buf, n, false);
@ -6212,7 +6206,7 @@ void mg_connect_resolved(struct mg_connection *c) {
if (rc == 0) { // Success if (rc == 0) { // Success
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
MG_DEBUG(("%lu %p -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem)); MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
c->is_connecting = 1; c->is_connecting = 1;
} else { } else {
mg_error(c, "connect: %d", MG_SOCK_ERR(rc)); mg_error(c, "connect: %d", MG_SOCK_ERR(rc));
@ -6266,11 +6260,10 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
c->pfn_data = lsn->pfn_data; c->pfn_data = lsn->pfn_data;
c->fn = lsn->fn; c->fn = lsn->fn;
c->fn_data = lsn->fn_data; c->fn_data = lsn->fn_data;
MG_DEBUG(("%lu %p accepted %M -> %M", c->id, c->fd, mg_print_ip_port, MG_DEBUG(("%lu %ld accepted %M -> %M", c->id, c->fd, mg_print_ip_port,
&c->rem, mg_print_ip_port, &c->loc)); &c->rem, mg_print_ip_port, &c->loc));
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
mg_call(c, MG_EV_ACCEPT, NULL); mg_call(c, MG_EV_ACCEPT, NULL);
if (lsn->is_tls) mg_tls_init(c, mg_str(""));
} }
} }
@ -6978,8 +6971,8 @@ void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
#if MG_TLS == MG_TLS_NONE #if MG_TLS == MG_TLS_NONE
void mg_tls_init(struct mg_connection *c, struct mg_str hostname) { void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
(void) hostname; (void) opts;
mg_error(c, "TLS is not enabled"); mg_error(c, "TLS is not enabled");
} }
void mg_tls_handshake(struct mg_connection *c) { void mg_tls_handshake(struct mg_connection *c) {
@ -6998,12 +6991,6 @@ size_t mg_tls_pending(struct mg_connection *c) {
(void) c; (void) c;
return 0; return 0;
} }
void mg_tls_ctx_free(struct mg_mgr *mgr) {
mgr->tls_ctx = NULL;
}
void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
(void) opts, (void) mgr;
}
#endif #endif
#ifdef MG_ENABLE_LINES #ifdef MG_ENABLE_LINES
@ -7012,20 +6999,54 @@ void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
#if MG_TLS == MG_TLS_MBED #if MG_TLS == MG_TLS_MBED
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
#define MGRNG , rng_get, NULL #define MG_MBEDTLS_RNG_GET , mg_mbed_rng, NULL
#else #else
#define MGRNG #define MG_MBEDTLS_RNG_GET
#endif #endif
static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) {
mg_random(buf, len);
(void) ctx;
return 0;
}
static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) {
int rc;
if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.ptr, str.len)) != 0) {
MG_ERROR(("cert err %#x", -rc));
return false;
}
return true;
}
static bool mg_load_key(struct mg_str str, mbedtls_pk_context *p) {
int rc;
if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.ptr, str.len, NULL,
0 MG_MBEDTLS_RNG_GET)) != 0) {
MG_ERROR(("key err %#x", -rc));
return false;
}
return true;
}
void mg_tls_free(struct mg_connection *c) { void mg_tls_free(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
if (tls != NULL) { if (tls != NULL) {
mbedtls_ssl_free(&tls->ssl); mbedtls_ssl_free(&tls->ssl);
mbedtls_pk_free(&tls->pk);
mbedtls_x509_crt_free(&tls->ca);
mbedtls_x509_crt_free(&tls->cert);
mbedtls_ssl_config_free(&tls->conf); mbedtls_ssl_config_free(&tls->conf);
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&tls->ticket);
#endif
free(tls); free(tls);
c->tls = NULL; c->tls = NULL;
} }
@ -7065,40 +7086,27 @@ void mg_tls_handshake(struct mg_connection *c) {
} }
} }
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) { static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
n = (int) strlen(s2) - 1; n = (int) strlen(s2) - 1;
MG_INFO(("%lu %d %.*s", ((struct mg_connection *) c)->id, lev, n, s2)); MG_INFO(("%lu %d %.*s", ((struct mg_connection *) c)->id, lev, n, s2));
(void) s; (void) s;
} }
#ifdef MBEDTLS_SSL_SESSION_TICKETS void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
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_str hostname) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) c->mgr->tls_ctx;
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
int rc = 0; int rc = 0;
c->tls = tls; c->tls = tls;
if (c->tls == NULL) { if (c->tls == NULL) {
mg_error(c, "TLS OOM"); mg_error(c, "TLS OOM");
goto fail; goto fail;
} }
if (c->is_listening) goto fail;
MG_DEBUG(("%lu Setting TLS", c->id)); MG_DEBUG(("%lu Setting TLS", c->id));
mbedtls_ssl_init(&tls->ssl); mbedtls_ssl_init(&tls->ssl);
mbedtls_ssl_config_init(&tls->conf); mbedtls_ssl_config_init(&tls->conf);
mbedtls_x509_crt_init(&tls->ca);
mbedtls_x509_crt_init(&tls->cert);
mbedtls_pk_init(&tls->pk);
mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c); mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
#if defined(MG_MBEDTLS_DEBUG_LEVEL) #if defined(MG_MBEDTLS_DEBUG_LEVEL)
mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL); mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL);
@ -7110,49 +7118,44 @@ void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
mg_error(c, "tls defaults %#x", -rc); mg_error(c, "tls defaults %#x", -rc);
goto fail; goto fail;
} }
mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c); mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c);
if (c->is_client && ctx->client_ca.version) { if (opts->ca.len == 0 || mg_vcmp(&opts->ca, "*") == 0) {
mbedtls_ssl_conf_ca_chain(&tls->conf, &ctx->client_ca, NULL);
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
if (hostname.ptr != NULL && hostname.ptr[0] != '\0') {
struct mg_addr addr;
if (!mg_aton(hostname, &addr)) { // if srvname is not an IP address
char *host = mg_mprintf("%.*s", (int) hostname.len, hostname.ptr);
mbedtls_ssl_set_hostname(&tls->ssl, host);
free(host);
}
}
} else if (!c->is_client && ctx->server_ca.version) {
mbedtls_ssl_conf_ca_chain(&tls->conf, &ctx->server_ca, NULL);
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
} else {
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
} else {
if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail;
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
if (c->is_client && opts->name.ptr != NULL && opts->name.ptr[0] != '\0') {
char *host = mg_mprintf("%.*s", opts->name.len, opts->name.ptr);
mbedtls_ssl_set_hostname(&tls->ssl, host);
MG_DEBUG(("%lu hostname verification: %s", c->id, host));
free(host);
}
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
} }
if (c->is_client && ctx->client_cert.version && if (!mg_load_cert(opts->cert, &tls->cert)) goto fail;
(rc = mbedtls_ssl_conf_own_cert(&tls->conf, &ctx->client_cert, if (!mg_load_key(opts->key, &tls->pk)) goto fail;
&ctx->client_key)) != 0) { if (tls->cert.version &&
mg_error(c, "own cert %#x", -rc); (rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk)) != 0) {
goto fail;
}
if (!c->is_client && ctx->server_cert.version &&
(rc = mbedtls_ssl_conf_own_cert(&tls->conf, &ctx->server_cert,
&ctx->server_key)) != 0) {
mg_error(c, "own cert %#x", -rc); mg_error(c, "own cert %#x", -rc);
goto fail; goto fail;
} }
#ifdef MBEDTLS_SSL_SESSION_TICKETS #ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_init(&tls->ticket);
if ((rc = mbedtls_ssl_ticket_setup(&tls->ticket, mg_mbed_rng, NULL,
MBEDTLS_CIPHER_AES_128_GCM, 86400)) != 0) {
mg_error(c, " mbedtls_ssl_ticket_setup %#x", -rc);
goto fail;
}
mbedtls_ssl_conf_session_tickets_cb(&tls->conf, mbedtls_ssl_ticket_write, mbedtls_ssl_conf_session_tickets_cb(&tls->conf, mbedtls_ssl_ticket_write,
mbedtls_ssl_ticket_parse, mbedtls_ssl_ticket_parse, &tls->ticket);
&ctx->ticket_ctx);
#endif #endif
if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
mg_error(c, "setup err %#x", -rc); mg_error(c, "setup err %#x", -rc);
goto fail; goto fail;
} }
c->tls = tls;
c->is_tls = 1; c->is_tls = 1;
c->is_tls_hs = 1; c->is_tls_hs = 1;
mbedtls_ssl_set_bio(&tls->ssl, c, mg_net_send, mg_net_recv, 0); mbedtls_ssl_set_bio(&tls->ssl, c, mg_net_send, mg_net_recv, 0);
@ -7186,80 +7189,6 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
if (n <= 0) return MG_IO_ERR; if (n <= 0) return MG_IO_ERR;
return n; return n;
} }
static bool load_cert(struct mg_str str, mbedtls_x509_crt *p) {
int rc;
if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.ptr, str.len)) != 0) {
MG_ERROR(("cert err %#x", -rc));
return false;
}
return true;
}
static bool load_key(struct mg_str str, mbedtls_pk_context *p) {
int rc;
if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.ptr, str.len, NULL,
0 MGRNG)) != 0) {
MG_ERROR(("key err %#x", -rc));
return false;
}
return true;
}
void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx));
if (ctx == NULL) goto fail;
MG_DEBUG(("Setting up TLS context"));
#if defined(MG_MBEDTLS_DEBUG_LEVEL)
mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL);
#endif
if (!load_cert(opts->client_ca, &ctx->client_ca)) goto fail;
if (!load_cert(opts->server_ca, &ctx->server_ca)) goto fail;
if (!load_cert(opts->client_cert, &ctx->client_cert)) goto fail;
if (!load_cert(opts->server_cert, &ctx->server_cert)) goto fail;
if (!load_key(opts->server_key, &ctx->server_key)) goto fail;
if (!load_key(opts->client_key, &ctx->client_key)) goto fail;
#ifdef MBEDTLS_SSL_SESSION_TICKETS
{
int rc;
mbedtls_ssl_ticket_init(&ctx->ticket_ctx);
if ((rc = mbedtls_ssl_ticket_setup(&ctx->ticket_ctx, rng_get, NULL,
MBEDTLS_CIPHER_AES_128_GCM, 86400)) !=
0) {
MG_ERROR(("setup session tickets err %#x", -rc));
goto fail;
}
}
#endif
mgr->tls_ctx = ctx;
return;
fail:
mg_tls_ctx_free(mgr);
}
void mg_tls_ctx_free(struct mg_mgr *mgr) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) mgr->tls_ctx;
if (ctx != NULL) {
mbedtls_x509_crt_free(&ctx->server_cert);
mbedtls_pk_free(&ctx->server_key);
mbedtls_x509_crt_free(&ctx->client_cert);
mbedtls_pk_free(&ctx->client_key);
mbedtls_x509_crt_free(&ctx->client_ca);
mbedtls_x509_crt_free(&ctx->server_ca);
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&ctx->ticket_ctx);
#endif
free(ctx);
mgr->tls_ctx = NULL;
}
}
#endif #endif
#ifdef MG_ENABLE_LINES #ifdef MG_ENABLE_LINES
@ -7287,11 +7216,11 @@ static int mg_tls_err(struct mg_tls *tls, int res) {
return err; return err;
} }
static STACK_OF(X509_INFO) * load_ca_certs(const char *ca, int ca_len) { static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) {
BIO *ca_bio = BIO_new_mem_buf(ca, ca_len); BIO *bio = BIO_new_mem_buf(ca.ptr, (int) ca.len);
if (!ca_bio) return NULL; STACK_OF(X509_INFO) *certs =
STACK_OF(X509_INFO) *certs = PEM_X509_INFO_read_bio(ca_bio, NULL, NULL, NULL); bio ? PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL) : NULL;
BIO_free(ca_bio); if (bio) BIO_free(bio);
return certs; return certs;
} }
@ -7305,45 +7234,52 @@ static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
return true; return true;
} }
static EVP_PKEY *load_key(const char *key, int key_len) { static EVP_PKEY *load_key(struct mg_str s) {
BIO *key_bio = BIO_new_mem_buf(key, key_len); BIO *bio = BIO_new_mem_buf(s.ptr, (int) (long) s.len);
if (!key_bio) return NULL; EVP_PKEY *key = bio ? PEM_read_bio_PrivateKey(bio, NULL, 0, NULL) : NULL;
EVP_PKEY *priv_key = PEM_read_bio_PrivateKey(key_bio, NULL, 0, NULL); if (bio) BIO_free(bio);
BIO_free(key_bio); return key;
return priv_key;
} }
static X509 *load_cert(const char *cert, int cert_len) { static X509 *load_cert(struct mg_str s) {
BIO *cert_bio = BIO_new_mem_buf(cert, cert_len); BIO *bio = BIO_new_mem_buf(s.ptr, (int) (long) s.len);
if (!cert_bio) return NULL; X509 *cert = bio == NULL ? NULL
X509 *x509 = PEM_read_bio_X509(cert_bio, NULL, 0, NULL); : s.ptr[0] == '-'
BIO_free(cert_bio); ? PEM_read_bio_X509(bio, NULL, NULL, NULL) // PEM
return x509; : d2i_X509_bio(bio, NULL); // DER
if (bio) BIO_free(bio);
return cert;
} }
void mg_tls_init(struct mg_connection *c, struct mg_str hostname) { void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) c->mgr->tls_ctx;
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
const char *id = "mongoose";
if (ctx == NULL) { static unsigned char s_initialised = 0;
mg_error(c, "TLS context not initialized"); int rc;
goto fail;
}
if (tls == NULL) { if (tls == NULL) {
mg_error(c, "TLS OOM"); mg_error(c, "TLS OOM");
goto fail; goto fail;
} }
tls->ctx = c->is_client ? SSL_CTX_new(TLS_client_method()) if (!s_initialised) {
: SSL_CTX_new(TLS_server_method()); SSL_library_init();
s_initialised++;
}
MG_DEBUG(("%lu Setting TLS", c->id));
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) { if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
mg_error(c, "SSL_new"); mg_error(c, "SSL_new");
goto fail; goto fail;
} }
SSL_set_session_id_context(tls->ssl, (const uint8_t *) id,
SSL_set_min_proto_version(tls->ssl, TLS1_2_VERSION); (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 #ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION); SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
#endif #endif
@ -7351,37 +7287,33 @@ void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE); SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
#endif #endif
if (c->is_client) { if (opts->ca.ptr != NULL && opts->ca.ptr[0] != '\0') {
if (ctx->client_ca) { SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
SSL_set_verify(tls->ssl, NULL);
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); STACK_OF(X509_INFO) *certs = load_ca_certs(opts->ca);
if (!add_ca_certs(tls->ctx, ctx->client_ca)) goto fail; rc = add_ca_certs(tls->ctx, certs);
sk_X509_INFO_pop_free(certs, X509_INFO_free);
if (!rc) {
mg_error(c, "CA err");
goto fail;
} }
if (ctx->client_cert && ctx->client_key) { }
if (SSL_use_certificate(tls->ssl, ctx->client_cert) != 1) { if (opts->cert.ptr != NULL && opts->cert.ptr[0] != '\0') {
mg_error(c, "SSL_CTX_use_certificate"); X509 *cert = load_cert(opts->cert);
goto fail; rc = cert == NULL ? 0 : SSL_use_certificate(tls->ssl, cert);
} X509_free(cert);
if (SSL_use_PrivateKey(tls->ssl, ctx->client_key) != 1) { if (cert == NULL || rc != 1) {
mg_error(c, "SSL_CTX_use_PrivateKey"); mg_error(c, "CERT err %d", mg_tls_err(tls, rc));
goto fail; goto fail;
}
} }
} else { }
if (ctx->server_ca) { if (opts->key.ptr != NULL && opts->key.ptr[0] != '\0') {
SSL_set_verify(tls->ssl, EVP_PKEY *key = load_key(opts->key);
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); rc = key == NULL ? 0 : SSL_use_PrivateKey(tls->ssl, key);
if (!add_ca_certs(tls->ctx, ctx->server_ca)) goto fail; EVP_PKEY_free(key);
} if (key == NULL || rc != 1) {
if (ctx->server_cert && ctx->server_key) { mg_error(c, "KEY err %d", mg_tls_err(tls, rc));
if (SSL_use_certificate(tls->ssl, ctx->server_cert) != 1) { goto fail;
mg_error(c, "SSL_CTX_use_certificate");
goto fail;
}
if (SSL_use_PrivateKey(tls->ssl, ctx->server_key) != 1) {
mg_error(c, "SSL_CTX_use_PrivateKey");
goto fail;
}
} }
} }
@ -7389,16 +7321,14 @@ void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
#if OPENSSL_VERSION_NUMBER > 0x10002000L #if OPENSSL_VERSION_NUMBER > 0x10002000L
SSL_set_ecdh_auto(tls->ssl, 1); SSL_set_ecdh_auto(tls->ssl, 1);
#endif #endif
#if OPENSSL_VERSION_NUMBER >= 0x10100000L #if OPENSSL_VERSION_NUMBER >= 0x10100000L
if (c->is_client && hostname.ptr && hostname.ptr[0] != '\0') { if (opts->name.len > 0) {
char *s = mg_mprintf("%.*s", (int) hostname.len, hostname.ptr); char *s = mg_mprintf("%.*s", (int) opts->name.len, opts->name.ptr);
SSL_set1_host(tls->ssl, s); SSL_set1_host(tls->ssl, s);
SSL_set_tlsext_host_name(tls->ssl, s); SSL_set_tlsext_host_name(tls->ssl, s);
free(s); free(s);
} }
#endif #endif
c->tls = tls; c->tls = tls;
c->is_tls = 1; c->is_tls = 1;
c->is_tls_hs = 1; c->is_tls_hs = 1;
@ -7407,9 +7337,7 @@ void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
} }
MG_DEBUG(("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client")); MG_DEBUG(("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
return; return;
fail: fail:
c->is_closing = 1;
free(tls); free(tls);
} }
@ -7457,70 +7385,6 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
if (n <= 0) return MG_IO_ERR; if (n <= 0) return MG_IO_ERR;
return n; return n;
} }
void mg_tls_ctx_free(struct mg_mgr *mgr) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) mgr->tls_ctx;
if (ctx) {
if (ctx->server_cert) X509_free(ctx->server_cert);
if (ctx->server_key) EVP_PKEY_free(ctx->server_key);
if (ctx->server_ca)
sk_X509_INFO_pop_free(ctx->server_ca, X509_INFO_free);
if (ctx->client_cert) X509_free(ctx->client_cert);
if (ctx->client_key) EVP_PKEY_free(ctx->client_key);
if (ctx->client_ca)
sk_X509_INFO_pop_free(ctx->client_ca, X509_INFO_free);
free(ctx);
mgr->tls_ctx = NULL;
}
}
void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
static unsigned char s_initialised = 0;
if (!s_initialised) {
SSL_library_init();
s_initialised++;
}
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx));
if (ctx == NULL) return;
if (opts->server_cert.ptr && opts->server_cert.ptr[0] != '\0') {
struct mg_str key = opts->server_key;
if (!key.ptr) key = opts->server_cert;
if (!(ctx->server_cert =
load_cert(opts->server_cert.ptr, (int) opts->server_cert.len)))
goto fail;
if (!(ctx->server_key = load_key(key.ptr, (int) key.len))) goto fail;
}
if (opts->server_ca.ptr && opts->server_ca.ptr[0] != '\0') {
if (!(ctx->server_ca =
load_ca_certs(opts->server_ca.ptr, (int) opts->server_ca.len)))
goto fail;
}
if (opts->client_cert.ptr && opts->client_cert.ptr[0] != '\0') {
struct mg_str key = opts->client_key;
if (!key.ptr) key = opts->client_cert;
if (!(ctx->client_cert =
load_cert(opts->client_cert.ptr, (int) opts->client_cert.len)))
goto fail;
if (!(ctx->client_key = load_key(key.ptr, (int) key.len))) goto fail;
}
if (opts->client_ca.ptr && opts->client_ca.ptr[0] != '\0') {
if (!(ctx->client_ca =
load_ca_certs(opts->client_ca.ptr, (int) opts->client_ca.len)))
goto fail;
}
mgr->tls_ctx = ctx;
return;
fail:
MG_ERROR(("TLS ctx init error"));
mg_tls_ctx_free(mgr);
}
#endif #endif
#ifdef MG_ENABLE_LINES #ifdef MG_ENABLE_LINES
@ -7535,7 +7399,7 @@ struct url {
int mg_url_is_ssl(const char *url) { int mg_url_is_ssl(const char *url) {
return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 || return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 ||
strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 || strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 ||
strncmp(url, "tls:", 4) == 0; strncmp(url, "tls:", 4) == 0 || strncmp(url, "tcps:", 5) == 0;
} }
static struct url urlparse(const char *url) { static struct url urlparse(const char *url) {
@ -7730,9 +7594,8 @@ uint64_t mg_millis(void) {
return GetTickCount(); return GetTickCount();
#elif MG_ARCH == MG_ARCH_RP2040 #elif MG_ARCH == MG_ARCH_RP2040
return time_us_64() / 1000; return time_us_64() / 1000;
#elif MG_ARCH == MG_ARCH_ESP32 #elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_ESP32 || \
return esp_timer_get_time() / 1000; MG_ARCH == MG_ARCH_FREERTOS
#elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_FREERTOS
return xTaskGetTickCount() * portTICK_PERIOD_MS; return xTaskGetTickCount() * portTICK_PERIOD_MS;
#elif MG_ARCH == MG_ARCH_AZURERTOS #elif MG_ARCH == MG_ARCH_AZURERTOS
return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND); return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND);

View File

@ -1176,7 +1176,6 @@ struct mg_mgr {
unsigned long nextid; // Next connection ID unsigned long nextid; // Next connection ID
unsigned long timerid; // Next timer ID unsigned long timerid; // Next timer ID
void *userdata; // Arbitrary user data pointer void *userdata; // Arbitrary user data pointer
void *tls_ctx; // TLS context shared by all TLS sessions
uint16_t mqtt_id; // MQTT IDs for pub/sub uint16_t mqtt_id; // MQTT IDs for pub/sub
void *active_dns_requests; // DNS requests in progress void *active_dns_requests; // DNS requests in progress
struct mg_timer *timers; // Active timers struct mg_timer *timers; // Active timers
@ -1342,17 +1341,13 @@ void mg_http_serve_ssi(struct mg_connection *c, const char *root,
struct mg_tls_opts { struct mg_tls_opts {
struct mg_str client_ca; struct mg_str ca; // PEM or DER
struct mg_str server_ca; struct mg_str cert; // PEM or DER
struct mg_str server_cert; struct mg_str key; // PEM or DER
struct mg_str server_key; struct mg_str name; // If not empty, enable host name verification
struct mg_str client_cert;
struct mg_str client_key;
}; };
void mg_tls_ctx_init(struct mg_mgr *, const struct mg_tls_opts *); void mg_tls_init(struct mg_connection *, const struct mg_tls_opts *opts);
void mg_tls_ctx_free(struct mg_mgr *);
void mg_tls_init(struct mg_connection *, struct mg_str hostname);
void mg_tls_free(struct mg_connection *); void mg_tls_free(struct mg_connection *);
long mg_tls_send(struct mg_connection *, const void *buf, size_t len); long mg_tls_send(struct mg_connection *, const void *buf, size_t len);
long mg_tls_recv(struct mg_connection *, void *buf, size_t len); long mg_tls_recv(struct mg_connection *, void *buf, size_t len);
@ -1371,21 +1366,15 @@ void mg_tls_handshake(struct mg_connection *);
#include <mbedtls/ssl.h> #include <mbedtls/ssl.h>
#include <mbedtls/ssl_ticket.h> #include <mbedtls/ssl_ticket.h>
struct mg_tls_ctx {
mbedtls_x509_crt server_ca; // Parsed CA certificate
mbedtls_x509_crt client_ca; // Parsed CA certificate
mbedtls_x509_crt server_cert; // Parsed server certificate
mbedtls_pk_context server_key; // Parsed server private key context
mbedtls_x509_crt client_cert; // Parsed client certificate
mbedtls_pk_context client_key; // Parsed client private key context
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_context ticket_ctx; // Session tickets context
#endif
};
struct mg_tls { struct mg_tls {
mbedtls_x509_crt ca; // Parsed CA certificate
mbedtls_x509_crt cert; // Parsed certificate
mbedtls_pk_context pk; // Private key context
mbedtls_ssl_context ssl; // SSL/TLS context mbedtls_ssl_context ssl; // SSL/TLS context
mbedtls_ssl_config conf; // SSL-TLS config mbedtls_ssl_config conf; // SSL-TLS config
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_context ticket; // Session tickets context
#endif
}; };
#endif #endif
@ -1395,15 +1384,6 @@ struct mg_tls {
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
struct mg_tls_ctx {
X509 *server_cert;
EVP_PKEY *server_key;
STACK_OF(X509_INFO) *server_ca;
X509 *client_cert;
EVP_PKEY *client_key;
STACK_OF(X509_INFO) *client_ca;
};
struct mg_tls { struct mg_tls {
SSL_CTX *ctx; SSL_CTX *ctx;
SSL *ssl; SSL *ssl;

View File

@ -17,7 +17,7 @@ void mg_error(struct mg_connection *c, const char *fmt, ...) {
va_start(ap, fmt); va_start(ap, fmt);
mg_vsnprintf(buf, sizeof(buf), fmt, &ap); mg_vsnprintf(buf, sizeof(buf), fmt, &ap);
va_end(ap); va_end(ap);
MG_ERROR(("%lu %p %s", c->id, c->fd, buf)); MG_ERROR(("%lu %ld %s", c->id, c->fd, buf));
c->is_closing = 1; // Set is_closing before sending MG_EV_CALL c->is_closing = 1; // Set is_closing before sending MG_EV_CALL
mg_call(c, MG_EV_ERROR, buf); // Let user handler to override it mg_call(c, MG_EV_ERROR, buf); // Let user handler to override it
} }

View File

@ -138,7 +138,7 @@ void mg_close_conn(struct mg_connection *c) {
// Order of operations is important. `MG_EV_CLOSE` event must be fired // Order of operations is important. `MG_EV_CLOSE` event must be fired
// before we deallocate received data, see #1331 // before we deallocate received data, see #1331
mg_call(c, MG_EV_CLOSE, NULL); mg_call(c, MG_EV_CLOSE, NULL);
MG_DEBUG(("%lu %p closed", c->id, c->fd)); MG_DEBUG(("%lu %ld closed", c->id, c->fd));
mg_tls_free(c); mg_tls_free(c);
mg_iobuf_free(&c->recv); mg_iobuf_free(&c->recv);
@ -161,13 +161,9 @@ struct mg_connection *mg_connect(struct mg_mgr *mgr, const char *url,
c->fn = fn; c->fn = fn;
c->is_client = true; c->is_client = true;
c->fn_data = fn_data; c->fn_data = fn_data;
MG_DEBUG(("%lu %p %s", c->id, c->fd, url)); MG_DEBUG(("%lu %ld %s", c->id, c->fd, url));
mg_call(c, MG_EV_OPEN, (void *) url); mg_call(c, MG_EV_OPEN, (void *) url);
mg_resolve(c, url); mg_resolve(c, url);
if (mg_url_is_ssl(url)) {
struct mg_str host = mg_url_host(url);
mg_tls_init(c, host);
}
} }
return c; return c;
} }
@ -189,7 +185,7 @@ struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
c->fn_data = fn_data; c->fn_data = fn_data;
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must if (mg_url_is_ssl(url)) c->is_tls = 1; // Accepted connection must
MG_DEBUG(("%lu %p %s", c->id, c->fd, url)); MG_DEBUG(("%lu %ld %s", c->id, c->fd, url));
} }
return c; return c;
} }
@ -232,7 +228,6 @@ void mg_mgr_free(struct mg_mgr *mgr) {
#if MG_ENABLE_EPOLL #if MG_ENABLE_EPOLL
if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1; if (mgr->epoll_fd >= 0) close(mgr->epoll_fd), mgr->epoll_fd = -1;
#endif #endif
mg_tls_ctx_free(mgr);
} }
void mg_mgr_init(struct mg_mgr *mgr) { void mg_mgr_init(struct mg_mgr *mgr) {

View File

@ -27,7 +27,6 @@ struct mg_mgr {
unsigned long nextid; // Next connection ID unsigned long nextid; // Next connection ID
unsigned long timerid; // Next timer ID unsigned long timerid; // Next timer ID
void *userdata; // Arbitrary user data pointer void *userdata; // Arbitrary user data pointer
void *tls_ctx; // TLS context shared by all TLS sessions
uint16_t mqtt_id; // MQTT IDs for pub/sub uint16_t mqtt_id; // MQTT IDs for pub/sub
void *active_dns_requests; // DNS requests in progress void *active_dns_requests; // DNS requests in progress
struct mg_timer *timers; // Active timers struct mg_timer *timers; // Active timers

View File

@ -544,7 +544,6 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
c->fn_data = lsn->fn_data; c->fn_data = lsn->fn_data;
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
mg_call(c, MG_EV_ACCEPT, NULL); mg_call(c, MG_EV_ACCEPT, NULL);
if (lsn->is_tls) mg_tls_init(c, mg_str(""));
return c; return c;
} }

View File

@ -137,7 +137,7 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
bool mg_send(struct mg_connection *c, const void *buf, size_t len) { bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
if (c->is_udp) { if (c->is_udp) {
long n = mg_io_send(c, buf, len); long n = mg_io_send(c, buf, len);
MG_DEBUG(("%lu %p %d:%d %ld err %d", c->id, c->fd, (int) c->send.len, MG_DEBUG(("%lu %ld %d:%d %ld err %d", c->id, c->fd, (int) c->send.len,
(int) c->recv.len, n, MG_SOCK_ERR(n))); (int) c->recv.len, n, MG_SOCK_ERR(n)));
iolog(c, (char *) buf, n, false); iolog(c, (char *) buf, n, false);
return n > 0; return n > 0;
@ -267,7 +267,7 @@ static void read_conn(struct mg_connection *c) {
char *buf = (char *) &c->recv.buf[c->recv.len]; char *buf = (char *) &c->recv.buf[c->recv.len];
size_t len = c->recv.size - c->recv.len; size_t len = c->recv.size - c->recv.len;
n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_io_recv(c, buf, len); n = c->is_tls ? mg_tls_recv(c, buf, len) : mg_io_recv(c, buf, len);
MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd, MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
(long) c->send.len, (long) c->send.size, (long) c->recv.len, (long) c->send.len, (long) c->send.size, (long) c->recv.len,
(long) c->recv.size, n, MG_SOCK_ERR(n))); (long) c->recv.size, n, MG_SOCK_ERR(n)));
iolog(c, buf, n, true); iolog(c, buf, n, true);
@ -278,7 +278,7 @@ static void write_conn(struct mg_connection *c) {
char *buf = (char *) c->send.buf; char *buf = (char *) c->send.buf;
size_t len = c->send.len; size_t len = c->send.len;
long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len); long n = c->is_tls ? mg_tls_send(c, buf, len) : mg_io_send(c, buf, len);
MG_DEBUG(("%lu %p snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd, MG_DEBUG(("%lu %ld snd %ld/%ld rcv %ld/%ld n=%ld err=%d", c->id, c->fd,
(long) c->send.len, (long) c->send.size, (long) c->recv.len, (long) c->send.len, (long) c->send.size, (long) c->recv.len,
(long) c->recv.size, n, MG_SOCK_ERR(n))); (long) c->recv.size, n, MG_SOCK_ERR(n)));
iolog(c, buf, n, false); iolog(c, buf, n, false);
@ -356,7 +356,7 @@ void mg_connect_resolved(struct mg_connection *c) {
if (rc == 0) { // Success if (rc == 0) { // Success
mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user mg_call(c, MG_EV_CONNECT, NULL); // Send MG_EV_CONNECT to the user
} else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake } else if (MG_SOCK_PENDING(rc)) { // Need to wait for TCP handshake
MG_DEBUG(("%lu %p -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem)); MG_DEBUG(("%lu %ld -> %M pend", c->id, c->fd, mg_print_ip_port, &c->rem));
c->is_connecting = 1; c->is_connecting = 1;
} else { } else {
mg_error(c, "connect: %d", MG_SOCK_ERR(rc)); mg_error(c, "connect: %d", MG_SOCK_ERR(rc));
@ -410,11 +410,10 @@ static void accept_conn(struct mg_mgr *mgr, struct mg_connection *lsn) {
c->pfn_data = lsn->pfn_data; c->pfn_data = lsn->pfn_data;
c->fn = lsn->fn; c->fn = lsn->fn;
c->fn_data = lsn->fn_data; c->fn_data = lsn->fn_data;
MG_DEBUG(("%lu %p accepted %M -> %M", c->id, c->fd, mg_print_ip_port, MG_DEBUG(("%lu %ld accepted %M -> %M", c->id, c->fd, mg_print_ip_port,
&c->rem, mg_print_ip_port, &c->loc)); &c->rem, mg_print_ip_port, &c->loc));
mg_call(c, MG_EV_OPEN, NULL); mg_call(c, MG_EV_OPEN, NULL);
mg_call(c, MG_EV_ACCEPT, NULL); mg_call(c, MG_EV_ACCEPT, NULL);
if (lsn->is_tls) mg_tls_init(c, mg_str(""));
} }
} }

View File

@ -15,17 +15,13 @@
#include "tls_openssl.h" #include "tls_openssl.h"
struct mg_tls_opts { struct mg_tls_opts {
struct mg_str client_ca; struct mg_str ca; // PEM or DER
struct mg_str server_ca; struct mg_str cert; // PEM or DER
struct mg_str server_cert; struct mg_str key; // PEM or DER
struct mg_str server_key; struct mg_str name; // If not empty, enable host name verification
struct mg_str client_cert;
struct mg_str client_key;
}; };
void mg_tls_ctx_init(struct mg_mgr *, const struct mg_tls_opts *); void mg_tls_init(struct mg_connection *, const struct mg_tls_opts *opts);
void mg_tls_ctx_free(struct mg_mgr *);
void mg_tls_init(struct mg_connection *, struct mg_str hostname);
void mg_tls_free(struct mg_connection *); void mg_tls_free(struct mg_connection *);
long mg_tls_send(struct mg_connection *, const void *buf, size_t len); long mg_tls_send(struct mg_connection *, const void *buf, size_t len);
long mg_tls_recv(struct mg_connection *, void *buf, size_t len); long mg_tls_recv(struct mg_connection *, void *buf, size_t len);

View File

@ -1,8 +1,8 @@
#include "tls.h" #include "tls.h"
#if MG_TLS == MG_TLS_NONE #if MG_TLS == MG_TLS_NONE
void mg_tls_init(struct mg_connection *c, struct mg_str hostname) { void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
(void) hostname; (void) opts;
mg_error(c, "TLS is not enabled"); mg_error(c, "TLS is not enabled");
} }
void mg_tls_handshake(struct mg_connection *c) { void mg_tls_handshake(struct mg_connection *c) {
@ -21,10 +21,4 @@ size_t mg_tls_pending(struct mg_connection *c) {
(void) c; (void) c;
return 0; return 0;
} }
void mg_tls_ctx_free(struct mg_mgr *mgr) {
mgr->tls_ctx = NULL;
}
void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
(void) opts, (void) mgr;
}
#endif #endif

View File

@ -1,20 +1,54 @@
#include "fs.h" #include "log.h"
#include "printf.h"
#include "tls.h" #include "tls.h"
#if MG_TLS == MG_TLS_MBED #if MG_TLS == MG_TLS_MBED
#if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000 #if defined(MBEDTLS_VERSION_NUMBER) && MBEDTLS_VERSION_NUMBER >= 0x03000000
#define MGRNG , rng_get, NULL #define MG_MBEDTLS_RNG_GET , mg_mbed_rng, NULL
#else #else
#define MGRNG #define MG_MBEDTLS_RNG_GET
#endif #endif
static int mg_mbed_rng(void *ctx, unsigned char *buf, size_t len) {
mg_random(buf, len);
(void) ctx;
return 0;
}
static bool mg_load_cert(struct mg_str str, mbedtls_x509_crt *p) {
int rc;
if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.ptr, str.len)) != 0) {
MG_ERROR(("cert err %#x", -rc));
return false;
}
return true;
}
static bool mg_load_key(struct mg_str str, mbedtls_pk_context *p) {
int rc;
if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.ptr, str.len, NULL,
0 MG_MBEDTLS_RNG_GET)) != 0) {
MG_ERROR(("key err %#x", -rc));
return false;
}
return true;
}
void mg_tls_free(struct mg_connection *c) { void mg_tls_free(struct mg_connection *c) {
struct mg_tls *tls = (struct mg_tls *) c->tls; struct mg_tls *tls = (struct mg_tls *) c->tls;
if (tls != NULL) { if (tls != NULL) {
mbedtls_ssl_free(&tls->ssl); mbedtls_ssl_free(&tls->ssl);
mbedtls_pk_free(&tls->pk);
mbedtls_x509_crt_free(&tls->ca);
mbedtls_x509_crt_free(&tls->cert);
mbedtls_ssl_config_free(&tls->conf); mbedtls_ssl_config_free(&tls->conf);
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&tls->ticket);
#endif
free(tls); free(tls);
c->tls = NULL; c->tls = NULL;
} }
@ -54,40 +88,27 @@ void mg_tls_handshake(struct mg_connection *c) {
} }
} }
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) { static void debug_cb(void *c, int lev, const char *s, int n, const char *s2) {
n = (int) strlen(s2) - 1; n = (int) strlen(s2) - 1;
MG_INFO(("%lu %d %.*s", ((struct mg_connection *) c)->id, lev, n, s2)); MG_INFO(("%lu %d %.*s", ((struct mg_connection *) c)->id, lev, n, s2));
(void) s; (void) s;
} }
#ifdef MBEDTLS_SSL_SESSION_TICKETS void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
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_str hostname) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) c->mgr->tls_ctx;
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
int rc = 0; int rc = 0;
c->tls = tls; c->tls = tls;
if (c->tls == NULL) { if (c->tls == NULL) {
mg_error(c, "TLS OOM"); mg_error(c, "TLS OOM");
goto fail; goto fail;
} }
if (c->is_listening) goto fail;
MG_DEBUG(("%lu Setting TLS", c->id)); MG_DEBUG(("%lu Setting TLS", c->id));
mbedtls_ssl_init(&tls->ssl); mbedtls_ssl_init(&tls->ssl);
mbedtls_ssl_config_init(&tls->conf); mbedtls_ssl_config_init(&tls->conf);
mbedtls_x509_crt_init(&tls->ca);
mbedtls_x509_crt_init(&tls->cert);
mbedtls_pk_init(&tls->pk);
mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c); mbedtls_ssl_conf_dbg(&tls->conf, debug_cb, c);
#if defined(MG_MBEDTLS_DEBUG_LEVEL) #if defined(MG_MBEDTLS_DEBUG_LEVEL)
mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL); mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL);
@ -99,49 +120,44 @@ void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
mg_error(c, "tls defaults %#x", -rc); mg_error(c, "tls defaults %#x", -rc);
goto fail; goto fail;
} }
mbedtls_ssl_conf_rng(&tls->conf, mbed_rng, c); mbedtls_ssl_conf_rng(&tls->conf, mg_mbed_rng, c);
if (c->is_client && ctx->client_ca.version) { if (opts->ca.len == 0 || mg_vcmp(&opts->ca, "*") == 0) {
mbedtls_ssl_conf_ca_chain(&tls->conf, &ctx->client_ca, NULL);
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
if (hostname.ptr != NULL && hostname.ptr[0] != '\0') {
struct mg_addr addr;
if (!mg_aton(hostname, &addr)) { // if srvname is not an IP address
char *host = mg_mprintf("%.*s", (int) hostname.len, hostname.ptr);
mbedtls_ssl_set_hostname(&tls->ssl, host);
free(host);
}
}
} else if (!c->is_client && ctx->server_ca.version) {
mbedtls_ssl_conf_ca_chain(&tls->conf, &ctx->server_ca, NULL);
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
} else {
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
} else {
if (mg_load_cert(opts->ca, &tls->ca) == false) goto fail;
mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL);
if (c->is_client && opts->name.ptr != NULL && opts->name.ptr[0] != '\0') {
char *host = mg_mprintf("%.*s", opts->name.len, opts->name.ptr);
mbedtls_ssl_set_hostname(&tls->ssl, host);
MG_DEBUG(("%lu hostname verification: %s", c->id, host));
free(host);
}
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
} }
if (c->is_client && ctx->client_cert.version && if (!mg_load_cert(opts->cert, &tls->cert)) goto fail;
(rc = mbedtls_ssl_conf_own_cert(&tls->conf, &ctx->client_cert, if (!mg_load_key(opts->key, &tls->pk)) goto fail;
&ctx->client_key)) != 0) { if (tls->cert.version &&
mg_error(c, "own cert %#x", -rc); (rc = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->cert, &tls->pk)) != 0) {
goto fail;
}
if (!c->is_client && ctx->server_cert.version &&
(rc = mbedtls_ssl_conf_own_cert(&tls->conf, &ctx->server_cert,
&ctx->server_key)) != 0) {
mg_error(c, "own cert %#x", -rc); mg_error(c, "own cert %#x", -rc);
goto fail; goto fail;
} }
#ifdef MBEDTLS_SSL_SESSION_TICKETS #ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_init(&tls->ticket);
if ((rc = mbedtls_ssl_ticket_setup(&tls->ticket, mg_mbed_rng, NULL,
MBEDTLS_CIPHER_AES_128_GCM, 86400)) != 0) {
mg_error(c, " mbedtls_ssl_ticket_setup %#x", -rc);
goto fail;
}
mbedtls_ssl_conf_session_tickets_cb(&tls->conf, mbedtls_ssl_ticket_write, mbedtls_ssl_conf_session_tickets_cb(&tls->conf, mbedtls_ssl_ticket_write,
mbedtls_ssl_ticket_parse, mbedtls_ssl_ticket_parse, &tls->ticket);
&ctx->ticket_ctx);
#endif #endif
if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) { if ((rc = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
mg_error(c, "setup err %#x", -rc); mg_error(c, "setup err %#x", -rc);
goto fail; goto fail;
} }
c->tls = tls;
c->is_tls = 1; c->is_tls = 1;
c->is_tls_hs = 1; c->is_tls_hs = 1;
mbedtls_ssl_set_bio(&tls->ssl, c, mg_net_send, mg_net_recv, 0); mbedtls_ssl_set_bio(&tls->ssl, c, mg_net_send, mg_net_recv, 0);
@ -175,78 +191,4 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
if (n <= 0) return MG_IO_ERR; if (n <= 0) return MG_IO_ERR;
return n; return n;
} }
static bool load_cert(struct mg_str str, mbedtls_x509_crt *p) {
int rc;
if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_x509_crt_parse(p, (uint8_t *) str.ptr, str.len)) != 0) {
MG_ERROR(("cert err %#x", -rc));
return false;
}
return true;
}
static bool load_key(struct mg_str str, mbedtls_pk_context *p) {
int rc;
if (str.ptr == NULL || str.ptr[0] == '\0' || str.ptr[0] == '*') return true;
if (str.ptr[0] == '-') str.len++; // PEM, include trailing NUL
if ((rc = mbedtls_pk_parse_key(p, (uint8_t *) str.ptr, str.len, NULL,
0 MGRNG)) != 0) {
MG_ERROR(("key err %#x", -rc));
return false;
}
return true;
}
void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx));
if (ctx == NULL) goto fail;
MG_DEBUG(("Setting up TLS context"));
#if defined(MG_MBEDTLS_DEBUG_LEVEL)
mbedtls_debug_set_threshold(MG_MBEDTLS_DEBUG_LEVEL);
#endif
if (!load_cert(opts->client_ca, &ctx->client_ca)) goto fail;
if (!load_cert(opts->server_ca, &ctx->server_ca)) goto fail;
if (!load_cert(opts->client_cert, &ctx->client_cert)) goto fail;
if (!load_cert(opts->server_cert, &ctx->server_cert)) goto fail;
if (!load_key(opts->server_key, &ctx->server_key)) goto fail;
if (!load_key(opts->client_key, &ctx->client_key)) goto fail;
#ifdef MBEDTLS_SSL_SESSION_TICKETS
{
int rc;
mbedtls_ssl_ticket_init(&ctx->ticket_ctx);
if ((rc = mbedtls_ssl_ticket_setup(&ctx->ticket_ctx, rng_get, NULL,
MBEDTLS_CIPHER_AES_128_GCM, 86400)) !=
0) {
MG_ERROR(("setup session tickets err %#x", -rc));
goto fail;
}
}
#endif
mgr->tls_ctx = ctx;
return;
fail:
mg_tls_ctx_free(mgr);
}
void mg_tls_ctx_free(struct mg_mgr *mgr) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) mgr->tls_ctx;
if (ctx != NULL) {
mbedtls_x509_crt_free(&ctx->server_cert);
mbedtls_pk_free(&ctx->server_key);
mbedtls_x509_crt_free(&ctx->client_cert);
mbedtls_pk_free(&ctx->client_key);
mbedtls_x509_crt_free(&ctx->client_ca);
mbedtls_x509_crt_free(&ctx->server_ca);
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_free(&ctx->ticket_ctx);
#endif
free(ctx);
mgr->tls_ctx = NULL;
}
}
#endif #endif

View File

@ -11,20 +11,14 @@
#include <mbedtls/ssl.h> #include <mbedtls/ssl.h>
#include <mbedtls/ssl_ticket.h> #include <mbedtls/ssl_ticket.h>
struct mg_tls_ctx {
mbedtls_x509_crt server_ca; // Parsed CA certificate
mbedtls_x509_crt client_ca; // Parsed CA certificate
mbedtls_x509_crt server_cert; // Parsed server certificate
mbedtls_pk_context server_key; // Parsed server private key context
mbedtls_x509_crt client_cert; // Parsed client certificate
mbedtls_pk_context client_key; // Parsed client private key context
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_context ticket_ctx; // Session tickets context
#endif
};
struct mg_tls { struct mg_tls {
mbedtls_x509_crt ca; // Parsed CA certificate
mbedtls_x509_crt cert; // Parsed certificate
mbedtls_pk_context pk; // Private key context
mbedtls_ssl_context ssl; // SSL/TLS context mbedtls_ssl_context ssl; // SSL/TLS context
mbedtls_ssl_config conf; // SSL-TLS config mbedtls_ssl_config conf; // SSL-TLS config
#ifdef MBEDTLS_SSL_SESSION_TICKETS
mbedtls_ssl_ticket_context ticket; // Session tickets context
#endif
}; };
#endif #endif

View File

@ -20,11 +20,11 @@ static int mg_tls_err(struct mg_tls *tls, int res) {
return err; return err;
} }
static STACK_OF(X509_INFO) * load_ca_certs(const char *ca, int ca_len) { static STACK_OF(X509_INFO) * load_ca_certs(struct mg_str ca) {
BIO *ca_bio = BIO_new_mem_buf(ca, ca_len); BIO *bio = BIO_new_mem_buf(ca.ptr, (int) ca.len);
if (!ca_bio) return NULL; STACK_OF(X509_INFO) *certs =
STACK_OF(X509_INFO) *certs = PEM_X509_INFO_read_bio(ca_bio, NULL, NULL, NULL); bio ? PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL) : NULL;
BIO_free(ca_bio); if (bio) BIO_free(bio);
return certs; return certs;
} }
@ -38,45 +38,52 @@ static bool add_ca_certs(SSL_CTX *ctx, STACK_OF(X509_INFO) * certs) {
return true; return true;
} }
static EVP_PKEY *load_key(const char *key, int key_len) { static EVP_PKEY *load_key(struct mg_str s) {
BIO *key_bio = BIO_new_mem_buf(key, key_len); BIO *bio = BIO_new_mem_buf(s.ptr, (int) (long) s.len);
if (!key_bio) return NULL; EVP_PKEY *key = bio ? PEM_read_bio_PrivateKey(bio, NULL, 0, NULL) : NULL;
EVP_PKEY *priv_key = PEM_read_bio_PrivateKey(key_bio, NULL, 0, NULL); if (bio) BIO_free(bio);
BIO_free(key_bio); return key;
return priv_key;
} }
static X509 *load_cert(const char *cert, int cert_len) { static X509 *load_cert(struct mg_str s) {
BIO *cert_bio = BIO_new_mem_buf(cert, cert_len); BIO *bio = BIO_new_mem_buf(s.ptr, (int) (long) s.len);
if (!cert_bio) return NULL; X509 *cert = bio == NULL ? NULL
X509 *x509 = PEM_read_bio_X509(cert_bio, NULL, 0, NULL); : s.ptr[0] == '-'
BIO_free(cert_bio); ? PEM_read_bio_X509(bio, NULL, NULL, NULL) // PEM
return x509; : d2i_X509_bio(bio, NULL); // DER
if (bio) BIO_free(bio);
return cert;
} }
void mg_tls_init(struct mg_connection *c, struct mg_str hostname) { void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) c->mgr->tls_ctx;
struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls)); struct mg_tls *tls = (struct mg_tls *) calloc(1, sizeof(*tls));
const char *id = "mongoose";
if (ctx == NULL) { static unsigned char s_initialised = 0;
mg_error(c, "TLS context not initialized"); int rc;
goto fail;
}
if (tls == NULL) { if (tls == NULL) {
mg_error(c, "TLS OOM"); mg_error(c, "TLS OOM");
goto fail; goto fail;
} }
tls->ctx = c->is_client ? SSL_CTX_new(TLS_client_method()) if (!s_initialised) {
: SSL_CTX_new(TLS_server_method()); SSL_library_init();
s_initialised++;
}
MG_DEBUG(("%lu Setting TLS", c->id));
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) { if ((tls->ssl = SSL_new(tls->ctx)) == NULL) {
mg_error(c, "SSL_new"); mg_error(c, "SSL_new");
goto fail; goto fail;
} }
SSL_set_session_id_context(tls->ssl, (const uint8_t *) id,
SSL_set_min_proto_version(tls->ssl, TLS1_2_VERSION); (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 #ifdef MG_ENABLE_OPENSSL_NO_COMPRESSION
SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION); SSL_set_options(tls->ssl, SSL_OP_NO_COMPRESSION);
#endif #endif
@ -84,37 +91,33 @@ void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE); SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
#endif #endif
if (c->is_client) { if (opts->ca.ptr != NULL && opts->ca.ptr[0] != '\0') {
if (ctx->client_ca) { SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
SSL_set_verify(tls->ssl, NULL);
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); STACK_OF(X509_INFO) *certs = load_ca_certs(opts->ca);
if (!add_ca_certs(tls->ctx, ctx->client_ca)) goto fail; rc = add_ca_certs(tls->ctx, certs);
sk_X509_INFO_pop_free(certs, X509_INFO_free);
if (!rc) {
mg_error(c, "CA err");
goto fail;
} }
if (ctx->client_cert && ctx->client_key) { }
if (SSL_use_certificate(tls->ssl, ctx->client_cert) != 1) { if (opts->cert.ptr != NULL && opts->cert.ptr[0] != '\0') {
mg_error(c, "SSL_CTX_use_certificate"); X509 *cert = load_cert(opts->cert);
goto fail; rc = cert == NULL ? 0 : SSL_use_certificate(tls->ssl, cert);
} X509_free(cert);
if (SSL_use_PrivateKey(tls->ssl, ctx->client_key) != 1) { if (cert == NULL || rc != 1) {
mg_error(c, "SSL_CTX_use_PrivateKey"); mg_error(c, "CERT err %d", mg_tls_err(tls, rc));
goto fail; goto fail;
}
} }
} else { }
if (ctx->server_ca) { if (opts->key.ptr != NULL && opts->key.ptr[0] != '\0') {
SSL_set_verify(tls->ssl, EVP_PKEY *key = load_key(opts->key);
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); rc = key == NULL ? 0 : SSL_use_PrivateKey(tls->ssl, key);
if (!add_ca_certs(tls->ctx, ctx->server_ca)) goto fail; EVP_PKEY_free(key);
} if (key == NULL || rc != 1) {
if (ctx->server_cert && ctx->server_key) { mg_error(c, "KEY err %d", mg_tls_err(tls, rc));
if (SSL_use_certificate(tls->ssl, ctx->server_cert) != 1) { goto fail;
mg_error(c, "SSL_CTX_use_certificate");
goto fail;
}
if (SSL_use_PrivateKey(tls->ssl, ctx->server_key) != 1) {
mg_error(c, "SSL_CTX_use_PrivateKey");
goto fail;
}
} }
} }
@ -122,16 +125,14 @@ void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
#if OPENSSL_VERSION_NUMBER > 0x10002000L #if OPENSSL_VERSION_NUMBER > 0x10002000L
SSL_set_ecdh_auto(tls->ssl, 1); SSL_set_ecdh_auto(tls->ssl, 1);
#endif #endif
#if OPENSSL_VERSION_NUMBER >= 0x10100000L #if OPENSSL_VERSION_NUMBER >= 0x10100000L
if (c->is_client && hostname.ptr && hostname.ptr[0] != '\0') { if (opts->name.len > 0) {
char *s = mg_mprintf("%.*s", (int) hostname.len, hostname.ptr); char *s = mg_mprintf("%.*s", (int) opts->name.len, opts->name.ptr);
SSL_set1_host(tls->ssl, s); SSL_set1_host(tls->ssl, s);
SSL_set_tlsext_host_name(tls->ssl, s); SSL_set_tlsext_host_name(tls->ssl, s);
free(s); free(s);
} }
#endif #endif
c->tls = tls; c->tls = tls;
c->is_tls = 1; c->is_tls = 1;
c->is_tls_hs = 1; c->is_tls_hs = 1;
@ -140,9 +141,7 @@ void mg_tls_init(struct mg_connection *c, struct mg_str hostname) {
} }
MG_DEBUG(("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client")); MG_DEBUG(("%lu SSL %s OK", c->id, c->is_accepted ? "accept" : "client"));
return; return;
fail: fail:
c->is_closing = 1;
free(tls); free(tls);
} }
@ -190,68 +189,4 @@ long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
if (n <= 0) return MG_IO_ERR; if (n <= 0) return MG_IO_ERR;
return n; return n;
} }
void mg_tls_ctx_free(struct mg_mgr *mgr) {
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) mgr->tls_ctx;
if (ctx) {
if (ctx->server_cert) X509_free(ctx->server_cert);
if (ctx->server_key) EVP_PKEY_free(ctx->server_key);
if (ctx->server_ca)
sk_X509_INFO_pop_free(ctx->server_ca, X509_INFO_free);
if (ctx->client_cert) X509_free(ctx->client_cert);
if (ctx->client_key) EVP_PKEY_free(ctx->client_key);
if (ctx->client_ca)
sk_X509_INFO_pop_free(ctx->client_ca, X509_INFO_free);
free(ctx);
mgr->tls_ctx = NULL;
}
}
void mg_tls_ctx_init(struct mg_mgr *mgr, const struct mg_tls_opts *opts) {
static unsigned char s_initialised = 0;
if (!s_initialised) {
SSL_library_init();
s_initialised++;
}
struct mg_tls_ctx *ctx = (struct mg_tls_ctx *) calloc(1, sizeof(*ctx));
if (ctx == NULL) return;
if (opts->server_cert.ptr && opts->server_cert.ptr[0] != '\0') {
struct mg_str key = opts->server_key;
if (!key.ptr) key = opts->server_cert;
if (!(ctx->server_cert =
load_cert(opts->server_cert.ptr, (int) opts->server_cert.len)))
goto fail;
if (!(ctx->server_key = load_key(key.ptr, (int) key.len))) goto fail;
}
if (opts->server_ca.ptr && opts->server_ca.ptr[0] != '\0') {
if (!(ctx->server_ca =
load_ca_certs(opts->server_ca.ptr, (int) opts->server_ca.len)))
goto fail;
}
if (opts->client_cert.ptr && opts->client_cert.ptr[0] != '\0') {
struct mg_str key = opts->client_key;
if (!key.ptr) key = opts->client_cert;
if (!(ctx->client_cert =
load_cert(opts->client_cert.ptr, (int) opts->client_cert.len)))
goto fail;
if (!(ctx->client_key = load_key(key.ptr, (int) key.len))) goto fail;
}
if (opts->client_ca.ptr && opts->client_ca.ptr[0] != '\0') {
if (!(ctx->client_ca =
load_ca_certs(opts->client_ca.ptr, (int) opts->client_ca.len)))
goto fail;
}
mgr->tls_ctx = ctx;
return;
fail:
MG_ERROR(("TLS ctx init error"));
mg_tls_ctx_free(mgr);
}
#endif #endif

View File

@ -5,15 +5,6 @@
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
struct mg_tls_ctx {
X509 *server_cert;
EVP_PKEY *server_key;
STACK_OF(X509_INFO) *server_ca;
X509 *client_cert;
EVP_PKEY *client_key;
STACK_OF(X509_INFO) *client_ca;
};
struct mg_tls { struct mg_tls {
SSL_CTX *ctx; SSL_CTX *ctx;
SSL *ssl; SSL *ssl;

View File

@ -7,7 +7,7 @@ struct url {
int mg_url_is_ssl(const char *url) { int mg_url_is_ssl(const char *url) {
return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 || return strncmp(url, "wss:", 4) == 0 || strncmp(url, "https:", 6) == 0 ||
strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 || strncmp(url, "mqtts:", 6) == 0 || strncmp(url, "ssl:", 4) == 0 ||
strncmp(url, "tls:", 4) == 0; strncmp(url, "tls:", 4) == 0 || strncmp(url, "tcps:", 5) == 0;
} }
static struct url urlparse(const char *url) { static struct url urlparse(const char *url) {

View File

@ -113,9 +113,8 @@ uint64_t mg_millis(void) {
return GetTickCount(); return GetTickCount();
#elif MG_ARCH == MG_ARCH_RP2040 #elif MG_ARCH == MG_ARCH_RP2040
return time_us_64() / 1000; return time_us_64() / 1000;
#elif MG_ARCH == MG_ARCH_ESP32 #elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_ESP32 || \
return esp_timer_get_time() / 1000; MG_ARCH == MG_ARCH_FREERTOS
#elif MG_ARCH == MG_ARCH_ESP8266 || MG_ARCH == MG_ARCH_FREERTOS
return xTaskGetTickCount() * portTICK_PERIOD_MS; return xTaskGetTickCount() * portTICK_PERIOD_MS;
#elif MG_ARCH == MG_ARCH_AZURERTOS #elif MG_ARCH == MG_ARCH_AZURERTOS
return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND); return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND);

View File

@ -17,7 +17,7 @@ static int s_num_tests = 0;
#define FETCH_BUF_SIZE (256 * 1024) #define FETCH_BUF_SIZE (256 * 1024)
// Self-signed CA, CERT, KEY // Self-signed CA, CERT, KEY
static const char *s_tls_ca = const char *s_tls_ca =
"-----BEGIN CERTIFICATE-----\n" "-----BEGIN CERTIFICATE-----\n"
"MIIBqjCCAU+gAwIBAgIUESoOPGqMhf9uarzblVFwzrQweMcwCgYIKoZIzj0EAwIw\n" "MIIBqjCCAU+gAwIBAgIUESoOPGqMhf9uarzblVFwzrQweMcwCgYIKoZIzj0EAwIw\n"
"RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n" "RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n"
@ -30,7 +30,7 @@ static const char *s_tls_ca =
"fL8OKzndegxOaB0CIQCPwSIwEGFdURDqCC0CY2dnMrUGY5ZXu3hHCojZGS7zvg==\n" "fL8OKzndegxOaB0CIQCPwSIwEGFdURDqCC0CY2dnMrUGY5ZXu3hHCojZGS7zvg==\n"
"-----END CERTIFICATE-----\n"; "-----END CERTIFICATE-----\n";
static const char *s_tls_cert = const char *s_tls_cert =
"-----BEGIN CERTIFICATE-----\n" "-----BEGIN CERTIFICATE-----\n"
"MIIBhzCCASygAwIBAgIUbnMoVd8TtWH1T09dANkK2LU6IUswCgYIKoZIzj0EAwIw\n" "MIIBhzCCASygAwIBAgIUbnMoVd8TtWH1T09dANkK2LU6IUswCgYIKoZIzj0EAwIw\n"
"RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n" "RDELMAkGA1UEBhMCSUUxDzANBgNVBAcMBkR1YmxpbjEQMA4GA1UECgwHQ2VzYW50\n"
@ -43,7 +43,7 @@ static const char *s_tls_cert =
"BllCI0eYQ9ggp/o=\n" "BllCI0eYQ9ggp/o=\n"
"-----END CERTIFICATE-----\n"; "-----END CERTIFICATE-----\n";
static const char *s_tls_key = const char *s_tls_key =
"-----BEGIN PRIVATE KEY-----\n" "-----BEGIN PRIVATE KEY-----\n"
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglNni0t9Dg9icgG8w\n" "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQglNni0t9Dg9icgG8w\n"
"kbfxWSS+TuNgbtNybIQXcm3NHpmhRANCAASS4EacicM3qXTrNVVDVVys68fkUO70\n" "kbfxWSS+TuNgbtNybIQXcm3NHpmhRANCAASS4EacicM3qXTrNVVDVVys68fkUO70\n"
@ -666,6 +666,8 @@ static void test_mqtt(void) {
} }
static void eh1(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void eh1(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
struct mg_tls_opts *topts = (struct mg_tls_opts *) fn_data;
if (ev == MG_EV_ACCEPT && topts != NULL) mg_tls_init(c, topts);
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
MG_INFO(("[%.*s %.*s] message len %d", (int) hm->method.len, hm->method.ptr, MG_INFO(("[%.*s %.*s] message len %d", (int) hm->method.len, hm->method.ptr,
@ -757,21 +759,20 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url,
int i; int i;
struct mg_connection *c = NULL; struct mg_connection *c = NULL;
va_list ap; va_list ap;
if (mgr->tls_ctx == NULL) {
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
opts.client_ca = mg_unpacked("test/data/ca.pem");
if (strstr(url, "127.0.0.1") != NULL) {
// Local connection, use self-signed certificates
opts.client_ca = mg_str(s_tls_ca);
opts.server_cert = mg_str(s_tls_cert);
opts.server_key = mg_str(s_tls_key);
}
mg_tls_ctx_init(mgr, &opts);
if (mgr->tls_ctx == NULL) fd.closed = 1;
}
c = mg_http_connect(mgr, url, fcb, &fd); c = mg_http_connect(mgr, url, fcb, &fd);
ASSERT(c != NULL); ASSERT(c != NULL);
if (c != NULL && mg_url_is_ssl(url)) {
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); // read CA from packed_fs
opts.ca = mg_unpacked("test/data/ca.pem");
if (strstr(url, "127.0.0.1") != NULL) {
// Local connection, use self-signed certificates
opts.ca = mg_str(s_tls_ca);
//opts.cert = mg_str(s_tls_cert);
//opts.key = mg_str(s_tls_key);
}
mg_tls_init(c, &opts);
}
// c->is_hexdumping = 1; // c->is_hexdumping = 1;
va_start(ap, fmt); va_start(ap, fmt);
mg_vprintf(c, fmt, &ap); mg_vprintf(c, fmt, &ap);
@ -1198,19 +1199,19 @@ static void test_http_404(void) {
} }
static void test_tls(void) { static void test_tls(void) {
// return;
#if MG_TLS #if MG_TLS
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts));
opts.client_ca = mg_str(s_tls_ca);
opts.server_cert = mg_str(s_tls_cert);
opts.server_key = mg_str(s_tls_key);
struct mg_mgr mgr; struct mg_mgr mgr;
struct mg_connection *c; struct mg_connection *c;
const char *url = "https://127.0.0.1:12347"; const char *url = "https://127.0.0.1:12347";
char buf[FETCH_BUF_SIZE]; char buf[FETCH_BUF_SIZE];
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts));
//opts.ca = mg_str(s_tls_ca);
opts.cert = mg_str(s_tls_cert);
opts.key = mg_str(s_tls_key);
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
mg_tls_ctx_init(&mgr, &opts); c = mg_http_listen(&mgr, url, eh1, &opts);
c = mg_http_listen(&mgr, url, eh1, NULL);
ASSERT(c != NULL); ASSERT(c != NULL);
ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200); ASSERT(fetch(&mgr, buf, url, "GET /a.txt HTTP/1.0\n\n") == 200);
// MG_INFO(("%s", buf)); // MG_INFO(("%s", buf));
@ -1242,19 +1243,19 @@ static void f3(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
} }
static void test_http_client(void) { static void test_http_client(void) {
struct mg_tls_opts opts;
struct mg_mgr mgr; struct mg_mgr mgr;
struct mg_connection *c = NULL; struct mg_connection *c = NULL;
const char *url = "http://cesanta.com";
int i, ok = 0; int i, ok = 0;
size_t size = 0; // read CA certs from plain file size_t size = 0; // read CA certs from plain file
char *data = mg_file_read(&mg_fs_posix, "test/data/ca.pem", &size); char *data = mg_file_read(&mg_fs_posix, "test/data/ca.pem", &size);
struct mg_tls_opts opts;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
opts.client_ca = mg_str_n(data, size); c = mg_http_connect(&mgr, url, f3, &ok);
mg_tls_ctx_init(&mgr, &opts);
c = mg_http_connect(&mgr, "http://cesanta.com", f3, &ok);
ASSERT(c != NULL); ASSERT(c != NULL);
for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10); for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1);
MG_INFO(("%d", ok));
ASSERT(ok == 301); ASSERT(ok == 301);
c->is_closing = 1; c->is_closing = 1;
mg_mgr_poll(&mgr, 0); mg_mgr_poll(&mgr, 0);
@ -1262,25 +1263,37 @@ static void test_http_client(void) {
#if MG_TLS #if MG_TLS
c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok); c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok);
ASSERT(c != NULL); ASSERT(c != NULL);
for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1000); if (c != NULL) {
opts.ca = mg_str_n(data, size);
//opts.name = mg_url_host(url);
mg_tls_init(c, &opts);
}
for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 1);
ASSERT(ok == 200); ASSERT(ok == 200);
c->is_closing = 1; c->is_closing = 1;
mg_mgr_poll(&mgr, 1); mg_mgr_poll(&mgr, 1);
#if 0
{ #if 1
// TODO(): Test failed host validation, mg_tls_init() is called on // Test failed host validation
// mg_connect() if url is https, c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok);
// hence we fake it and manually call it later with a wrong host name ASSERT(c != NULL);
const char *furl = "http://cesanta.com:443"; opts.name = mg_str("dummy"); // Set some invalid hostname value
struct mg_str srvname; mg_tls_init(c, &opts);
srvname = mg_str("dummy"); ok = 0;
c = mg_http_connect(&mgr, furl, f3, &ok); for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
ASSERT(c != NULL); MG_INFO(("OK: %d", ok));
mg_tls_init(c, srvname); ASSERT(ok == 777);
for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10); mg_mgr_poll(&mgr, 1);
ASSERT(ok == 777);
mg_mgr_poll(&mgr, 1); opts.name = mg_str("cesanta.com");
} opts.ca = mg_str("");
c = mg_http_connect(&mgr, "https://cesanta.com", f3, &ok);
mg_tls_init(c, &opts);
ok = 0;
for (i = 0; i < 500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
MG_INFO(("OK: %d", ok));
ASSERT(ok == 200);
mg_mgr_poll(&mgr, 1);
#endif #endif
#endif #endif
@ -1308,11 +1321,12 @@ static void test_host_validation(void) {
int i, ok = 0; int i, ok = 0;
memset(&opts, 0, sizeof(opts)); memset(&opts, 0, sizeof(opts));
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
mg_tls_ctx_init(&mgr, &opts);
ok = 0; ok = 0;
c = mg_http_connect(&mgr, url, f3, &ok); c = mg_http_connect(&mgr, url, f3, &ok);
ASSERT(c != NULL); ASSERT(c != NULL);
opts.ca = mg_unpacked("test/data/ca.pem");
mg_tls_init(c, &opts);
for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10); for (i = 0; i < 1500 && ok <= 0; i++) mg_mgr_poll(&mgr, 10);
ASSERT(ok == 200); ASSERT(ok == 200);
c->is_closing = 1; c->is_closing = 1;
@ -1734,12 +1748,43 @@ static void test_timer(void) {
mg_timer_free(&head, &t3); mg_timer_free(&head, &t3);
ASSERT(head == NULL); ASSERT(head == NULL);
// Start a timer, then shift system time a long time back and long time forth
v1 = 0;
mg_timer_init(&head, &t1, 5, MG_TIMER_REPEAT, f1, &v1);
mg_timer_poll(&head, 0);
ASSERT(v1 == 0);
// Shift a long time forth, make sure it ticks
mg_timer_poll(&head, 100);
ASSERT(v1 == 1);
mg_timer_poll(&head, 101);
ASSERT(v1 == 1);
mg_timer_poll(&head, 102);
ASSERT(v1 == 1);
mg_timer_poll(&head, 103);
ASSERT(v1 == 1);
mg_timer_poll(&head, 104);
ASSERT(v1 == 1);
mg_timer_poll(&head, 105);
ASSERT(v1 == 2);
// Shift a long time back, make sure it ticks
mg_timer_poll(&head, 50);
ASSERT(v1 == 2);
mg_timer_poll(&head, 60);
ASSERT(v1 == 3);
mg_timer_free(&head, &t1);
ASSERT(head == NULL);
// Test proper timer deallocation, see #1539 // Test proper timer deallocation, see #1539
{ {
struct mg_mgr mgr; struct mg_mgr mgr;
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
mg_timer_add(&mgr, 1, MG_TIMER_REPEAT, f1, NULL); mg_timer_add(&mgr, 1, MG_TIMER_REPEAT, f1, NULL);
ASSERT(mgr.timers != NULL);
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
ASSERT(mgr.timers == NULL);
ASSERT(mgr.conns == NULL); ASSERT(mgr.conns == NULL);
} }
} }
@ -3162,10 +3207,10 @@ int main(void) {
test_commalist(); test_commalist();
test_base64(); test_base64();
test_http_get_var(); test_http_get_var();
test_http_client();
test_tls(); test_tls();
test_ws(); test_ws();
test_ws_fragmentation(); test_ws_fragmentation();
test_http_client();
test_host_validation(); test_host_validation();
test_http_server(); test_http_server();
test_http_404(); test_http_404();