Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esp_encrypted_img: Add pre_encrypted_ota example to the component #201

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .build-test-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ esp_lcd_qemu_rgb/examples/lcd_qemu_rgb_panel:
enable:
- if: ((IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 3) or (IDF_VERSION_MAJOR > 5)) and (IDF_TARGET in ["esp32", "esp32c3"])
reason: Example is meant to be run under QEMU, which currently only supports ESP32 and ESP32-C3
esp_encrypted_img/examples/pre_encrypted_ota:
enable:
- if: IDF_VERSION_MAJOR > 4 and INCLUDE_DEFAULT == 1
reason: Example uses esp_encrypted_img component which was introduced in IDF v5.0
4 changes: 2 additions & 2 deletions .github/workflows/build_and_run_examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/"
run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf
run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf rangehttpserver
- name: Run examples
run: pytest --target=${{ matrix.idf_target }} -m generic --build-dir=build_${{ matrix.idf_target }} --ignore=usb --ignore=test_app

Expand Down Expand Up @@ -90,6 +90,6 @@ jobs:
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/"
run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf
run: pip install --only-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf rangehttpserver
- name: Run examples
run: pytest --target=${{ matrix.idf_target }} -m ethernet --build-dir=build_${{ matrix.idf_target }} --ignore=usb --ignore=test_app
84 changes: 84 additions & 0 deletions .github/workflows/pre_encrypted_ota_build_and_run.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: "Pre Encrypted OTA: Build and Run Example"

on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]

jobs:
build_pre_encrypted_ota:
name: Build
strategy:
fail-fast: false
matrix:
idf_ver: ["latest"]
test: [ { app: example, path: "examples/pre_encrypted_ota" } ]
runs-on: ubuntu-20.04
container: espressif/idf:${{ matrix.idf_ver }}
env:
TEST_DIR: esp_encrypted_img/${{ matrix.test.path }}
steps:
- name: Checkout idf-extra-components
uses: actions/checkout@v3
with:
submodules: 'true'
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
python -m pip install idf-component-manager idf-build-apps --upgrade
export PEDANTIC_FLAGS="-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function"
export EXTRA_CFLAGS="${PEDANTIC_FLAGS} -Wstrict-prototypes"
export EXTRA_CXXFLAGS="${PEDANTIC_FLAGS}"
cd ${TEST_DIR}
idf.py set-target esp32
cat sdkconfig.ci >> sdkconfig
idf.py build

for dir in `ls -d build`; do
find $1 ! -regex ".*/build[^/]*/[^/]+.\(bin\|elf\)" -a ! -regex ".*\(bootloader\|partition-table\).bin" -a ! -name "flasher_args.json" -a ! -regex ".*/build[^/]*/config/sdkconfig.\(h\|json\)" -delete || true
zip -qur artifacts.zip $dir
done
- uses: actions/upload-artifact@v3
with:
name: pre_encrypted_ota_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
path: ${{ env.TEST_DIR }}/artifacts.zip
if-no-files-found: error

run-target-pre-encrypted-ota:
# Skip running on forks since it won't have access to secrets
name: Target test
needs: build_pre_encrypted_ota
strategy:
fail-fast: false
matrix:
idf_ver: ["latest"]
idf_target: ["esp32"]
test: [ { app: example, path: "examples/pre_encrypted_ota" }]
runs-on:
- self-hosted
- ESP32-ETHERNET-KIT
env:
TEST_DIR: esp_encrypted_img/${{ matrix.test.path }}
container:
image: python:3.7-buster
options: --privileged # Privileged mode has access to serial ports
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: pre_encrypted_ota_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
# path: ${{ env.TEST_DIR }}/ci/
- name: Install Python packages
env:
PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/"
run: pip install --only-binary pytest-embedded cryptography pytest-embedded-serial-esp pytest-embedded-idf rangehttpserver
- name: Run Pre Encrypted OTA Test on target
working-directory: ${{ env.TEST_DIR }}
run: |
rm -rf build sdkconfig.defaults
unzip artifacts.zip
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"build"}.xml --target=${{ matrix.idf_target }}
done
8 changes: 8 additions & 0 deletions esp_encrypted_img/examples/pre_encrypted_ota/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# 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)
49 changes: 49 additions & 0 deletions esp_encrypted_img/examples/pre_encrypted_ota/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | 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).

## 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.

## 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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
idf_build_get_property(project_dir PROJECT_DIR)
idf_component_register(SRCS "pre_encrypted_ota.c"
INCLUDE_DIRS "."
EMBED_TXTFILES ${project_dir}/server_certs/ca_cert.pem
${project_dir}/rsa_key/private.pem)

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)
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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.
endmenu
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## IDF Component Manager Manifest File
version: "1.0.0"
description: Pre Encrypted OTA Example
dependencies:
espressif/esp_encrypted_img:
version: "^2.0.1"
override_path: '../../../'
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
Loading
Loading