storage: flash_map: Add SHA-256 integrity method
Add SHA-256 flash integrity method. It reads flash data from a device giving an offset creating a SHA-256 hash to be compared with a reference. On sucess match, zero is returned, otherwise a negative errno value. Signed-off-by: Gerson Fernando Budke <nandojve@gmail.com>
This commit is contained in:
parent
9904022e77
commit
eb0f571790
7 changed files with 166 additions and 1 deletions
|
@ -75,6 +75,34 @@ struct flash_sector {
|
||||||
size_t fs_size; /** flash sector size */
|
size_t fs_size; /** flash sector size */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(CONFIG_FLASH_AREA_CHECK_INTEGRITY)
|
||||||
|
/**
|
||||||
|
* @brief Structure for verify flash region integrity
|
||||||
|
*
|
||||||
|
* This is used to pass data to be used to check flash integrity using SHA-256
|
||||||
|
* algorithm.
|
||||||
|
*/
|
||||||
|
struct flash_area_check {
|
||||||
|
const uint8_t *match; /** 256 bits match vector */
|
||||||
|
size_t clen; /** Content len to be compared */
|
||||||
|
size_t off; /** Start Offset */
|
||||||
|
uint8_t *rbuf; /** Temporary read buffer */
|
||||||
|
size_t rblen; /** Size of read buffer */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify flash memory length bytes integrity from a flash area. The start
|
||||||
|
* point is indicated by an offset value.
|
||||||
|
*
|
||||||
|
* @param[in] fa Flash area
|
||||||
|
* @param[in] fic Flash area check integrity data
|
||||||
|
*
|
||||||
|
* @return 0 on success, negative errno code on fail
|
||||||
|
*/
|
||||||
|
int flash_area_check_int_sha256(const struct flash_area *fa,
|
||||||
|
const struct flash_area_check *fac);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieve partitions flash area from the flash_map.
|
* @brief Retrieve partitions flash area from the flash_map.
|
||||||
*
|
*
|
||||||
|
|
|
@ -28,4 +28,12 @@ config FLASH_MAP_CUSTOM
|
||||||
User must provide such a description in place of default on
|
User must provide such a description in place of default on
|
||||||
if had enabled this option.
|
if had enabled this option.
|
||||||
|
|
||||||
|
config FLASH_AREA_CHECK_INTEGRITY
|
||||||
|
bool "Enable flash check functions"
|
||||||
|
select TINYCRYPT
|
||||||
|
select TINYCRYPT_SHA256
|
||||||
|
help
|
||||||
|
If enabled, there will be available the backend to check flash
|
||||||
|
integrity using SHA-256 verification algorithm.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||||
* Copyright (c) 2015 Runtime Inc
|
* Copyright (c) 2015 Runtime Inc
|
||||||
* Copyright (c) 2017 Linaro Ltd
|
* Copyright (c) 2017 Linaro Ltd
|
||||||
|
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -15,6 +16,12 @@
|
||||||
#include <soc.h>
|
#include <soc.h>
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_FLASH_AREA_CHECK_INTEGRITY)
|
||||||
|
#include <tinycrypt/constants.h>
|
||||||
|
#include <tinycrypt/sha256.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||||
struct layout_data {
|
struct layout_data {
|
||||||
uint32_t area_idx;
|
uint32_t area_idx;
|
||||||
|
@ -262,3 +269,60 @@ const struct device *flash_area_get_device(const struct flash_area *fa)
|
||||||
{
|
{
|
||||||
return device_get_binding(fa->fa_dev_name);
|
return device_get_binding(fa->fa_dev_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_FLASH_AREA_CHECK_INTEGRITY)
|
||||||
|
int flash_area_check_int_sha256(const struct flash_area *fa,
|
||||||
|
const struct flash_area_check *fac)
|
||||||
|
{
|
||||||
|
unsigned char hash[TC_SHA256_DIGEST_SIZE];
|
||||||
|
struct tc_sha256_state_struct sha;
|
||||||
|
struct device *dev;
|
||||||
|
int to_read;
|
||||||
|
int pos;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!fa || !fac || !fac->match || !fac->rbuf ||
|
||||||
|
fac->clen <= 0 || fac->off < 0 || fac->rblen <= 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_in_flash_area_bounds(fa, fac->off, fac->clen)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tc_sha256_init(&sha) != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = device_get_binding(fa->fa_dev_name);
|
||||||
|
to_read = fac->rblen;
|
||||||
|
|
||||||
|
for (pos = 0; pos < fac->clen; pos += to_read) {
|
||||||
|
if (pos + to_read > fac->clen) {
|
||||||
|
to_read = fac->clen - pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = flash_read(dev, (fa->fa_off + fac->off + pos),
|
||||||
|
fac->rbuf, to_read);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tc_sha256_update(&sha,
|
||||||
|
fac->rbuf,
|
||||||
|
to_read) != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -ESRCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tc_sha256_final(hash, &sha) != TC_CRYPTO_SUCCESS) {
|
||||||
|
return -ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(hash, fac->match, TC_SHA256_DIGEST_SIZE)) {
|
||||||
|
return -EILSEQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_FLASH_AREA_CHECK_INTEGRITY */
|
||||||
|
|
|
@ -2,3 +2,4 @@ CONFIG_ZTEST=y
|
||||||
CONFIG_FLASH=y
|
CONFIG_FLASH=y
|
||||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||||
CONFIG_FLASH_MAP=y
|
CONFIG_FLASH_MAP=y
|
||||||
|
CONFIG_FLASH_AREA_CHECK_INTEGRITY=y
|
||||||
|
|
|
@ -2,3 +2,4 @@ CONFIG_ZTEST=y
|
||||||
CONFIG_FLASH=y
|
CONFIG_FLASH=y
|
||||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||||
CONFIG_FLASH_MAP=y
|
CONFIG_FLASH_MAP=y
|
||||||
|
CONFIG_FLASH_AREA_CHECK_INTEGRITY=y
|
||||||
|
|
|
@ -2,3 +2,4 @@ CONFIG_ZTEST=y
|
||||||
CONFIG_FLASH=y
|
CONFIG_FLASH=y
|
||||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||||
CONFIG_FLASH_MAP=y
|
CONFIG_FLASH_MAP=y
|
||||||
|
CONFIG_FLASH_AREA_CHECK_INTEGRITY=y
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017 Nordic Semiconductor ASA
|
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||||
* Copyright (c) 2015 Runtime Inc
|
* Copyright (c) 2015 Runtime Inc
|
||||||
|
* Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -98,9 +99,70 @@ void test_flash_area_get_sectors(void)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_flash_area_check_int_sha256(void)
|
||||||
|
{
|
||||||
|
/* echo $'0123456789abcdef\nfedcba98765432' > tst.sha
|
||||||
|
* hexdump tst.sha
|
||||||
|
*/
|
||||||
|
uint8_t tst_vec[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||||
|
0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
|
||||||
|
0x0a, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x39,
|
||||||
|
0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x0a };
|
||||||
|
/* sha256sum tst.sha */
|
||||||
|
uint8_t tst_sha[] = { 0x28, 0xf1, 0x6e, 0xea, 0xc3, 0xea, 0x89, 0x8d,
|
||||||
|
0x80, 0x9e, 0x98, 0xeb, 0x09, 0x49, 0x98, 0x08,
|
||||||
|
0x40, 0x69, 0x43, 0xa6, 0xef, 0xe1, 0xa3, 0xf9,
|
||||||
|
0x3d, 0xdf, 0x15, 0x9e, 0x06, 0xf8, 0xdd, 0xbd };
|
||||||
|
|
||||||
|
const struct flash_area *fa;
|
||||||
|
struct flash_area_check fac = { NULL, 0, -1, NULL, 0 };
|
||||||
|
uint8_t buffer[16];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_ID(image_1), &fa);
|
||||||
|
zassert_true(rc == 0, "flash_area_open() fail, error %d\n", rc);
|
||||||
|
rc = flash_area_erase(fa, 0, fa->fa_size);
|
||||||
|
zassert_true(rc == 0, "Flash erase failure (%d), error %d\n", rc);
|
||||||
|
rc = flash_area_write(fa, 0, tst_vec, sizeof(tst_vec));
|
||||||
|
zassert_true(rc == 0, "Flash img write, error %d\n", rc);
|
||||||
|
|
||||||
|
rc = flash_area_check_int_sha256(NULL, NULL);
|
||||||
|
zassert_true(rc == -EINVAL, "Flash area check int 256 params 1, 2\n");
|
||||||
|
rc = flash_area_check_int_sha256(NULL, &fac);
|
||||||
|
zassert_true(rc == -EINVAL, "Flash area check int 256 params 2\n");
|
||||||
|
rc = flash_area_check_int_sha256(fa, NULL);
|
||||||
|
zassert_true(rc == -EINVAL, "Flash area check int 256 params 1\n");
|
||||||
|
|
||||||
|
rc = flash_area_check_int_sha256(fa, &fac);
|
||||||
|
zassert_true(rc == -EINVAL, "Flash area check int 256 fac match\n");
|
||||||
|
fac.match = tst_sha;
|
||||||
|
rc = flash_area_check_int_sha256(fa, &fac);
|
||||||
|
zassert_true(rc == -EINVAL, "Flash area check int 256 fac clen\n");
|
||||||
|
fac.clen = sizeof(tst_vec);
|
||||||
|
rc = flash_area_check_int_sha256(fa, &fac);
|
||||||
|
zassert_true(rc == -EINVAL, "Flash area check int 256 fac off\n");
|
||||||
|
fac.off = 0;
|
||||||
|
rc = flash_area_check_int_sha256(fa, &fac);
|
||||||
|
zassert_true(rc == -EINVAL, "Flash area check int 256 fac rbuf\n");
|
||||||
|
fac.rbuf = buffer;
|
||||||
|
rc = flash_area_check_int_sha256(fa, &fac);
|
||||||
|
zassert_true(rc == -EINVAL, "Flash area check int 256 fac rblen\n");
|
||||||
|
fac.rblen = sizeof(buffer);
|
||||||
|
|
||||||
|
rc = flash_area_check_int_sha256(fa, &fac);
|
||||||
|
zassert_true(rc == 0, "Flash area check int 256 OK, error %d\n", rc);
|
||||||
|
tst_sha[0] = 0x00;
|
||||||
|
rc = flash_area_check_int_sha256(fa, &fac);
|
||||||
|
zassert_false(rc == 0, "Flash area check int 256 wrong sha\n");
|
||||||
|
|
||||||
|
flash_area_close(fa);
|
||||||
|
}
|
||||||
|
|
||||||
void test_main(void)
|
void test_main(void)
|
||||||
{
|
{
|
||||||
ztest_test_suite(test_flash_map,
|
ztest_test_suite(test_flash_map,
|
||||||
ztest_unit_test(test_flash_area_get_sectors));
|
ztest_unit_test(test_flash_area_get_sectors),
|
||||||
|
ztest_unit_test(test_flash_area_check_int_sha256)
|
||||||
|
);
|
||||||
ztest_run_test_suite(test_flash_map);
|
ztest_run_test_suite(test_flash_map);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue