From d3d145285dbc48b9caa842850c0e1b9e22ba611a Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Wed, 17 Mar 2021 16:11:03 +0800 Subject: [PATCH] flash enc: add flash encryption unit and example test for C3 --- .gitlab/ci/target-test.yml | 18 ++++++++ examples/security/flash_encryption/README.md | 11 ++--- .../security/flash_encryption/example_test.py | 19 +++++++-- .../ota/simple_ota_example/example_test.py | 42 +++++++++++++++++-- .../sdkconfig.ci.flash_enc_wifi | 15 +++++++ .../unit-test-app/configs/flash_encryption_c3 | 10 +++++ 6 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 examples/system/ota/simple_ota_example/sdkconfig.ci.flash_enc_wifi create mode 100644 tools/unit-test-app/configs/flash_encryption_c3 diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index 752f61e9a3..e4701de5db 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -252,6 +252,18 @@ example_test_C3_GENERIC: - ESP32C3 - Example_GENERIC +example_test_C3_FLASH_ENC: + extends: .example_test_esp32c3_template + tags: + - ESP32C3 + - Example_Flash_Encryption + +example_test_C3_FLASH_ENC_OTA: + extends: .example_test_esp32c3_template + tags: + - ESP32C3 + - Example_Flash_Encryption_OTA_WiFi + .test_app_template: extends: .target_test_job_template @@ -601,6 +613,12 @@ UT_C3_SPI_DUAL: - ESP32C3_IDF - Example_SPI_Multi_device +UT_C3_FLASH_ENC: + extends: .unit_test_esp32c3_template + tags: + - ESP32C3_IDF + - UT_T1_FlashEncryption + .integration_test_template: extends: - .target_test_job_template diff --git a/examples/security/flash_encryption/README.md b/examples/security/flash_encryption/README.md index 3120ee47e8..7d53618430 100644 --- a/examples/security/flash_encryption/README.md +++ b/examples/security/flash_encryption/README.md @@ -1,9 +1,6 @@ -| Supported Targets | ESP32 | -| ----------------- | ----- | - # Flash Encryption -The example checks if the flash encryption feature is enabled/disabled and if enabled prints the flash encryption mode (DEVELOPMENT / RELEASE) and FLASH_CRYPT_CNT eFuse value. +The example checks if the flash encryption feature is enabled/disabled and if enabled prints the flash encryption mode (DEVELOPMENT / RELEASE) and FLASH_CRYPT_CNT (for ESP32) or SPI_BOOT_CRYPT_CNT (for ESP32-S2 and newer targets) eFuse value. The example also demonstrates writing and reading encrypted partitions in flash. @@ -51,7 +48,7 @@ The configuration for NVS encryption involves generating the XTS encryption keys ### Build and Flash -When building the project and flashing it to the board FOR THE FIRST TIME after enabling flash encryption feature in menuconfig, run following command to program ESP32 and monitor the output: +When building the project and flashing it to the board FOR THE FIRST TIME after enabling flash encryption feature in menuconfig, run following command to program the target and monitor the output: ``` idf.py -p PORT flash monitor @@ -75,7 +72,7 @@ idf.py -p PORT encrypted-flash monitor ## Example Output -When running the example without enabling flash encryption, the output would be as follows: +When running the example without enabling flash encryption, the output would be as follows (on ESP32): ``` Example to check Flash Encryption status @@ -145,4 +142,4 @@ It is also possible to use esptool.py utility to read the eFuse values and check python $IDF_PATH/components/esptool_py/esptool/espefuse.py --port PORT summary ``` -If FLASH_CRYPT_CNT eFuse value is non-zero flash encryption is enabled +If FLASH_CRYPT_CNT (for ESP32) or SPI_BOOT_CRYPT_CNT (for ESP32-S2 and newer targets) eFuse value is non-zero flash encryption is enabled diff --git a/examples/security/flash_encryption/example_test.py b/examples/security/flash_encryption/example_test.py index f9346d016d..9df9510232 100644 --- a/examples/security/flash_encryption/example_test.py +++ b/examples/security/flash_encryption/example_test.py @@ -25,20 +25,31 @@ except ImportError: # espefuse.py --do-not-confirm -p $ESPPORT burn_efuse FLASH_CRYPT_CONFIG 0xf # espefuse.py --do-not-confirm -p $ESPPORT burn_efuse FLASH_CRYPT_CNT 0x1 # espefuse.py --do-not-confirm -p $ESPPORT burn_key flash_encryption key.bin -@ttfw_idf.idf_example_test(env_tag='Example_Flash_Encryption') +@ttfw_idf.idf_example_test(env_tag='Example_Flash_Encryption', target=['esp32', 'esp32c3']) def test_examples_security_flash_encryption(env, extra_data): - dut = env.get_dut('flash_encryption', 'examples/security/flash_encryption', dut_class=ttfw_idf.ESP32DUT) + dut = env.get_dut('flash_encryption', 'examples/security/flash_encryption') + + dut.erase_flash() # start test dut.start_app() - # calculate the expected ciphertext flash_addr = dut.app.partition_table['storage']['offset'] plain_hex_str = '00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f' plain_data = binascii.unhexlify(plain_hex_str.replace(' ', '')) + # espsecure uses the cryptography package for encrypting + # with aes-xts, but does not allow for a symmetric key + # so the key for later chips are not all zeros + if dut.TARGET == 'esp32': + key_bytes = b'\x00' * 32 + aes_xts = False + else: + key_bytes = b'\xff' + b'\x00' * 31 + aes_xts = True + # Emulate espsecure encrypt_flash_data command EncryptFlashDataArgs = namedtuple('EncryptFlashDataArgs', ['output', 'plaintext_file', 'address', 'keyfile', 'flash_crypt_conf', 'aes_xts']) - args = EncryptFlashDataArgs(BytesIO(), BytesIO(plain_data), flash_addr, BytesIO(b'\x00' * 32), 0xF, None) + args = EncryptFlashDataArgs(BytesIO(), BytesIO(plain_data), flash_addr, BytesIO(key_bytes), 0xF, aes_xts) espsecure.encrypt_flash_data(args) expected_ciphertext = args.output.getvalue() diff --git a/examples/system/ota/simple_ota_example/example_test.py b/examples/system/ota/simple_ota_example/example_test.py index ca1d552543..a69246109f 100644 --- a/examples/system/ota/simple_ota_example/example_test.py +++ b/examples/system/ota/simple_ota_example/example_test.py @@ -117,7 +117,6 @@ def test_examples_protocol_simple_ota_example(env, extra_data): print('Connected to AP with IP: {}'.format(ip_address)) except DUT.ExpectTimeout: raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP') - thread1.close() dut1.expect('Starting OTA example', timeout=30) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) @@ -151,7 +150,6 @@ def test_examples_protocol_simple_ota_example_ethernet_with_spiram_config(env, e print('Connected to AP with IP: {}'.format(ip_address)) except DUT.ExpectTimeout: raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP') - thread1.close() dut1.expect('Starting OTA example', timeout=30) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) @@ -189,7 +187,44 @@ def test_examples_protocol_simple_ota_example_with_flash_encryption(env, extra_d print('Connected to AP with IP: {}'.format(ip_address)) except DUT.ExpectTimeout: raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP') - thread1.close() + dut1.expect('Starting OTA example', timeout=30) + + print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) + dut1.write('https://' + host_ip + ':8000/simple_ota.bin') + dut1.expect('Loaded app from partition at offset 0x120000', timeout=60) + dut1.expect('Flash encryption mode is DEVELOPMENT (not secure)', timeout=10) + dut1.expect('Starting OTA example', timeout=30) + + +@ttfw_idf.idf_example_test(env_tag='Example_Flash_Encryption_OTA_WiFi', target=['esp32c3']) +def test_examples_protocol_simple_ota_example_with_flash_encryption_wifi(env, extra_data): + """ + steps: | + 1. join AP + 2. Fetch OTA image over HTTPS + 3. Reboot with the new OTA image + """ + dut1 = env.get_dut('simple_ota_example', 'examples/system/ota/simple_ota_example', app_config_name='flash_enc_wifi') + # check and log bin size + binary_file = os.path.join(dut1.app.binary_path, 'simple_ota.bin') + bin_size = os.path.getsize(binary_file) + ttfw_idf.log_performance('simple_ota_bin_size', '{}KB'.format(bin_size // 1024)) + # erase flash on the device + print('Erasing the flash in order to have an empty NVS key partiton') + dut1.erase_flash() + # start test + host_ip = get_my_ip() + thread1 = Thread(target=start_https_server, args=(dut1.app.binary_path, host_ip, 8000)) + thread1.daemon = True + thread1.start() + dut1.start_app() + dut1.expect('Loaded app from partition at offset 0x20000', timeout=30) + dut1.expect('Flash encryption mode is DEVELOPMENT (not secure)', timeout=10) + try: + ip_address = dut1.expect(re.compile(r' sta ip: ([^,]+),'), timeout=30) + print('Connected to AP with IP: {}'.format(ip_address)) + except DUT.ExpectTimeout: + raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP') dut1.expect('Starting OTA example', timeout=30) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) @@ -214,3 +249,4 @@ if __name__ == '__main__': test_examples_protocol_simple_ota_example() test_examples_protocol_simple_ota_example_ethernet_with_spiram_config() test_examples_protocol_simple_ota_example_with_flash_encryption() + test_examples_protocol_simple_ota_example_with_flash_encryption_wifi() diff --git a/examples/system/ota/simple_ota_example/sdkconfig.ci.flash_enc_wifi b/examples/system/ota/simple_ota_example/sdkconfig.ci.flash_enc_wifi new file mode 100644 index 0000000000..cfd62a636f --- /dev/null +++ b/examples/system/ota/simple_ota_example/sdkconfig.ci.flash_enc_wifi @@ -0,0 +1,15 @@ +CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN" +CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y +CONFIG_SECURE_FLASH_ENC_ENABLED=y +CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y +CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y +CONFIG_SECURE_BOOT_ALLOW_JTAG=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y +CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y +CONFIG_PARTITION_TABLE_OFFSET=0x9000 +CONFIG_EXAMPLE_CONNECT_ETHERNET=n +CONFIG_EXAMPLE_CONNECT_WIFI=y +# This is required for nvs encryption (which is enabled by default with flash encryption) +CONFIG_PARTITION_TABLE_TWO_OTA_ENCRYPTED_NVS=y diff --git a/tools/unit-test-app/configs/flash_encryption_c3 b/tools/unit-test-app/configs/flash_encryption_c3 new file mode 100644 index 0000000000..74df0aa736 --- /dev/null +++ b/tools/unit-test-app/configs/flash_encryption_c3 @@ -0,0 +1,10 @@ +CONFIG_IDF_TARGET="esp32c3" +TEST_COMPONENTS=spi_flash +TEST_GROUPS=flash_encryption +CONFIG_EFUSE_VIRTUAL=n +CONFIG_SECURE_FLASH_ENC_ENABLED=y +CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y +CONFIG_SECURE_BOOT_ALLOW_JTAG=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y +CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y