Cant make ESP32 NVS encryption work. What am I doing wrong?
Posted: Tue Jan 21, 2025 12:48 pm
Hi people! I've been struggling to set up a workflow for flash encryption, NVS encryption and secure boot. I am using the ESP32C3 chip. But after adding NVS encryption i can't retrieve the data from NVS and dont know what I am doing wrong. Any insights?
Heres my current workflow:
But when I try to execute a reading of the NVS data i get the following:
Functions involved in the process:
Context: secure_nvs_cfg_init is called in the app_main on start up and retrieve_certification_data is called after wifi has been setup and I will use certificates to setup mqtt client.
Commented portions of the code where used to add some logging to try to understand whats happening. But both versions result in the same output.
Heres my current workflow:
- # 1. Create keys:
- espsecure.py generate_flash_encryption_key flash_encryption_key.bin
- nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_keygen \
- --kp_hmac_keyfile hmac_key.bin --keyfile nvs_encr_key.bin
- # 2. Burn keys:
- espefuse.py -p /dev/ttyACM0 burn_key BLOCK_KEY2 flash_encryption_key.bin XTS_AES_128_KEY
- espefuse.py -p /dev/ttyACM0 burn_key BLOCK_KEY3 keys/hmac_key.bin HMAC_UP
- # 3. Create nvs partition image:
- nvs_partition_gen.py encrypt certs/cert_data.csv nvs_encr_partition.bin 0x8000 --inputkey keys/nvs_encr_key.bin
- # 4. Encrypt build:
- espsecure.py encrypt_flash_data --aes_xts --keyfile flash_encryption_key.bin \
- --address 0x0 --output bootloader-enc.bin build/bootloader/bootloader.bin
- espsecure.py encrypt_flash_data --aes_xts --keyfile flash_encryption_key.bin \
- --address 0x8000 --output partition-table-enc.bin build/partition_table/partition-table.bin
- espsecure.py encrypt_flash_data --aes_xts --keyfile flash_encryption_key.bin \
- --address 0x19000 --output ota_data_initial-enc.bin build/ota_data_initial.bin
- espsecure.py encrypt_flash_data --aes_xts --keyfile flash_encryption_key.bin \
- --address 0x20000 --output app-enc.bin build/app.bin
- espsecure.py encrypt_flash_data --aes_xts --keyfile flash_encryption_key.bin \
- --address 0xf000 --output final_nvs_encr_partition.bin nvs_encr_partition.bin
- # 5. Flash encrypted data:
- esptool.py --chip esp32c3 -p /dev/ttyACM0 -b 460800 --before=default_reset \
- --after=no_reset --no-stub write_flash --flash_mode dio --flash_freq 80m --flash_size keep \
- 0x0 bootloader-enc.bin \
- 0xf000 final_nvs_encr_partition.bin \
- 0x8000 partition-table-enc.bin \
- 0x19000 ota_data_initial-enc.bin \
- 0x20000 app-enc.bin
- I (279) cpu_start: Unicore app
- I (287) cpu_start: Pro cpu start user code
- I (287) cpu_start: cpu freq: 160000000 Hz
- I (288) app_init: Application information:
- I (290) app_init: Project name: icollector
- I (295) app_init: App version: 4c30755-dirty
- I (301) app_init: Compile time: Jan 17 2025 16:33:19
- I (307) app_init: ELF file SHA256: ec0e0f887...
- I (312) app_init: ESP-IDF: v5.3.1
- I (317) efuse_init: Min chip rev: v0.3
- I (322) efuse_init: Max chip rev: v1.99
- I (327) efuse_init: Chip rev: v0.4
- I (331) heap_init: Initializing. RAM available for dynamic allocation:
- I (339) heap_init: At 3FC9F0D0 len 00020F30 (131 KiB): RAM
- I (345) heap_init: At 3FCC0000 len 0001C710 (113 KiB): Retention RAM
- I (352) heap_init: At 3FCDC710 len 00002950 (10 KiB): Retention RAM
- I (359) heap_init: At 50000204 len 00001DE4 (7 KiB): RTCRAM
- I (366) spi_flash: detected chip: generic
- I (370) spi_flash: flash io: dio
- W (374) flash_encrypt: Flash encryption mode is DEVELOPMENT (not secure)
- I (382) nvs_sec_provider: NVS Encryption - Registering HMAC-based scheme...
- I (389) sleep: Configure to isolate all GPIO pins in sleep state
- I (395) sleep: Enable automatic switching of GPIO sleep configuration
- I (403) main_task: Started on CPU0
- I (403) main_task: Calling app_main()
- I (403) gpio: GPIO[0]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
- I (413) MAIN: Collector code: 0076A727843C
- I (423) CERT_MANAGER: NVS security cfg set up successfully.
- I (453) STORAGE: Partition size: total: 956561, used: 502
- I (453) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2
- I (463) WIFI STATION: Content retrieved from last successful connection. Using it...
- I (463) WIFI STATION: Trying to connect to wifi access point...
- I (513) nvs: NVS partition "nvs" is encrypted.
- I (513) pp: pp rom version: 9387209
- I (513) net80211: net80211 rom version: 9387209
- (... wifi related stuff)
- I (17353) CERT_MANAGER: NVS Partition labeled "nvs_storage" found.
- I (17353) CERT_MANAGER: Flash initialized successfully.
- I (17353) CERT_MANAGER: NVS handle opened successfully.
- E (17363) CERT_MANAGER: Failed to retrieve PEM: ESP_ERR_NVS_NOT_FOUND
- E (17363) MQTT: Could not retrieve certification data. Retrying...
- I (17373) CERT_MANAGER: NVS Partition labeled "nvs_storage" found.
- (.. loops)
Functions involved in the process:
Context: secure_nvs_cfg_init is called in the app_main on start up and retrieve_certification_data is called after wifi has been setup and I will use certificates to setup mqtt client.
- esp_err_t secure_nvs_cfg_init(void)
- {
- esp_err_t err = ESP_FAIL;
- nvs_sec_scheme_t *sec_scheme_handle = NULL;
- nvs_sec_config_hmac_t sec_scheme_cfg = NVS_SEC_PROVIDER_CFG_HMAC_DEFAULT();
- err = nvs_sec_provider_register_hmac(&sec_scheme_cfg, &sec_scheme_handle);
- if (err != ESP_OK) {
- ESP_LOGE(TAG, "Failed to register HMAC scheme for NVS encription: [0x%02X] (%s)", err, esp_err_to_name(err));
- return err;
- }
- err = nvs_flash_read_security_cfg_v2(sec_scheme_handle, &nvs_sec_cfg);
- if (err != ESP_OK)
- {
- ESP_LOGE(TAG, "Failed to read NVS security cfg: [0x%02X] (%s)", err, esp_err_to_name(err));
- }
- else
- {
- ESP_LOGI(TAG, "NVS security cfg set up successfully.");
- }
- return err;
- }
- bool retrieve_certification_data(char* certificate_id, char* pem, char* private_key, char* ca_cert, char* type)
- {
- nvs_handle_t nvs_handle;
- esp_err_t err = nvs_flash_secure_init_partition(NVS_CUSTOM_PARTITION_LABEL, &nvs_sec_cfg);
- if (err != ESP_OK)
- {
- ESP_LOGE(TAG, "Error: %s", esp_err_to_name(err));
- return false;
- }
- // const esp_partition_t* nvs_storage_partition_pointer = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NVS_CUSTOM_PARTITION_LABEL);
- // if (nvs_storage_partition_pointer == NULL)
- // {
- // ESP_LOGI(TAG, "NVS Partition with name \"%s\" not found.", NVS_CUSTOM_PARTITION_LABEL);
- // nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- // return false;
- // }
- // else
- // {
- // ESP_LOGI(TAG, "NVS Partition labeled \"%s\" found.", nvs_storage_partition_pointer->label);
- // }
- // err = nvs_flash_init_partition_ptr(nvs_storage_partition_pointer);
- // if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
- // {
- // ESP_LOGI(TAG, "Flash could not be initialized successfully. Error: %s", esp_err_to_name(err));
- // nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- // return false;
- // }
- // if (err == ESP_OK)
- // {
- // ESP_LOGI(TAG, "Flash initialized successfully.");
- // }
- err = nvs_open_from_partition(
- NVS_CUSTOM_PARTITION_LABEL, // nvs_storage_partition_pointer->label,
- "cert_storage",
- NVS_READWRITE,
- &nvs_handle
- );
- if (err != ESP_OK)
- {
- ESP_LOGE(TAG, "Failed to open NVS handle: %s", esp_err_to_name(err));
- nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- return false;
- }
- else
- {
- ESP_LOGI(TAG, "NVS handle opened successfully.");
- }
- if (certificate_id != NULL)
- {
- size_t certificate_id_size = CERTIFICATE_ID_SIZE;
- err = nvs_get_str(nvs_handle, "cert_id", certificate_id, &certificate_id_size);
- if (err != ESP_OK)
- {
- ESP_LOGE(TAG, "Failed to retrieve certificate_id: %s", esp_err_to_name(err));
- nvs_close(nvs_handle);
- nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- return false;
- }
- certificate_id[certificate_id_size - 1] = '\0';
- }
- size_t pem_size = CERTIFICATE_PAYLOAD_SIZE;
- err = nvs_get_str(nvs_handle, "pem", pem, &pem_size);
- if (err != ESP_OK)
- {
- ESP_LOGE(TAG, "Failed to retrieve PEM: %s", esp_err_to_name(err));
- nvs_close(nvs_handle);
- nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- return false;
- }
- pem[pem_size - 1] = '\0';
- size_t private_key_size = CERTIFICATE_PAYLOAD_SIZE;
- err = nvs_get_str(nvs_handle, "private_key", private_key, &private_key_size);
- if (err != ESP_OK)
- {
- ESP_LOGE(TAG, "Failed to retrieve private key: %s", esp_err_to_name(err));
- nvs_close(nvs_handle);
- nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- return false;
- }
- private_key[private_key_size - 1] = '\0';
- if (ca_cert != NULL)
- {
- size_t ca_cert_size = CERTIFICATE_PAYLOAD_SIZE;
- err = nvs_get_str(nvs_handle, "ca_cert", ca_cert, &ca_cert_size);
- if (err != ESP_OK)
- {
- ESP_LOGE(TAG, "Failed to retrieve ca cert: %s", esp_err_to_name(err));
- nvs_close(nvs_handle);
- nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- return false;
- }
- ca_cert[ca_cert_size - 1] = '\0';
- }
- if (type != NULL)
- {
- size_t type_size = 10;
- err = nvs_get_str(nvs_handle, "type", type, &type_size);
- if (err != ESP_OK)
- {
- ESP_LOGE(TAG, "Failed to retrieve certification data type: %s", esp_err_to_name(err));
- nvs_close(nvs_handle);
- nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- return false;
- }
- type[type_size - 1] = '\0';
- }
- nvs_close(nvs_handle);
- nvs_flash_deinit_partition(NVS_CUSTOM_PARTITION_LABEL);
- ESP_LOGI(TAG, "Certificate data successfully retrieved.");
- return true;
- }