/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int sunxi_secure_storage_list(void) { int ret, index = 1; unsigned char *buf_start = secure_storage_map; unsigned char buffer[4096]; if(sunxi_secure_storage_init()) { printf("%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++; } printf("name in map %s\n", name); len = simple_strtoul((const char *)length, NULL, 10); ret = sunxi_secstorage_read(index, buffer, 4096); 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, len); } index ++; buf_start += strlen((const char *)buf_start) + 1; } return 0; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int do_read_from_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { #ifdef CONFIG_SUNXI_SECURE_STORAGE if(argc == 1) { return sunxi_secure_storage_list(); } if(argc == 2) { char buffer[4096]; int ret, data_len; memset(buffer, 0, 4096); ret = sunxi_secure_storage_init(); if(ret < 0) { printf("%s secure storage init err\n", __func__); return -1; } ret = sunxi_secure_object_read(argv[1], buffer, 4096, &data_len); if(ret < 0) { printf("private data %s is not exist\n", argv[1]); return -1; } printf("private data:\n"); sunxi_dump(buffer, strlen((const char *)buffer)); return 0; } #endif return -1; }
int smc_load_sst_test(void) { char buffer[4096], en_buffer[4096]; unsigned int retLen ; store_object_t *so ; int ret ; /*call to encrypt data */ ret = sunxi_secure_storage_read("Widevine", buffer, 4096, (int *)&retLen); if(ret <0 ){ printf("read Widevine secure object fail\n"); return -1 ; } printf("Widevine data: \n"); sunxi_dump(buffer, retLen); so = (store_object_t *)buffer; printf("so name %s\n",so->name); ret = smc_load_sst_encrypt("Widevine", (char *)so->data,so->actual_len, en_buffer, &retLen); if(ret <0){ printf("smc load sst encrypt fail\n"); return -1 ; } printf("Encrypt Widevine data: \n"); sunxi_dump(en_buffer, retLen); memcpy(so->data, en_buffer, retLen); so->actual_len = retLen; so->re_encrypt = STORE_REENCRYPT_MAGIC; so->crc = crc32( 0 , (void *)so, sizeof(*so)-4 ); printf("so name %s\n",so->name); /*call to decrypt data to secure memory*/ 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 ; } 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; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int sunxi_pburn_state_loop(void *buffer) { static struct umass_bbb_cbw_t *cbw; static struct umass_bbb_csw_t csw; static uint pburn_flash_start = 0; //static uint pburn_flash_sectors = 0; int ret; sunxi_ubuf_t *sunxi_ubuf = (sunxi_ubuf_t *)buffer; switch(sunxi_usb_pburn_status) { case SUNXI_USB_PBURN_IDLE: if(sunxi_ubuf->rx_ready_for_data == 1) { sunxi_usb_pburn_status = SUNXI_USB_PBURN_SETUP; } break; case SUNXI_USB_PBURN_SETUP: sunxi_usb_dbg("SUNXI_USB_PBURN_SETUP\n"); if(sunxi_ubuf->rx_req_length != sizeof(struct umass_bbb_cbw_t)) { printf("sunxi usb error: received bytes 0x%x is not equal cbw struct size 0x%zx\n", sunxi_ubuf->rx_req_length, sizeof(struct umass_bbb_cbw_t)); sunxi_ubuf->rx_ready_for_data = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE; break; } cbw = (struct umass_bbb_cbw_t *)sunxi_ubuf->rx_req_buffer; if(CBWSIGNATURE != cbw->dCBWSignature) { printf("sunxi usb error: the cbw signature 0x%x is bad, need 0x%x\n", cbw->dCBWSignature, CBWSIGNATURE); sunxi_ubuf->rx_ready_for_data = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE; break; } csw.dCSWSignature = CSWSIGNATURE; csw.dCSWTag = cbw->dCBWTag; #if defined(SUNXI_USB_30) sunxi_usb_pburn_status_enable = 1; #endif sunxi_usb_dbg("usb cbw command = 0x%x\n", cbw->CBWCDB[0]); switch(cbw->CBWCDB[0]) { #ifdef CONFIG_SUNXI_SECURE_STORAGE case 0xf0: //自定义命令,用于烧录用户数据 sunxi_usb_dbg("usb burn secure storage data\n"); printf("usb command = %d\n", cbw->CBWCDB[1]); switch(cbw->CBWCDB[1]) { case 0: //握手 { __usb_handshake_sec_t *handshake = (__usb_handshake_sec_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_sec_t)); strcpy(handshake->magic, "usb_burn_handshake"); sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_sec_t)); sunxi_usb_burn_from_boot_setup = 1; private_data_ext_buff = (u8 *)malloc(4 * 1024 * 1024); if(private_data_ext_buff == NULL) { printf("there is no memorfy to store all user key data\n"); csw.bCSWStatus = -1; } else { csw.bCSWStatus = 0; sunxi_usb_burn_from_boot_handshake = 1; } private_data_ext_buff_step = private_data_ext_buff; } break; case 1: //小机端接收数据 { trans_data.recv_size = cbw->dCBWDataTransferLength; sunxi_usb_pburn_write_enable = 0; sunxi_udc_start_recv_by_dma(private_data_ext_buff_step, trans_data.recv_size); //start dma to receive data printf("recv_size=%d\n", trans_data.recv_size); sunxi_dump(private_data_ext_buff, trans_data.recv_size); sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_NULL; } break; case 2: //工具端声明数据传输已经完毕,要求获取烧录状态 { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); //strcpy(handshake->magic, "usb_burn_receive_data_all"); sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; printf("recv_size=%d\n", trans_data.recv_size); sunxi_dump(private_data_ext_buff, trans_data.recv_size); int ret = __sunxi_burn_key(private_data_ext_buff, trans_data.recv_size); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); //开始根据数据类型进行烧录动作 if(!ret) //数据烧写成功 { strcpy(handshake->magic, "usb_burn_success"); csw.bCSWStatus = 0; } else //数据烧写失败 { strcpy(handshake->magic, "usb_burn_error"); csw.bCSWStatus = -1; } if(private_data_ext_buff) { free(private_data_ext_buff); } } break; // case 3: //小机端读取每个key // { // uint start, sectors; // uint offset; // // start = *(int *)(cbw->CBWCDB + 4); //读数据的偏移量 // sectors = *(int *)(cbw->CBWCDB + 8); //扇区数; // // trans_data.send_size = min(cbw->dCBWDataTransferLength, sectors * 512); // trans_data.act_send_buffer = (uint)trans_data.base_send_buffer; // // offset = burn_private_start; // ret = sunxi_flash_read(start + offset, sectors, trans_data.base_send_buffer); // if(!ret) // { // printf("sunxi flash read err: start,0x%x sectors 0x%x\n", start, sectors); // // csw.bCSWStatus = 1; // } // else // { // csw.bCSWStatus = 0; // } // // sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; // } // break; case 4: //关闭usb { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); strcpy(handshake->magic, "usb_burn_finish"); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size); csw.bCSWStatus = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_EXIT; } break; case 5: { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); strcpy(handshake->magic, "usb_burn_saved"); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); csw.bCSWStatus = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; if(sunxi_secure_storage_write("key_burned_flag", "key_burned", strlen("key_burned"))) { printf("save burned flag err\n"); csw.bCSWStatus = -1; } sunxi_secure_storage_exit(); } break; default: break; } break; #endif case 0xf3: //自定义命令,用于烧录用户数据 sunxi_usb_dbg("usb burn private\n"); printf("usb command = %d\n", cbw->CBWCDB[1]); switch(cbw->CBWCDB[1]) { case 0: //握手 { __usb_handshake_t *handshake = (__usb_handshake_t *)trans_data.base_send_buffer; burn_private_start = sunxi_partition_get_offset_byname("private"); burn_private_len = sunxi_partition_get_size_byname("private"); if(!burn_private_start) { printf("private partition is not exist\n"); csw.bCSWStatus = -1; } else { csw.bCSWStatus = 0; } memset(handshake, 0, sizeof(__usb_handshake_t)); strcpy(handshake->magic, "usb_burn_handshake"); handshake->sizelo = burn_private_len; handshake->sizehi = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; sunxi_usb_burn_from_boot_setup = 1; sunxi_usb_burn_from_boot_handshake = 1; trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_t)); } break; case 1: //小机端接收数据 { //pburn_flash_sectors = *(int *)(cbw->CBWCDB + 8); //pburn_flash_start = *(int *)(cbw->CBWCDB + 4); memcpy(&pburn_flash_start,(cbw->CBWCDB + 4),4); trans_data.recv_size = cbw->dCBWDataTransferLength; trans_data.act_recv_buffer = trans_data.base_recv_buffer; pburn_flash_start += burn_private_start; sunxi_usb_pburn_write_enable = 0; sunxi_udc_start_recv_by_dma(trans_data.act_recv_buffer, trans_data.recv_size); //start dma to receive data sunxi_usb_pburn_status = SUNXI_USB_PBURN_RECEIVE_DATA; } break; case 3: //小机端发送数据 { uint start, sectors; //start = *(int *)(cbw->CBWCDB + 4); //读数据的偏移量 //sectors = *(int *)(cbw->CBWCDB + 8); //扇区数; memcpy(&start,(cbw->CBWCDB + 4),4); memcpy(§ors,(cbw->CBWCDB + 8),4); printf("start=%d, sectors=%d\n", start, sectors); trans_data.send_size = min(cbw->dCBWDataTransferLength, sectors * 512); trans_data.act_send_buffer = trans_data.base_send_buffer; printf("send size=%d\n", trans_data.send_size); ret = sunxi_flash_read(start + burn_private_start, sectors, trans_data.base_send_buffer); if(!ret) { printf("sunxi flash read err: start,0x%x sectors 0x%x\n", start, sectors); csw.bCSWStatus = 1; } else { csw.bCSWStatus = 0; } sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; } break; case 4: //关闭usb { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); strcpy(handshake->magic, "usb_burn_finish"); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size); csw.bCSWStatus = 0; sunxi_flash_flush(); sunxi_usb_pburn_status = SUNXI_USB_PBURN_EXIT; } break; case 5: { __usb_handshake_ext_t *handshake = (__usb_handshake_ext_t *)trans_data.base_send_buffer; char buffer[512]; memset(handshake, 0, sizeof(__usb_handshake_ext_t)); strcpy(handshake->magic, "usb_burn_saved"); trans_data.act_send_buffer = trans_data.base_send_buffer; trans_data.send_size = min(cbw->dCBWDataTransferLength, sizeof(__usb_handshake_ext_t)); csw.bCSWStatus = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_SEND_DATA; memset(buffer, 0, 512); strcpy(buffer, "key_burned"); if(!sunxi_flash_write(burn_private_start + burn_private_len - (8192+512)/512, 1, buffer)) { printf("save burned flag err\n"); csw.bCSWStatus = -1; } sunxi_flash_flush(); #ifdef CONFIG_SUNXI_SECURE_STORAGE if(sunxi_secure_storage_init()) { printf("init secure storage failed\n"); csw.bCSWStatus = -1; } else { if(sunxi_secure_storage_write("key_burned_flag", "key_burned", strlen("key_burned"))) { printf("save burned flag err\n"); csw.bCSWStatus = -1; } } sunxi_secure_storage_exit(); #endif } break; default: break; } break; default: sunxi_usb_dbg("not supported command 0x%x now\n", cbw->CBWCDB[0]); sunxi_usb_dbg("asked size 0x%x\n", cbw->dCBWDataTransferLength); csw.bCSWStatus = 1; sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS; break; } break; case SUNXI_USB_PBURN_SEND_DATA: sunxi_usb_dbg("SUNXI_USB_SEND_DATA\n"); sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS; printf("SUNXI_USB_SEND_DATA=%d\n", trans_data.send_size); sunxi_udc_send_data((void *)trans_data.act_send_buffer, trans_data.send_size); #if defined(SUNXI_USB_30) sunxi_usb_pburn_status_enable = 0; #endif break; case SUNXI_USB_PBURN_RECEIVE_DATA: sunxi_usb_dbg("SUNXI_USB_RECEIVE_DATA\n"); if(sunxi_usb_pburn_write_enable == 1) { sunxi_usb_dbg("write flash, start 0x%x, sectors 0x%x\n", pburn_flash_start, trans_data.recv_size/512); ret = sunxi_flash_write(pburn_flash_start, (trans_data.recv_size+511)/512, (void *)trans_data.act_recv_buffer); if(!ret) { printf("sunxi flash write err: start,0x%x sectors 0x%x\n", pburn_flash_start, (trans_data.recv_size+511)/512); csw.bCSWStatus = 1; } else { csw.bCSWStatus = 0; } sunxi_usb_pburn_write_enable = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS; } break; case SUNXI_USB_PBURN_STATUS: sunxi_usb_dbg("SUNXI_USB_PBURN_STATUS\n"); #if defined(SUNXI_USB_30) if(sunxi_usb_pburn_status_enable) #endif { sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE; sunxi_ubuf->rx_ready_for_data = 0; __sunxi_pburn_send_status(&csw, sizeof(struct umass_bbb_csw_t)); } break; case SUNXI_USB_PBURN_EXIT: printf("SUNXI_USB_PBURN_EXIT\n"); sunxi_usb_pburn_status = SUNXI_USB_PBURN_IDLE; sunxi_ubuf->rx_ready_for_data = 0; __sunxi_pburn_send_status(&csw, sizeof(struct umass_bbb_csw_t)); printf("Device will shutdown in 3 Secends...\n"); __msdelay(3000); return SUNXI_UPDATE_NEXT_ACTION_SHUTDOWN; case SUNXI_USB_PBURN_RECEIVE_NULL: sunxi_usb_dbg("SUNXI_USB_PBURN_RECEIVE_NULL\n"); if(sunxi_usb_pburn_write_enable == 1) { csw.bCSWStatus = 0; sunxi_usb_pburn_write_enable = 0; sunxi_usb_pburn_status = SUNXI_USB_PBURN_STATUS; } break; default: break; } return 0; }
int __sunxi_burn_key(u8 *buff, uint buff_len) { sunxi_usb_burn_main_info_t *key_main = (sunxi_usb_burn_main_info_t *)buff; sunxi_usb_burn_key_info_t *key_list; #ifdef CONFIG_SUNXI_SECURE_SYSTEM sunxi_efuse_key_info_t efuse_key_info; #endif int key_count; int offset; u8 *p_buff = (u8 *)&key_main->key_info; //比较key主体的信息 if(strcmp((const char *)key_main->magic, "key-group-db")) { printf("key data magic unmatch, err\n"); return -1; } key_count = key_main->count; printf("key_count=%d\n", key_count); if(sunxi_secure_storage_init()) { printf("%s secure storage init failed\n", __func__); return -1; } for(;key_count>0;key_count--, key_list++) { key_list = (sunxi_usb_burn_key_info_t *)p_buff; printf("^^^^^^^^^^^^^^^^^^^\n"); printf("key index=%d\n", key_main->count - key_count); printf("key name=%s\n", key_list->name); printf("key type=%d\n", key_list->type); printf("key len=%d\n", key_list->len); printf("key if_burn=%d\n", key_list->if_burn); printf("key if_replace=%d\n", key_list->if_replace); printf("key if_crypt=%d\n", key_list->if_crypt); printf("key data:\n"); sunxi_dump(key_list->key_data, key_list->len); printf("###################\n"); offset = (sizeof(sunxi_usb_burn_key_info_t)) + ((key_list->len + 15) & (~15)); printf("offset=%d\n", offset); p_buff += offset; #ifdef CONFIG_SUNXI_SECURE_SYSTEM if(!key_list->type) { memset(&efuse_key_info, 0, sizeof(efuse_key_info)); strcpy(efuse_key_info.name, (const char *)key_list->name); efuse_key_info.len = key_list->len; efuse_key_info.key_data = (u8 *)key_list->key_data; if(smc_efuse_writel(&efuse_key_info)) { return -1; } } else #endif { #ifdef CONFIG_SUNXI_HDCP_IN_SECURESTORAGE int ret; if(!strcmp("hdcpkey", key_list->name)) { ret = sunxi_deal_hdcp_key((char *)key_list->key_data, key_list->len); if(ret) { printf("sunxi deal with hdcp key failed\n"); return -1; } } else #endif { if(key_list->if_crypt) smc_set_sst_crypt_name(key_list->name); if(sunxi_secure_object_write(key_list->name, (char *)key_list->key_data, key_list->len)) { return -1; } } } } if(sunxi_secure_storage_exit()) { printf("sunxi_secure_storage_exit err\n"); return -1; } 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); //获取来自toc1的证书序列 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)) { //取出证书的扩展项 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; } //比较扩展项和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; }