diff --git a/Makefile.projbuild b/Makefile.projbuild new file mode 100644 index 000000000..3145eaf46 --- /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 4dc1c0f09..ca211da7c 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 df232cd32..5b9b22360 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 b9b2c63b0..ed614e060 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,6 +1656,138 @@ lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i, return 0; } +static int +_rngf(void *context, unsigned char *buf, size_t len) +{ + 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; + size_t s; + + 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; + 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 (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) { @@ -1662,27 +1795,8 @@ lws_esp32_init(struct lws_context_creation_info *info, struct lws_vhost **pvh) struct lws_context *context; struct lws_esp32_image i; struct lws_vhost *vhost; - nvs_handle nvh; + struct lws wsi; char buf[512]; - size_t s; - int n; - - ESP_ERROR_CHECK(nvs_open("lws-station", NVS_READWRITE, &nvh)); - 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) - n |= 2; - nvs_close(nvh); - - 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"); - } 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 39e115510..e4130c7c8 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 1bf725770..3288b2cc2 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 dd7ba9726..fe302ce73 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 c5c0afc8c..031ae51bb 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 adf8efc96..aed1ac783 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 d351b0c3a..88970890f 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 9204fa28b..fcc829d00 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; }