From d327ee9834f3d8251e55c13fd2ad1ed5005e4896 Mon Sep 17 00:00:00 2001 From: cpq Date: Sat, 30 Jan 2021 13:03:11 +0000 Subject: [PATCH] Improve SNI --- docs/README.md | 14 +++----------- examples/http-client/Makefile | 11 +++++++---- examples/http-client/main.c | 28 +++++++++++++++++++--------- mongoose.c | 15 ++++++++++++--- mongoose.h | 10 +++++----- src/tls.c | 15 ++++++++++++--- src/tls.h | 10 +++++----- test/unit_test.c | 3 +++ 8 files changed, 66 insertions(+), 40 deletions(-) diff --git a/docs/README.md b/docs/README.md index 9bae268b..58a00d97 100644 --- a/docs/README.md +++ b/docs/README.md @@ -952,7 +952,7 @@ Subscribe to topic `topic`. ## TLS -### struct mg\_tls\_opts +### mg\_tls\_init() ```c struct mg_tls_opts { @@ -960,20 +960,12 @@ struct mg_tls_opts { const char *cert; // Certificate const char *certkey; // Certificate key const char *ciphers; // Cipher list - const char *srvname; // If not NULL, enables server name verification + struct mg_str srvname; // If not empty, enables server name verification }; -``` - -Describes TLS parameters - - -### mg\_tls\_init() - -```c int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts); ``` -Turns on TLS on a given connection. +Initialise TLS on a given connection. ## Timers diff --git a/examples/http-client/Makefile b/examples/http-client/Makefile index aa649765..5155a48e 100644 --- a/examples/http-client/Makefile +++ b/examples/http-client/Makefile @@ -1,13 +1,16 @@ PROG ?= example -CFLAGS ?= -DMG_ENABLE_LINES $(CFLAGS_EXTRA) -MBEDTLS_DIR ?= +CFLAGS ?= -DMG_ENABLE_LINES $(EXTRA) -ifeq "$(MBEDTLS_DIR)" "" -else +ifneq ($(MBEDTLS),) CFLAGS += -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -I/usr/include CFLAGS += -L$(MBEDTLS_DIR)/lib -lmbedtls -lmbedcrypto -lmbedx509 endif +ifneq ($(OPENSSL),) +CFLAGS += -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL)/include +CFLAGS += -L$(OPENSSL)/lib -lssl -lcrypto +endif + all: $(PROG) $(DEBUGGER) ./$(PROG) $(ARGS) diff --git a/examples/http-client/main.c b/examples/http-client/main.c index 7415d509..ab50c4f4 100644 --- a/examples/http-client/main.c +++ b/examples/http-client/main.c @@ -1,43 +1,53 @@ -// Copyright (c) 2020 Cesanta Software Limited +// Copyright (c) 2021 Cesanta Software Limited // All rights reserved // // Example HTTP client. Connect to `s_url`, send request, wait for a response, // print the response and exit. +// You can change `s_url` from the command line by executing: ./example YOUR_URL // // To enable SSL/TLS for this client, build it like this: -// make MBEDTLS_DIR=/path/to/your/mbedtls/installation +// make MBEDTLS=/path/to/your/mbedtls/installation +// make OPENSSL=/path/to/your/openssl/installation #include "mongoose.h" -// The very first web page in history +// The very first web page in history. You can replace it from command line static const char *s_url = "http://info.cern.ch"; // Print HTTP response and signal that we're done static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { if (ev == MG_EV_CONNECT) { - // Connected to server + // Connected to server. Extract host name from URL struct mg_str host = mg_url_host(s_url); + // If s_url is https://, tell client connection to use TLS if (mg_url_is_ssl(s_url)) { - // If s_url is https://, tell client connection to use TLS - struct mg_tls_opts opts = {.ca = "ca.pem"}; + // struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = host}; + struct mg_tls_opts opts = {.ca = "ca.pem", .srvname = mg_str("x")}; mg_tls_init(c, &opts); } + // Send request - mg_printf(c, "GET %s HTTP/1.0\r\nHost: %.*s\r\n\r\n", mg_url_uri(s_url), - (int) host.len, host.ptr); + mg_printf(c, + "GET %s HTTP/1.0\r\n" + "Host: %.*s\r\n" + "\r\n", + mg_url_uri(s_url), (int) host.len, host.ptr); } else if (ev == MG_EV_HTTP_MSG) { // Response is received. Print it struct mg_http_message *hm = (struct mg_http_message *) ev_data; printf("%.*s", (int) hm->message.len, hm->message.ptr); c->is_closing = 1; // Tell mongoose to close this connection *(bool *) fn_data = true; // Tell event loop to stop + } else if (ev == MG_EV_ERROR) { + *(bool *) fn_data = true; // Error, tell event loop to stop } } -int main(void) { +int main(int argc, char *argv[]) { struct mg_mgr mgr; // Event manager bool done = false; // Event handler flips it to true + if (argc > 1) s_url = argv[1]; // Use URL from command line mg_log_set("3"); // Set to 0 to disable debug mg_mgr_init(&mgr); // Initialise event manager mg_http_connect(&mgr, s_url, fn, &done); // Create client connection diff --git a/mongoose.c b/mongoose.c index 9c386d89..a74c1d71 100644 --- a/mongoose.c +++ b/mongoose.c @@ -3374,6 +3374,11 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { } mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL); #endif + if (opts->srvname.len > 0) { + char buf[opts->srvname.len + 1]; + sprintf(buf, "%.*s", (int) opts->srvname.len, opts->srvname.ptr); + mbedtls_ssl_set_hostname(&tls->ssl, buf); + } mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); } if (opts->cert != NULL && opts->cert[0] != '\0') { @@ -3502,9 +3507,9 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE); #endif - SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - 0); if (opts->ca != NULL && opts->ca[0] != '\0') { + SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + NULL); if ((rc = SSL_CTX_load_verify_locations(tls->ctx, opts->ca, NULL)) != 1) { mg_error(c, "parse(%s): err %d", opts->ca, mg_tls_err(tls, rc)); goto fail; @@ -3533,7 +3538,11 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { } } if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers); - if (opts->srvname != NULL) SSL_set_tlsext_host_name(tls->ssl, opts->srvname); + if (opts->srvname.len > 0) { + char buf[opts->srvname.len + 1]; + sprintf(buf, "%.*s", (int) opts->srvname.len, opts->srvname.ptr); + SSL_set_tlsext_host_name(tls->ssl, buf); + } c->tls = tls; c->is_tls = 1; c->is_tls_hs = 1; diff --git a/mongoose.h b/mongoose.h index fdbdf95f..6350cb1d 100644 --- a/mongoose.h +++ b/mongoose.h @@ -726,11 +726,11 @@ void mg_http_serve_ssi(struct mg_connection *c, const char *root, struct mg_tls_opts { - const char *ca; // CA certificate file. For both listeners and clients - const char *cert; // Certificate - const char *certkey; // Certificate key - const char *ciphers; // Cipher list - const char *srvname; // If not NULL, enables server name verification + const char *ca; // CA certificate file. For both listeners and clients + const char *cert; // Certificate + const char *certkey; // Certificate key + const char *ciphers; // Cipher list + struct mg_str srvname; // If not empty, enables server name verification }; int mg_tls_init(struct mg_connection *, struct mg_tls_opts *); diff --git a/src/tls.c b/src/tls.c index dd7ac461..c3a7f71a 100644 --- a/src/tls.c +++ b/src/tls.c @@ -105,6 +105,11 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { } mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->ca, NULL); #endif + if (opts->srvname.len > 0) { + char buf[opts->srvname.len + 1]; + sprintf(buf, "%.*s", (int) opts->srvname.len, opts->srvname.ptr); + mbedtls_ssl_set_hostname(&tls->ssl, buf); + } mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED); } if (opts->cert != NULL && opts->cert[0] != '\0') { @@ -233,9 +238,9 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { SSL_set_options(tls->ssl, SSL_OP_CIPHER_SERVER_PREFERENCE); #endif - SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - 0); if (opts->ca != NULL && opts->ca[0] != '\0') { + SSL_set_verify(tls->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + NULL); if ((rc = SSL_CTX_load_verify_locations(tls->ctx, opts->ca, NULL)) != 1) { mg_error(c, "parse(%s): err %d", opts->ca, mg_tls_err(tls, rc)); goto fail; @@ -264,7 +269,11 @@ int mg_tls_init(struct mg_connection *c, struct mg_tls_opts *opts) { } } if (opts->ciphers != NULL) SSL_set_cipher_list(tls->ssl, opts->ciphers); - if (opts->srvname != NULL) SSL_set_tlsext_host_name(tls->ssl, opts->srvname); + if (opts->srvname.len > 0) { + char buf[opts->srvname.len + 1]; + sprintf(buf, "%.*s", (int) opts->srvname.len, opts->srvname.ptr); + SSL_set_tlsext_host_name(tls->ssl, buf); + } c->tls = tls; c->is_tls = 1; c->is_tls_hs = 1; diff --git a/src/tls.h b/src/tls.h index b25087ae..a7a2c40c 100644 --- a/src/tls.h +++ b/src/tls.h @@ -2,11 +2,11 @@ #include "net.h" struct mg_tls_opts { - const char *ca; // CA certificate file. For both listeners and clients - const char *cert; // Certificate - const char *certkey; // Certificate key - const char *ciphers; // Cipher list - const char *srvname; // If not NULL, enables server name verification + const char *ca; // CA certificate file. For both listeners and clients + const char *cert; // Certificate + const char *certkey; // Certificate key + const char *ciphers; // Cipher list + struct mg_str srvname; // If not empty, enables server name verification }; int mg_tls_init(struct mg_connection *, struct mg_tls_opts *); diff --git a/test/unit_test.c b/test/unit_test.c index b88db0dc..0a233d9e 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -413,12 +413,15 @@ static int fetch(struct mg_mgr *mgr, char *buf, const char *url, ASSERT(c != NULL); if (mg_url_is_ssl(url)) { struct mg_tls_opts opts; + struct mg_str host = mg_url_host(url); memset(&opts, 0, sizeof(opts)); opts.ca = "./test/data/ca.pem"; if (strstr(url, "127.0.0.1") != NULL) { // Local connection, use self-signed certificates opts.ca = "./test/data/ss_ca.pem"; opts.cert = "./test/data/ss_client.pem"; + } else { + opts.srvname = host; } mg_tls_init(c, &opts); // c->is_hexdumping = 1;