OSHW-DEIMOS/SOFTWARE/A64-TERES/u-boot-teres/sprite/sprite_secure_object.c
2017-01-29 13:27:37 +02:00

441 lines
10 KiB
C

/*
* (C) Copyright 2000-2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/*
* Allwinner secure storage data format
*/
#include <common.h>
#include <command.h>
#include <asm-generic/errno.h>
#include <malloc.h>
#include <asm/io.h>
#include <securestorage.h>
#include <sunxi_board.h>
#include "sprite_storage_crypt.h"
//#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 = 0;
obj->id = 0;
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){
printf("sunxi storage read fail\n");
return -1 ;
}
so = (store_object_t *)secure_object;
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
ret = smc_load_sst_decrypt(so->name, (char *)so->data,so->actual_len);
if(ret <0){
printf("smc load sst decrypt fail\n");
return -1 ;
}else if(ret >0){
printf("Don't need to decrypt object\n");
}else
printf("Decrypt request done\n");
#endif
return unwrap_secure_object((char *)so, retLen, buffer, data_len);
}
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;
#ifdef CONFIG_SUNXI_SECURE_SYSTEM
store_object_t *en_so ;
en_so = malloc(sizeof(*en_so));
if(!en_so){
printf("wrap fail out of memory\n");
return -1 ;
}
ret = smc_load_sst_encrypt(
so->name,
(char *)so->data,so->actual_len,
(char *)en_so, (unsigned int *)&retLen);
if(ret <0){
printf("smc load sst encrypt fail\n");
free(en_so);
return -1 ;
}else if(ret >0){
printf("Don't need to encrypt object\n");
}else{
memcpy(so->data, en_so, retLen);
so->actual_len = retLen;
so->id = sst_oem_item_id((char *)item_name);
so->re_encrypt = STORE_REENCRYPT_MAGIC;
so->crc = crc32( 0 , (void *)so, sizeof(*so)-4 );
}
free(en_so);
#endif
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 *)malloc(LEN);
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( !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);
}
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[])
{
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 ){
return clear_secure_store(0xffff);
}else{
unsigned int index = simple_strtoul( (const char *)argv[2], NULL, 10 ) ;
return clear_secure_store(index) ;
}
}else if(strncmp("dump", argv[1], strlen("dump"))== 0){
return dump_secure_store(argv[2]);
}else if( (strncmp("test", argv[1],strlen("test")) == 0) ) {
#ifdef _SO_TEST_
return secure_object_op_test();
#else
return 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
return 0 ;
}else
return cmd_usage(cmdtp);
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"
);