diff --git a/.build-test-rules.yml b/.build-test-rules.yml index 4567c80a02..14cd48abe6 100644 --- a/.build-test-rules.yml +++ b/.build-test-rules.yml @@ -19,6 +19,11 @@ esp_delta_ota: - if: SOC_WIFI_SUPPORTED != 1 reason: Relevant only for WiFi enabled targets +esp_encrypted_img/examples/pre_encrypted_ota: + disable: + - if: IDF_TARGET not in ["esp32"] + reason: Unable to recieve correct data from pytest + sh2lib/examples/http2_request: enable: - if: IDF_VERSION_MAJOR > 4 and INCLUDE_DEFAULT == 1 diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/CMakeLists.txt b/esp_encrypted_img/examples/pre_encrypted_ota/CMakeLists.txt new file mode 100644 index 0000000000..3cb56e6a69 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/CMakeLists.txt @@ -0,0 +1,17 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five 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.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(pre_encrypted_ota) + +# Flash the pre_encrypted_ota_secure.bin to the OTA 1 partition. +if(CONFIG_EXAMPLE_ENABLE_CI_TEST) + set(partition ota_1) + idf_build_get_property(build_dir BUILD_DIR) + set(image_file ${build_dir}/pre_encrypted_ota_secure.bin) + partition_table_get_partition_info(offset "--partition-name ${partition}" "offset") + esptool_py_flash_target_image(flash "${partition}" "${offset}" "${image_file}") +endif() \ No newline at end of file diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/README.md b/esp_encrypted_img/examples/pre_encrypted_ota/README.md new file mode 100644 index 0000000000..2433e3789b --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/README.md @@ -0,0 +1,58 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | + +# Encrypted Binary OTA + +This example demonstrates OTA updates with pre-encrypted binary using `esp_encrypted_img` component's APIs and tool. + +Pre-encrypted firmware binary must be hosted on OTA update server. +This firmware will be fetched and then decrypted on device before being flashed. +This allows firmware to remain `confidential` on the OTA update channel irrespective of underlying transport (e.g., non-TLS). + +* **NOTE:** Pre-encrypted OTA is a completely different scheme from Flash Encryption. Pre-encrypted OTA helps in ensuring the confidentiality of the firmware on the network channel, whereas Flash Encryption is intended for encrypting the contents of the ESP32's off-chip flash memory. + +> [!CAUTION] +> Using the Pre-encrypted Binary OTA provides confidentiality of the firmware, but it does not ensure authenticity of the firmware. For ensuring that the firmware is coming from trusted source, please consider enabling secure boot feature along with the Pre-encrypted binary OTA. Please refer to security guide in the ESP-IDF docs for more details. + +## ESP Encrypted Image Abstraction Layer + +This example uses `esp_encrypted_img` component hosted at [idf-extra-components/esp_encrypted_img](https://github.com/espressif/idf-extra-components/blob/master/esp_encrypted_img) and available though the [IDF component manager](https://components.espressif.com/component/espressif/esp_encrypted_img). + +Please refer to its documentation [here](https://github.com/espressif/idf-extra-components/blob/master/esp_encrypted_img/README.md) for more details. + + +## How to use the example + +To create self-signed certificate and key, refer to README.md in upper level 'examples' directory. This certificate should be flashed with binary as it will be used for connection with server. + +### Creating RSA key for encryption + +You can generate a public and private RSA key pair using following commands: + +`openssl genrsa -out rsa_key/private.pem 3072` + +This generates a 3072-bit RSA key pair, and writes them to a file. + +Private key is required for decryption process and is used as input to the `esp_encrypted_img` component. Private key can either be embedded into the firmware or stored in NVS. + +Encrypted image generation tool will derive public key (from private key) and use it for encryption purpose. + +* **NOTE:** We highly recommend the use of flash encryption or NVS encryption to protect the RSA Private Key on the device. +* **NOTE:** RSA key provided in the example is for demonstration purpose only. We recommend to create a new key for production applications. + +### How to take firware URL from STDIN + +You can take the firmware URL (or other data, just include the data with URL using " " deliminator) by enabling both CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN and CONFIG_EXAMPLE_ENABLE_CI_TEST configs. + +## Build and Flash example + +``` +idf.py build flash +``` + +* An encrypted image is automatically generated by build system. Upload the generated encrypted image (`build/pre_encrypted_ota_secure.bin`) to a server for performing OTA update. + + +## Configuration + +Refer the README.md in the parent directory for the setup details. diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/conftest.py b/esp_encrypted_img/examples/pre_encrypted_ota/conftest.py new file mode 100644 index 0000000000..0e60e4ac9b --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/conftest.py @@ -0,0 +1,16 @@ +import logging +import os + +import pytest +from _pytest.fixtures import FixtureRequest +from pytest_embedded.plugin import multi_dut_fixture + +@pytest.fixture +@multi_dut_fixture +def build_dir(target: str, config: str) -> str: + return f'build_{target}_{config}' + +@pytest.fixture +@multi_dut_fixture +def config(request: FixtureRequest) -> str: + return getattr(request, 'param', None) or "default" \ No newline at end of file diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/main/CMakeLists.txt b/esp_encrypted_img/examples/pre_encrypted_ota/main/CMakeLists.txt new file mode 100644 index 0000000000..afa0560141 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/main/CMakeLists.txt @@ -0,0 +1,27 @@ +idf_build_get_property(project_dir PROJECT_DIR) + +set(SRCS "") +set(INCLUDE_DIRS "") +set(EMBED_TXTFILES "") + +if(CONFIG_EXAMPLE_ENABLE_CI_TEST) + list(APPEND SRCS + "tests/test_local_server_ota.c") + list(APPEND INCLUDE_DIRS "tests") + list(APPEND EMBED_TXTFILES "tests/certs/servercert.pem" + "tests/certs/prvtkey.pem") +endif() + +idf_component_register(SRCS "pre_encrypted_ota.c" ${SRCS} + PRIV_REQUIRES esp_http_client app_update esp_https_ota nvs_flash esp_netif esp_wifi esp_netif esp_partition + INCLUDE_DIRS "." ${INCLUDE_DIRS} + EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem + ${project_dir}/rsa_key/private.pem + ${EMBED_TXTFILES}) + +create_esp_enc_img(${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin + ${project_dir}/rsa_key/private.pem ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}_secure.bin app) + +if(CONFIG_EXAMPLE_ENABLE_CI_TEST) + target_link_libraries(${COMPONENT_LIB} PRIVATE idf::esp_https_server) +endif() diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/main/Kconfig.projbuild b/esp_encrypted_img/examples/pre_encrypted_ota/main/Kconfig.projbuild new file mode 100644 index 0000000000..2f433de60c --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/main/Kconfig.projbuild @@ -0,0 +1,51 @@ +menu "Example Configuration" + + config EXAMPLE_FIRMWARE_UPGRADE_URL + string "firmware upgrade url endpoint" + default "https://192.168.0.3:8070/hello_world.bin" + help + URL of server which hosts the encrypted firmware image. + + config EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN + bool + default y if EXAMPLE_FIRMWARE_UPGRADE_URL = "FROM_STDIN" + + config EXAMPLE_SKIP_COMMON_NAME_CHECK + bool "Skip server certificate CN fieldcheck" + default n + help + This allows you to skip the validation of OTA server certificate CN field. + + config EXAMPLE_SKIP_VERSION_CHECK + bool "Skip firmware version check" + default n + help + This allows you to skip the firmware version check. + + config EXAMPLE_OTA_RECV_TIMEOUT + int "OTA Receive Timeout" + default 5000 + help + Maximum time for reception + + config EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD + bool "Enable partial HTTP download" + default n + help + This enables use of Range header in esp_https_ota component. + Firmware image will be downloaded over multiple HTTP requests. + + config EXAMPLE_HTTP_REQUEST_SIZE + int "HTTP request size" + default MBEDTLS_SSL_IN_CONTENT_LEN + depends on EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD + help + This options specifies HTTP request size. Number of bytes specified + in this option will be downloaded in single HTTP request. + + config EXAMPLE_ENABLE_CI_TEST + bool "Enbale the CI test code" + default n + help + This enables the CI test code i.e. https local server code. +endmenu diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/main/idf_component.yml b/esp_encrypted_img/examples/pre_encrypted_ota/main/idf_component.yml new file mode 100644 index 0000000000..c4f90613ca --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/main/idf_component.yml @@ -0,0 +1,6 @@ +dependencies: + espressif/esp_encrypted_img: + version: "*" + override_path: ../../../ + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/main/pre_encrypted_ota.c b/esp_encrypted_img/examples/pre_encrypted_ota/main/pre_encrypted_ota.c new file mode 100644 index 0000000000..9ab2b1f2a5 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/main/pre_encrypted_ota.c @@ -0,0 +1,226 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Pre Encrypted HTTPS OTA 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 +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_ota_ops.h" +#include "esp_http_client.h" +#include "esp_https_ota.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "protocol_examples_common.h" +#include "esp_encrypted_img.h" + +#if CONFIG_EXAMPLE_ENABLE_CI_TEST +#include "test_local_server_ota.h" +#endif +#if CONFIG_EXAMPLE_CONNECT_WIFI +#include "esp_wifi.h" +#endif + +static const char *TAG = "pre_encrypted_ota_example"; + +extern const char server_cert_pem_start[] asm("_binary_ca_cert_pem_start"); +extern const char server_cert_pem_end[] asm("_binary_ca_cert_pem_end"); + +extern const char rsa_private_pem_start[] asm("_binary_private_pem_start"); +extern const char rsa_private_pem_end[] asm("_binary_private_pem_end"); + +static esp_err_t validate_image_header(esp_app_desc_t *new_app_info) +{ + if (new_app_info == NULL) { + return ESP_ERR_INVALID_ARG; + } + + const esp_partition_t *running = esp_ota_get_running_partition(); + esp_app_desc_t running_app_info; + if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) { + ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version); + } + +#ifndef CONFIG_EXAMPLE_SKIP_VERSION_CHECK + if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) { + ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update."); + return ESP_FAIL; + } +#endif + return ESP_OK; +} + +static esp_err_t _decrypt_cb(decrypt_cb_arg_t *args, void *user_ctx) +{ + if (args == NULL || user_ctx == NULL) { + ESP_LOGE(TAG, "_decrypt_cb: Invalid argument"); + return ESP_ERR_INVALID_ARG; + } + esp_err_t err; + pre_enc_decrypt_arg_t pargs = {}; + pargs.data_in = args->data_in; + pargs.data_in_len = args->data_in_len; + err = esp_encrypted_img_decrypt_data((esp_decrypt_handle_t *)user_ctx, &pargs); + if (err != ESP_OK && err != ESP_ERR_NOT_FINISHED) { + return err; + } + + static bool is_image_verified = false; + if (pargs.data_out_len > 0) { + args->data_out = pargs.data_out; + args->data_out_len = pargs.data_out_len; + if (!is_image_verified) { + is_image_verified = true; + const int app_desc_offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t); + // It is unlikely to not have App Descriptor available in first iteration of decrypt callback. + assert(args->data_out_len >= app_desc_offset + sizeof(esp_app_desc_t)); + esp_app_desc_t *app_info = (esp_app_desc_t *) &args->data_out[app_desc_offset]; + err = validate_image_header(app_info); + if (err != ESP_OK) { + free(pargs.data_out); + } + return err; + } + } else { + args->data_out_len = 0; + } + + return ESP_OK; +} + +void pre_encrypted_ota_task(void *pvParameter) +{ + ESP_LOGI(TAG, "Starting Pre Encrypted OTA example"); + + esp_err_t ota_finish_err = ESP_OK; + + esp_http_client_config_t config = { + .url = CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL, + .cert_pem = server_cert_pem_start, + .timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT, + .keep_alive_enable = true, + }; + esp_decrypt_cfg_t cfg = {}; + cfg.rsa_priv_key = rsa_private_pem_start; + cfg.rsa_priv_key_len = rsa_private_pem_end - rsa_private_pem_start; + esp_decrypt_handle_t decrypt_handle = esp_encrypted_img_decrypt_start(&cfg); + if (!decrypt_handle) { + ESP_LOGE(TAG, "OTA upgrade failed"); + vTaskDelete(NULL); + } + +#if CONFIG_EXAMPLE_ENABLE_CI_TEST + example_test_firmware_data_from_stdin(&config.url); +#endif + +#ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK + config.skip_cert_common_name_check = true; +#endif + + esp_https_ota_config_t ota_config = { + .http_config = &config, +#ifdef CONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD + .partial_http_download = true, + .max_http_request_size = CONFIG_EXAMPLE_HTTP_REQUEST_SIZE, +#endif + .decrypt_cb = _decrypt_cb, + .decrypt_user_ctx = (void *)decrypt_handle, + .enc_img_header_size = esp_encrypted_img_get_header_size(), + }; + + esp_https_ota_handle_t https_ota_handle = NULL; + esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "ESP HTTPS OTA Begin failed"); + vTaskDelete(NULL); + } + + while (1) { + err = esp_https_ota_perform(https_ota_handle); + if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) { + break; + } + // esp_https_ota_perform returns after every read operation which gives user the ability to + // monitor the status of OTA upgrade by calling esp_https_ota_get_image_len_read, which gives length of image + // data read so far. + ESP_LOGD(TAG, "Image bytes read: %d", esp_https_ota_get_image_len_read(https_ota_handle)); + } + + if (!esp_https_ota_is_complete_data_received(https_ota_handle)) { + // the OTA image was not completely received and user can customise the response to this situation. + ESP_LOGE(TAG, "Complete data was not received."); + } else { + err = esp_encrypted_img_decrypt_end(decrypt_handle); + if (err != ESP_OK) { + goto ota_end; + } + ota_finish_err = esp_https_ota_finish(https_ota_handle); + if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) { + ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade successful. Rebooting ..."); + vTaskDelay(1000 / portTICK_PERIOD_MS); + esp_restart(); + } else { + if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) { + ESP_LOGE(TAG, "Image validation failed, image is corrupted"); + } + ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed 0x%x", ota_finish_err); + vTaskDelete(NULL); + } + } + +ota_end: + esp_https_ota_abort(https_ota_handle); + ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed"); + vTaskDelete(NULL); +} + +void app_main(void) +{ + // Initialize NVS. + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + // 1.OTA app partition table has a smaller NVS partition size than the non-OTA + // partition table. This size mismatch may cause NVS initialization to fail. + // 2.NVS partition contains data in new format and cannot be recognized by this version of code. + // If this happens, we erase NVS partition and initialize NVS again. + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + +#if CONFIG_EXAMPLE_CONNECT_WIFI + /* Ensure to disable any WiFi power save mode, this allows best throughput + * and hence timings for overall OTA operation. + */ + esp_wifi_set_ps(WIFI_PS_NONE); +#endif // CONFIG_EXAMPLE_CONNECT_WIFI + +#if CONFIG_EXAMPLE_ENABLE_CI_TEST + if (example_test_start_webserver() != ESP_OK) { + ESP_LOGE(TAG, "Unable to start server"); + } +#endif + xTaskCreate(&pre_encrypted_ota_task, "pre_encrypted_ota_task", 1024 * 8, NULL, 5, NULL); +} diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/certs/prvtkey.pem b/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/certs/prvtkey.pem new file mode 100644 index 0000000000..70d29078c4 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/certs/prvtkey.pem @@ -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/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/certs/servercert.pem b/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/certs/servercert.pem new file mode 100644 index 0000000000..cd2b80c824 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/certs/servercert.pem @@ -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/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/test_local_server_ota.c b/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/test_local_server_ota.c new file mode 100644 index 0000000000..1ea1463870 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/test_local_server_ota.c @@ -0,0 +1,191 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Pre Encrypted HTTPS OTA example's test file + + 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_https_server.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "test_local_server_ota.h" +#include "protocol_examples_common.h" + +#define OTA_URL_SIZE 256 +#define PARTITION_READ_BUFFER_SIZE 256 +#define PARTITION_READ_SIZE 256 +#define PARTITION_READ_OFFSET 0 + +static const char *TAG = "test_local_server_ota"; +static size_t binary_size; + +#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN +void example_test_firmware_data_from_stdin(const char **data) +{ + char input_buf[OTA_URL_SIZE]; + if (strcmp(*data, "FROM_STDIN") == 0) { + example_configure_stdin_stdout(); + fflush(stdin); + char *url = NULL; + char *tokens[OTA_URL_SIZE], *saveptr; + int token_count = 0; + + fgets(input_buf, OTA_URL_SIZE, stdin); + int len = strlen(input_buf); + if (len > 0 && input_buf[len - 1] == '\n') { + input_buf[len - 1] = '\0'; + } + char *token = strtok_r(input_buf, " ", &saveptr); + if (token == NULL) { + return; + } + // First token is the URL + url = token; + tokens[token_count++] = url; + // Process remaining tokens + while ((token = strtok_r(NULL, " ", &saveptr)) != NULL) { + tokens[token_count++] = token; + } + // Return if no further data is captured + if (strchr(input_buf, ' ') != NULL) { + return; + } + *data = strdup(tokens[0]); + // Assign the URL and additional data after the loop + if (token_count > 1) { + ESP_LOGI(TAG, "binary_size: %s\n", tokens[1]); + binary_size = atoi(tokens[1]); // Assuming the next token is the binary size + } + // Tokens are collected in the tokens array + } else { + ESP_LOGE(TAG, "Configuration mismatch: wrong firmware upgrade image url"); + abort(); + } +} +#endif +/* An HTTP GET handler */ +static esp_err_t root_get_handler(httpd_req_t *req) +{ + httpd_resp_set_type(req, "text/plain"); + const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_APP, + ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL); + + + assert(p != NULL); + + if (binary_size == 0) { + return ESP_FAIL; + } + + int image_len = binary_size; + char buffer[PARTITION_READ_BUFFER_SIZE]; + int size = PARTITION_READ_SIZE; + int offset = PARTITION_READ_OFFSET; + + do { + /* Read file in chunks into the scratch buffer */ + if (offset + size > image_len) { + size = image_len - offset; + } + if (size == 0) { + break; + } + esp_err_t ret = esp_partition_read(p, offset, buffer, size); + if (ret == ESP_OK) { + /* Send the buffer contents as HTTP response chunk */ + if (httpd_resp_send_chunk(req, buffer, size) != ESP_OK) { + ESP_LOGE(TAG, "File sending failed!"); + /* Abort sending file */ + httpd_resp_sendstr_chunk(req, NULL); + /* Respond with 500 Internal Server Error */ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file"); + return ESP_FAIL; + } + } + offset += size; + + /* Keep looping till the whole file is sent */ + } while (offset <= image_len); + + ESP_LOGI(TAG, "File sending complete"); + + // Set headers + httpd_resp_set_type(req, "application/octet-stream"); + httpd_resp_set_hdr(req, "Accept-Ranges", "bytes"); + httpd_resp_set_hdr(req, "Connection", "close"); + httpd_resp_send_chunk(req, NULL, 0); + + return ESP_OK; +} + +static esp_err_t root_head_handler(httpd_req_t *req) +{ + const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL); + + if (partition == NULL) { + ESP_LOGE(TAG, "Partition not found"); + httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Partition not found"); + return ESP_FAIL; + } + + if (binary_size == 0) { + return ESP_FAIL; + } + // Get the size of the binary + httpd_resp_set_type(req, "application/octet-stream"); + httpd_resp_set_hdr(req, "Accept-Ranges", "bytes"); + httpd_resp_set_hdr(req, "Connection", "close"); + + // Complete HEAD response with no body + return httpd_resp_send(req, NULL, binary_size); // No body for HEAD method +} + +static const httpd_uri_t root = { + .uri = "/", + .method = HTTP_GET, + .handler = root_get_handler +}; + +static const httpd_uri_t root1 = { + .uri = "/", + .method = HTTP_HEAD, + .handler = root_head_handler + +}; + +esp_err_t example_test_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 servercert_start[] asm("_binary_servercert_pem_start"); + extern const unsigned char servercert_end[] asm("_binary_servercert_pem_end"); + conf.servercert = servercert_start; + conf.servercert_len = servercert_end - servercert_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 ret; + } + + // Set URI handlers + ESP_LOGI(TAG, "Registering URI handlers"); + httpd_register_uri_handler(server, &root); + httpd_register_uri_handler(server, &root1); + return ESP_OK; +} diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/test_local_server_ota.h b/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/test_local_server_ota.h new file mode 100644 index 0000000000..4e604f8819 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/main/tests/test_local_server_ota.h @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "esp_https_server.h" + +/** + * @brief starts the https server + * + * @param bin_size the size of binary image which will be exposed + * by the server. NOTE - bin_size connot be 0. + */ +esp_err_t example_test_start_webserver(void); + +/** + * @brief Takes the firmware URL from the STDIN (if want to send + * other data write the data in just one line by adding " " deleminator). + * + * @param data pointer to the firmware URL (or URL including other data) + */ +void example_test_firmware_data_from_stdin(const char **data); diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/partitions.csv b/esp_encrypted_img/examples/pre_encrypted_ota/partitions.csv new file mode 100644 index 0000000000..f06afdcca8 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/partitions.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, , 0x4000, +otadata, data, ota, , 0x2000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 0x14B000, +ota_0, app, ota_0, , 0x14B000, +ota_1, app, ota_1, , 0x14B000, diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/pytest_pre_encrypted_ota.py b/esp_encrypted_img/examples/pre_encrypted_ota/pytest_pre_encrypted_ota.py new file mode 100644 index 0000000000..25a956579d --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/pytest_pre_encrypted_ota.py @@ -0,0 +1,65 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import http.server +import multiprocessing +import os +import socket +import ssl +from typing import Callable + +import pexpect +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.app import FlashFile +from pytest_embedded_idf.serial import IdfSerial + +enc_bin_name = 'pre_encrypted_ota_secure.bin' +host_ip = '127.0.0.1' +server_port = 443 +EXAMPLE_HTTP_REQUEST_SIZE = 16384 + +@pytest.mark.generic +def test_examples_protocol_pre_encrypted_ota_example(dut: Dut) -> None: + bin_path = os.path.join(dut.app.binary_path, enc_bin_name) + bin_size = os.path.getsize(bin_path) + # Construct the URI + uri = f'https://{host_ip}:{server_port}/' + + try: + dut.expect('Loaded app from partition at offset', timeout=30) + dut.expect('Starting Pre Encrypted OTA example', timeout=30) + dut.expect('main_task: Returned from app_main()', timeout=30) + dut.write(f'{uri} {bin_size}\n') + dut.expect('Magic Verified', timeout=30) + dut.expect('Reading RSA private key', timeout=30) + dut.expect('upgrade successful. Rebooting', timeout=60) + # after reboot + dut.expect('Loaded app from partition at offset', timeout=30) + finally: + pass + +@pytest.mark.generic +@pytest.mark.parametrize('config', ['partial_download',], indirect=True) +def test_examples_protocol_pre_encrypted_ota_example_partial_request(config, dut: Dut) -> None: + # Size of partial HTTP request + request_size = EXAMPLE_HTTP_REQUEST_SIZE + + # File to be downloaded. This file is generated after compilation + binary_file = os.path.join(dut.app.binary_path, enc_bin_name) + bin_size = os.path.getsize(binary_file) + http_requests = int((bin_size / request_size) - 1) + assert http_requests > 1 + uri = f'https://{host_ip}:{server_port}/' + + try: + dut.expect('Loaded app from partition at offset', timeout=30) + dut.expect('Starting Pre Encrypted OTA example', timeout=30) + dut.expect('main_task: Returned from app_main()', timeout=30) + dut.write(f'{uri} {bin_size}\n') + dut.expect('Magic Verified', timeout=30) + dut.expect('Reading RSA private key', timeout=30) + dut.expect('upgrade successful. Rebooting', timeout=60) + # after reboot + dut.expect('Loaded app from partition at offset', timeout=30) + finally: + pass diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/rsa_key/private.pem b/esp_encrypted_img/examples/pre_encrypted_ota/rsa_key/private.pem new file mode 100644 index 0000000000..cb0a8b7aae --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/rsa_key/private.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci b/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci new file mode 100644 index 0000000000..41ebb66990 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci @@ -0,0 +1,10 @@ +CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN" +CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y +CONFIG_EXAMPLE_SKIP_VERSION_CHECK=y +CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000 +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_ENABLE_CI_TEST=y +CONFIG_EXAMPLE_CONNECT_ETHERNET=n +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_ESP_HTTPS_SERVER_ENABLE=y diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci.default b/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci.default new file mode 100644 index 0000000000..c47088025f --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci.default @@ -0,0 +1 @@ +CONFIG_COMPILER_OPTIMIZATION_SIZE=y \ No newline at end of file diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci.partial_download b/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci.partial_download new file mode 100644 index 0000000000..88755ec37c --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.ci.partial_download @@ -0,0 +1,11 @@ +CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN" +CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y +CONFIG_EXAMPLE_SKIP_VERSION_CHECK=y +CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=3000 +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_ENABLE_CI_TEST=y +CONFIG_EXAMPLE_CONNECT_ETHERNET=n +CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_ESP_HTTPS_SERVER_ENABLE=y +CONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD=y diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.defaults b/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.defaults new file mode 100644 index 0000000000..298a6b5aa0 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/sdkconfig.defaults @@ -0,0 +1,6 @@ +# Default sdkconfig parameters to use the OTA +# partition table layout, with a 4MB flash size +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_PARTITION_TABLE_TWO_OTA=y +# Enable ESP HTTPS OTA decryption callback +CONFIG_ESP_HTTPS_OTA_DECRYPT_CB=y diff --git a/esp_encrypted_img/examples/pre_encrypted_ota/server_certs/ca_cert.pem b/esp_encrypted_img/examples/pre_encrypted_ota/server_certs/ca_cert.pem new file mode 100644 index 0000000000..cd2b80c824 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/server_certs/ca_cert.pem @@ -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/esp_encrypted_img/examples/pre_encrypted_ota/server_certs/server_key.pem b/esp_encrypted_img/examples/pre_encrypted_ota/server_certs/server_key.pem new file mode 100644 index 0000000000..20a4bdb624 --- /dev/null +++ b/esp_encrypted_img/examples/pre_encrypted_ota/server_certs/server_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDhxF/y7bygndxP +wiWLSwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQu +c32WukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2m +KRbQS5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO +2fEzYaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnv +L6Oz3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdO +AoaprFTRAgMBAAECggEAE0HCxV/N1Q1h+1OeDDGL5+74yjKSFKyb/vTVcaPCrmaH +fPvp0ddOvMZJ4FDMAsiQS6/n4gQ7EKKEnYmwTqj4eUYW8yxGUn3f0YbPHbZT+Mkj +z5woi3nMKi/MxCGDQZX4Ow3xUQlITUqibsfWcFHis8c4mTqdh4qj7xJzehD2PVYF +gNHZsvVj6MltjBDAVwV1IlGoHjuElm6vuzkfX7phxcA1B4ZqdYY17yCXUnvui46z +Xn2kUTOOUCEgfgvGa9E+l4OtdXi5IxjaSraU+dlg2KsE4TpCuN2MEVkeR5Ms3Y7Q +jgJl8vlNFJDQpbFukLcYwG7rO5N5dQ6WWfVia/5XgQKBgQD74at/bXAPrh9NxPmz +i1oqCHMDoM9sz8xIMZLF9YVu3Jf8ux4xVpRSnNy5RU1gl7ZXbpdgeIQ4v04zy5aw +8T4tu9K3XnR3UXOy25AK0q+cnnxZg3kFQm+PhtOCKEFjPHrgo2MUfnj+EDddod7N +JQr9q5rEFbqHupFPpWlqCa3QmQKBgQDldWUGokNaEpmgHDMnHxiibXV5LQhzf8Rq +gJIQXb7R9EsTSXEvsDyqTBb7PHp2Ko7rZ5YQfyf8OogGGjGElnPoU/a+Jij1gVFv +kZ064uXAAISBkwHdcuobqc5EbG3ceyH46F+FBFhqM8KcbxJxx08objmh58+83InN +P9Qr25Xw+QKBgEGXMHuMWgQbSZeM1aFFhoMvlBO7yogBTKb4Ecpu9wI5e3Kan3Al +pZYltuyf+VhP6XG3IMBEYdoNJyYhu+nzyEdMg8CwXg+8LC7FMis/Ve+o7aS5scgG +1to/N9DK/swCsdTRdzmc/ZDbVC+TuVsebFBGYZTyO5KgqLpezqaIQrTxAoGALFCU +10glO9MVyl9H3clap5v+MQ3qcOv/EhaMnw6L2N6WVT481tnxjW4ujgzrFcE4YuxZ +hgwYu9TOCmeqopGwBvGYWLbj+C4mfSahOAs0FfXDoYazuIIGBpuv03UhbpB1Si4O +rJDfRnuCnVWyOTkl54gKJ2OusinhjztBjcrV1XkCgYEA3qNi4uBsPdyz9BZGb/3G +rOMSw0CaT4pEMTLZqURmDP/0hxvTk1polP7O/FYwxVuJnBb6mzDa0xpLFPTpIAnJ +YXB8xpXU69QVh+EBbemdJWOd+zp5UCfXvb2shAeG3Tn/Dz4cBBMEUutbzP+or0nG +vSXnRLaxQhooWm+IuX9SuBQ= +-----END PRIVATE KEY-----