/* * Driver for NAND support, Rick Bronson * borrowed heavily from: * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * * Ported 'dynenv' to 'nand env.oob' command * (C) 2010 Nanometrics, Inc. * 'dynenv' -- Dynamic environment offset in NAND OOB * (C) Copyright 2006-2007 OpenMoko, Inc. * Added 16-bit nand support * (C) 2004 Texas Instruments * * Copyright 2010 Freescale Semiconductor * The portions of this file whose copyright is held by Freescale and which * are not considered a derived work of GPL v2-only code may be distributed * and/or modified 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. */ /* A. 加密解密 1. 密钥的产生 1) 找出两个相异的大素数P和Q,令N=P×Q,M=(P-1)*(Q-1)。 2) 找出与M互素的大数E,且E #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; int signature_erase_all(sunxi_mbr_t *mbr); #ifndef CONFIG_OPENSSL typedef struct public_key_pairs_t { unsigned int public_key; // e unsigned int divider; // n } public_key_pairs; typedef struct private_key_pairs_t { unsigned int private_key; // d unsigned int divider; // n } private_key_pairs; #define P (127) #define Q (401) #define N ((P) * (Q)) #define M ((P-1) * (Q-1)) #define E (53) public_key_pairs pblc_keys; private_key_pairs prvt_keys; void rsa_dump(void); static unsigned int probe_gcd(unsigned int divdend, unsigned int divder) { unsigned int ret = divdend % divder; while(ret) { divdend = divder; divder = ret; ret = divdend % divder; } return divder; } unsigned probe_high_level_power_mod(unsigned int base_value, unsigned int power, unsigned int divider) { unsigned int ret = 1; base_value %= divider; while(power > 0) { if(power & 1) { ret = (ret * base_value) % divider; } power /= 2; base_value = (base_value * base_value) % divider; } return ret; } unsigned rsa_init(void) { unsigned int k; unsigned int product; unsigned int m_value; m_value = M; k = 1; if(probe_gcd(m_value, E) == 1) //e,M互质 { do { product = M * k + 1; if(!(product % E)) { pblc_keys.public_key = E; pblc_keys.divider = N; prvt_keys.private_key = product/E; prvt_keys.divider = N; #ifdef DEBUG_MODE rsa_dump(); #endif return 0; } k ++; } while(1); } return -1; } void rsa_dump(void) { printf("base value\n"); printf("M = %d(%d * %d), N = %d(%d * %d)\n", M, P-1, Q-1, N, P, Q); printf("public key: \n"); printf("{e, n} = %d, %d\n", pblc_keys.public_key, pblc_keys.divider); printf("private key: \n"); printf("{d, n} = %d, %d\n", prvt_keys.private_key, prvt_keys.divider); } void rsa_encrypt( unsigned int *input, unsigned int length, unsigned int *output ) { unsigned int i; for(i=0;i 0 ) // { // ch = *key++; // seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2); // seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3; // length --; // } // // return seed1; key += add_sum((void *)str, length); return (unsigned int)key; } void HashString_init(void) { key = 0; } #define HASH_BUFFER_BYTES (32 * 1024) #define HASH_BUFFER_SECTORS (HASH_BUFFER_BYTES/512) //static void change_boot_signature(int partition_index) //{ // unsigned int summary = 0; // uint boot_start ; // uchar buffer[HASH_BUFFER_BYTES]; // uint read_bytes; // unsigned int s_value[4], h_value[4]; // // memset(buffer,0,HASH_BUFFER_BYTES); // prepareCryptTable(); // boot_start = sunxi_partition_get_offset(partition_index); // if(boot_start == 0) // { // printf("get the boot partition offest error!!\n"); // return ; // } // HashString_init(); // read_bytes = sizeof(struct fastboot_boot_img_hdr); // if(!sunxi_flash_read(boot_start, (read_bytes + 511)/512, buffer)) // { // printf("signature0 read flash sig1 err\n"); // // return ; // } // summary = HashString(buffer, 1, read_bytes); //1类hash // printf("the summary is 0x%x\n",summary); // read_bytes = sizeof(struct image_header); // if(!sunxi_flash_read(boot_start+ CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE/512, (read_bytes + 511)/512, buffer)) // { // printf("signature0 read flash sig2 err\n"); // // return ; // } // summary = HashString(buffer, 1, read_bytes); //1类hash // printf("the summary is 0x%x\n",summary); // rsa_init(); // h_value[3] = (summary>>24)&0xff; // h_value[2] = (summary>>16)&0xff; // h_value[1] = (summary>>8)&0xff; // h_value[0] = (summary>>0)&0xff; // // rsa_encrypt(h_value,4,s_value); // // if(!sunxi_flash_read(boot_start, 2, buffer)) // { // printf("signature0 read flash sig3 err\n"); // return; // } // // *(unsigned int *)(buffer + 608) = s_value[0]; // *(unsigned int *)(buffer + 612) = s_value[1]; // *(unsigned int *)(buffer + 616) = s_value[2]; // *(unsigned int *)(buffer + 620) = s_value[3]; // debug("change_boot_signature!!!!\n"); // debug("s_value[0] = %d\n",s_value[0]); // debug("s_value[1] = %d\n",s_value[1]); // debug("s_value[2] = %d\n",s_value[2]); // debug("s_value[3] = %d\n",s_value[3]); // if(!sunxi_flash_write(boot_start,2, buffer)) // { // printf("cant write the signature into flash!!\n"); // return ; // } // // return ; //} // //static void change_system_signature(int partition_index) //{ // unsigned int summary = 0; // unsigned int system_start; // unsigned int s_value[4], h_value[4]; // unsigned char buffer[HASH_BUFFER_BYTES]; // unsigned int read_bytes; // struct ext4_super_block *sblock; // system_start = sunxi_partition_get_offset(partition_index); // // HashString_init(); // read_bytes = sizeof(struct ext4_super_block); // if(!sunxi_flash_read(system_start + CFG_SUPER_BLOCK_SECTOR, (read_bytes + 511)/512, buffer)) // { // printf("read the system fail!!!\n"); // return ; // } // sblock = (struct ext4_super_block *)buffer; // sblock->s_mtime = CFG_SUPER_BLOCK_STAMP_VALUE; // sblock->s_mnt_count = CFG_SUPER_BLOCK_STAMP_VALUE & 0xffff; // memset(sblock->s_last_mounted, 0, 64); // // summary = HashString(buffer, 1, (unsigned int)&(((struct ext4_super_block *)0)->s_snapshot_list)); //1类hash // printf("the summary is 0x%x\n",summary); // rsa_init(); // // h_value[3] = (summary>>24)&0xff; // h_value[2] = (summary>>16)&0xff; // h_value[1] = (summary>>8)&0xff; // h_value[0] = (summary>>0)&0xff; // // rsa_encrypt(h_value,4,s_value); // // if(!sunxi_flash_read(system_start, 2, buffer)) // { // printf("fail to read the system signature!!!\n"); // return; // } // // *(unsigned int *)(buffer + 1000 - 10 * 4 + 0) = s_value[0]; // *(unsigned int *)(buffer + 1000 - 10 * 4 + 4) = s_value[1]; // *(unsigned int *)(buffer + 1000 - 10 * 4 + 8 ) = s_value[2]; // *(unsigned int *)(buffer + 1000 - 10 * 4 + 12 ) = s_value[3] ; // // debug("change_system_signature!!!!\n"); // debug("s_value[0] = %d\n",s_value[0]); // debug("s_value[1] = %d\n",s_value[1]); // debug("s_value[2] = %d\n",s_value[2]); // debug("s_value[3] = %d\n",s_value[3]); // // if(!sunxi_flash_write(system_start,2, buffer)) // { // printf("write the system signature fail!!\n"); // return ; // } // return ; //} //static void change_signature(void) //{ // int partition_num = 0; // int i; // char partition_name[16]; // partition_num = sunxi_partition_get_total_num(); // if((partition_num <= 0) || (partition_num > SUNXI_MBR_MAX_PART_COUNT)) // { // printf("mbr not exist\n"); // return; // } // for(i=0;i>0) & 0xff; h_value[1] = (hash_value>>8) & 0xff; h_value[2] = (hash_value>>16) & 0xff; h_value[3] = (hash_value>>24) & 0xff; rsa_encrypt( h_value, 4, s_value); sig_value[0] = s_value[0]; sig_value[1] = s_value[1]; sig_value[2] = s_value[2]; sig_value[3] = s_value[3]; return 0; } static int __signature_add_for_ext4_format(uint start, uint *sig_value) { unsigned char buffer[4096]; unsigned int h_value[4], s_value[4]; struct ext4_super_block *sblock; uint hash_value; HashString_init(); if(sunxi_flash_read(start + CFG_SUPER_BLOCK_SECTOR, 4096/512, buffer) != (4096/512)) { puts("sunxi add signature fail: read flash err\n"); return -1; } sblock = (struct ext4_super_block *)buffer; sblock->s_mtime = CFG_SUPER_BLOCK_STAMP_VALUE; sblock->s_mnt_count = CFG_SUPER_BLOCK_STAMP_VALUE & 0xffff; memset(sblock->s_last_mounted, 0, 64); hash_value = HashString(buffer, 1, (unsigned int)&(((struct ext4_super_block *)0)->s_snapshot_list)); //1类hash rsa_init(); h_value[0] = (hash_value>>0) & 0xff; h_value[1] = (hash_value>>8) & 0xff; h_value[2] = (hash_value>>16) & 0xff; h_value[3] = (hash_value>>24) & 0xff; rsa_encrypt( h_value, 4, s_value); sig_value[0] = s_value[0]; sig_value[1] = s_value[1]; sig_value[2] = s_value[2]; sig_value[3] = s_value[3]; return 0; } static int __signature_add(sunxi_partition *partition) { int ret; if(partition->sig_verify == 0x8000) { ret = __signature_add_for_boot_format(partition->addrlo, partition->sig_value); } else if(partition->sig_verify == 0x8001) { ret = __signature_add_for_ext4_format(partition->addrlo, partition->sig_value); } else { printf("the part is not need to add signature\n"); ret = 0; } if(ret < 0) { printf("sunxi add signature for part %s failed\n", partition->name); return -1; } return 0; } static int __signature_verify_for_boot_format(uint start, uint *sig_value) { unsigned char buffer[4096]; unsigned int h_value[4], s_value[4]; uint summary1, summary2; HashString_init(); if(sunxi_flash_read(start, 4096/512, buffer) != (4096/512)) { puts("sunxi add signature fail: read flash err\n"); return -1; } summary1 = HashString(buffer, 1, sizeof(struct fastboot_boot_img_hdr)); //1类hash summary1 = HashString(buffer + CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE, 1, sizeof(struct image_header)); //1类hash s_value[0] = sig_value[0]; s_value[1] = sig_value[1]; s_value[2] = sig_value[2]; s_value[3] = sig_value[3]; rsa_init(); rsa_decrypt( s_value, 4, h_value ); summary2 = (h_value[0]<<0) | (h_value[1]<<8) | (h_value[2]<<16) | (h_value[3]<<24); if(summary1 != summary2) { printf("summary by hash 0x%x\n", summary1); printf("summary by key 0x%x\n", summary2); printf("boot signature invalid\n"); return -1; } return 0; } static int __signature_verify_for_ext4_format(uint start, uint *sig_value) { unsigned char buffer[4096]; unsigned int h_value[4], s_value[4]; struct ext4_super_block *sblock; uint summary1, summary2; HashString_init(); if(sunxi_flash_read(start + CFG_SUPER_BLOCK_SECTOR, 4096/512, buffer) != (4096/512)) { puts("sunxi add signature fail: read flash err\n"); return -1; } sblock = (struct ext4_super_block *)buffer; sblock->s_mtime = CFG_SUPER_BLOCK_STAMP_VALUE; sblock->s_mnt_count = CFG_SUPER_BLOCK_STAMP_VALUE & 0xffff; memset(sblock->s_last_mounted, 0, 64); summary1 = HashString(buffer, 1, (unsigned int)&(((struct ext4_super_block *)0)->s_snapshot_list)); //1类hash s_value[0] = sig_value[0]; s_value[1] = sig_value[1]; s_value[2] = sig_value[2]; s_value[3] = sig_value[3]; rsa_init(); rsa_decrypt( s_value, 4, h_value ); summary2 = (h_value[0]<<0) | (h_value[1]<<8) | (h_value[2]<<16) | (h_value[3]<<24); if(summary1 != summary2) { printf("summary by hash 0x%x\n", summary1); printf("summary by key 0x%x\n", summary2); printf("system signature invalid\n"); return -1; } return 0; } static int __signature_verify(sunxi_partition *partition) { int ret; if(partition->sig_verify == 0x8000) { ret = __signature_verify_for_boot_format(partition->addrlo, partition->sig_value); } else if(partition->sig_verify == 0x8001) { ret = __signature_verify_for_ext4_format(partition->addrlo, partition->sig_value); } else { printf("the part is not need to verify signature\n"); ret = 0; } if(ret < 0) { printf("sunxi verify signature for part %s failed\n", partition->name); return -1; } return 0; } //static int __signature_verify(char *part_name) //{ // unsigned int tmp_start; // unsigned int summary1, summary2; // unsigned int s_value[4], h_value[4]; // unsigned char buffer[HASH_BUFFER_BYTES]; // unsigned int read_bytes; // // memset(buffer, 0, HASH_BUFFER_BYTES); // //计算hash值 // prepareCryptTable(); //准备hash表 // //获取签名 // printf("ras init\n"); // rsa_init(); // printf("ras start\n"); // // if(!strcmp("boot", part_name)) // { // tmp_start = sunxi_partition_get_offset_byname(part_name); // // printf("find part %s\n", part_name); // HashString_init(); // read_bytes = sizeof(struct fastboot_boot_img_hdr); // if(!sunxi_flash_read(tmp_start, (read_bytes + 511)/512, buffer)) // { // printf("signature0 read flash sig1 err\n"); // // return -1; // } // summary1 = HashString(buffer, 1, read_bytes); //1类hash // read_bytes = sizeof(struct image_header); // if(!sunxi_flash_read(tmp_start + CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE/512, (read_bytes + 511)/512, buffer)) // { // printf("signature0 read flash sig2 err\n"); // // return -1; // } // summary1 = HashString(buffer, 1, read_bytes); //1类hash // // //获取保存的签名 // if(!sunxi_flash_read(tmp_start, 2, buffer)) // { // printf("signature0 read flash sig3 err\n"); // // return -1; // } // s_value[0] = *(unsigned int *)(buffer + 608); // s_value[1] = *(unsigned int *)(buffer + 612); // s_value[2] = *(unsigned int *)(buffer + 616); // s_value[3] = *(unsigned int *)(buffer + 620); // // rsa_decrypt( s_value, 4, h_value ); // // summary2 = (h_value[0]<<0) | (h_value[1]<<8) | (h_value[2]<<16) | (h_value[3]<<24); //#if 0 // for(j=0;j<4;j++) // { // printf("s_value[%d] = %x\n", j, s_value[j]); // } // for(j=0;j<4;j++) // { // printf("h_value[%d] = %x\n", j, h_value[j]); // } //#endif // printf("summary by hash 0x%x\n", summary1); // printf("summary by rsa 0x%x\n", summary2); // if(summary1 != summary2) // { // printf("boot signature invalid\n"); // // return -1; // } // } // else if(!strcmp("system", part_name)) // { // struct ext4_super_block *sblock; // // tmp_start = sunxi_partition_get_offset_byname(part_name); // printf("find part %s\n", part_name); // // HashString_init(); // // read_bytes = sizeof(struct ext4_super_block); // if(!sunxi_flash_read(tmp_start + CFG_SUPER_BLOCK_SECTOR, (read_bytes + 511)/512, buffer)) // { // printf("signature1 read flash sig1 err\n"); // // return -1; // } // sblock = (struct ext4_super_block *)buffer; //#if 0 // { // int k; // printf("s_inodes_count = %x\n", sblock->s_inodes_count); // printf("s_blocks_count_lo = %x\n", sblock->s_blocks_count_lo); // printf("s_r_blocks_count_lo = %x\n", sblock->s_r_blocks_count_lo); // printf("s_free_blocks_count_lo= %x\n", sblock->s_free_blocks_count_lo); // printf("s_free_inodes_count = %x\n", sblock->s_free_inodes_count); // printf("s_first_data_block = %x\n", sblock->s_first_data_block); // printf("s_log_block_size = %x\n", sblock->s_log_block_size); // printf("s_log_cluster_size = %x\n", sblock->s_log_cluster_size); // printf("s_blocks_per_group = %x\n", sblock->s_blocks_per_group); // printf("s_clusters_per_group = %x\n", sblock->s_clusters_per_group); // printf("s_inodes_per_group = %x\n", sblock->s_inodes_per_group); // printf("s_mtime = %x\n", sblock->s_mtime); // printf("s_wtime = %x\n", sblock->s_wtime); // printf("s_mnt_count = %x\n", sblock->s_mnt_count); // printf("s_max_mnt_count = %x\n", sblock->s_max_mnt_count); // printf("s_magic = %x\n", sblock->s_magic); // printf("s_state = %x\n", sblock->s_state); // printf("s_errors = %x\n", sblock->s_errors); // printf("s_minor_rev_level = %x\n", sblock->s_minor_rev_level); // printf("s_lastcheck = %x\n", sblock->s_lastcheck); // printf("s_checkinterval = %x\n", sblock->s_checkinterval); // printf("s_creator_os = %x\n", sblock->s_creator_os); // printf("s_rev_level = %x\n", sblock->s_rev_level); // printf("s_def_resuid = %x\n", sblock->s_def_resuid); // printf("s_def_resgid = %x\n", sblock->s_def_resgid); // // printf("s_first_ino = %x\n", sblock->s_first_ino); // printf("s_inode_size = %x\n", sblock->s_inode_size); // printf("s_block_group_nr = %x\n", sblock->s_block_group_nr); // printf("s_feature_compat = %x\n", sblock->s_feature_compat); // printf("s_feature_incompat = %x\n", sblock->s_feature_incompat); // printf("s_feature_ro_compat = %x\n", sblock->s_feature_ro_compat); // for(k=0;k<16;k++) // { // printf("s_uuid[%d] = %x\n", k, sblock->s_uuid[k]); // } // for(k=0;k<16;k++) // { // printf("s_volume_name[%d] = %x\n", k, sblock->s_volume_name[k]); // } // for(k=0;k<64;k++) // { // printf("s_last_mounted[%d]= %x\n", k, sblock->s_last_mounted[k]); // } // printf("s_algorithm_usage_bitmap= %x\n", sblock->s_algorithm_usage_bitmap); // // printf("s_prealloc_blocks = %x\n", sblock->s_prealloc_blocks); // printf("s_prealloc_dir_blocks = %x\n", sblock->s_prealloc_dir_blocks); // printf("s_reserved_gdt_blocks = %x\n", sblock->s_reserved_gdt_blocks); // // for(k=0;k<16;k++) // { // printf("s_journal_uuid[%d]= %x\n", k, sblock->s_journal_uuid[k]); // } // printf("s_journal_inum = %x\n", sblock->s_journal_inum); // printf("s_journal_dev = %x\n", sblock->s_journal_dev); // printf("s_last_orphan = %x\n", sblock->s_last_orphan); // for(k=0;k<16;k++) // { // printf("s_hash_seed[%d] = %x\n", k, sblock->s_hash_seed[k]); // } // printf("s_def_hash_version = %x\n", sblock->s_def_hash_version); // printf("s_jnl_backup_type = %x\n", sblock->s_jnl_backup_type); // printf("s_desc_size = %x\n", sblock->s_desc_size); // printf("s_default_mount_opts = %x\n", sblock->s_default_mount_opts); // printf("s_first_meta_bg = %x\n", sblock->s_first_meta_bg); // printf("s_mkfs_time = %x\n", sblock->s_mkfs_time); // for(k=0;k<17;k++) // { // printf("s_jnl_blocks[%d] = %x\n", k, sblock->s_jnl_blocks[k]); // } // // printf("s_blocks_count_hi = %x\n", sblock->s_blocks_count_hi); // printf("s_r_blocks_count_hi = %x\n", sblock->s_r_blocks_count_hi); // printf("s_free_blocks_count_hi= %x\n", sblock->s_free_blocks_count_hi); // printf("s_min_extra_isize = %x\n", sblock->s_min_extra_isize); // printf("s_want_extra_isize = %x\n", sblock->s_want_extra_isize); // printf("s_flags = %x\n", sblock->s_flags); // // printf("s_raid_stride = %x\n", sblock->s_raid_stride); // printf("s_mmp_update_interval = %x\n", sblock->s_mmp_update_interval); // printf("s_mmp_block = %x\n", sblock->s_mmp_block); // printf("s_raid_stripe_width = %x\n", sblock->s_raid_stripe_width); // printf("s_log_groups_per_flex = %x\n", sblock->s_log_groups_per_flex); // printf("s_reserved_char_pad = %x\n", sblock->s_reserved_char_pad); // // printf("s_reserved_pad = %x\n", sblock->s_reserved_pad); // printf("s_kbytes_written = %x\n", sblock->s_kbytes_written); // printf("s_snapshot_inum = %x\n", sblock->s_snapshot_inum); // printf("s_snapshot_id = %x\n", sblock->s_snapshot_id); // printf("s_snapshot_r_blocks_count= %x\n", sblock->s_snapshot_r_blocks_count); // printf("s_snapshot_list = %x\n", sblock->s_snapshot_list); // } //#endif // sblock->s_mtime = CFG_SUPER_BLOCK_STAMP_VALUE; // sblock->s_mnt_count = CFG_SUPER_BLOCK_STAMP_VALUE & 0xffff; // memset(sblock->s_last_mounted, 0, 64); // summary1 = HashString(buffer, 1, (unsigned int)&(((struct ext4_super_block *)0)->s_snapshot_list)); //1类hash // // //获取保存的签名 // if(!sunxi_flash_read(tmp_start, 2, buffer)) // { // printf("signature1 read flash sig3 err\n"); // // return -1; // } // s_value[0] = *(unsigned int *)(buffer + 1000 - 10 * 4 + 0); // s_value[1] = *(unsigned int *)(buffer + 1000 - 10 * 4 + 4); // s_value[2] = *(unsigned int *)(buffer + 1000 - 10 * 4 + 8); // s_value[3] = *(unsigned int *)(buffer + 1000 - 10 * 4 + 12); // // rsa_decrypt( s_value, 4, h_value ); // summary2 = (h_value[0]<<0) | (h_value[1]<<8) | (h_value[2]<<16) | (h_value[3]<<24); //#if 0 // for(j=0;j<4;j++) // { // printf("s_value[%d] = %x\n", j, s_value[j]); // } // for(j=0;j<4;j++) // { // printf("h_value[%d] = %x\n", j, h_value[j]); // } //#endif // printf("summary by hash %x\n", summary1); // printf("summary by rsa %x\n", summary2); // if(summary1 != summary2) // { // printf("system signature invalid\n"); // // return -1; // } // } // // return 0; //} /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int do_sunxi_boot_signature(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int ret; int i; sunxi_mbr_t *mbr = (sunxi_mbr_t *)sunxi_partition_fetch_mbr(); if(mbr == NULL) { puts("sunxi signature fail: unable to get the signature table\n"); return -1; } if(gd->lockflag == SUNXI_NOLOCK) { puts("no signature\n"); return 0; } if(gd->lockflag == SUNXI_UNLOCK) { puts("signature abandon\n"); setenv("signature", "abandon"); return 0; } for(i=0;iPartCount;i++) { if((mbr->array[i].sig_verify & 0x8000) == 0x8000) { ret = __signature_verify(&mbr->array[i]); if(ret < 0) { printf("sunxi signature fail: the part %s signature is not passed\n", mbr->array[i].name); ret = signature_erase_all(mbr); if(ret < 0) { printf("sunxi signature fail: erase part fail\n"); return -1; } if(gd->lockflag == SUNXI_LOCKING) { puts("signature failed\n"); setenv("signature", "failed"); } else if(gd->lockflag == SUNXI_RELOCKING) { puts("signature relock_failed\n"); setenv("signature", "relock_failed"); } return 0; } } } if(gd->lockflag == SUNXI_LOCKING) { puts("signature pass\n"); setenv("signature", "pass"); } else if(gd->lockflag == SUNXI_RELOCKING) { puts("signature relock_pass\n"); setenv("signature", "relock_pass"); } return 0; } U_BOOT_CMD( sunxi_boot_signature, CONFIG_SYS_MAXARGS, 1, do_sunxi_boot_signature, "sunxi_boot_signature sub-system", "no parmeters : \n" ); static int sunxi_resignature(sunxi_mbr_t *mbr) { int ret; int i; for(i=0;iPartCount;i++) { if((mbr->array[i].sig_verify & 0x8000) == 0x8000) { printf("resignature for part %s\n", mbr->array[i].name); ret = __signature_add(&mbr->array[i]); if(ret < 0) { setenv("signature", "failed"); printf("sunxi signature fail: the part %s signature is not passed\n", mbr->array[i].name); return -1; } } } return 0; } int sunxi_oem_op_lock(int request_flag, char *info, int force) { char buffer[SUNXI_MBR_COPY_NUM * SUNXI_MBR_SIZE]; char *tmp_buffer; sunxi_mbr_t *mbr, *tmp_mbr; char local_info[64]; char *info_p; uint store_flag; int i; uint crc_cal; if(info == NULL) { memset(local_info, 0, 64); info_p = local_info; } else { info_p = info; } if(sunxi_flash_read(0, SUNXI_MBR_COPY_NUM * SUNXI_MBR_SIZE/512, buffer) != (SUNXI_MBR_COPY_NUM * SUNXI_MBR_SIZE/512)) { strcpy(info_p, "sunxi oem operation fail, cant get oem flag"); printf("%s\n", info_p); return -1; } mbr = (sunxi_mbr_t *)buffer; store_flag = mbr->lockflag; if( (request_flag == SUNXI_RELOCKING) || (request_flag == SUNXI_LOCKING) ) //要求加锁 { if( ((store_flag == SUNXI_UNLOCK) || (store_flag == SUNXI_NOLOCK)) || (force == 1) ) //如果没有锁上 { if(!sunxi_resignature(mbr)) //执行加锁操作 { if(!force) { mbr->lockflag = SUNXI_RELOCKING; } else { mbr->lockflag = SUNXI_LOCKING; } tmp_mbr = mbr + 1; for(i=1;iarray[i].sig_value[0] = mbr->array[i].sig_value[0]; tmp_mbr->array[i].sig_value[1] = mbr->array[i].sig_value[1]; tmp_mbr->array[i].sig_value[2] = mbr->array[i].sig_value[2]; tmp_mbr->array[i].sig_value[3] = mbr->array[i].sig_value[3]; tmp_mbr ++; } } else //如果加锁失败 { strcpy(info_p, "the lock flag is invalid"); printf("%s\n", info_p); return -2; } } //else if(lockflag == SUNXI_LOCKING) //如果已经锁上 else //默认都是锁上 { strcpy(info_p, "system is already locked"); printf("%s\n", info_p); return -3; } } else if(request_flag == SUNXI_UNLOCK) //要求解锁 { if( ((store_flag == SUNXI_UNLOCK) || (store_flag == SUNXI_NOLOCK)) && (force != 1) )// { strcpy(info_p, "system is not locked"); printf("%s\n", info_p); return -4; } //else if(store_flag == SUNXI_LOCKING) //如果已经锁上 else //默认都是锁上 { puts("ready to erase all dedicate parts\n"); if(!signature_erase_all(mbr))//开始擦除数据 { if(!force) { mbr->lockflag = SUNXI_UNLOCK; } else { mbr->lockflag = SUNXI_NOLOCK; } } else { strcpy(info_p, "system cant erase parts"); printf("%s\n", info_p); return -5; } } } else { strcpy(info_p, "the requst is invalid"); printf("%s\n", info_p); return -6; } tmp_mbr = mbr; tmp_buffer = buffer; for(i=0;ilockflag = mbr->lockflag; crc_cal = crc32(0, (const unsigned char *)tmp_buffer + 4, SUNXI_MBR_SIZE-4); *(unsigned int *)tmp_buffer = crc_cal; tmp_buffer += SUNXI_MBR_SIZE; tmp_mbr ++; } if(sunxi_flash_write(0, SUNXI_MBR_COPY_NUM * SUNXI_MBR_SIZE/512, buffer) != (SUNXI_MBR_COPY_NUM * SUNXI_MBR_SIZE/512)) { strcpy(info_p, "sunxi oem operation fail, cant set oem flag"); printf("%s\n", info_p); return -7; } sunxi_partition_refresh(buffer, SUNXI_MBR_SIZE); gd->lockflag = mbr->lockflag; return 0; } #else /* CONFIG_OPENSSL */ #define SUNXI_SIGN_READ_MAX (1024 * 1024) #include #include #include #include "../fs/aw_fs/ff.h" #include #include #include #include #include #include #include static FILE sign_file; #define SUNXI_SIGN_READ_MAX (1024 * 1024) /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int __probe_sign_file(unsigned char *partition_name, char *sign_buffer) { unsigned char file_name[32]; int ret; int index; uint rbytes; memset(file_name, 0, 32); strcpy((char *)file_name, (char *)partition_name); index = strlen((const char *)file_name); file_name[index++] = '.'; file_name[index++] = 's'; file_name[index++] = 'i'; file_name[index++] = 'g'; ret = f_open (&sign_file, (const TCHAR *)file_name, FA_OPEN_EXISTING | FA_READ ); if(ret) { printf("validata err: open sign file %s error\n", file_name); return -1; } f_read(&sign_file, sign_buffer, 256, &rbytes); //公钥解密rsa f_close(&sign_file); //sunxi_dump(sign_buffer, 256); return 0; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int __calculate_for_bootimg_format(char *data_buffer, char *hash_buffer) { SHA256_CTX ctx; memset(hash_buffer, 0, SHA256_DIGEST_LENGTH); //计算sha256 SHA256_Init(&ctx); SHA256_Update(&ctx, (u_int8_t *)data_buffer, sizeof(struct fastboot_boot_img_hdr)); //sunxi_dump(data_buffer, sizeof(struct fastboot_boot_img_hdr)); SHA256_Update(&ctx, (u_int8_t *)(data_buffer + CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE), sizeof(struct image_header) + 512); //sunxi_dump(data_buffer + CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE, sizeof(struct image_header) + 512); SHA256_Final((unsigned char *)hash_buffer, &ctx); if(hash_buffer[0] >= 0xe0) hash_buffer[0] = 0xcc; //sunxi_dump(hash_buffer, 256); return 0; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int __calculate_for_sparse_format(char *data_buffer, char *hash_buffer) { char *tmp_buffer = data_buffer + CFG_SUPER_BLOCK_SECTOR * 512; struct ext4_super_block *sblock; SHA256_CTX ctx; unsigned int data_len; sblock = (struct ext4_super_block *)tmp_buffer; sblock->s_mtime = CFG_SUPER_BLOCK_STAMP_VALUE; sblock->s_mnt_count = CFG_SUPER_BLOCK_STAMP_VALUE & 0xffff; memset(sblock->s_last_mounted, 0, 64); //计算sha256 data_len = (unsigned int)&(((struct ext4_super_block *)0)->s_snapshot_list); SHA256_Init(&ctx); SHA256_Update(&ctx, (u_int8_t *)tmp_buffer, data_len); SHA256_Final((unsigned char *)hash_buffer, &ctx); if(hash_buffer[0] >= 0xe0) hash_buffer[0] = 0xcc; //sunxi_dump(hash_buffer, 256); return 0; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int __validata_verify(sunxi_partition *partition) { int ret; char *data_buffer; char sign_buffer[256]; char hash1_buffer[512]; char hash2_buffer[512]; if( (partition->sig_verify != 0x8000) && (partition->sig_verify != 0x8001) ) { printf("the part is not need to verify signature\n"); return 0; } data_buffer = malloc(SUNXI_SIGN_READ_MAX); memset(data_buffer, 0, SUNXI_SIGN_READ_MAX); if(!sunxi_flash_read(partition->addrlo, SUNXI_SIGN_READ_MAX/512, data_buffer)) { printf("validata err: read partition %s err\n", partition->name); free(data_buffer); return -1; } memset(hash1_buffer, 0, 512); if(partition->sig_verify == 0x8000) { ret = __calculate_for_bootimg_format(data_buffer, hash1_buffer); } else { ret = __calculate_for_sparse_format(data_buffer, hash1_buffer); } //获取分区对应的签名文件 memset(sign_buffer, 0, SHA256_DIGEST_LENGTH); memset(hash2_buffer, 0, 512); if(__probe_sign_file(partition->name, sign_buffer)) { free(data_buffer); return -1; } ret = sunxi_rsa_publickey_decrypt(sign_buffer, hash2_buffer, 256, "0:public.pem"); if(ret < 0) { free(data_buffer); printf("validata err: when public decrypt %s\n", partition->name); return -1; } if(hash2_buffer[0] >= 0xe0) hash2_buffer[0] = 0xcc; //printf("\n\n"); //sunxi_dump(hash2_buffer, 256); //比较两个值 if(memcmp(hash1_buffer, hash2_buffer, 256)) { free(data_buffer); printf("validate err: when compare the signature on %s\n", partition->name); return -1; } free(data_buffer); printf("validate ok: validate the signature on %s\n", partition->name); return 0; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int sunxi_oem_op_lock(int request_flag, char *info, int force) { return -1; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int do_sunxi_boot_signature(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int ret; int i; sunxi_mbr_t *mbr = (sunxi_mbr_t *)sunxi_partition_fetch_mbr(); FATFS openssl_mount; if(mbr == NULL) { puts("sunxi signature fail: unable to get the signature table\n"); return -1; } if(gd->lockflag == SUNXI_NOLOCK) { puts("sunxi validata: no signature\n"); return 0; } if(gd->lockflag == SUNXI_UNLOCK) { puts("sunxi validata: signature abandon\n"); setenv("signature", "abandon"); return 0; } arm_neon_init(); f_mount_ex(0, &openssl_mount, 0); for(i=0;iPartCount;i++) { if((mbr->array[i].sig_verify & 0x8000) == 0x8000) { ret = __validata_verify(&mbr->array[i]); if(ret < 0) { printf("sunxi signature fail: the part %s signature is not passed\n", mbr->array[i].name); ret = signature_erase_all(mbr); if(ret < 0) { printf("sunxi signature fail: erase part fail\n"); f_mount(0, NULL, NULL); return -1; } if(gd->lockflag == SUNXI_LOCKING) { puts("signature failed\n"); setenv("signature", "failed"); } else if(gd->lockflag == SUNXI_RELOCKING) { puts("signature relock_failed\n"); setenv("signature", "relock_failed"); } f_mount(0, NULL, NULL); return 0; } } } if(gd->lockflag == SUNXI_LOCKING) { puts("signature pass\n"); setenv("signature", "pass"); } else if(gd->lockflag == SUNXI_RELOCKING) { puts("signature relock_pass\n"); setenv("signature", "relock_pass"); } f_mount(0, NULL, NULL); return 0; } U_BOOT_CMD( sunxi_boot_signature, 16, 0, do_sunxi_boot_signature, "do validata", "[public key name]" ); #endif /* CONFIG_OPENSSL */ /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int __signature_erase_part(uint sector_start, uint nsector, void *erase_buffer, uint buffer_sectors) { uint tmp_nsectors, tmp_start; tmp_start = sector_start; tmp_nsectors = nsector; while(tmp_nsectors>=buffer_sectors) { if(sunxi_flash_write(tmp_start, buffer_sectors, erase_buffer) != buffer_sectors) { printf("signature err: unable to erase part when signature fail\n"); return -1; } tmp_start += buffer_sectors; tmp_nsectors -= buffer_sectors; } if(tmp_nsectors) { if(sunxi_flash_write(tmp_start, tmp_nsectors, erase_buffer) != tmp_nsectors) { printf("signature err: unable to erase part when signature fail\n"); return -1; } } return 0; } /* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : 4 steps: 1, erase cache; 2 erase data; 3 erase private; 4 erase drm; 5 erase UDISK * * ************************************************************************************************************ */ int signature_erase_all(sunxi_mbr_t *mbr) { int i; uint part_start, part_sectors; void *buffer; buffer = malloc(4 * 1024 * 1024); if(!buffer) { puts("sunxi signature fail: unable to malloc memory to erase parts\n"); return -1; } puts("ready to erase dedicated parts\n"); memset(buffer, 0xff, 4 * 1024 * 1024); for(i=0;iPartCount;i++) { printf("try part %s\n", mbr->array[i].name); if(mbr->array[i].sig_erase == 0x8000) { if(!uboot_spare_head.boot_data.storage_type) { NAND_build_all_partition(); } part_start = mbr->array[i].addrlo; //part_sectors = mbr->array[i].lenlo; part_sectors = 16 * 1024 * 1024/512; printf("erase part %s ...\n", mbr->array[i].name); if(__signature_erase_part(part_start, part_sectors, buffer, 4 * 1024 * 1024/512)) { printf("erase part %s fail\n", mbr->array[i].name); free(buffer); return -1; } printf("erase part %s ok\n", mbr->array[i].name); } } free(buffer); return 0; }