Merge branch 'feature/c3_flash_enc_tests' into 'master'

flash enc: add flash encryption unit and example test for C3

Closes IDF-2936

See merge request espressif/esp-idf!12774
This commit is contained in:
Angus Gratton 2021-03-29 06:45:32 +00:00
commit 2a6dd33d35
6 changed files with 101 additions and 14 deletions

View File

@ -252,6 +252,18 @@ example_test_C3_GENERIC:
- ESP32C3 - ESP32C3
- Example_GENERIC - 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: .test_app_template:
extends: .target_test_job_template extends: .target_test_job_template
@ -601,6 +613,12 @@ UT_C3_SPI_DUAL:
- ESP32C3_IDF - ESP32C3_IDF
- Example_SPI_Multi_device - Example_SPI_Multi_device
UT_C3_FLASH_ENC:
extends: .unit_test_esp32c3_template
tags:
- ESP32C3_IDF
- UT_T1_FlashEncryption
.integration_test_template: .integration_test_template:
extends: extends:
- .target_test_job_template - .target_test_job_template

View File

@ -1,9 +1,6 @@
| Supported Targets | ESP32 |
| ----------------- | ----- |
# Flash Encryption # 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. 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 ### 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 idf.py -p PORT flash monitor
@ -75,7 +72,7 @@ idf.py -p PORT encrypted-flash monitor
## Example Output ## 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 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 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

View File

@ -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_CONFIG 0xf
# espefuse.py --do-not-confirm -p $ESPPORT burn_efuse FLASH_CRYPT_CNT 0x1 # 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 # 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): 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 # start test
dut.start_app() dut.start_app()
# calculate the expected ciphertext # calculate the expected ciphertext
flash_addr = dut.app.partition_table['storage']['offset'] 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_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(' ', '')) 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 # Emulate espsecure encrypt_flash_data command
EncryptFlashDataArgs = namedtuple('EncryptFlashDataArgs', ['output', 'plaintext_file', 'address', 'keyfile', 'flash_crypt_conf', 'aes_xts']) 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) espsecure.encrypt_flash_data(args)
expected_ciphertext = args.output.getvalue() expected_ciphertext = args.output.getvalue()

View File

@ -117,7 +117,6 @@ def test_examples_protocol_simple_ota_example(env, extra_data):
print('Connected to AP with IP: {}'.format(ip_address)) print('Connected to AP with IP: {}'.format(ip_address))
except DUT.ExpectTimeout: except DUT.ExpectTimeout:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP') raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
thread1.close()
dut1.expect('Starting OTA example', timeout=30) dut1.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) 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)) print('Connected to AP with IP: {}'.format(ip_address))
except DUT.ExpectTimeout: except DUT.ExpectTimeout:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP') raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
thread1.close()
dut1.expect('Starting OTA example', timeout=30) dut1.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) 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)) print('Connected to AP with IP: {}'.format(ip_address))
except DUT.ExpectTimeout: except DUT.ExpectTimeout:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP') 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) dut1.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) 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()
test_examples_protocol_simple_ota_example_ethernet_with_spiram_config() 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()
test_examples_protocol_simple_ota_example_with_flash_encryption_wifi()

View File

@ -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

View File

@ -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