From eb0f5717901b6f2707d866d35bc5dfc16acefe7d Mon Sep 17 00:00:00 2001 From: Gerson Fernando Budke Date: Tue, 18 Aug 2020 21:53:34 -0300 Subject: [PATCH] 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 --- include/storage/flash_map.h | 28 ++++++++ subsys/storage/flash_map/Kconfig | 8 +++ subsys/storage/flash_map/flash_map.c | 64 +++++++++++++++++++ tests/subsys/storage/flash_map/prj.conf | 1 + .../storage/flash_map/prj_native_posix.conf | 1 + .../flash_map/prj_native_posix_64.conf | 1 + tests/subsys/storage/flash_map/src/main.c | 64 ++++++++++++++++++- 7 files changed, 166 insertions(+), 1 deletion(-) diff --git a/include/storage/flash_map.h b/include/storage/flash_map.h index da57a04d737..7a227f2d57b 100644 --- a/include/storage/flash_map.h +++ b/include/storage/flash_map.h @@ -75,6 +75,34 @@ struct flash_sector { 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. * diff --git a/subsys/storage/flash_map/Kconfig b/subsys/storage/flash_map/Kconfig index 8d3b0224a62..6aba25fda64 100644 --- a/subsys/storage/flash_map/Kconfig +++ b/subsys/storage/flash_map/Kconfig @@ -28,4 +28,12 @@ config FLASH_MAP_CUSTOM User must provide such a description in place of default on 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 diff --git a/subsys/storage/flash_map/flash_map.c b/subsys/storage/flash_map/flash_map.c index 954b81f6099..cf07db44bbd 100644 --- a/subsys/storage/flash_map/flash_map.c +++ b/subsys/storage/flash_map/flash_map.c @@ -2,6 +2,7 @@ * Copyright (c) 2017 Nordic Semiconductor ASA * Copyright (c) 2015 Runtime Inc * Copyright (c) 2017 Linaro Ltd + * Copyright (c) 2020 Gerson Fernando Budke * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +16,12 @@ #include #include +#if defined(CONFIG_FLASH_AREA_CHECK_INTEGRITY) +#include +#include +#include +#endif + #if defined(CONFIG_FLASH_PAGE_LAYOUT) struct layout_data { 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); } + +#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 */ diff --git a/tests/subsys/storage/flash_map/prj.conf b/tests/subsys/storage/flash_map/prj.conf index 734d2d02c4c..fb9e5a0fd26 100644 --- a/tests/subsys/storage/flash_map/prj.conf +++ b/tests/subsys/storage/flash_map/prj.conf @@ -2,3 +2,4 @@ CONFIG_ZTEST=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y +CONFIG_FLASH_AREA_CHECK_INTEGRITY=y diff --git a/tests/subsys/storage/flash_map/prj_native_posix.conf b/tests/subsys/storage/flash_map/prj_native_posix.conf index 734d2d02c4c..fb9e5a0fd26 100644 --- a/tests/subsys/storage/flash_map/prj_native_posix.conf +++ b/tests/subsys/storage/flash_map/prj_native_posix.conf @@ -2,3 +2,4 @@ CONFIG_ZTEST=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y +CONFIG_FLASH_AREA_CHECK_INTEGRITY=y diff --git a/tests/subsys/storage/flash_map/prj_native_posix_64.conf b/tests/subsys/storage/flash_map/prj_native_posix_64.conf index 734d2d02c4c..fb9e5a0fd26 100644 --- a/tests/subsys/storage/flash_map/prj_native_posix_64.conf +++ b/tests/subsys/storage/flash_map/prj_native_posix_64.conf @@ -2,3 +2,4 @@ CONFIG_ZTEST=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y +CONFIG_FLASH_AREA_CHECK_INTEGRITY=y diff --git a/tests/subsys/storage/flash_map/src/main.c b/tests/subsys/storage/flash_map/src/main.c index f3a5526c7bb..5a0290e8169 100644 --- a/tests/subsys/storage/flash_map/src/main.c +++ b/tests/subsys/storage/flash_map/src/main.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2017 Nordic Semiconductor ASA * Copyright (c) 2015 Runtime Inc + * Copyright (c) 2020 Gerson Fernando Budke * * 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) { 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); }