소스 검색

https_request_example: Updated the example to showcase cacert_buf and global_ca store
* Made required changes in the example_test

Aditya Patwardhan 5 년 전
부모
커밋
b06fa1d7c2

+ 59 - 11
examples/protocols/https_request/example_test.py

@@ -1,7 +1,7 @@
-import re
 import os
-
+import re
 import ttfw_idf
+from tiny_test_fw import Utility
 
 
 @ttfw_idf.idf_example_test(env_tag="Example_EthKitV1")
@@ -9,7 +9,8 @@ def test_examples_protocol_https_request(env, extra_data):
     """
     steps: |
       1. join AP
-      2. connect to www.howsmyssl.com:443
+      2. establish TLS connection to www.howsmyssl.com:443 with multiple
+         certificate verification options
       3. send http request
     """
     dut1 = env.get_dut("https_request", "examples/protocols/https_request", dut_class=ttfw_idf.ESP32DUT)
@@ -17,13 +18,51 @@ def test_examples_protocol_https_request(env, extra_data):
     binary_file = os.path.join(dut1.app.binary_path, "https_request.bin")
     bin_size = os.path.getsize(binary_file)
     ttfw_idf.log_performance("https_request_bin_size", "{}KB".format(bin_size // 1024))
-    # start test
+    # start tes
+    Utility.console_log("Starting https_request simple test app")
     dut1.start_app()
-    dut1.expect("Connection established...", timeout=30)
-    dut1.expect("Reading HTTP response...")
-    dut1.expect(re.compile(r"Completed (\d) requests"))
 
-    # test mbedtls dynamic resource
+    # Check for connection using crt bundle
+    Utility.console_log("Testing for \"https_request using crt bundle\"")
+    try:
+        dut1.expect(re.compile("https_request using crt bundle"), timeout=30)
+        dut1.expect_all("Certificate validated",
+                        "Connection established...",
+                        "Reading HTTP response...",
+                        "HTTP/1.1 200 OK",
+                        re.compile("connection closed"))
+    except Exception:
+        Utility.console_log("Failed the test for \"https_request using crt bundle\"")
+        raise
+    Utility.console_log("Passed the test for \"https_request using crt bundle\"")
+
+    # Check for connection using cacert_buf
+    Utility.console_log("Testing for \"https_request using cacert_buf\"")
+    try:
+        dut1.expect(re.compile("https_request using cacert_buf"), timeout=20)
+        dut1.expect_all("Connection established...",
+                        "Reading HTTP response...",
+                        "HTTP/1.1 200 OK",
+                        re.compile("connection closed"))
+    except Exception:
+        Utility.console_log("Passed the test for \"https_request using cacert_buf\"")
+        raise
+    Utility.console_log("Passed the test for \"https_request using cacert_buf\"")
+
+    # Check for connection using global ca_store
+    Utility.console_log("Testing for \"https_request using global ca_store\"")
+    try:
+        dut1.expect(re.compile("https_request using global ca_store"), timeout=20)
+        dut1.expect_all("Connection established...",
+                        "Reading HTTP response...",
+                        "HTTP/1.1 200 OK",
+                        re.compile("connection closed"))
+    except Exception:
+        Utility.console_log("Failed the test for \"https_request using global ca_store\"")
+        raise
+    Utility.console_log("Passed the test for \"https_request using global ca_store\"")
+
+    # Check for connection using crt bundle with mbedtls dynamic resource enabled
     dut1 = env.get_dut("https_request", "examples/protocols/https_request", dut_class=ttfw_idf.ESP32DUT, app_config_name='ssldyn')
     # check and log bin size
     binary_file = os.path.join(dut1.app.binary_path, "https_request.bin")
@@ -31,9 +70,18 @@ def test_examples_protocol_https_request(env, extra_data):
     ttfw_idf.log_performance("https_request_bin_size", "{}KB".format(bin_size // 1024))
     # start test
     dut1.start_app()
-    dut1.expect("Connection established...", timeout=30)
-    dut1.expect("Reading HTTP response...")
-    dut1.expect(re.compile(r"Completed (\d) requests"))
+    # only check if one connection is established
+    Utility.console_log("Testing for \"https_request using crt bundle\" with mbedtls dynamic resource enabled")
+    try:
+        dut1.expect(re.compile("https_request using crt bundle"), timeout=30)
+        dut1.expect_all("Connection established...",
+                        "Reading HTTP response...",
+                        "HTTP/1.1 200 OK",
+                        re.compile("connection closed"))
+    except Exception:
+        Utility.console_log("Failed the test for \"https_request using crt bundle\" when mbedtls dynamic resource was enabled")
+        raise
+    Utility.console_log("Passed the test for \"https_request using crt bundle\" when mbedtls dynamic resource was enabled")
 
 
 if __name__ == '__main__':

+ 2 - 1
examples/protocols/https_request/main/CMakeLists.txt

@@ -2,4 +2,5 @@
 #
 # (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.)
 idf_component_register(SRCS "https_request_example_main.c"
-                    INCLUDE_DIRS ".")
+                    INCLUDE_DIRS "."
+                    EMBED_TXTFILES server_root_cert.pem)

+ 1 - 0
examples/protocols/https_request/main/component.mk

@@ -2,3 +2,4 @@
 # "main" pseudo-component makefile.
 #
 # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+COMPONENT_EMBED_TXTFILES := server_root_cert.pem

+ 116 - 69
examples/protocols/https_request/main/https_request_example_main.c

@@ -50,90 +50,137 @@
 
 static const char *TAG = "example";
 
-static const char *REQUEST = "GET " WEB_URL " HTTP/1.1\r\n"
-    "Host: "WEB_SERVER"\r\n"
-    "User-Agent: esp-idf/1.0 esp32\r\n"
-    "\r\n";
+static const char REQUEST[] = "GET " WEB_URL " HTTP/1.1\r\n"
+                             "Host: "WEB_SERVER"\r\n"
+                             "User-Agent: esp-idf/1.0 esp32\r\n"
+                             "\r\n";
 
-static void https_get_task(void *pvParameters)
+/* Root cert for howsmyssl.com, taken from server_root_cert.pem
+
+   The PEM file was extracted from the output of this command:
+   openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
+
+   The CA root cert is the last cert given in the chain of certs.
+
+   To embed it in the app binary, the PEM file is named
+   in the component.mk COMPONENT_EMBED_TXTFILES variable.
+*/
+extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
+extern const uint8_t server_root_cert_pem_end[]   asm("_binary_server_root_cert_pem_end");
+
+static void https_get_request(esp_tls_cfg_t cfg)
 {
     char buf[512];
     int ret, len;
 
-    while(1) {
-        esp_tls_cfg_t cfg = {
-            .crt_bundle_attach = esp_crt_bundle_attach,
-        };
+    struct esp_tls *tls = esp_tls_conn_http_new(WEB_URL, &cfg);
 
-        struct esp_tls *tls = esp_tls_conn_http_new(WEB_URL, &cfg);
+    if (tls != NULL) {
+        ESP_LOGI(TAG, "Connection established...");
+    } else {
+        ESP_LOGE(TAG, "Connection failed...");
+        goto exit;
+    }
 
-        if(tls != NULL) {
-            ESP_LOGI(TAG, "Connection established...");
-        } else {
-            ESP_LOGE(TAG, "Connection failed...");
+    size_t written_bytes = 0;
+    do {
+        ret = esp_tls_conn_write(tls,
+                                 REQUEST + written_bytes,
+                                 sizeof(REQUEST) - written_bytes);
+        if (ret >= 0) {
+            ESP_LOGI(TAG, "%d bytes written", ret);
+            written_bytes += ret;
+        } else if (ret != ESP_TLS_ERR_SSL_WANT_READ  && ret != ESP_TLS_ERR_SSL_WANT_WRITE) {
+            ESP_LOGE(TAG, "esp_tls_conn_write  returned: [0x%02X](%s)", ret, esp_err_to_name(ret));
             goto exit;
         }
+    } while (written_bytes < sizeof(REQUEST));
 
-        size_t written_bytes = 0;
-        do {
-            ret = esp_tls_conn_write(tls,
-                                     REQUEST + written_bytes,
-                                     strlen(REQUEST) - written_bytes);
-            if (ret >= 0) {
-                ESP_LOGI(TAG, "%d bytes written", ret);
-                written_bytes += ret;
-            } else if (ret != ESP_TLS_ERR_SSL_WANT_READ  && ret != ESP_TLS_ERR_SSL_WANT_WRITE) {
-                ESP_LOGE(TAG, "esp_tls_conn_write  returned 0x%x", ret);
-                goto exit;
-            }
-        } while(written_bytes < strlen(REQUEST));
-
-        ESP_LOGI(TAG, "Reading HTTP response...");
-
-        do
-        {
-            len = sizeof(buf) - 1;
-            bzero(buf, sizeof(buf));
-            ret = esp_tls_conn_read(tls, (char *)buf, len);
-
-            if(ret == ESP_TLS_ERR_SSL_WANT_WRITE  || ret == ESP_TLS_ERR_SSL_WANT_READ)
-                continue;
-
-            if(ret < 0)
-           {
-                ESP_LOGE(TAG, "esp_tls_conn_read  returned -0x%x", -ret);
-                break;
-            }
-
-            if(ret == 0)
-            {
-                ESP_LOGI(TAG, "connection closed");
-                break;
-            }
-
-            len = ret;
-            ESP_LOGD(TAG, "%d bytes read", len);
-            /* Print response directly to stdout as it is read */
-            for(int i = 0; i < len; i++) {
-                putchar(buf[i]);
-            }
-        } while(1);
-
-    exit:
-        esp_tls_conn_delete(tls);
-        putchar('\n'); // JSON output doesn't have a newline at end
+    ESP_LOGI(TAG, "Reading HTTP response...");
 
-        static int request_count;
-        ESP_LOGI(TAG, "Completed %d requests", ++request_count);
+    do {
+        len = sizeof(buf) - 1;
+        bzero(buf, sizeof(buf));
+        ret = esp_tls_conn_read(tls, (char *)buf, len);
+
+        if (ret == ESP_TLS_ERR_SSL_WANT_WRITE  || ret == ESP_TLS_ERR_SSL_WANT_READ) {
+            continue;
+        }
 
-        for(int countdown = 10; countdown >= 0; countdown--) {
-            ESP_LOGI(TAG, "%d...", countdown);
-            vTaskDelay(1000 / portTICK_PERIOD_MS);
+        if (ret < 0) {
+            ESP_LOGE(TAG, "esp_tls_conn_read  returned [-0x%02X](%s)", -ret, esp_err_to_name(ret));
+            break;
         }
-        ESP_LOGI(TAG, "Starting again!");
+
+        if (ret == 0) {
+            ESP_LOGI(TAG, "connection closed");
+            break;
+        }
+
+        len = ret;
+        ESP_LOGD(TAG, "%d bytes read", len);
+        /* Print response directly to stdout as it is read */
+        for (int i = 0; i < len; i++) {
+            putchar(buf[i]);
+        }
+        putchar('\n'); // JSON output doesn't have a newline at end
+    } while (1);
+
+exit:
+    esp_tls_conn_delete(tls);
+    for (int countdown = 10; countdown >= 0; countdown--) {
+        ESP_LOGI(TAG, "%d...", countdown);
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
     }
 }
 
+static void https_get_request_using_crt_bundle(void)
+{
+    ESP_LOGI(TAG, "https_request using crt bundle");
+    esp_tls_cfg_t cfg = {
+        .crt_bundle_attach = esp_crt_bundle_attach,
+    };
+    https_get_request(cfg);
+}
+
+static void https_get_request_using_cacert_buf(void)
+{
+    ESP_LOGI(TAG, "https_request using cacert_buf");
+    esp_tls_cfg_t cfg = {
+        .cacert_buf = (const unsigned char *) server_root_cert_pem_start,
+        .cacert_bytes = server_root_cert_pem_end - server_root_cert_pem_start,
+    };
+    https_get_request(cfg);
+}
+
+static void https_get_request_using_global_ca_store(void)
+{
+    esp_err_t esp_ret = ESP_FAIL;
+    ESP_LOGI(TAG, "https_request using global ca_store");
+    esp_ret = esp_tls_set_global_ca_store(server_root_cert_pem_start, server_root_cert_pem_end - server_root_cert_pem_start);
+    if (esp_ret != ESP_OK) {
+        ESP_LOGE(TAG, "Error in setting the global ca store: [%02X] (%s),could not complete the https_request using global_ca_store", esp_ret, esp_err_to_name(esp_ret));
+        return;
+    }
+    esp_tls_cfg_t cfg = {
+        .use_global_ca_store = true,
+    };
+    https_get_request(cfg);
+    esp_tls_free_global_ca_store();
+}
+
+static void https_request_task(void *pvparameters)
+{
+    ESP_LOGI(TAG, "Start https_request example");
+
+    https_get_request_using_crt_bundle();
+    https_get_request_using_cacert_buf();
+    https_get_request_using_global_ca_store();
+
+    ESP_LOGI(TAG, "Finish https_request example");
+    vTaskDelete(NULL);
+}
+
 void app_main(void)
 {
     ESP_ERROR_CHECK( nvs_flash_init() );
@@ -146,5 +193,5 @@ void app_main(void)
      */
     ESP_ERROR_CHECK(example_connect());
 
-    xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
+    xTaskCreate(&https_request_task, "https_get_task", 8192, NULL, 5, NULL);
 }

+ 27 - 0
examples/protocols/https_request/main/server_root_cert.pem

@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
+SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
+GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
+q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
+SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
+Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
+a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
+/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
+AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
+CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
+bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
+c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
+VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
+ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
+MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
+Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
+AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
+uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
+wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
+X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
+PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
+KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
+-----END CERTIFICATE-----