]> granicus.if.org Git - esp-idf/commitdiff
Add a 'esp_https_server' component allowing to use http_server with OpenSSL
authorOndřej Hruška <ondra@ondrovo.com>
Wed, 31 Oct 2018 22:17:00 +0000 (23:17 +0100)
committerbot <bot@espressif.com>
Mon, 19 Nov 2018 04:00:21 +0000 (04:00 +0000)
15 files changed:
components/esp_https_server/CMakeLists.txt [new file with mode: 0644]
components/esp_https_server/README.md [new file with mode: 0644]
components/esp_https_server/component.mk [new file with mode: 0644]
components/esp_https_server/include/esp_https_server.h [new file with mode: 0644]
components/esp_https_server/src/https_server.c [new file with mode: 0644]
examples/protocols/https_server/CMakeLists.txt [new file with mode: 0644]
examples/protocols/https_server/Makefile [new file with mode: 0644]
examples/protocols/https_server/README.md [new file with mode: 0644]
examples/protocols/https_server/main/CMakeLists.txt [new file with mode: 0644]
examples/protocols/https_server/main/Kconfig.projbuild [new file with mode: 0644]
examples/protocols/https_server/main/certs/cacert.pem [new file with mode: 0644]
examples/protocols/https_server/main/certs/gencert.sh [new file with mode: 0644]
examples/protocols/https_server/main/certs/prvtkey.pem [new file with mode: 0644]
examples/protocols/https_server/main/component.mk [new file with mode: 0644]
examples/protocols/https_server/main/main.c [new file with mode: 0644]

diff --git a/components/esp_https_server/CMakeLists.txt b/components/esp_https_server/CMakeLists.txt
new file mode 100644 (file)
index 0000000..dfdaa11
--- /dev/null
@@ -0,0 +1,7 @@
+set(COMPONENT_ADD_INCLUDEDIRS include)
+set(COMPONENT_SRCS "src/https_server.c")
+
+set(COMPONENT_REQUIRES esp_http_server openssl)
+set(COMPONENT_PRIV_REQUIRES lwip)
+
+register_component()
diff --git a/components/esp_https_server/README.md b/components/esp_https_server/README.md
new file mode 100644 (file)
index 0000000..2d7bc7f
--- /dev/null
@@ -0,0 +1,44 @@
+# HTTPS server
+
+This component is built on top of `esp_http_server`. The HTTPS server takes advantage of hooks and 
+function overrides in the regular HTTP server to provide encryption using OpenSSL. 
+
+All documentation for `esp_http_server` applies also to a server you create this way.
+
+## Used APIs
+
+The following API of `esp_http_server` should not be used with `esp_https_server`, as they are
+used internally to handle secure sessions and to maintain internal state:
+
+- "send", "receive" and "pending" function overrides - secure socket handling
+  - `httpd_set_sess_send_override()`
+  - `httpd_set_sess_recv_override()`
+  - `httpd_set_sess_pending_override()`
+  - `httpd_set_send_override()`
+  - `httpd_set_recv_override()`
+  - `httpd_set_pending_override()`
+- "transport context" - both global and session
+  - `httpd_sess_get_transport_ctx()` - returns SSL used for the session
+  - `httpd_sess_set_transport_ctx()`
+  - `httpd_get_global_transport_ctx()` - returns the shared SSL context
+  - `httpd_config_t.global_transport_ctx`
+  - `httpd_config_t.global_transport_ctx_free_fn`
+  - `httpd_config_t.open_fn` - used to set up secure sockets
+
+Everything else can be used without limitations.
+
+## Usage
+
+Please see the example `protocols/https_server` to learn how to set up a secure server.
+
+Basically all you need is to generate a certificate, embed it in the firmware, and provide
+its pointers and lengths to the start function via the init struct.
+
+The server can be started with or without SSL by changing a flag in the init struct. 
+This could be used e.g. for testing or in trusted environments where you prefer speed over security.
+
+## Performance
+
+The initial session setup can take about two seconds, or more with slower clock speeds or more 
+verbose logging. Subsequent requests through the open secure socket are much faster (down to under
+100 ms).
diff --git a/components/esp_https_server/component.mk b/components/esp_https_server/component.mk
new file mode 100644 (file)
index 0000000..be1bffc
--- /dev/null
@@ -0,0 +1,2 @@
+COMPONENT_SRCDIRS := src
+COMPONENT_ADD_INCLUDEDIRS := include
diff --git a/components/esp_https_server/include/esp_https_server.h b/components/esp_https_server/include/esp_https_server.h
new file mode 100644 (file)
index 0000000..1bc9885
--- /dev/null
@@ -0,0 +1,112 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _ESP_HTTPS_SERVER_H_
+#define _ESP_HTTPS_SERVER_H_
+
+#include <stdbool.h>
+#include "esp_err.h"
+#include "esp_http_server.h"
+
+/**
+ * HTTPS server config struct
+ *
+ * Please use HTTPD_SSL_CONFIG_DEFAULT() to initialize it.
+ */
+struct httpd_ssl_config {
+    /**
+     * Underlying HTTPD server config
+     *
+     * Parameters like task stack size and priority can be adjusted here.
+     */
+    httpd_config_t httpd;
+
+    /** CA certificate */
+    const uint8_t *cacert_pem;
+
+    /** CA certificate byte length */
+    size_t cacert_len;
+
+    /** Private key */
+    const uint8_t *prvtkey_pem;
+
+    /** Private key byte length */
+    size_t prvtkey_len;
+
+    /** Enable SSL (default true) */
+    bool secure_enable;
+
+    /** Port used when SSL is enabled (default 443) */
+    uint16_t port_secure;
+
+    /** Port used when SSL is disabled (default 80) */
+    uint16_t port_insecure;
+};
+
+typedef struct httpd_ssl_config httpd_ssl_config_t;
+
+/**
+ * Default config struct init
+ *
+ * (http_server default config had to be copied for customization)
+ *
+ * Notes:
+ * - port is set when starting the server, according to 'secure_enable'
+ * - one socket uses ~ 40kB RAM with SSL, we reduce the default socket count to 4
+ * - SSL sockets are usually long-lived, closing LRU prevents pool exhaustion DOS
+ * - Stack size may need adjustments depending on the user application
+ */
+#define HTTPD_SSL_CONFIG_DEFAULT() {              \
+    .httpd = {                                    \
+        .task_priority      = tskIDLE_PRIORITY+5, \
+        .stack_size         = 10240,              \
+        .server_port        = 0,                  \
+        .ctrl_port          = 32768,              \
+        .max_open_sockets   = 4,                  \
+        .max_uri_handlers   = 8,                  \
+        .max_resp_headers   = 8,                  \
+        .backlog_conn       = 5,                  \
+        .lru_purge_enable   = true,               \
+        .recv_wait_timeout  = 5,                  \
+        .send_wait_timeout  = 5,                  \
+        .global_user_ctx = NULL,                  \
+        .global_user_ctx_free_fn = NULL,          \
+        .global_transport_ctx = NULL,             \
+        .global_transport_ctx_free_fn = NULL,     \
+        .open_fn = NULL,                          \
+        .close_fn = NULL,                         \
+    },                                            \
+    .secure_enable = true,                        \
+    .port_secure = 443,                           \
+    .port_insecure = 80,                          \
+}
+
+/**
+ * Create a SSL capable HTTP server (secure mode may be disabled in config)
+ *
+ * @param[in,out] config - server config, must not be const. Does not have to stay valid after
+ *                         calling this function.
+ * @param[out] handle - storage for the server handle, must be a valid pointer
+ * @return success
+ */
+esp_err_t httpd_ssl_start(httpd_handle_t *handle, httpd_ssl_config_t *config);
+
+/**
+ * Stop the server. Blocks until the server is shut down.
+ *
+ * @param[in] handle
+ */
+void httpd_ssl_stop(httpd_handle_t handle);
+
+#endif // _ESP_HTTPS_SERVER_H_
diff --git a/components/esp_https_server/src/https_server.c b/components/esp_https_server/src/https_server.c
new file mode 100644 (file)
index 0000000..0cf741b
--- /dev/null
@@ -0,0 +1,220 @@
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+#include "esp_https_server.h"
+#include "openssl/ssl.h"
+#include "esp_log.h"
+#include "sdkconfig.h"
+
+const static char *TAG = "esp_https_server";
+
+/**
+ * SSL socket close handler
+ *
+ * @param[in] ctx - session transport context (SSL context we stored there)
+ */
+static void httpd_ssl_close(void *ctx)
+{
+    assert(ctx != NULL);
+    SSL_shutdown(ctx);
+    SSL_free(ctx);
+    ESP_LOGD(TAG, "Secure socket closed");
+}
+
+/**
+ * SSL socket pending-check function
+ *
+ * @param server
+ * @param sockfd
+ * @return number of pending bytes, negative on error
+ */
+static int httpd_ssl_pending(httpd_handle_t server, int sockfd)
+{
+    SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
+    assert(ssl != NULL);
+    return SSL_pending(ssl);
+}
+
+/**
+ * Receive from a SSL socket
+ *
+ * @param server
+ * @param sockfd
+ * @param buf
+ * @param buf_len
+ * @param flags
+ * @return bytes read, negative on error
+ */
+static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t buf_len, int flags)
+{
+    SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
+    assert(ssl != NULL);
+    return SSL_read(ssl, buf, buf_len);
+}
+
+/**
+ * Send to a SSL socket
+ *
+ * @param server
+ * @param sockfd
+ * @param buf
+ * @param buf_len
+ * @param flags
+ * @return bytes sent, negative on error
+ */
+static int httpd_ssl_send(httpd_handle_t server, int sockfd, const char *buf, size_t buf_len, int flags)
+{
+    SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
+    assert(ssl != NULL);
+    return SSL_write(ssl, buf, buf_len);
+}
+
+/**
+ * Open a SSL socket for the server.
+ * The fd is already open and ready to read / write raw data.
+ *
+ * @param server
+ * @param sockfd - raw socket fd
+ * @return success
+ */
+static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd)
+{
+    assert(server != NULL);
+
+    // Retrieve the SSL context from the global context field (set in config)
+    SSL_CTX *global_ctx = httpd_get_global_transport_ctx(server);
+    assert(global_ctx != NULL);
+
+    SSL *ssl = SSL_new(global_ctx);
+    if (NULL == ssl) {
+        ESP_LOGE(TAG, "SSL_new ret NULL (out of memory)");
+        return ESP_ERR_NO_MEM;
+    }
+
+    if (1 != SSL_set_fd(ssl, sockfd)) {
+        ESP_LOGE(TAG, "fail to set SSL fd");
+        goto teardown;
+    }
+
+    ESP_LOGD(TAG, "SSL accept");
+    if (1 != SSL_accept(ssl)) {
+        ESP_LOGW(TAG, "fail to SSL_accept - handshake error");
+        goto teardown;
+    }
+
+    // Store the SSL session into the context field of the HTTPD session object
+    httpd_sess_set_transport_ctx(server, sockfd, ssl, httpd_ssl_close);
+
+    // Set rx/tx/pending override functions
+    httpd_set_sess_send_override(server, sockfd, httpd_ssl_send);
+    httpd_set_sess_recv_override(server, sockfd, httpd_ssl_recv);
+    httpd_set_sess_pending_override(server, sockfd, httpd_ssl_pending);
+
+    // all access should now go through SSL
+
+    ESP_LOGD(TAG, "Secure socket open");
+
+    return ESP_OK;
+
+teardown:
+    SSL_free(ssl);
+    return ESP_FAIL;
+}
+
+/**
+ * Tear down the HTTPD global transport context
+ *
+ * @param ctx
+ */
+static void free_secure_context(void *ctx)
+{
+    assert(ctx != NULL);
+
+    ESP_LOGI(TAG, "Server shuts down, releasing SSL context");
+    SSL_CTX_free(ctx);
+}
+
+/**
+* Create and perform basic init of a SSL_CTX, or return NULL on failure
+*
+* @return ctx or null
+*/
+static SSL_CTX *create_secure_context(const struct httpd_ssl_config *config)
+{
+    SSL_CTX *ctx = NULL;
+
+    ESP_LOGD(TAG, "SSL server context create");
+    ctx = SSL_CTX_new(TLS_server_method());
+    if (NULL != ctx) {
+        //region SSL ctx alloc'd
+        ESP_LOGD(TAG, "SSL ctx set own cert");
+        if (SSL_CTX_use_certificate_ASN1(ctx, config->cacert_len, config->cacert_pem)
+            && SSL_CTX_use_PrivateKey_ASN1(0, ctx, config->prvtkey_pem, (long) config->prvtkey_len)) {
+            return ctx;
+        }
+        else {
+            ESP_LOGE(TAG, "Failed to set certificate");
+            SSL_CTX_free(ctx);
+            ctx = NULL;
+        }
+    } else {
+        ESP_LOGE(TAG, "Failed to create SSL context");
+    }
+    return NULL;
+}
+
+/** Start the server */
+esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *config)
+{
+    assert(config != NULL);
+    assert(pHandle != NULL);
+
+    ESP_LOGI(TAG, "Starting server");
+
+    if (config->secure_enable) {
+        SSL_CTX *ctx = create_secure_context(config);
+        if (!ctx) {
+            return ESP_FAIL;
+        }
+
+        ESP_LOGD(TAG, "SSL context ready");
+
+        // set SSL specific config
+        config->httpd.global_transport_ctx = ctx;
+        config->httpd.global_transport_ctx_free_fn = free_secure_context;
+        config->httpd.open_fn = httpd_ssl_open; // the open function configures the created SSL sessions
+
+        config->httpd.server_port = config->port_secure;
+    } else {
+        ESP_LOGD(TAG, "SSL disabled, using plain HTTP");
+        config->httpd.server_port = config->port_insecure;
+    }
+
+    httpd_handle_t handle = NULL;
+
+    esp_err_t ret = httpd_start(&handle, &config->httpd);
+    if (ret != ESP_OK) return ret;
+
+    *pHandle = handle;
+
+    ESP_LOGI(TAG, "Server listening on port %d", config->httpd.server_port);
+    return ESP_OK;
+}
+
+/** Stop the server */
+void httpd_ssl_stop(httpd_handle_t handle)
+{
+    httpd_stop(handle);
+}
diff --git a/examples/protocols/https_server/CMakeLists.txt b/examples/protocols/https_server/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7f58e02
--- /dev/null
@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(https_server)
diff --git a/examples/protocols/https_server/Makefile b/examples/protocols/https_server/Makefile
new file mode 100644 (file)
index 0000000..5a20b6f
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := https_server
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/examples/protocols/https_server/README.md b/examples/protocols/https_server/README.md
new file mode 100644 (file)
index 0000000..c89c0f7
--- /dev/null
@@ -0,0 +1,15 @@
+# HTTP server with SSL support using OpenSSL
+
+This example creates a SSL server that returns a simple HTML page when you visit its root URL.
+
+See the `esp_https_server` component documentation for details.
+
+## Certificates
+
+You will need to approve a security exception in your browser. This is because of a self signed 
+certificate; this will be always the case, unless you preload the CA root into your browser/system
+as trusted.
+
+You can generate a new certificate using the OpenSSL command line tool as shown in the script
+`main/certs/gencert.sh`. It is **strongly recommended** to not reuse the example certificate in 
+your application; it is included only for demonstration.
diff --git a/examples/protocols/https_server/main/CMakeLists.txt b/examples/protocols/https_server/main/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9e08fb4
--- /dev/null
@@ -0,0 +1,8 @@
+set(COMPONENT_SRCS "main.c")
+set(COMPONENT_ADD_INCLUDEDIRS ".")
+
+set(COMPONENT_EMBED_TXTFILES
+        "certs/cacert.pem"
+        "certs/prvtkey.pem")
+
+register_component()
diff --git a/examples/protocols/https_server/main/Kconfig.projbuild b/examples/protocols/https_server/main/Kconfig.projbuild
new file mode 100644 (file)
index 0000000..9e2813c
--- /dev/null
@@ -0,0 +1,16 @@
+menu "Example Configuration"
+
+config WIFI_SSID
+    string "WiFi SSID"
+    default "myssid"
+    help
+        SSID (network name) for the example to connect to.
+
+config WIFI_PASSWORD
+    string "WiFi Password"
+    default "mypassword"
+    help
+        WiFi password (WPA or WPA2) for the example to use.
+        Can be left blank if the network has no security set.
+
+endmenu
diff --git a/examples/protocols/https_server/main/certs/cacert.pem b/examples/protocols/https_server/main/certs/cacert.pem
new file mode 100644 (file)
index 0000000..cd2b80c
--- /dev/null
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL
+BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx
+MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ
+UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T
+sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k
+qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd
+GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4
+sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb
+jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/
+ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud
+EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3
+emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY
+W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx
+bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN
+ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl
+hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=
+-----END CERTIFICATE-----
diff --git a/examples/protocols/https_server/main/certs/gencert.sh b/examples/protocols/https_server/main/certs/gencert.sh
new file mode 100644 (file)
index 0000000..5b2f79d
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Example command to generate a new certificate in the correct format.
+# Expiry time and metadata fields can be adjusted in the invocation.
+
+# Please see the openssl man pages (man openssl-req) for more details
+
+openssl req -newkey rsa:2048 -nodes -keyout prvtkey.pem -x509 -days 3650 -out cacert.pem -subj "/CN=ESP32 HTTPS server example"
diff --git a/examples/protocols/https_server/main/certs/prvtkey.pem b/examples/protocols/https_server/main/certs/prvtkey.pem
new file mode 100644 (file)
index 0000000..70d2907
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH
+JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw
+h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT
+aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al
+3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg
+0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB
+vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui
+f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9
+Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y
+JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX
+49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc
++3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6
+pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D
+0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG
+YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV
+MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL
+CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin
+7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1
+noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8
+4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g
+Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/
+nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3
+q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2
+lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB
+jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr
+v/t+MeGJP/0Zw8v/X2CFll96
+-----END PRIVATE KEY-----
diff --git a/examples/protocols/https_server/main/component.mk b/examples/protocols/https_server/main/component.mk
new file mode 100644 (file)
index 0000000..b120d66
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
+COMPONENT_EMBED_TXTFILES := certs/cacert.pem
+COMPONENT_EMBED_TXTFILES += certs/prvtkey.pem
diff --git a/examples/protocols/https_server/main/main.c b/examples/protocols/https_server/main/main.c
new file mode 100644 (file)
index 0000000..d46897f
--- /dev/null
@@ -0,0 +1,150 @@
+/* Simple HTTP + SSL Server Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <esp_wifi.h>
+#include <esp_event_loop.h>
+#include <esp_log.h>
+#include <esp_system.h>
+#include <nvs_flash.h>
+#include <sys/param.h>
+
+#include <esp_https_server.h>
+
+/* A simple example that demonstrates how to create GET and POST
+ * handlers for the web server.
+ * The examples use simple WiFi configuration that you can set via
+ * 'make menuconfig'.
+ * If you'd rather not, just change the below entries to strings
+ * with the config you want -
+ * ie. #define EXAMPLE_WIFI_SSID "mywifissid"
+*/
+#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
+#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
+
+static const char *TAG="APP";
+
+
+/* An HTTP GET handler */
+esp_err_t root_get_handler(httpd_req_t *req)
+{
+    httpd_resp_set_type(req, "text/html");
+    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", -1); // -1 = use strlen()
+
+    return ESP_OK;
+}
+
+const httpd_uri_t root = {
+    .uri       = "/",
+    .method    = HTTP_GET,
+    .handler   = root_get_handler
+};
+
+
+httpd_handle_t start_webserver(void)
+{
+    httpd_handle_t server = NULL;
+
+    // Start the httpd server
+    ESP_LOGI(TAG, "Starting server");
+
+    httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();
+
+    extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
+    extern const unsigned char cacert_pem_end[]   asm("_binary_cacert_pem_end");
+    conf.cacert_pem = cacert_pem_start;
+    conf.cacert_len = cacert_pem_end - cacert_pem_start;
+
+    extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
+    extern const unsigned char prvtkey_pem_end[]   asm("_binary_prvtkey_pem_end");
+    conf.prvtkey_pem = prvtkey_pem_start;
+    conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
+
+    esp_err_t ret = httpd_ssl_start(&server, &conf);
+    if (ESP_OK != ret) {
+        ESP_LOGI(TAG, "Error starting server!");
+        return NULL;
+    }
+
+    // Set URI handlers
+    ESP_LOGI(TAG, "Registering URI handlers");
+    httpd_register_uri_handler(server, &root);
+    return server;
+}
+
+void stop_webserver(httpd_handle_t server)
+{
+    // Stop the httpd server
+    httpd_ssl_stop(server);
+}
+
+
+
+
+// ------------------------- application boilerplate ------------------------
+
+static esp_err_t event_handler(void *ctx, system_event_t *event)
+{
+    httpd_handle_t *server = (httpd_handle_t *) ctx;
+
+    switch(event->event_id) {
+    case SYSTEM_EVENT_STA_START:
+        ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
+        ESP_ERROR_CHECK(esp_wifi_connect());
+        break;
+    case SYSTEM_EVENT_STA_GOT_IP:
+        ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
+        ESP_LOGI(TAG, "Got IP: '%s'",
+                ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
+
+        /* Start the web server */
+        if (*server == NULL) {
+            *server = start_webserver();
+        }
+        break;
+    case SYSTEM_EVENT_STA_DISCONNECTED:
+        ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
+        ESP_ERROR_CHECK(esp_wifi_connect());
+
+        /* Stop the web server */
+        if (*server) {
+            stop_webserver(*server);
+            *server = NULL;
+        }
+        break;
+    default:
+        break;
+    }
+    return ESP_OK;
+}
+
+static void initialise_wifi(void *arg)
+{
+    tcpip_adapter_init();
+    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, arg));
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
+    wifi_config_t wifi_config = {
+        .sta = {
+            .ssid = EXAMPLE_WIFI_SSID,
+            .password = EXAMPLE_WIFI_PASS,
+        },
+    };
+    ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
+    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
+    ESP_ERROR_CHECK(esp_wifi_start());
+}
+
+void app_main()
+{
+    static httpd_handle_t server = NULL;
+    ESP_ERROR_CHECK(nvs_flash_init());
+    initialise_wifi(&server);
+}