489 lines
13 KiB
C
Executable File
489 lines
13 KiB
C
Executable File
/*
|
||
* (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: ֤<><D6A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ len<65><6E><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD>
|
||
*
|
||
* return :
|
||
*
|
||
* note : ֤<><D6A4><EFBFBD><EFBFBD>У<EFBFBD><D0A3>
|
||
*
|
||
*
|
||
************************************************************************************************************
|
||
*/
|
||
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"
|
||
);
|
||
|