From 516001db8a6ac1a10b75e6a9d152831de274e8be Mon Sep 17 00:00:00 2001
From: Andy Green <andy@warmcat.com>
Date: Wed, 8 Nov 2017 14:21:03 +0800
Subject: [PATCH] esp32-selfsigned
---
Makefile.projbuild | 1 +
lib/context.c | 9 +-
lib/libwebsockets.h | 4 +
lib/plat/lws-plat-esp32.c | 198 ++++++++++++++++++++++++++++++------
lib/plat/lws-plat-esp8266.c | 2 +-
lib/plat/lws-plat-optee.c | 2 +-
lib/plat/lws-plat-unix.c | 2 +-
lib/plat/lws-plat-win.c | 2 +-
lib/service.c | 3 +-
lib/tls/mbedtls/server.c | 10 +-
lib/tls/tls.c | 27 ++++-
11 files changed, 214 insertions(+), 46 deletions(-)
create mode 100644 Makefile.projbuild
diff --git a/Makefile.projbuild b/Makefile.projbuild
new file mode 100644
index 00000000..3145eaf4
--- /dev/null
+++ b/Makefile.projbuild
@@ -0,0 +1 @@
+CPPFLAGS += -I$(BUILD_DIR_BASE)/libwebsockets/include
diff --git a/lib/context.c b/lib/context.c
index 4dc1c0f0..ca211da7 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -275,10 +275,10 @@ lws_protocol_init(struct lws_context *context)
if (vh->protocols[n].callback(&wsi,
LWS_CALLBACK_PROTOCOL_INIT, NULL,
(void *)pvo, 0)) {
- lwsl_err("%s: vhost %s failed init\n", __func__,
+ lws_free(vh->protocol_vh_privs[n]);
+ vh->protocol_vh_privs[n] = NULL;
+ lwsl_err("%s: protocol %s failed init\n", __func__,
vh->protocols[n].name);
- context->doing_protocol_init = 0;
- return 1;
}
}
@@ -855,7 +855,8 @@ lws_create_vhost(struct lws_context *context,
/* for the case we are adding a vhost much later, after server init */
if (context->protocol_init_done)
- lws_protocol_init(context);
+ if (lws_protocol_init(context))
+ goto bail;
return vh;
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index df232cd3..5b9b2236 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -4306,6 +4306,10 @@ lws_sql_purify(char *escaped, const char *string, int len);
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_json_purify(char *escaped, const char *string, int len);
+
+LWS_VISIBLE int
+lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
+ int len);
///@}
/*! \defgroup ev libev helpers
diff --git a/lib/plat/lws-plat-esp32.c b/lib/plat/lws-plat-esp32.c
index b9b2c63b..ed614e06 100644
--- a/lib/plat/lws-plat-esp32.c
+++ b/lib/plat/lws-plat-esp32.c
@@ -1601,8 +1601,9 @@ lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
part = lws_esp_ota_get_boot_partition();
(void)part;
+ info->vhost_name = "default";
info->port = 443;
- info->fd_limit_per_thread = 10;
+ info->fd_limit_per_thread = 30;
info->max_http_header_pool = 16;
info->max_http_header_data = 512;
info->pt_serv_buf_size = 2048;
@@ -1612,8 +1613,8 @@ lws_esp32_set_creation_defaults(struct lws_context_creation_info *info)
info->options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
- info->ssl_cert_filepath = "ssl-pub.pem";
- info->ssl_private_key_filepath = "ssl-pri.pem";
+// info->ssl_cert_filepath = "default-cert.pem";
+// info->ssl_private_key_filepath = "default-key.pem";
}
int
@@ -1655,34 +1656,147 @@ lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i,
return 0;
}
-struct lws_context *
-lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
+static int
+_rngf(void *context, unsigned char *buf, size_t len)
{
- const esp_partition_t *part = lws_esp_ota_get_boot_partition();
- struct lws_context *context;
- struct lws_esp32_image i;
- struct lws_vhost *vhost;
+ if ((size_t)lws_get_random(context, buf, len) == len)
+ return 0;
+
+ return -1;
+}
+
+int
+lws_esp32_selfsigned(struct lws_vhost *vhost)
+{
+ mbedtls_x509write_cert crt;
+ char subject[200];
+ mbedtls_pk_context mpk;
+ int buf_size = 4096, n;
+ uint8_t *buf = malloc(buf_size); /* malloc because given to user code */
+ mbedtls_mpi mpi;
nvs_handle nvh;
- char buf[512];
size_t s;
- int n;
- ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh));
+ lwsl_notice("%s: %s\n", __func__, vhost->name);
+
+ if (!buf)
+ return -1;
+
+ if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
+ lwsl_notice("%s: can't open nvs\n", __func__);
+ free(buf);
+ return 1;
+ }
+
n = 0;
- s = 1;
- if (nvs_get_blob(nvh, "ssl-pub.pem", NULL, &s) == ESP_OK)
- n = 1;
- s = 1;
- if (nvs_get_blob(nvh, "ssl-pri.pem", NULL, &s) == ESP_OK)
+ if (!nvs_get_blob(nvh, vhost->alloc_cert_path, NULL, &s))
+ n |= 1;
+ if (!nvs_get_blob(nvh, vhost->key_path, NULL, &s))
n |= 2;
+
nvs_close(nvh);
+ if (n == 3) {
+ lwsl_notice("%s: certs exist\n", __func__);
+ return 0; /* certs already exist */
+ }
+
+ lwsl_notice("%s: creating selfsigned initial certs\n", __func__);
+
+ mbedtls_x509write_crt_init(&crt);
+
+ mbedtls_pk_init(&mpk);
+ if (mbedtls_pk_setup(&mpk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))) {
+ lwsl_notice("%s: pk_setup failed\n", __func__);
+ goto fail;
+ }
+ lwsl_notice("%s: generating 2048-bit RSA keypair... "
+ "this may take a minute or so...\n", __func__);
+ n = mbedtls_rsa_gen_key(mbedtls_pk_rsa(mpk), _rngf, vhost->context,
+ 2048, 65537);
+ if (n) {
+ lwsl_notice("%s: failed to generate keys\n", __func__);
+ goto fail1;
+ }
+ lwsl_notice("%s: keys done\n", __func__);
+
+ /* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
+
+ lws_snprintf(subject, sizeof(subject) - 1,
+ "C=TW,ST=New Taipei City,L=Taipei,O=warmcat,CN=%s",
+ lws_esp32.hostname);
- if (n != 3) {
- /* we are not configured for SSL yet... fall back to port 80 / http */
- info->port = 80;
- info->options &= ~LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
- lwsl_notice("No SSL certs... using port 80\n");
+ if (mbedtls_x509write_crt_set_subject_name(&crt, subject)) {
+ lwsl_notice("set SN failed\n");
+ goto fail1;
}
+ mbedtls_x509write_crt_set_subject_key(&crt, &mpk);
+ if (mbedtls_x509write_crt_set_issuer_name(&crt, subject)) {
+ lwsl_notice("set IN failed\n");
+ goto fail1;
+ }
+ mbedtls_x509write_crt_set_issuer_key(&crt, &mpk);
+
+ lws_get_random(vhost->context, &n, sizeof(n));
+ lws_snprintf(subject, sizeof(subject), "%d", n);
+
+ mbedtls_mpi_init(&mpi);
+ mbedtls_mpi_read_string(&mpi, 10, subject);
+ mbedtls_x509write_crt_set_serial(&crt, &mpi);
+ mbedtls_mpi_free(&mpi);
+
+ mbedtls_x509write_crt_set_validity(&crt, "20171105235959",
+ "20491231235959");
+
+ mbedtls_x509write_crt_set_key_usage(&crt,
+ MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
+ MBEDTLS_X509_KU_KEY_ENCIPHERMENT);
+
+
+ mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
+
+ n = mbedtls_x509write_crt_pem(&crt, buf, buf_size, _rngf,
+ vhost->context);
+ if (n < 0) {
+ lwsl_notice("%s: write crt der failed\n", __func__);
+ goto fail1;
+ }
+
+ lws_plat_write_cert(vhost, 0, 0, buf, strlen((const char *)buf));
+
+ if (mbedtls_pk_write_key_pem(&mpk, buf, buf_size)) {
+ lwsl_notice("write key pem failed\n");
+ goto fail1;
+ }
+
+ lws_plat_write_cert(vhost, 1, 0, buf, strlen((const char *)buf));
+
+ mbedtls_pk_free(&mpk);
+ mbedtls_x509write_crt_free(&crt);
+
+ lwsl_notice("%s: cert creation complete\n", __func__);
+
+ return n;
+
+fail1:
+ mbedtls_pk_free(&mpk);
+fail:
+ mbedtls_x509write_crt_free(&crt);
+ free(buf);
+
+ nvs_close(nvh);
+
+ return -1;
+}
+
+struct lws_context *
+lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
+{
+ const esp_partition_t *part = lws_esp_ota_get_boot_partition();
+ struct lws_context *context;
+ struct lws_esp32_image i;
+ struct lws_vhost *vhost;
+ struct lws wsi;
+ char buf[512];
context = lws_create_context(info);
if (context == NULL) {
@@ -1706,16 +1820,29 @@ lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh)
lws_set_fops(context, &fops);
+ info->options |= LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX |
+ LWS_SERVER_OPTION_IGNORE_MISSING_CERT;
+
vhost = lws_create_vhost(context, info);
- if (!vhost)
+ if (!vhost) {
lwsl_err("Failed to create vhost\n");
- else
- lws_init_vhost_client_ssl(info, vhost);
+ return NULL;
+ }
+
+ lws_esp32_selfsigned(vhost);
+ wsi.context = vhost->context;
+ wsi.vhost = vhost;
+
+ lws_tls_server_certs_load(vhost, &wsi, info->ssl_cert_filepath,
+ info->ssl_private_key_filepath, NULL, 0, NULL, 0);
+
+ lws_init_vhost_client_ssl(info, vhost);
if (pvh)
*pvh = vhost;
- lws_protocol_init(context);
+ if (lws_protocol_init(context))
+ return NULL;
return context;
}
@@ -1763,24 +1890,31 @@ uint16_t lws_esp32_sine_interp(int n)
/* we write vhostname.cert.pem and vhostname.key.pem, 0 return means OK */
-int
+LWS_VISIBLE int
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
int len)
{
- char name[64];
+ const char *name = vhost->alloc_cert_path;
+ nvs_handle nvh;
int n;
- lws_snprintf(name, sizeof(name) - 1, "%s-%s.pem", vhost->name,
- is_key ? "key" : "cert");
+ if (is_key)
+ name = vhost->key_path;
- if (nvs_open("lws-station", NVS_READWRITE, &nvh))
+ if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
+ lwsl_notice("%s: failed to open nvs\n", __func__);
return 1;
+ }
- n = nvs_set_blob(nvh, ssl_names[n], pss->buffer, pss->file_length);
+ n = nvs_set_blob(nvh, name, buf, len);
if (n)
nvs_commit(nvh);
nvs_close(nvh);
+ lwsl_notice("%s: wrote %s\n", __func__, name);
+
return n;
}
+
+
diff --git a/lib/plat/lws-plat-esp8266.c b/lib/plat/lws-plat-esp8266.c
index 39e11551..e4130c7c 100644
--- a/lib/plat/lws-plat-esp8266.c
+++ b/lib/plat/lws-plat-esp8266.c
@@ -713,7 +713,7 @@ lws_plat_init(struct lws_context *context,
return 0;
}
-int
+LWS_VISIBLE int
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
int len)
{
diff --git a/lib/plat/lws-plat-optee.c b/lib/plat/lws-plat-optee.c
index 1bf72577..3288b2cc 100644
--- a/lib/plat/lws-plat-optee.c
+++ b/lib/plat/lws-plat-optee.c
@@ -326,7 +326,7 @@ lws_plat_init(struct lws_context *context,
return 0;
}
-int
+LWS_VISIBLE int
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
int len)
{
diff --git a/lib/plat/lws-plat-unix.c b/lib/plat/lws-plat-unix.c
index dd7ba972..fe302ce7 100644
--- a/lib/plat/lws-plat-unix.c
+++ b/lib/plat/lws-plat-unix.c
@@ -870,7 +870,7 @@ lws_plat_init(struct lws_context *context,
return 0;
}
-int
+LWS_VISIBLE int
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
int len)
{
diff --git a/lib/plat/lws-plat-win.c b/lib/plat/lws-plat-win.c
index c5c0afc8..031ae51b 100644
--- a/lib/plat/lws-plat-win.c
+++ b/lib/plat/lws-plat-win.c
@@ -755,7 +755,7 @@ int fork(void)
exit(0);
}
-int
+LWS_VISIBLE int
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
int len)
{
diff --git a/lib/service.c b/lib/service.c
index adf8efc9..aed1ac78 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -983,7 +983,8 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
int more;
if (!context->protocol_init_done)
- lws_protocol_init(context);
+ if (lws_protocol_init(context))
+ return -1;
time(&now);
diff --git a/lib/tls/mbedtls/server.c b/lib/tls/mbedtls/server.c
index d351b0c3..88970890 100644
--- a/lib/tls/mbedtls/server.c
+++ b/lib/tls/mbedtls/server.c
@@ -104,13 +104,20 @@ lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
const char *mem_cert, size_t len_mem_cert,
const char *mem_privkey, size_t mem_privkey_len)
{
- int n = lws_tls_generic_cert_checks(vhost, cert, private_key), f = 0;
+ int n, f = 0;
const char *filepath = private_key;
uint8_t *mem = NULL, *p = NULL;
size_t mem_len = 0;
lws_filepos_t flen;
long err;
+ if (!cert || !private_key) {
+ lwsl_notice("%s: no paths\n", __func__);
+ return 0;
+ }
+
+ n = lws_tls_generic_cert_checks(vhost, cert, private_key);
+
if (n == LWS_TLS_EXTANT_NO && (!mem_cert || !mem_privkey))
return 0;
@@ -613,3 +620,4 @@ fail:
return -1;
}
#endif
+
diff --git a/lib/tls/tls.c b/lib/tls/tls.c
index 9204fa28..fcc829d0 100644
--- a/lib/tls/tls.c
+++ b/lib/tls/tls.c
@@ -111,7 +111,7 @@ int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
n = 1;
goto bail;
}
- *buf = lws_malloc(s, "alloc_file");
+ *buf = lws_malloc(s + 1, "alloc_file");
if (!*buf) {
n = 2;
goto bail;
@@ -123,6 +123,9 @@ int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
}
*amount = s;
+ (*buf)[s] = '\0';
+
+ lwsl_notice("%s: nvs: read %s, %d bytes\n", __func__, filename, (int)s);
bail:
nvs_close(nvh);
@@ -286,7 +289,7 @@ lws_tls_check_all_cert_lifetimes(struct lws_context *context)
return 0;
}
-
+#if !defined(LWS_WITH_ESP32)
static int
lws_tls_extant(const char *name)
{
@@ -303,7 +306,7 @@ lws_tls_extant(const char *name)
return n != 1;
}
-
+#endif
/*
* Returns 0 if the filepath "name" exists and can be read from.
*
@@ -337,8 +340,9 @@ lws_tls_extant(const char *name)
enum lws_tls_extant
lws_tls_use_any_upgrade_check_extant(const char *name)
{
- char buf[256];
int n;
+#if !defined(LWS_WITH_ESP32)
+ char buf[256];
lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", name);
if (!lws_tls_extant(buf)) {
@@ -368,6 +372,21 @@ lws_tls_use_any_upgrade_check_extant(const char *name)
if (lws_tls_extant(name))
return LWS_TLS_EXTANT_NO;
+#else
+ nvs_handle nvh;
+ size_t s = 8192;
+
+ if (nvs_open("lws-station", NVS_READWRITE, &nvh)) {
+ lwsl_notice("%s: can't open nvs\n", __func__);
+ return LWS_TLS_EXTANT_NO;
+ }
+
+ n = nvs_get_blob(nvh, name, NULL, &s);
+ nvs_close(nvh);
+
+ if (n)
+ return LWS_TLS_EXTANT_NO;
+#endif
return LWS_TLS_EXTANT_YES;
}
--
GitLab