Browse Source

Merge pull request #919 from Qinch/master

civetweb support mbedtsl v2.16.2
bel2125 4 years ago
parent
commit
8eb091a09e
2 changed files with 322 additions and 5 deletions
  1. 145 5
      src/civetweb.c
  2. 177 0
      src/mod_mbedtls.inl

+ 145 - 5
src/civetweb.c

@@ -446,6 +446,9 @@ _civet_safe_clock_gettime(int clk_id, struct timespec *t)
 #include "zlib.h"
 #endif
 
+#if defined(USE_MBEDTLS)
+#include "mod_mbedtls.inl"
+#endif
 
 /********************************************************************/
 /* CivetWeb configuration defines */
@@ -1876,9 +1879,11 @@ typedef int socklen_t;
 #endif
 
 
-#if defined(NO_SSL)
-typedef struct SSL SSL; /* dummy for SSL argument to push/pull */
-typedef struct SSL_CTX SSL_CTX;
+#if defined(NO_SSL) 
+   #if !defined(USE_MBEDTLS)
+   typedef struct SSL SSL; /* dummy for SSL argument to push/pull */
+   typedef struct SSL_CTX SSL_CTX;
+   #endif
 #else
 #if defined(NO_SSL_DL)
 #include <openssl/bn.h>
@@ -6531,7 +6536,7 @@ push_inner(struct mg_context *ctx,
 		return -2;
 	}
 
-#if defined(NO_SSL)
+#if defined(NO_SSL) && !defined(USE_MBEDTLS)
 	if (ssl) {
 		return -2;
 	}
@@ -6563,6 +6568,23 @@ push_inner(struct mg_context *ctx,
 			}
 		} else
 #endif
+
+#if defined(USE_MBEDTLS)
+		if (ssl != NULL) {
+			n = mbed_ssl_write(ssl, (const unsigned char *)buf, len);
+			if (n <= 0) {
+				if ((n == MBEDTLS_ERR_SSL_WANT_READ)
+				           || (n == MBEDTLS_ERR_SSL_WANT_WRITE) || n == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) {
+					n = 0;
+				} else {
+					fprintf(stderr, "SSL write failed, error %d\n", n);
+					return -2;
+				}
+			} else {
+				err = 0;
+			}
+		} else
+#endif
 		    if (fp != NULL) {
 			n = (int)fwrite(buf, 1, (size_t)len, fp);
 			if (ferror(fp)) {
@@ -6790,6 +6812,47 @@ pull_inner(FILE *fp,
 		}
 #endif
 
+#if defined(USE_MBEDTLS)
+	} else if (conn->ssl != NULL) {
+		/* We already know there is no more data buffered in conn->buf
+		 * but there is more available in the SSL layer. So don't poll
+		 * conn->client.sock yet. */
+		struct pollfd pfd[1];
+		int pollres;
+
+		pfd[0].fd = conn->client.sock;
+		pfd[0].events = POLLIN;
+		pollres = mg_poll(pfd,
+		                  1,
+		                  (int)(timeout * 1000.0),
+		                  &(conn->phys_ctx->stop_flag));
+		if (conn->phys_ctx->stop_flag) {
+			return -2;
+		}
+
+		if (pollres > 0) {
+			nread = mbed_ssl_read(conn->ssl, (unsigned char *)buf, len);
+			if (nread <= 0) {
+				if ((nread == MBEDTLS_ERR_SSL_WANT_READ)
+					|| (nread == MBEDTLS_ERR_SSL_WANT_WRITE)|| nread == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) {
+					nread = 0;
+				} else {
+					fprintf(stderr, "SSL read failed, error %d\n", nread);
+					return -2;
+				}
+			} else {
+				err = 0;
+			}
+
+		} else if (pollres < 0) {
+			/* Error */
+			return -2;
+		} else {
+			/* pollres = 0 means timeout */
+			nread = 0;
+		}
+#endif
+
 	} else {
 		struct mg_pollfd pfd[1];
 		int pollres;
@@ -16881,6 +16944,34 @@ uninitialize_ssl(void)
 }
 #endif /* !NO_SSL */
 
+#if defined(USE_MBEDTLS)
+/* Check if SSL is required.
+ * If so, set up ctx->ssl_ctx pointer. */
+static int
+mg_sslctx_init(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
+{
+	if (!phys_ctx) {
+		return 0;
+	}
+
+	if (!dom_ctx) {
+		dom_ctx = &(phys_ctx->dd);
+	}
+
+	if (!is_ssl_port_used(dom_ctx->config[LISTENING_PORTS])) {
+		/* No SSL port is set. No need to setup SSL. */
+		return 1;
+	}
+
+	dom_ctx->ssl_ctx = mg_calloc(1, sizeof(*dom_ctx->ssl_ctx));	
+	if (dom_ctx->ssl_ctx == NULL) {
+		fprintf(stderr, "ssl_ctx malloc failed\n");
+		return 0;
+	}
+
+	return mbed_sslctx_init(dom_ctx->ssl_ctx, dom_ctx->config[SSL_CERTIFICATE]) == 0 ? 1 : 0;
+}
+#endif /* USE_MBEDTLS */
 
 #if !defined(NO_FILESYSTEMS)
 static int
@@ -17139,6 +17230,14 @@ close_connection(struct mg_connection *conn)
 	conn->conn_state = 7; /* closing */
 #endif
 
+#if defined(USE_MBEDTLS)
+	if (conn->ssl != NULL) {
+		mbed_ssl_close(conn->ssl);
+		mg_free(conn->ssl);
+		conn->ssl = NULL;
+	}
+#endif
+
 #if !defined(NO_SSL)
 	if (conn->ssl != NULL) {
 		/* Run SSL_shutdown twice to ensure completely close SSL connection
@@ -18883,6 +18982,19 @@ worker_thread_run(struct mg_connection *conn)
 		conn->request_info.is_ssl = conn->client.is_ssl;
 
 		if (conn->client.is_ssl) {
+#if defined(USE_MBEDTLS)
+			/* HTTPS connection */
+			if (mbed_ssl_accept(&conn->ssl,
+				conn->dom_ctx->ssl_ctx, &conn->client.sock) == 0) {
+				/* conn->dom_ctx is set in get_request */
+				/* process HTTPS connection */
+				process_new_connection(conn);
+			} else {
+				/* make sure the connection is cleaned up on SSL failure */
+				close_connection(conn);
+			}
+#endif
+
 #if !defined(NO_SSL)
 			/* HTTPS connection */
 			if (sslize(conn, SSL_accept, NULL)) {
@@ -19301,6 +19413,14 @@ free_context(struct mg_context *ctx)
 		mg_free(tmp_rh);
 	}
 
+#if defined(USE_MBEDTLS)
+	if (ctx->dd.ssl_ctx != NULL) {
+		mbed_sslctx_uninit(ctx->dd.ssl_ctx);
+		mg_free(ctx->dd.ssl_ctx);
+		ctx->dd.ssl_ctx = NULL;
+	}
+#endif
+
 #if !defined(NO_SSL)
 	/* Deallocate SSL context */
 	if (ctx->dd.ssl_ctx != NULL) {
@@ -19783,6 +19903,26 @@ static
 	}
 #endif
 
+#if defined(USE_MBEDTLS)
+	if (!mg_sslctx_init(ctx, NULL)) {
+		const char *err_msg = "Error initializing SSL context";
+		/* Fatal error - abort start. */
+		mg_cry_ctx_internal(ctx, "%s", err_msg);
+
+		if ((error != NULL) && (error->text_buffer_size > 0)) {
+			mg_snprintf(NULL,
+			            NULL, /* No truncation check for error buffers */
+			            error->text,
+			            error->text_buffer_size,
+			            "%s",
+			            err_msg);
+		}
+		free_context(ctx);
+		pthread_setspecific(sTlsKey, NULL);
+		return NULL;
+	}
+#endif
+
 #if !defined(NO_SSL)
 	if (!init_ssl_ctx(ctx, NULL)) {
 		const char *err_msg = "Error initializing SSL context";
@@ -20288,7 +20428,7 @@ mg_check_feature(unsigned feature)
 #if !defined(NO_FILES)
 	                                    | MG_FEATURES_FILES
 #endif
-#if !defined(NO_SSL)
+#if !defined(NO_SSL) || defined(USE_MBEDTLS)
 	                                    | MG_FEATURES_SSL
 #endif
 #if !defined(NO_CGI)

+ 177 - 0
src/mod_mbedtls.inl

@@ -0,0 +1,177 @@
+#if defined(USE_MBEDTLS)  // USE_MBEDTLS used with NO_SSL
+
+#include <string.h>
+#include "mbedtls/certs.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/net.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/error.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/platform.h"
+
+typedef mbedtls_ssl_context SSL;
+
+typedef struct {
+    mbedtls_ssl_config conf; /* SSL configuration */
+    mbedtls_x509_crt cert; /* Certificate */
+    mbedtls_ctr_drbg_context ctr; /* Counter random generator state */
+    mbedtls_entropy_context entropy; /* Entropy context */
+    mbedtls_pk_context pkey; /* Private key */
+} SSL_CTX;
+
+// public api
+int mbed_sslctx_init(SSL_CTX *ctx, const char *crt);
+void mbed_sslctx_uninit(SSL_CTX *ctx);
+void mbed_ssl_close(mbedtls_ssl_context *ssl);
+int mbed_ssl_accept(mbedtls_ssl_context **ssl, SSL_CTX *ssl_ctx, int *sock);
+int mbed_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, int len);
+int mbed_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, int len);
+
+static void mbed_debug(void *context, int level, const char *file, int line, const char *str);
+static int mbed_ssl_handshake(mbedtls_ssl_context *ssl);
+
+int
+mbed_sslctx_init(SSL_CTX *ctx, const char *crt)
+{
+    mbedtls_ssl_config *conf;
+    int rc;
+
+    fprintf(stdout, "Initializing MbedTLS SSL\n");
+    if (ctx == NULL || crt == NULL) {
+        return -1;
+    }
+
+    mbedtls_entropy_init(&ctx->entropy);
+
+    conf = &ctx->conf;
+    mbedtls_ssl_config_init(conf);
+
+    // set debug level
+    mbedtls_debug_set_threshold(1);
+    mbedtls_ssl_conf_dbg(conf, mbed_debug, stdout);
+    mbedtls_pk_init(&ctx->pkey);
+    mbedtls_ctr_drbg_init(&ctx->ctr);
+    mbedtls_x509_crt_init(&ctx->cert);
+    if ((rc = mbedtls_ctr_drbg_seed(&ctx->ctr,
+                                    mbedtls_entropy_func,
+                                    &ctx->entropy,
+                                    (unsigned char *)"CivetWeb",
+                                    strlen("CivetWeb")))
+        != 0) {
+        fprintf(stderr, "Cannot seed rng\n");
+        return -1;
+    }
+
+    if (mbedtls_pk_parse_keyfile(&ctx->pkey, crt, NULL) != 0) {
+        fprintf(stderr, "parse key file failed\n");
+        return -1;
+    }
+
+    if (mbedtls_x509_crt_parse_file(&ctx->cert, crt) != 0) {
+        fprintf(stderr, "parse crt file faied\n");
+        return -1;
+    }
+
+    if ((rc = mbedtls_ssl_config_defaults(conf,
+                                            MBEDTLS_SSL_IS_SERVER,
+                                            MBEDTLS_SSL_TRANSPORT_STREAM,
+                                            MBEDTLS_SSL_PRESET_DEFAULT))
+        != 0) {
+        fprintf(stderr, "Cannot set mbedtls defaults\n");
+        return -1;
+    }
+
+    mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, &ctx->ctr);
+
+    // Set auth mode if peer cert should be verified
+    mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
+    mbedtls_ssl_conf_ca_chain(conf, NULL, NULL);
+
+    // Configure server cert and key
+    if ((rc = mbedtls_ssl_conf_own_cert(conf, &ctx->cert, &ctx->pkey))
+        != 0) {
+        fprintf(stderr, "Cannot define certificate and private key\n");
+        return -1;
+    }
+    return 0;
+}
+
+void 
+mbed_sslctx_uninit(SSL_CTX *ctx)
+{
+    mbedtls_ctr_drbg_free(&ctx->ctr);
+    mbedtls_pk_free(&ctx->pkey);
+    mbedtls_x509_crt_free(&ctx->cert);
+    mbedtls_entropy_free(&ctx->entropy);
+    mbedtls_ssl_config_free(&ctx->conf);
+}
+
+int
+mbed_ssl_accept(mbedtls_ssl_context **ssl, SSL_CTX *ssl_ctx, int *sock)
+{
+    *ssl = calloc(1, sizeof(**ssl));
+    if (*ssl == NULL) {
+        fprintf(stderr, "malloc ssl failed\n");
+        return -1;
+    }
+
+    mbedtls_ssl_init(*ssl);
+    mbedtls_ssl_setup(*ssl, &ssl_ctx->conf);
+	mbedtls_ssl_set_bio(*ssl, sock, mbedtls_net_send, mbedtls_net_recv, NULL);
+    if (mbed_ssl_handshake(*ssl) != 0) {
+        fprintf(stderr, "handshake failed\n");
+        return -1;
+    }
+    return 0;
+}
+
+void
+mbed_ssl_close(mbedtls_ssl_context *ssl)
+{
+    mbedtls_ssl_close_notify(ssl);
+    mbedtls_ssl_free(ssl);
+    ssl = NULL;
+}
+
+static int
+mbed_ssl_handshake(mbedtls_ssl_context *ssl)
+{
+    int rc;
+    while ((rc = mbedtls_ssl_handshake(ssl)) != 0) {
+		if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE && rc != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)  {
+            break;
+        }
+    }
+
+    fprintf(stdout, "mbedtls handshake rc:%d state:%d\n", rc, ssl->state);
+    return rc;
+}
+
+int
+mbed_ssl_read(mbedtls_ssl_context *ssl, unsigned char *buf, int len)
+{
+    int rc = mbedtls_ssl_read(ssl, buf, len);
+    fprintf(stdout, "mbedtls: mbedtls_ssl_read %d\n", rc);
+    return rc;
+}
+
+int
+mbed_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, int len)
+{
+    int rc = mbedtls_ssl_write(ssl, buf, len);
+    fprintf(stdout, "mbedtls: mbedtls_ssl_write:%d\n", rc);
+    return rc;
+}
+
+static void
+mbed_debug(void *context, int level, const char *file, int line, const char *str)
+{
+    (void)level;
+    mbedtls_fprintf((FILE *)context, "file:%s line:%d str:%s\n", file, line, str);
+}
+
+#endif /* USE_MBEDTLS */