Browse Source

KBF-19 implement HTTPS support

Bence Balint 3 years ago
parent
commit
dac12c5059

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+# gtags
+GPATH
+GRTAGS
+GTAGS
+
+# emacs
+\#*\#
+*~
+
+# backups
+*.old

+ 1 - 0
CMakeLists.txt

@@ -28,6 +28,7 @@ idf_component_register(
         "esp_adc_cal"
         "esp_http_client"
         "esp_http_server"
+        "esp_https_server"
         "hd44780"
         "nvs_flash"
         "spiffs"

+ 10 - 0
include/kbf/http/server.h

@@ -78,6 +78,14 @@ namespace kbf::http {
          */
         Server &start(int port = 80);
 
+        /**
+         * @brief Starts the server in SSL (HTTPS) mode.
+         *
+         * @param port TCP port, default is 443
+         * @return *this (to enable builder-like syntax)
+         */
+        Server &startSSL(int port = 443);
+
         /**
          * @brief Stops the HTTP server.
          */
@@ -96,6 +104,8 @@ namespace kbf::http {
         vector<Route>  routes;
 
         static esp_err_t handleHttpRequest(httpd_req_t *httpdRequest);
+
+        void registerUriHandlers();
     };
 }
 

+ 37 - 4
src/http/server.cpp

@@ -1,6 +1,7 @@
 #include "kbf/http/server.h"
 
 #include <esp_log.h>
+#include <esp_https_server.h>
 #include <memory>
 
 #include "kbf/macros.h"
@@ -14,7 +15,7 @@ http::Server &http::Server::route(http::Server::Route route) {
 }
 
 http::Server &http::Server::start(int port) {
-    ESP_LOGI(TAG, "starting HTTP server on port %d", port);
+    ESP_LOGI(TAG, "start(%d)", port);
     if (running) {
         ESP_LOGE(TAG, "server already running");
         ABORT("fix me");
@@ -26,6 +27,41 @@ http::Server &http::Server::start(int port) {
     config.stack_size  = 16384;
     CHECK(httpd_start(&handle, &config));
 
+    registerUriHandlers();
+
+    running = true;
+    return *this;
+}
+
+http::Server &http::Server::startSSL(int port) {
+    ESP_LOGI(TAG, "startSSL(%d)", port);
+    if (running) {
+        ESP_LOGE(TAG, "server already running");
+        ABORT("fix me");
+    }
+
+    handle = nullptr;
+    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;
+
+    CHECK(httpd_ssl_start(&handle, &conf));
+
+    registerUriHandlers();
+
+    running = true;
+    return *this;
+}
+
+void http::Server::registerUriHandlers() {
     ESP_LOGI(TAG, "registering URI handlers");
     for (auto &route : routes) {
         ESP_LOGI(TAG, "  method: %d; uri: %s", static_cast<int>(route.method), route.uri.c_str());
@@ -37,9 +73,6 @@ http::Server &http::Server::start(int port) {
         };
         CHECK(httpd_register_uri_handler(handle, &uriHandler));
     }
-
-    running = true;
-    return *this;
 }
 
 void http::Server::stop() {

+ 0 - 28
test/test_http.cpp

@@ -116,34 +116,6 @@ TEST_CASE("HTTP custom headers", "[kbf_http]") {
     wifi::stop();
 }
 
-TEST_CASE("HTTP async", "[notimplemented]") {
-    wifi::start();
-
-    http::Response (*handleRequest)(const http::Request &, void *) = {[](const http::Request &request, void *) {
-        auto response = http::Response("OK");
-        kbf::sleep(100);
-        return response;
-    }};
-    auto server = http::Server()
-            .route({http::GET, "/", handleRequest, nullptr})
-            .start();
-
-    auto client = http::Client(true);
-    client.onSuccess = {[](http::Client &client, const http::Response &response) {
-        TEST_ASSERT_EQUAL_STRING("OK", response.body.data());
-        asyncFinished = true;
-    }};
-
-    auto response = client.get("http://localhost/");
-    TEST_ASSERT_NULL(response)
-    TEST_ASSERT_EQUAL(false, asyncFinished);
-    kbf::sleep(200);
-    TEST_ASSERT_EQUAL(true, asyncFinished);
-
-    server.stop();
-    wifi::stop();
-}
-
 TEST_CASE("HTTP JSON request / response", "[kbf_http]") {
     wifi::start();
 

+ 65 - 0
test/test_https.cpp

@@ -0,0 +1,65 @@
+#include <nlohmann_json/json.hpp>
+
+#include "kbf.h"
+#include "kbf/wifi.h"
+#include "kbf/http/server.h"
+#include "kbf/http/client.h"
+#include "kbf/rtos.h"
+
+#include <unity.h>
+
+using namespace kbf;
+using namespace std;
+using nlohmann::json;
+
+TEST_CASE("HTTPS GET", "[kbf_http]") {
+    wifi::start();
+    auto server = http::Server();
+    TEST_ASSERT_FALSE(server.isRunning())
+
+    http::Response (*handleGet)(const http::Request &, void *) = {[](const http::Request &request, void *) {
+        TEST_ASSERT_EQUAL(http::GET, request.method);
+        return http::Response("OK");
+    }};
+    server.route({http::GET, "/get-me", handleGet, nullptr});
+    server.startSSL();
+    TEST_ASSERT_TRUE(server.isRunning())
+
+    auto client   = http::Client();
+    auto response = client.get("https://localhost/get-me");
+    TEST_ASSERT_EQUAL(200, response->status);
+    TEST_ASSERT_EQUAL_STRING("OK", response->body.c_str());
+
+    server.stop();
+    wifi::stop();
+}
+
+// TODO KBF-22 fix async test
+static rtos::EventGroup eventGroup;
+TEST_CASE("HTTPS async", "[broken]") {
+    wifi::start();
+
+    http::Response (*handleRequest)(const http::Request &, void *) = {[](const http::Request &request, void *) {
+        auto response = http::Response("OK");
+        kbf::sleep(100);
+        return response;
+    }};
+    auto server = http::Server()
+            .route({http::GET, "/", handleRequest, nullptr})
+            .startSSL();
+
+    auto client = http::Client(true);
+    client.onSuccess = {[](http::Client &client, const http::Response &response) {
+        TEST_ASSERT_EQUAL_STRING("OK", response.body.data());
+        eventGroup.setBit(0);
+    }};
+
+    auto response = client.get("https://localhost/");
+    TEST_ASSERT_NULL(response)
+    TEST_ASSERT_EQUAL(0, eventGroup.getBit(0));
+    kbf::sleep(200);
+    TEST_ASSERT_EQUAL(1, eventGroup.getBit(0));
+
+    server.stop();
+    wifi::stop();
+}

+ 8 - 2
test_app/main/CMakeLists.txt

@@ -1,4 +1,10 @@
-idf_component_register(SRCS "main_test.c"
-        INCLUDE_DIRS ".")
+idf_component_register(
+  SRCS "main_test.c"
+  INCLUDE_DIRS "."
+
+  EMBED_TXTFILES
+  "certs/cacert.pem"
+  "certs/prvtkey.pem"
+)
 
 spiffs_create_partition_image("storage" "spiffs" FLASH_IN_PROJECT)

+ 19 - 0
test_app/main/certs/cacert.pem

@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDDzCCAfegAwIBAgIUDdzYo6ANlTi9J0HbGea7tpGXnacwDQYJKoZIhvcNAQEL
+BQAwFzEVMBMGA1UEAwwMS0JGIFNTTCB0ZXN0MB4XDTIxMDQyNzA4NTE1NFoXDTMx
+MDQyNTA4NTE1NFowFzEVMBMGA1UEAwwMS0JGIFNTTCB0ZXN0MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzLHIG2k+Y7mZ/Uq9hR1eDkCv8dS7ceuK0X/S
+R3Dkq8PAGIEm+xH3MRcxT3CyhA06P0RhZMke9NZqA7E51qpT0e7REENto5LrYUuX
+HtU5jAGE9da6kwDa4ZbeJQeib4ppTZICjkiTzMZMy7xNL/xF6jWjMbwXSJaRcutB
+OusQ3pQOnCfXDLsas+zY+j6uydPl6AMCP6ZIXpr7Vt//H6CkJNENUdNnPgFIV1rm
+belvuw/YaIcOTdpm9YnIoeTvwoTb4hSfl8dDVjGrd3bzbvEzxwBypx2UgN3JvxpP
+/DQLbUGiDnvFUhrs4p2nGkyYK14H0hbdUmtRgDNCDofVL948KQIDAQABo1MwUTAd
+BgNVHQ4EFgQUwvXLD/DTPrgU6VjoAnpgTPRmjbEwHwYDVR0jBBgwFoAUwvXLD/DT
+PrgU6VjoAnpgTPRmjbEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+AQEAhMOsfKWVKrs1uZt6AjM4PVW23TN0qb0/80lnkLIPKTz5eJmI8ZJJPZaSfNfj
+lDrdvx1wGzp5QpHt0utYw6pqm+TOqCjUB9fejHGbdZ/jVBFwDX/UHAsi8bG56znw
+OSXd/80vf+tuS1m5aLaG838L3RCjUxGcJF8FDk8eiYAfWvHiX7u3wcvRjgI22tIl
+b04XeqIuBMqHvW++PTrHVIPkjO3lmAYMF1dSnZw0RyB2rSCDXXMzrhEHiDiDvzgC
+uH9jWM5VbuQk6CQjSmYhbOT9mAZ84zeigzFE/ZldskMzyxJ5dmRO51lz1mzcWS4f
+YVG3Yq1mWyBCfKe6TBap0e3i+g==
+-----END CERTIFICATE-----

+ 28 - 0
test_app/main/certs/prvtkey.pem

@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDMscgbaT5juZn9
+Sr2FHV4OQK/x1Ltx64rRf9JHcOSrw8AYgSb7EfcxFzFPcLKEDTo/RGFkyR701moD
+sTnWqlPR7tEQQ22jkuthS5ce1TmMAYT11rqTANrhlt4lB6JvimlNkgKOSJPMxkzL
+vE0v/EXqNaMxvBdIlpFy60E66xDelA6cJ9cMuxqz7Nj6Pq7J0+XoAwI/pkhemvtW
+3/8foKQk0Q1R02c+AUhXWuZt6W+7D9hohw5N2mb1icih5O/ChNviFJ+Xx0NWMat3
+dvNu8TPHAHKnHZSA3cm/Gk/8NAttQaIOe8VSGuzinacaTJgrXgfSFt1Sa1GAM0IO
+h9Uv3jwpAgMBAAECggEAeT3sSuAhhiwPG8pDSy9D4KlMDa91f1qGlORjBtHFgD+n
+7lvBXQEdK0STfnxAIJs9HvA/x9Sgs2C01o8ItS+aCkSsLDfkHvkM1kpRrn+ZYGYd
+/Qc854mgG/Kijchh3DNdgAa14NT4RlhGcH6OMZf5SWqPyQuhtusIJ8tUjbNiAJMe
+FuB97oL/lQDkFGUkosQtdZRP8kW3GFQuTi+y3uucTAao/7TYUdLRm6XKc4yhkPNE
+QgPgKePh4mfQjCNg/leAZgZqzzq1Ulcm3HntVXa64MO+nM7M+pDWOEcUgYoJML5e
+dgrCvfxZdl15e+oLRuRMnivkOaQg6kGnB0vAzoF3AQKBgQDyvvFWre7cLzedaUEa
+obmngYhVNiLEA4HyObqHGNvImtvf4QKh/fc+9QYy65kjznl4P9ytz1hqveLiky07
+8jUvhHRYCghl/g/BHKUMAnYKES/Ivu6LENouqYYcCqPDyT4fcTzEFlctPYDGQCfN
+4Si7iUV0idyQQoF9rZpQETZvWQKBgQDX3vaa3KX66F3bSS1spAcyPa9OYjQyr0DT
+LbMRLovNyMz0hkNZicaPxX7UIbRppLlfjo43MtZ69LPlwSLLtyRTrlDOQ1UGwNED
+xh0Iu15eEE5QPUZU1ZpR6dHmQHluLQ7l8Y9nhz4PlVhJNqjndZ5UzUrlxcxz7uvi
+ybcckBXpUQKBgQCsrK0KZsHB+QiLveKk6iQhhqAPVWoXmxMl1nDcRw+YvKfpsqrn
+xrvJGg0lzbfq46Y+ptb5AMS5cYfieqUzvlCdE5CbS8+7laVpTlINn/aNpLokB8Wy
+QPOjO839RohF7nJ1dVyvc+Dhep2O6PYnmqIZ/UTd6G9wYw6v8v0RNZ1OSQKBgQDM
+FDBlBTYxN14LwmmcLJHVEHXcD4EzbXVGcAy6sJtgp3YDsa6YRmUeZGJbn6WUvjK1
+wOp4CqqzwQUVrvn7Rx+jsMcZyJPod37iJ3gpWiGDoby3pMYJy4pB6GAUYl2qKBTO
+lAizoiqsxs6ZIICbmRlfKFmnUdDQxU3hsDtZWGoukQKBgQDGejnc+whsG7wO3F9r
+DTFJerOxR3r67IDF2UPMQFgfoN9qpEqXuMBcZIGtlouxI4ziZicrNFk+o5QB6ODr
+7wcEOhinSnMC1iRkCFDeCnIh1pJXlnNXglnqmbx2AC74K5Q7Ij8lyzDXNuLOpkg8
+QOc+7JvkDM65Vq7tTTzaV0QQYw==
+-----END PRIVATE KEY-----

+ 4 - 3
test_app/sdkconfig

@@ -268,9 +268,10 @@ CONFIG_EFUSE_MAX_BLK_LEN=192
 #
 CONFIG_ESP_TLS_USING_MBEDTLS=y
 # CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
-# CONFIG_ESP_TLS_SERVER is not set
+CONFIG_ESP_TLS_SERVER=y
 # CONFIG_ESP_TLS_PSK_VERIFICATION is not set
-# CONFIG_ESP_TLS_INSECURE is not set
+CONFIG_ESP_TLS_INSECURE=y
+CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
 # end of ESP-TLS
 
 #
@@ -423,7 +424,7 @@ CONFIG_HTTPD_PURGE_BUF_LEN=32
 #
 # ESP HTTPS server
 #
-# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
+CONFIG_ESP_HTTPS_SERVER_ENABLE=y
 # end of ESP HTTPS server
 
 #