sdk-hwV1.3/lichee/brandy-2.0/u-boot-2018/sprite/sprite_secstorage.c

773 lines
18 KiB
C
Raw Normal View History

2024-05-07 10:09:20 +00:00
/*
* (C) Copyright 2018 allwinnertech <wangwei@allwinnertech.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <malloc.h>
//#include "sprite_storage_crypt.h"
#include <sunxi_board.h>
#include <sunxi_flash.h>
#include <memalign.h>
#include <securestorage.h>
int sunxi_secure_storage_erase(const char *item_name);
int sunxi_secure_storage_erase_data_only(const char *item_name);
static unsigned int secure_storage_inited = 0;
static unsigned int map_dirty;
static inline void set_map_dirty(void)
{
map_dirty = 1;
}
static inline void clear_map_dirty(void)
{
map_dirty = 0;
}
static inline int try_map_dirty(void)
{
return map_dirty;
}
static struct map_info secure_storage_map = { { 0 } };
/*
************************************************************************************************************
*
* function
*
* name : __probe_name_in_map <EFBFBD><EFBFBD>secure storage map<EFBFBD>в<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
*parmeters : buffer :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int __probe_name_in_map(unsigned char *buffer, const char *item_name,
int *len)
{
unsigned char *buf_start = buffer;
int index = 1;
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, name, MAP_KEY_NAME_SIZE);
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, length, MAP_KEY_DATA_SIZE);
int i, j;
while (*buf_start != '\0' && (buf_start - buffer) < SEC_BLK_SIZE) {
memset(name, 0, 64);
memset(length, 0, 32);
i = j = 0;
while (buf_start[i] != ':' && (buf_start[i] != '\0') &&
(&buf_start[i] - buffer) < SEC_BLK_SIZE &&
j < MAP_KEY_NAME_SIZE) {
name[j] = buf_start[i];
i++;
j++;
}
if (j >= MAP_KEY_NAME_SIZE)
return -1;
i++;
j = 0;
while ((buf_start[i] != ' ') && (buf_start[i] != '\0') &&
(&buf_start[i] - buffer) < SEC_BLK_SIZE &&
j < MAP_KEY_DATA_SIZE) {
length[j] = buf_start[i];
i++;
j++;
}
/* deal dirty data */
if ((&buf_start[i] - buffer) >= SEC_BLK_SIZE ||
j >= MAP_KEY_DATA_SIZE) {
return -1;
}
if (!strcmp(item_name, (const char *)name)) {
buf_start += strlen(item_name) + 1;
*len = simple_strtoul((const char *)length, NULL, 10);
if (strlen(item_name) ==
strlen(SECURE_STORAGE_DUMMY_KEY_NAME) &&
!memcmp(item_name, SECURE_STORAGE_DUMMY_KEY_NAME,
strlen(SECURE_STORAGE_DUMMY_KEY_NAME)) &&
*len == 0) {
/*
* if *len == 0 it is a actual DUMMY_KEY,
* a key happen to has same name should have a non-zero len
*/
} else {
pr_msg("name in map %s\n", name);
return index;
}
}
index++;
buf_start += strlen((const char *)buf_start) + 1;
}
return -1;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int __fill_name_in_map(unsigned char *buffer, const char *item_name,
int length)
{
unsigned char *buf_start = buffer;
int index = 1;
int name_len;
uint8_t write_back_buf[sizeof(struct map_info)];
int dummy_key_index = -1;
unsigned char *dummy_key_start = NULL;
unsigned char *write_back_start = NULL;
while (*buf_start != '\0' && (buf_start - buffer) < SEC_BLK_SIZE) {
name_len = 0;
while (buf_start[name_len] != ':' &&
(&buf_start[name_len] - buffer) < SEC_BLK_SIZE &&
name_len < MAP_KEY_NAME_SIZE)
name_len++;
/* deal dirty data */
if ((&buf_start[name_len] - buffer) >= SEC_BLK_SIZE ||
name_len >= MAP_KEY_NAME_SIZE) {
pr_msg("__fill_name_in_map: dirty map, memset 0\n");
memset(buffer, 0x0, SEC_BLK_SIZE);
buf_start = buffer;
index = 1;
break;
}
if (!memcmp((const char *)buf_start, item_name, name_len) &&
strlen(item_name) == name_len) {
pr_msg("name in map %s\n", buf_start);
return index;
}
if (name_len == strlen(SECURE_STORAGE_DUMMY_KEY_NAME) &&
!memcmp((const char *)buf_start,
SECURE_STORAGE_DUMMY_KEY_NAME, name_len) &&
dummy_key_index == -1) {
/*
* DUMMY_KEY could be replaced with the input key,
* but we dont know whether to do so at this point,
* save relate info first
*/
pr_msg("found dummy_key %s\n", buf_start);
dummy_key_index = index;
dummy_key_start = buf_start;
write_back_start = dummy_key_start +
strlen((const char *)buf_start) + 1;
memset(write_back_buf, 0, sizeof(write_back_buf));
memcpy((char *)write_back_buf, write_back_start,
4096 - (write_back_start - buffer));
}
index++;
buf_start += strlen((const char *)buf_start) + 1;
}
if ((index >= 32) && (dummy_key_index == -1))
return -1;
if (dummy_key_index != -1) {
/*use index reserved by DUMMY_KEY*/
sprintf((char *)dummy_key_start, "%s:%d", item_name, length);
write_back_start = dummy_key_start +
strlen((const char *)dummy_key_start) + 1;
memcpy(write_back_start, write_back_buf,
4096 - (write_back_start - buffer));
return dummy_key_index;
} else {
/* add new index */
sprintf((char *)buf_start, "%s:%d", item_name, length);
return index;
}
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static int __discard_name_in_map(unsigned char *buffer, const char *item_name)
{
unsigned char *buf_start = buffer, *last_start;
int index = 1;
int name_len;
uint8_t write_back_buf[sizeof(struct map_info)];
while (*buf_start != '\0' && (buf_start - buffer) < SEC_BLK_SIZE) {
name_len = 0;
while (buf_start[name_len] != ':' &&
(&buf_start[name_len] - buffer) < SEC_BLK_SIZE &&
name_len < MAP_KEY_NAME_SIZE)
name_len++;
/* deal dirty data */
if ((&buf_start[name_len] - buffer) >= SEC_BLK_SIZE ||
name_len >= MAP_KEY_NAME_SIZE) {
return -1;
}
if (!memcmp((const char *)buf_start, item_name, name_len) &&
strlen(item_name) == name_len) {
/*
* replace discarded key with DUMMY_KEY, so following
* keys do not need to change their index
*/
memset(write_back_buf, 0, sizeof(write_back_buf));
last_start =
buf_start + strlen((const char *)buf_start) + 1;
memcpy(write_back_buf, last_start,
4096 - (last_start - buffer));
sprintf((char *)buf_start, "%s:%d",
SECURE_STORAGE_DUMMY_KEY_NAME, 0);
last_start =
buf_start + strlen((const char *)buf_start) + 1;
memcpy((char *)last_start, (char *)write_back_buf,
4096 - (last_start - buffer));
return index;
}
index++;
buf_start += strlen((const char *)buf_start) + 1;
}
return -1;
}
int check_secure_storage_map(void *buffer)
{
struct map_info *map_buf = (struct map_info *)buffer;
if (map_buf->magic != STORE_OBJECT_MAGIC) {
pr_err("Item0 (Map) magic is bad\n");
return 2;
}
if (map_buf->crc !=
crc32(0, (void *)map_buf, sizeof(struct map_info) - 4)) {
pr_err("Item0 (Map) crc is fail [0x%x]\n", map_buf->crc);
return -1;
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_secure_storage_init(void)
{
int ret;
if (!secure_storage_inited) {
ret = sunxi_secstorage_read(
0, (unsigned char *)&secure_storage_map, 4096);
if (ret < 0) {
pr_err("get secure storage map err\n");
return -1;
}
ret = check_secure_storage_map(&secure_storage_map);
if (ret == -1) {
if ((secure_storage_map.data[0] == 0xff) ||
(secure_storage_map.data[0] == 0x0))
memset(&secure_storage_map, 0, SEC_BLK_SIZE);
} else if (ret == 2) {
if ((secure_storage_map.data[0] == 0xff) ||
(secure_storage_map.data[0] == 0x00)) {
pr_msg("the secure storage map is empty\n");
memset(&secure_storage_map, 0, SEC_BLK_SIZE);
} else {
/* no things */
}
}
}
secure_storage_inited = 1;
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_secure_storage_exit(void)
{
int ret;
if (!secure_storage_inited) {
pr_err("%s err: secure storage has not been inited\n",
__func__);
return -1;
}
if (try_map_dirty()) {
secure_storage_map.magic = STORE_OBJECT_MAGIC;
secure_storage_map.crc = crc32(0, (void *)&secure_storage_map,
sizeof(struct map_info) - 4);
ret = sunxi_secstorage_write(
0, (unsigned char *)&secure_storage_map, 4096);
if (ret < 0) {
pr_err("write secure storage map\n");
return -1;
}
clear_map_dirty();
}
ret = sunxi_secstorage_flush();
secure_storage_inited = 0;
return ret;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_secure_storage_list(void)
{
int ret, index = 1;
unsigned char *buf_start = (unsigned char *)&secure_storage_map;
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 4096);
if (sunxi_secure_storage_init()) {
pr_err("%s secure storage init err\n", __func__);
return -1;
}
char name[64], length[32];
int i, j, len;
while (*buf_start != '\0') {
memset(name, 0, 64);
memset(length, 0, 32);
i = 0;
while (buf_start[i] != ':') {
name[i] = buf_start[i];
i++;
}
i++;
j = 0;
while ((buf_start[i] != ' ') && (buf_start[i] != '\0')) {
length[j] = buf_start[i];
i++;
j++;
}
pr_msg("name in map %s\n", name);
len = simple_strtoul((const char *)length, NULL, 10);
if (strlen(name) == strlen(SECURE_STORAGE_DUMMY_KEY_NAME) &&
!memcmp(name, SECURE_STORAGE_DUMMY_KEY_NAME,
strlen(SECURE_STORAGE_DUMMY_KEY_NAME)) &&
len == 0) {
/*dummy key, not used, goto next key*/
goto next_key;
}
ret = sunxi_secstorage_read(index, buffer, 4096);
if (ret < 0) {
pr_err("get secure storage index %d err\n", index);
return -1;
} else if (ret > 0) {
pr_msg("the secure storage index %d is empty\n", index);
return -1;
} else {
pr_force("%d data:\n", index);
sunxi_dump(buffer, len);
}
next_key:
index++;
buf_start += strlen((const char *)buf_start) + 1;
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_secure_storage_probe(const char *item_name)
{
int ret;
int len;
if (!secure_storage_inited) {
pr_err("%s err: secure storage has not been inited\n",
__func__);
return -1;
}
ret = __probe_name_in_map((unsigned char *)&secure_storage_map,
item_name, &len);
if (ret < 0) {
pr_err("no item name %s in the map\n", item_name);
return -1;
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_secure_storage_read(const char *item_name, char *buffer,
int buffer_len, int *data_len)
{
int ret, index;
int len_in_store;
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer_to_sec, 4096);
if (!secure_storage_inited) {
pr_err("%s err: secure storage has not been inited\n",
__func__);
return -1;
}
index = __probe_name_in_map((unsigned char *)&secure_storage_map,
item_name, &len_in_store);
if (index < 0) {
pr_msg("no item name %s in the map\n", item_name);
return -2;
}
memset(buffer_to_sec, 0, 4096);
ret = sunxi_secstorage_read(index, buffer_to_sec, 4096);
if (ret < 0) {
pr_err("read secure storage block %d name %s err\n", index,
item_name);
return -3;
}
if (len_in_store > buffer_len) {
memcpy(buffer, buffer_to_sec, buffer_len);
} else {
memcpy(buffer, buffer_to_sec, len_in_store);
}
*data_len = len_in_store;
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_secure_storage_write(const char *item_name, char *buffer, int length)
{
int ret, index;
int len = 0;
ALLOC_CACHE_ALIGN_BUFFER(char, tmp_buf, 4096);
if (!secure_storage_inited) {
pr_err("%s err: secure storage has not been inited\n",
__func__);
return -1;
}
index = __probe_name_in_map((unsigned char *)&secure_storage_map,
item_name, &len);
if (index < 0) {
index = __fill_name_in_map((unsigned char *)&secure_storage_map,
item_name, length);
if (index < 0) {
pr_err("write secure storage block %d name %s overrage\n",
index, item_name);
return -1;
}
} else {
pr_force("There is the same name in the secure storage, try to erase it\n");
if (len != length) {
pr_err("the length is not match with key has store in secure storage\n");
return -1;
} else {
if (sunxi_secure_storage_erase_data_only(item_name) <
0) {
pr_err("Erase item %s fail\n", item_name);
return -1;
}
}
}
memset(tmp_buf, 0x0, 4096);
memcpy(tmp_buf, buffer, length);
ret = sunxi_secstorage_write(index, (unsigned char *)tmp_buf, 4096);
if (ret < 0) {
pr_err("write secure storage block %d name %s err\n", index,
item_name);
return -1;
}
set_map_dirty();
pr_force("write secure storage: %d ok\n", index);
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_secure_storage_erase_data_only(const char *item_name)
{
int ret, index, len;
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 4096);
if (!secure_storage_inited) {
pr_err("%s err: secure storage has not been inited\n",
__func__);
return -1;
}
index = __probe_name_in_map((unsigned char *)&secure_storage_map,
item_name, &len);
if (index < 0) {
pr_err("no item name %s in the map\n", item_name);
return -2;
}
memset(buffer, 0xff, 4096);
ret = sunxi_secstorage_write(index, buffer, 4096);
if (ret < 0) {
pr_err("erase secure storage block %d name %s err\n", index,
item_name);
return -1;
}
set_map_dirty();
pr_force("erase secure storage: %d data only ok\n", index);
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_secure_storage_erase(const char *item_name)
{
int ret, index;
ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, 4096);
if (!secure_storage_inited) {
pr_err("%s err: secure storage has not been inited\n",
__func__);
return -1;
}
index = __discard_name_in_map((unsigned char *)&secure_storage_map,
item_name);
if (index < 0) {
pr_err("no item name %s in the map\n", item_name);
return -2;
}
memset(buffer, 0xff, 4096);
ret = sunxi_secstorage_write(index, buffer, 4096);
if (ret < 0) {
pr_err("erase secure storage block %d name %s err\n", index,
item_name);
return -1;
}
set_map_dirty();
pr_force("erase secure storage: %d ok\n", index);
return 0;
}
/*
************************************************************************************************************
* function
* erase all the secure storage data
* name :
* parmeters :
* return :
* note :
*
************************************************************************************************************
*/
int sunxi_secure_storage_erase_all(void)
{
int ret;
if (!secure_storage_inited) {
sunxi_secure_storage_init();
}
memset(&secure_storage_map, 0x00, 4096);
ret = sunxi_secstorage_write(0, (unsigned char *)&secure_storage_map,
4096);
if (ret < 0) {
pr_err("erase secure storage block 0 err\n");
return -1;
}
pr_force("erase secure storage: 0 ok\n");
return 0;
}
int sunxi_secure_storage_write_or_read(const char *item_name, char *buffer,
int length, int dir)
{
int ret = 0;
int data_len;
ret = sunxi_secure_storage_init();
if (ret < 0) {
printf("secure storage init err\n");
return -1;
}
if (dir) {
ret = sunxi_secure_object_read(item_name, buffer, length,
&data_len);
if (ret < 0) {
sunxi_secure_storage_exit();
printf("erase secure storage failed\n");
ret = -1;
}
} else {
ret = sunxi_secure_object_write(item_name, buffer, length);
if (ret < 0) {
sunxi_secure_storage_exit();
printf("erase secure storage failed\n");
ret = -1;
}
}
sunxi_secure_storage_exit();
return ret;
}