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:
Gerson Fernando Budke 2020-08-18 21:53:34 -03:00 committed by Carles Cufí
commit eb0f571790
7 changed files with 166 additions and 1 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
} }