From d32128440d836a65412698afb0b0d03b34fc14ee Mon Sep 17 00:00:00 2001 From: Sagar Bijwe Date: Fri, 1 Feb 2019 13:05:48 +0530 Subject: [PATCH] nvs_flash: Detect key partition as uninitialised even if encrypted by bootloader Currently, only erase operation performed by the application leads to detection of NVS key partition as uninitialised. This change adds additional checks for detecting partition as uninitialised, when device boots first time right after encryption by bootloader. --- components/nvs_flash/src/nvs_api.cpp | 23 ++++-- components/nvs_flash/test/test_nvs.c | 101 +++++++++++++++------------ 2 files changed, 73 insertions(+), 51 deletions(-) diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index 35462dd338..e993c9637a 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -627,6 +627,16 @@ extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partitio uint8_t eky_raw[NVS_KEY_SIZE], tky_raw[NVS_KEY_SIZE]; uint32_t crc_raw, crc_read, crc_calc; + auto check_if_initialized = [](uint8_t* eky, uint8_t* tky, uint32_t crc) { + uint8_t cnt = 0; + while(cnt < NVS_KEY_SIZE && eky[cnt] == 0xff && tky[cnt] == 0xff) cnt++; + + if(cnt == NVS_KEY_SIZE && crc == 0xffffffff) { + return false; + } + return true; + }; + auto err = spi_flash_read(partition->address, eky_raw, NVS_KEY_SIZE); if(err != ESP_OK) { return err; @@ -642,12 +652,7 @@ extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partitio return err; } - - uint8_t cnt = 0; - - while(cnt < NVS_KEY_SIZE && eky_raw[cnt] == 0xff && tky_raw[cnt] == 0xff) cnt++; - - if(cnt == NVS_KEY_SIZE && crc_raw == 0xffffffff) { + if(!check_if_initialized(eky_raw, tky_raw, crc_raw)) { /* This is an uninitialized key partition*/ return ESP_ERR_NVS_KEYS_NOT_INITIALIZED; } @@ -673,7 +678,11 @@ extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partitio crc_calc = crc32_le(0xffffffff, cfg->eky, NVS_KEY_SIZE); crc_calc = crc32_le(crc_calc, cfg->tky, NVS_KEY_SIZE); - if(crc_calc != crc_read) { + if(crc_calc != crc_read) { + if(!check_if_initialized(cfg->eky, cfg->tky, crc_read)) { + /* This is an uninitialized key partition*/ + return ESP_ERR_NVS_KEYS_NOT_INITIALIZED; + } return ESP_ERR_NVS_CORRUPT_KEY_PART; } diff --git a/components/nvs_flash/test/test_nvs.c b/components/nvs_flash/test/test_nvs.c index 2e10ebde20..a8667dc016 100644 --- a/components/nvs_flash/test/test_nvs.c +++ b/components/nvs_flash/test/test_nvs.c @@ -310,77 +310,90 @@ TEST_CASE("Check nvs key partition APIs (read and generate keys)", "[nvs]") TEST_CASE("test nvs apis with encryption enabled", "[nvs]") { - - if (!esp_flash_encryption_enabled()) { TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_api tests with encryption enabled"); } const esp_partition_t* key_part = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL); + + assert(key_part && "partition table must have an NVS Key partition"); const esp_partition_t* nvs_partition = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); assert(nvs_partition && "partition table must have an NVS partition"); - ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + ESP_ERROR_CHECK( esp_partition_erase_range(key_part, 0, key_part->size) ); - nvs_sec_cfg_t cfg; - esp_err_t err = nvs_flash_read_security_cfg(key_part, &cfg); + bool done = false; - if(err == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) { - TEST_ESP_OK(nvs_flash_generate_keys(key_part, &cfg)); - } else { - ESP_ERROR_CHECK(err); - } - TEST_ESP_OK(nvs_flash_secure_init(&cfg)); - - nvs_handle handle_1; + do { + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); - TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND); + nvs_sec_cfg_t cfg; + esp_err_t err = nvs_flash_read_security_cfg(key_part, &cfg); + if(err == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) { + uint8_t value[4096] = {[0 ... 4095] = 0xff}; + TEST_ESP_OK(esp_partition_write(key_part, 0, value, sizeof(value))); - TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1)); + TEST_ESP_ERR(nvs_flash_read_security_cfg(key_part, &cfg), ESP_ERR_NVS_KEYS_NOT_INITIALIZED); - TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678)); - TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789)); + TEST_ESP_OK(nvs_flash_generate_keys(key_part, &cfg)); + } else { + /* Second time key_partition exists already*/ + ESP_ERROR_CHECK(err); + done = true; + } + TEST_ESP_OK(nvs_flash_secure_init(&cfg)); - nvs_handle handle_2; - TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2)); - TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a)); - const char* str = "value 0123456789abcdef0123456789abcdef"; - TEST_ESP_OK(nvs_set_str(handle_2, "key", str)); + nvs_handle handle_1; - int32_t v1; - TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1)); - TEST_ASSERT_TRUE(0x23456789 == v1); + TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND); - int32_t v2; - TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2)); - TEST_ASSERT_TRUE(0x3456789a == v2); - char buf[strlen(str) + 1]; - size_t buf_len = sizeof(buf); + TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1)); - size_t buf_len_needed; - TEST_ESP_OK(nvs_get_str(handle_2, "key", NULL, &buf_len_needed)); - TEST_ASSERT_TRUE(buf_len_needed == buf_len); + TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678)); + TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789)); - size_t buf_len_short = buf_len - 1; - TEST_ESP_ERR(ESP_ERR_NVS_INVALID_LENGTH, nvs_get_str(handle_2, "key", buf, &buf_len_short)); - TEST_ASSERT_TRUE(buf_len_short == buf_len); + nvs_handle handle_2; + TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2)); + TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a)); + const char* str = "value 0123456789abcdef0123456789abcdef"; + TEST_ESP_OK(nvs_set_str(handle_2, "key", str)); - size_t buf_len_long = buf_len + 1; - TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len_long)); - TEST_ASSERT_TRUE(buf_len_long == buf_len); + int32_t v1; + TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1)); + TEST_ASSERT_TRUE(0x23456789 == v1); - TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len)); + int32_t v2; + TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2)); + TEST_ASSERT_TRUE(0x3456789a == v2); - TEST_ASSERT_TRUE(0 == strcmp(buf, str)); + char buf[strlen(str) + 1]; + size_t buf_len = sizeof(buf); - nvs_close(handle_1); - nvs_close(handle_2); + size_t buf_len_needed; + TEST_ESP_OK(nvs_get_str(handle_2, "key", NULL, &buf_len_needed)); + TEST_ASSERT_TRUE(buf_len_needed == buf_len); - TEST_ESP_OK(nvs_flash_deinit()); + size_t buf_len_short = buf_len - 1; + TEST_ESP_ERR(ESP_ERR_NVS_INVALID_LENGTH, nvs_get_str(handle_2, "key", buf, &buf_len_short)); + TEST_ASSERT_TRUE(buf_len_short == buf_len); + + size_t buf_len_long = buf_len + 1; + TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len_long)); + TEST_ASSERT_TRUE(buf_len_long == buf_len); + + TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len)); + + TEST_ASSERT_TRUE(0 == strcmp(buf, str)); + + nvs_close(handle_1); + nvs_close(handle_2); + + TEST_ESP_OK(nvs_flash_deinit()); + } while(!done); } TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled", "[nvs_part_gen]") -- 2.40.0