SmartAudio/lichee/brandy/u-boot-2014.07/common/cmd_sunxi_verify.c

489 lines
13 KiB
C
Raw Normal View History

2018-07-13 01:31:50 +00:00
/*
* (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 boot verify trust-chain
*/
#include <common.h>
#include <openssl_ext.h>
#include <private_toc.h>
#include <asm/arch/ss.h>
#include <sunxi_board.h>
static int sunxi_certif_pubkey_check( sunxi_key_t *pubkey, u8 *hash_buf);
static int sunxi_root_certif_pk_verify(sunxi_certif_info_t *sunxi_certif, u8 *buf, u32 len, u8 *hash_buf);
static int check_public_in_rootcert(const char *name, sunxi_certif_info_t *sub_certif )
{
struct sbrom_toc1_item_info *toc1_item;
sunxi_certif_info_t root_certif;
u8 *buf;
int ret, i;
toc1_item = (struct sbrom_toc1_item_info *)(CONFIG_TOC1_STORE_IN_DRAM_BASE + \
sizeof(struct sbrom_toc1_head_info));
/*Parse root certificate*/
buf = (u8 *)(CONFIG_TOC1_STORE_IN_DRAM_BASE + toc1_item->data_offset);
ret = sunxi_certif_probe_ext(&root_certif, buf, toc1_item->data_len );
if(ret < 0)
{
printf("fail to create root certif\n");
return -1;
}
for(i=0;i<root_certif.extension.extension_num;i++)
{
if(strcmp((const char *)root_certif.extension.name[i], name))
{
continue;
}
printf("find %s key stored in root certif\n", name);
if(memcmp(root_certif.extension.value[i],
sub_certif->pubkey.n+1, sub_certif->pubkey.n_len-1))
{
printf("%s key n is incompatible\n", name);
printf(">>>>>>>key in rootcertif<<<<<<<<<<\n");
sunxi_dump((u8 *)root_certif.extension.value[i], sub_certif->pubkey.n_len-1);
printf(">>>>>>>key in certif<<<<<<<<<<\n");
sunxi_dump((u8 *)sub_certif->pubkey.n+1, sub_certif->pubkey.n_len-1);
return -1;
}
if(memcmp(root_certif.extension.value[i] + sub_certif->pubkey.n_len-1,
sub_certif->pubkey.e, sub_certif->pubkey.e_len))
{
printf("%s key e is incompatible\n", name);
printf(">>>>>>>key in rootcertif<<<<<<<<<<\n");
sunxi_dump((u8 *)root_certif.extension.value[i] + sub_certif->pubkey.n_len-1, sub_certif->pubkey.e_len);
printf(">>>>>>>key in certif<<<<<<<<<<\n");
sunxi_dump((u8 *)sub_certif->pubkey.e, sub_certif->pubkey.e_len);
return -1;
}
break;
}
return 0 ;
}
int sunxi_verify_signature(void *buff, uint len, const char *cert_name)
{
u8 hash_of_file[32];
int ret;
struct sbrom_toc1_head_info *toc1_head;
struct sbrom_toc1_item_info *toc1_item;
sunxi_certif_info_t sub_certif;
int i;
memset(hash_of_file, 0, 32);
sunxi_ss_open();
ret = sunxi_sha_calc(hash_of_file, 32, buff, len);
if(ret)
{
printf("sunxi_verify_signature err: calc hash failed\n");
//sunxi_ss_close();
return -1;
}
//sunxi_ss_close();
printf("show hash of file\n");
sunxi_dump(hash_of_file, 32);
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>toc1<63><31>֤<EFBFBD><D6A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
toc1_head = (struct sbrom_toc1_head_info *)CONFIG_TOC1_STORE_IN_DRAM_BASE;
toc1_item = (struct sbrom_toc1_item_info *)(CONFIG_TOC1_STORE_IN_DRAM_BASE + sizeof(struct sbrom_toc1_head_info));
for(i=1;i<toc1_head->items_nr;i++, toc1_item++)
{
if(toc1_item->type == TOC_ITEM_ENTRY_TYPE_BIN_CERTIF)
{
printf("find cert name %s\n", toc1_item->name);
if(!strcmp((const char *)toc1_item->name, cert_name))
{
//ȡ<><C8A1>֤<EFBFBD><D6A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>չ<EFBFBD><D5B9>
if(sunxi_certif_probe_ext(&sub_certif, (u8 *)(CONFIG_TOC1_STORE_IN_DRAM_BASE + toc1_item->data_offset), toc1_item->data_len))
{
printf("%s error: cant verify the content certif\n", __func__);
return -1;
}
//<2F>Ƚ<EFBFBD><C8BD><EFBFBD>չ<EFBFBD><D5B9><EFBFBD><EFBFBD>hash
printf("show hash in certif\n");
sunxi_dump(sub_certif.extension.value[0], 32);
if(memcmp(hash_of_file, sub_certif.extension.value[0], 32))
{
printf("hash compare is not correct\n");
printf(">>>>>>>hash of file<<<<<<<<<<\n");
sunxi_dump(hash_of_file, 32);
printf(">>>>>>>hash in certif<<<<<<<<<<\n");
sunxi_dump(sub_certif.extension.value[0], 32);
return -1;
}
return 0;
}
}
}
printf("cant find a certif belong to %s\n", cert_name);
return -1;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_verify_embed_signature(void *buff, uint len, const char *cert_name, void *cert, unsigned cert_len)
{
u8 hash_of_file[32];
int ret;
sunxi_certif_info_t sub_certif;
void *cert_buf;
cert_buf = malloc(cert_len);
if(!cert_buf){
printf("out of memory\n");
return -1;
}
memcpy(cert_buf, cert,cert_len);
memset(hash_of_file, 0, 32);
sunxi_ss_open();
ret = sunxi_sha_calc(hash_of_file, 32, buff, len);
if(ret)
{
printf("sunxi_verify_signature err: calc hash failed\n");
goto __ERROR_END;
}
if(sunxi_certif_verify_itself(&sub_certif, cert_buf, cert_len)){
printf("%s error: cant verify the content certif\n", __func__);
printf("cert dump\n");
sunxi_dump(cert_buf, cert_len);
goto __ERROR_END;
}
if(memcmp(hash_of_file, sub_certif.extension.value[0], 32))
{
printf("hash compare is not correct\n");
printf(">>>>>>>hash of file<<<<<<<<<<\n");
sunxi_dump(hash_of_file, 32);
printf(">>>>>>>hash in certif<<<<<<<<<<\n");
sunxi_dump(sub_certif.extension.value[0], 32);
goto __ERROR_END;
}
/*Approvel certificate by trust-chain*/
if( check_public_in_rootcert(cert_name, &sub_certif) ){
printf("check rootpk[%s] in rootcert fail\n",cert_name);
goto __ERROR_END;
}
free(cert_buf);
return 0;
__ERROR_END:
if(cert_buf)
free(cert_buf);
return -1;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_verify_rotpk_hash(void *input_hash_buf, int len)
{
u8 hash_of_pubkey[32];
struct sbrom_toc1_item_info *toc1_item;
sunxi_certif_info_t root_certif;
if(len < 32)
{
printf("the input hash is not equal to 32 bytes\n");
return -1;
}
sunxi_ss_open();
memset(hash_of_pubkey, 0, 32);
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>toc1<63><31>֤<EFBFBD><D6A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
toc1_item = (struct sbrom_toc1_item_info *)(CONFIG_TOC1_STORE_IN_DRAM_BASE + sizeof(struct sbrom_toc1_head_info));
if(toc1_item->type == TOC_ITEM_ENTRY_TYPE_NULL)
{
printf("find cert name %s\n", toc1_item->name);
//ȡ<><C8A1>֤<EFBFBD><D6A4><EFBFBD>Ĺ<EFBFBD>Կ
if(sunxi_root_certif_pk_verify(&root_certif, (u8 *)(CONFIG_TOC1_STORE_IN_DRAM_BASE + toc1_item->data_offset), \
toc1_item->data_len, hash_of_pubkey))
{
printf("%s error: cant get the content certif publickey hash\n", __func__);
return -1;
}
//<2F>Ƚ<EFBFBD>hashֵ
printf("show hash of publickey in certif\n");
sunxi_dump(input_hash_buf, 32);
if(memcmp(input_hash_buf, hash_of_pubkey, 32))
{
printf("hash compare is not correct\n");
printf(">>>>>>>hash of certif<<<<<<<<<<\n");
sunxi_dump(hash_of_pubkey, 32);
printf(">>>>>>>hash of user input<<<<<<<<<<\n");
sunxi_dump(input_hash_buf, 32);
return -1;
}
else
{
printf("the hash of input data and toc are equal\n");
}
return 0;
}
return -1;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int sunxi_key_ladder_verify_rotpk_hash(void *input_hash_buf, int len)
{
SBROM_TOC0_ITEM_info_t *toc0_item = NULL;
SBROM_TOC0_KEY_ITEM_info_t *key_item = NULL;
toc0_private_head_t *toc0 = NULL;
int i = 0, ret = 0;
u8 hash_of_pubkey[32];
sunxi_key_t pubkey;
printf("\nenter the sunxi_key_ladder_verify_rotpk_hash \n");
if (len < 32) {
printf("the input hash is not equal to 32 bytes\n");
return -1;
}
toc0 = (toc0_private_head_t *)CONFIG_SBROMSW_BASE;
if (toc0->items_nr != 3) {
ret = sunxi_verify_rotpk_hash(input_hash_buf, len);
return ret;
}
printf("ready to verify key ladder rotpk\n");
sunxi_ss_open();
memset(hash_of_pubkey, 0, 32);
toc0_item = (SBROM_TOC0_ITEM_info_t *) (CONFIG_SBROMSW_BASE + sizeof(toc0_private_head_t));
for (i = 0; i < toc0->items_nr; i++) {
if (toc0_item->name == ITEM_NAME_SBROMSW_KEY) {
key_item = (SBROM_TOC0_KEY_ITEM_info_t *) (CONFIG_SBROMSW_BASE + toc0_item->data_offset);
break ;
}
toc0_item++;
}
if (key_item == NULL) {
printf("can not find the key item\n");
return -1;
}
pubkey.n_len = key_item->KEY0_PK_mod_len;
pubkey.n = key_item->KEY0_PK;
pubkey.e_len = key_item->KEY0_PK_e_len;
pubkey.e = (key_item->KEY0_PK+key_item->KEY0_PK_mod_len);
ret = sunxi_certif_pubkey_check(&pubkey, hash_of_pubkey);
if (ret < 0) {
printf("%s error: cant get the key item publickey hash\n", __func__);
}
printf("show hash of publickey in certif\n");
sunxi_dump(input_hash_buf, 32);
if (memcmp(input_hash_buf, hash_of_pubkey, 32)) {
printf("hash compare is not correct\n");
printf(">>>>>>>hash of certif<<<<<<<<<<\n");
sunxi_dump(hash_of_pubkey, 32);
printf(">>>>>>>hash of user input<<<<<<<<<<\n");
sunxi_dump(input_hash_buf, 32);
return -1;
} else {
printf("the hash of input data and toc are equal\n");
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
#define RSA_BIT_WITDH 2048
static int sunxi_certif_pubkey_check( sunxi_key_t *pubkey, u8 *hash_buf)
{
char rotpk_hash[256];
char all_zero[32];
char pk[RSA_BIT_WITDH/8 * 2 + 256]; /*For the stupid sha padding */
memset(all_zero, 0, 32);
memset(pk, 0x91, sizeof(pk));
char *align = (char *)(((u32)pk+31)&(~31));
if( *(pubkey->n) ){
memcpy(align, pubkey->n, pubkey->n_len);
memcpy(align+pubkey->n_len, pubkey->e, pubkey->e_len);
}else{
memcpy(align, pubkey->n+1, pubkey->n_len-1);
memcpy(align+pubkey->n_len-1, pubkey->e, pubkey->e_len);
}
if(sunxi_sha_calc( (u8 *)rotpk_hash, 32, (u8 *)align, RSA_BIT_WITDH/8*2 ))
{
printf("sunxi_sha_calc: calc pubkey sha256 with hardware err\n");
return -1;
}
memcpy(hash_buf, rotpk_hash, 32);
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters : buf: ֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ len<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
*
* return :
*
* note : ֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><EFBFBD>
*
*
************************************************************************************************************
*/
static int sunxi_root_certif_pk_verify(sunxi_certif_info_t *sunxi_certif, u8 *buf, u32 len, u8 *hash_buf)
{
X509 *certif;
int ret;
//<2F>ڴ<EFBFBD><DAB4><EFBFBD>ʼ<EFBFBD><CABC>
sunxi_certif_mem_reset();
//<2F><><EFBFBD><EFBFBD>֤<EFBFBD><D6A4>
ret = sunxi_certif_create(&certif, buf, len);
if(ret < 0)
{
printf("fail to create a certif\n");
return -1;
}
//<2F><>ȡ֤<C8A1>鹫Կ
ret = sunxi_certif_probe_pubkey(certif, &sunxi_certif->pubkey);
if(ret)
{
printf("fail to probe the public key\n");
return -1;
}
#if 0
printf("public key e: %d\n", sunxi_certif->pubkey.e_len);
sunxi_dump(sunxi_certif->pubkey.e, sunxi_certif->pubkey.e_len);
printf("public key n: %d\n", sunxi_certif->pubkey.n_len);
sunxi_dump(sunxi_certif->pubkey.n, sunxi_certif->pubkey.n_len);
#endif
ret = sunxi_certif_pubkey_check(&sunxi_certif->pubkey, hash_buf);
if(ret){
printf("fail to check the public key hash against efuse\n");
return -1;
}
sunxi_certif_free(certif);
return 0;
}
int do_rotpk_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
u8 input_hash_buf[32];
int ret;
memset(input_hash_buf, 0, 32);
ret = sunxi_verify_rotpk_hash(input_hash_buf, 32);
return ret;
}
U_BOOT_CMD(
rotpk_test, 3, 0, do_rotpk_test,
"test the rotpk key",
"usage: rotpk_test"
);