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

520 lines
12 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+
*/
/*
* Allwinner secure storage data format
*/
#include <common.h>
#include <command.h>
#include <securestorage.h>
#include <sunxi_board.h>
#include <smc.h>
#include "sprite_storage_crypt.h"
#include <linux/ctype.h>
DECLARE_GLOBAL_DATA_PTR;
#include "sprite_storage_crypt.h"
extern int smc_set_sst_crypt_name(char *name);
static char write_protect_item[MAX_OEM_STORE_NUM][64];
static int __write_protect_item_id(const char *item)
{
return 0; //default can't be place in burn-key flow
}
static int __set_write_protect_name(const char *name)
{
int id;
if ((id = __write_protect_item_id(name)) > 0)
return 0; /*The name had been set*/
printf("set name[%s] to write_protect list\n", name);
for (id = 0; id < MAX_OEM_STORE_NUM; id++) {
if (write_protect_item[id][0] == 0) {
memcpy(write_protect_item[id], name, strnlen(name, 64));
break;
}
}
return 0;
}
//#define _SO_TEST_
/*Store source data to secure_object struct
*
* src : payload data to secure_object
* name : input payloader data name
* len : input payload data length
* tagt : taregt secure_object
* retLen : target secure_object length
* */
static int wrap_secure_object(void *src, const char *name, unsigned int len,
void *tagt, int *retLen)
{
store_object_t *obj;
if (len > MAX_STORE_LEN) {
printf("Input length larger then secure object payload size\n");
return -1;
}
obj = (store_object_t *)tagt;
*retLen = sizeof(store_object_t);
obj->magic = STORE_OBJECT_MAGIC;
strncpy(obj->name, name, 64);
obj->re_encrypt = 0;
obj->version = SUNXI_SECSTORE_VERSION;
obj->id = 0;
obj->write_protect = (__write_protect_item_id(name) < 0) ?
0 :
STORE_WRITE_PROTECT_MAGIC;
memset(obj->reserved, 0, ARRAY_SIZE(obj->reserved));
obj->actual_len = len;
memcpy(obj->data, src, len);
obj->crc = crc32(0, (void *)obj, sizeof(*obj) - 4);
return 0;
}
/*load source data to secure_object struct
*
* src : secure_object
* len : secure_object buffer len
* payload : taregt payload
* retLen : target payload actual length
* */
static int unwrap_secure_object(void *src, unsigned int len, void *payload,
int *retLen)
{
store_object_t *obj;
if (len != sizeof(store_object_t)) {
printf("Input length not equal secure object size 0x%x\n", len);
return -1;
}
obj = (store_object_t *)src;
if (obj->magic != STORE_OBJECT_MAGIC) {
printf("Input object magic fail [0x%x]\n", obj->magic);
return -1;
}
if (obj->re_encrypt == STORE_REENCRYPT_MAGIC) {
printf("secure object is encrypt by chip\n");
}
if (obj->crc != crc32(0, (void *)obj, sizeof(*obj) - 4)) {
printf("Input object crc fail [0x%x]\n", obj->crc);
return -1;
}
memcpy(payload, obj->data, obj->actual_len);
*retLen = obj->actual_len;
return 0;
}
int sunxi_secure_object_read(const char *item_name, char *buffer,
int buffer_len, int *data_len)
{
char secure_object[4096];
int retLen, ret;
store_object_t *so;
memset(secure_object, 0, 4096);
ret = sunxi_secure_storage_read(item_name, secure_object, 4096,
&retLen);
if (ret) {
return -1;
}
so = (store_object_t *)secure_object;
return unwrap_secure_object((char *)so, retLen, buffer, data_len);
}
int sunxi_secure_object_set(const char *name, int encrypt, int write_protect,
int res1, int res2, int res3)
{
if (encrypt)
smc_set_sst_crypt_name((char *)name);
if (write_protect)
__set_write_protect_name(name);
return 0;
}
int sunxi_secure_object_write(const char *item_name, char *buffer, int length)
{
char secure_object[4096];
int retLen, ret;
store_object_t *so;
memset(secure_object, 0, 4096);
ret = wrap_secure_object((void *)buffer, item_name, length,
secure_object, &retLen);
if (ret < 0 || retLen > 4096) {
printf("wrap fail before secure storage write\n");
return -1;
}
so = (store_object_t *)secure_object;
return sunxi_secure_storage_write(item_name, (char *)so, sizeof(*so));
}
/*
* Test data and function
*/
#ifdef _SO_TEST_
static unsigned char hdmi_data[] = { 0x44, 0xe5, 0xb5, 0xac, 0x2b, 0x53,
0xbc, 0xb9, 0xbf, 0x89, 0x67, 0x96,
0x1e, 0xbb, 0xbd, 0xfb };
static unsigned char widevine_data[] = { 0xeb, 0x8f, 0x55, 0x26, 0x0d, 0x7a,
0xab, 0xf3, 0x58, 0x3b, 0xf9, 0xc0,
0x5e, 0x12, 0x79, 0x85 };
static unsigned char sec_buf[4096];
static int secure_object_op_test(void)
{
unsigned char *tagt;
int LEN = 4096, retLen;
int ret;
tagt = (unsigned char *)memalign(CONFIG_SYS_CACHELINE_SIZE, ALIGN(LEN, CONFIG_SYS_CACHELINE_SIZE));
if (!tagt) {
printf("out of memory\n");
return -1;
}
ret = wrap_secure_object(hdmi_data, "HDMI", ARRAY_SIZE(hdmi_data), tagt,
&retLen);
if (ret < 0) {
printf("Error: wrap secure object fail\n");
free(tagt);
return -1;
}
ret = sunxi_secure_storage_write("HDMI", (void *)tagt, retLen);
if (ret < 0) {
printf("Error: store HDMI object fail\n");
free(tagt);
return -1;
}
ret = sunxi_secure_storage_read("HDMI", (void *)sec_buf, 4096,
(int *)&retLen);
if (ret < 0) {
printf("Error: store HDMI object read fail\n");
free(tagt);
return -1;
}
if (memcmp(tagt, sec_buf, retLen) != 0) {
printf("Error: HDMI write/read fail\n");
return -1;
}
printf("HDMI dump:\n");
print_buffer((u32)sec_buf, (void *)sec_buf, 1, retLen, 16);
ret = wrap_secure_object(widevine_data, "Widevine",
ARRAY_SIZE(widevine_data), tagt, &retLen);
if (ret < 0) {
printf("Error: wrap secure object fail\n");
free(tagt);
return -1;
}
ret = sunxi_secure_storage_write("Widevine", (void *)tagt, retLen);
if (ret < 0) {
printf("Error: store Widevine object fail\n");
free(tagt);
return -1;
}
ret = sunxi_secure_storage_read("Widevine", (void *)sec_buf, 4096,
(int *)&retLen);
if (ret < 0) {
printf("Error: store Widevine object read fail\n");
free(tagt);
return -1;
}
if (memcmp(tagt, sec_buf, retLen) != 0) {
printf("Error: Widevine write/read fail\n");
return -1;
}
printf("Widevine dump:\n");
print_buffer((u32)sec_buf, (void *)sec_buf, 1, retLen, 16);
sunxi_secure_storage_exit();
free(tagt);
return 0;
}
#endif
extern int sunxi_secstorage_read(int item, unsigned char *buf,
unsigned int len);
extern int sunxi_secstorage_write(int item, unsigned char *buf,
unsigned int len);
static unsigned char _inner_buffer[4096];
static int clear_secure_store(int index)
{
memset(_inner_buffer, 0, 4096);
if (index == 0xffff) {
int i = 0;
printf("clean whole secure store");
for (; i < 32; i++) {
printf("..");
sunxi_secstorage_write(i, (void *)_inner_buffer, 4096);
printf("clearn %d done\n", i);
}
} else {
printf("clean secure store %d\n", index);
printf("..");
sunxi_secstorage_write(index, (void *)_inner_buffer, 4096);
printf("clearn %d done\n", index);
}
return 0;
}
static int sunxi_secure_object_list(void)
{
int ret, index = 1;
unsigned char *buf_start = _inner_buffer;
unsigned char buffer[4096];
int retLen;
if (sunxi_secure_storage_init()) {
printf("%s secure storage init err\n", __func__);
return -1;
}
if (sunxi_secstorage_read(0, _inner_buffer, 4096) < 0) {
printf("read map fail\n");
return -1;
}
char name[64], length[32];
int i, j, len;
printf("Map: \n");
sunxi_dump(_inner_buffer, 0x100);
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++;
}
len = simple_strtoul((const char *)length, NULL, 10);
printf("name in map %s, len 0x%x\n", name, len);
memset(buffer, 0, 4096);
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;
}
if (!strncmp("key_burned_flag", name,
strlen("key_burned_flag")))
ret = sunxi_secure_storage_read(name, (void *)buffer,
4096, &retLen);
else
ret = sunxi_secure_object_read(name, (void *)buffer,
4096, &retLen);
if (ret < 0) {
printf("get secure storage index %d err\n", index);
return -1;
} else if (ret > 0) {
printf("the secure storage index %d is empty\n", index);
return -1;
} else {
printf("%d data:\n", index);
sunxi_dump(buffer, retLen);
}
next_key:
index++;
buf_start += strlen((const char *)buf_start) + 1;
}
return 0;
}
static int dump_secure_store(char *type)
{
if (!memcmp(type, "pure", 4)) {
return sunxi_secure_object_list();
} else
return sunxi_secure_storage_list();
}
static int cmd_secure_object(cmd_tbl_t *cmdtp, int flag, int argc,
char *const argv[])
{
int ret = -1;
if (argc > 3 || argc < 1) {
printf("wrong argc\n");
return -1;
}
if (sunxi_secure_storage_init() < 0) {
printf("secure storage init fail\n");
return -1;
}
if ((strncmp("clean", argv[1], strlen("clean")) == 0)) {
if (strncmp("all", argv[2], strlen("all")) == 0) {
ret = clear_secure_store(0xffff);
} else {
unsigned int index =
simple_strtoul((const char *)argv[2], NULL, 10);
ret = clear_secure_store(index);
}
} else if (strncmp("dump", argv[1], strlen("dump")) == 0) {
ret = dump_secure_store(argv[2]);
} else if ((strncmp("test", argv[1], strlen("test")) == 0)) {
#ifdef _SO_TEST_
ret = secure_object_op_test();
#else
ret = cmd_usage(cmdtp);
#endif
} else if (strncmp("crypt", argv[1], strlen("crypt")) == 0) {
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
extern int smc_load_sst_test(void);
smc_load_sst_test();
#endif
ret = 0;
} else
ret = cmd_usage(cmdtp);
if (sunxi_secure_storage_exit() < 0) {
printf("secure storage exit fail\n");
return -1;
}
return ret;
}
int sunxi_secure_object_build(const char *name, char *buf, int len, int encrypt,
int write_protect, char *secdata_buf)
{
sunxi_secure_storage_info_t *secdata =
(sunxi_secure_storage_info_t *)secdata_buf;
char lower_name[64];
int ret, i, align_len = 0;
i = 0;
memset(lower_name, 0, 64);
while (name[i] != '\0') {
lower_name[i] = tolower(name[i]);
i++;
}
strcpy(secdata->name, name);
secdata->encrypted = encrypt;
secdata->write_protect = write_protect;
secdata->len = len;
if (gd->securemode == SUNXI_SECURE_MODE_WITH_SECUREOS) {
if (!strcmp("hdcpkey", secdata->name))
ret = smc_tee_rssk_encrypt(secdata->key_data, buf, len,
&align_len);
else
ret = smc_tee_ssk_encrypt(secdata->key_data, buf, len,
&align_len);
if (ret) {
printf("ssk encrypt failed\n");
return -1;
}
secdata->len = align_len;
sunxi_dump(secdata->key_data, secdata->len);
} else {
debug("no secure os, data can't be encrypted\n");
memcpy(secdata->key_data, buf, len);
}
return 0;
}
int sunxi_secure_object_down(const char *name, char *buf, int len, int encrypt,
int write_protect)
{
int ret;
sunxi_secure_storage_info_t secdata;
if (len > 4096) {
printf("the input key is too long!\n");
return -1;
}
memset(&secdata, 0, sizeof(secdata));
ret = sunxi_secure_object_build(name, buf, len, encrypt, write_protect,
(char *)&secdata);
if (ret) {
return ret;
}
ret = sunxi_secure_object_write(secdata.name, (void *)&secdata,
SUNXI_SECURE_STORTAGE_INFO_HEAD_LEN +
secdata.len);
if (ret) {
printf("secure storage write fail\n");
return -1;
}
return 0;
}
int sunxi_secure_object_up(const char *name, char *buf, int len)
{
sunxi_secure_storage_info_t secdata;
int data_len;
int ret;
memset(&secdata, 0, sizeof(secdata));
ret = sunxi_secure_object_read(name, (char *)&secdata, sizeof(secdata),
&data_len);
if (ret) {
printf("secure storage read %s fail\n", name);
return -1;
}
if (buf) {
memcpy(buf, &secdata,
len < sizeof(secdata) ? len : sizeof(secdata));
}
return 0;
}
U_BOOT_CMD(sunxi_so, 3, 1, cmd_secure_object, "sunxi_so sub-system",
"sunxi_so <cmd> \n"
"\t Allwinner secure object storage \n");