import sys import os import struct import subprocess import shutil script_folder, script_name = os.path.split(os.path.realpath(__file__)) sys.path.append(os.path.join(script_folder, "lib")) import gfh import cert def get_file_sizeb(file_path): if not os.path.isfile(file_path): return 0 file_handle = open(file_path, "rb") file_handle.seek(0, 2) file_size = file_handle.tell() file_handle.close() return file_size def concatb(file1_path, file2_path): file1_size = get_file_sizeb(file1_path) file2_size = get_file_sizeb(file2_path) file1 = open(file1_path, "ab+") file2 = open(file2_path, "rb") file1.write(file2.read(file2_size)) file2.close() file1.close() class bootloader: def __init__(self, out_path, in_bootloader_file_path, out_bootloader_file_path): self.m_gfh = gfh.image_gfh() self.m_out_path = out_path if not os.path.exists(self.m_out_path): os.makedirs(self.m_out_path) self.m_in_bootloader_file_path = in_bootloader_file_path self.m_out_bootloader_file_path = out_bootloader_file_path self.m_bootloader_is_signed = False self.m_bootloader_content_offset = 0 #initialize content size to bootloader file size self.m_bootloader_content_length = get_file_sizeb(self.m_in_bootloader_file_path) self.m_bootloader_sig_size = 0 #generate file path for bootloader without gfh and signature bootloader_path = in_bootloader_file_path.split('.') self.m_bootloader_no_gfh_file_path = bootloader_path[0] + "_plain.bin" self.m_sig_ver = 0 self.m_sw_ver = 0 self.m_root_prvk_path = "" self.m_img_prvk_path = "" self.m_ac_key = 0 self.m_sig_handler = None def is_signed(self): if self.m_in_bootloader_file_path: bootloader_file = open(self.m_in_bootloader_file_path, "rb") gfh_hdr_obj = gfh.gfh_header() gfh_hdr_size = gfh_hdr_obj.get_size() gfh_hdr_buf = bootloader_file.read(gfh_hdr_size) self.m_bootloader_is_signed = gfh_hdr_obj.is_gfh(gfh_hdr_buf) bootloader_file.close() return self.m_bootloader_is_signed def parse(self): print "===parse bootloader===" #image will be decomposed if it's signed if self.is_signed(): gfh_total_size = self.m_gfh.parse(self.m_in_bootloader_file_path) self.m_bootloader_content_offset = gfh_total_size self.m_bootloader_content_length -= gfh_total_size self.m_bootloader_content_length -= self.m_gfh.get_sig_size() self.m_bootloader_sig_size = self.m_gfh.get_sig_size() in_file = open(self.m_in_bootloader_file_path, "rb") out_file = open(self.m_bootloader_no_gfh_file_path, "wb") in_file.seek(self.m_bootloader_content_offset) out_file.write(in_file.read(self.m_bootloader_content_length)) out_file.close() in_file.close() else: shutil.copyfile(self.m_in_bootloader_file_path, self.m_bootloader_no_gfh_file_path) print "bootloader content size = " + hex(self.m_bootloader_content_length) def create_gfh(self, gfh_config): self.parse() if gfh_config: if self.is_signed(): del self.m_gfh.gfhs[:] self.m_gfh.load_ini(gfh_config) elif not self.is_signed(): print "GFH_CONFIG.ini does not exist!!" return -1 #self.m_gfh.dump() return 0 def sign(self, key_ini_path, key_cert_path, content_config_file_path): self.m_gfh.finalize(self.m_bootloader_content_length, key_ini_path) #create tbs_bootloader.bin tbs_bootloader_file_path = os.path.join(self.m_out_path, "tbs_preloader.bin") tbs_bootloader_file = open(tbs_bootloader_file_path, "wb") tbs_bootloader_file.write(self.m_gfh.pack()) bootloader_no_gfh_file = open(self.m_bootloader_no_gfh_file_path, "rb") tbs_bootloader_file.write(bootloader_no_gfh_file.read(self.m_bootloader_content_length)) bootloader_no_gfh_file.close() tbs_bootloader_file.close() print "===sign===" if self.m_gfh.get_sig_type() == "CERT_CHAIN": self.m_sig_handler = cert.cert_chain_v2() #create key cert if key cert does not exist if key_cert_path == "": key_cert_path = os.path.join(self.m_out_path, "key_cert.bin") if not os.path.isfile(key_cert_path): key_cert_folder_name, key_cert_file_name = os.path.split(os.path.abspath(key_cert_path)) self.m_sig_handler.create_key_cert(key_ini_path, self.m_out_path, key_cert_file_name) key_cert_path = os.path.join(self.m_out_path, key_cert_file_name) else: self.m_sig_handler.set_key_cert(key_cert_path) #create content cert content_cert_name = "content_cert.bin" self.m_sig_handler.create_content_cert(content_config_file_path, tbs_bootloader_file_path, self.m_out_path, content_cert_name) #create final cert chain sig_name = "preloader.sig" sig_file_path = os.path.join(self.m_out_path, sig_name) self.m_sig_handler.output(self.m_out_path, sig_name) #output final cert chain size sig_size_name = "sig_size.txt" sig_size_file_path = os.path.join(self.m_out_path, sig_size_name) sig_size_file = open(sig_size_file_path, 'w') sig_size_file.write(hex(get_file_sizeb(sig_file_path))) sig_size_file.close() #create final preloader image if os.path.isfile(self.m_out_bootloader_file_path): os.remove(self.m_out_bootloader_file_path) concatb(self.m_out_bootloader_file_path, tbs_bootloader_file_path) concatb(self.m_out_bootloader_file_path, sig_file_path) #clean up os.remove(os.path.join(self.m_out_path, content_cert_name)) elif self.m_gfh.get_sig_type() == "SINGLE_AND_PHASH": self.m_sig_handler = cert.sig_single_and_phash(self.m_gfh.get_pad_type()) self.m_sig_handler.set_out_path(self.m_out_path) self.m_sig_handler.create(key_ini_path, tbs_bootloader_file_path) #signature generation self.m_sig_handler.sign() sig_name = "preloader.sig" sig_file_path = os.path.join(self.m_out_path, sig_name) self.m_sig_handler.output(self.m_out_path, sig_name) #output signature size sig_size_name = "sig_size.txt" sig_size_file_path = os.path.join(self.m_out_path, sig_size_name) sig_size_file = open(sig_size_file_path, 'w') sig_size_file.write(hex(get_file_sizeb(sig_file_path))) sig_size_file.close() #create final preloader image if os.path.isfile(self.m_out_bootloader_file_path): os.remove(self.m_out_bootloader_file_path) concatb(self.m_out_bootloader_file_path, tbs_bootloader_file_path) concatb(self.m_out_bootloader_file_path, sig_file_path) else: print "unknown signature type" #clean up os.remove(self.m_bootloader_no_gfh_file_path) os.remove(tbs_bootloader_file_path) os.remove(sig_file_path) return def main(): #parameter parsing idx = 1 key_ini_path = "" key_path = "" gfh_config_ini_path = "" content_config_ini_path = "" key_cert_path = "" in_bootloader_path = "" function = "sign" function_out_path = "" while idx < len(sys.argv): if sys.argv[idx][0] == '-': if sys.argv[idx][1] == 'i': print "key ini: " + sys.argv[idx + 1] key_ini_path = sys.argv[idx + 1] idx += 2 if sys.argv[idx][1] == 'j': print "key(pem): " + sys.argv[idx + 1] key_path = sys.argv[idx + 1] idx += 2 elif sys.argv[idx][1] == 'g': print "gfh config: " + sys.argv[idx + 1] gfh_config_ini_path = sys.argv[idx + 1] idx += 2 elif sys.argv[idx][1] == 'c': print "content config: " + sys.argv[idx + 1] content_config_ini_path = sys.argv[idx + 1] idx += 2 elif sys.argv[idx][1] == 'k': print "key cert: " + sys.argv[idx + 1] key_cert_path = sys.argv[idx + 1] idx += 2 elif sys.argv[idx][1:] == 'func': print "function: " + sys.argv[idx + 1] function = sys.argv[idx + 1] idx += 2 elif sys.argv[idx][1] == 'o': print "function output: " + sys.argv[idx + 1] function_out_path = sys.argv[idx + 1] idx += 2 else: print "unknown input" idx += 2 else: in_bootloader_path = sys.argv[idx] print "bootloader: " + in_bootloader_path idx += 1 if (function == "sign") and (not in_bootloader_path): print "bootloader path is not given!" return -1 if (not function_out_path): print "function out path is not given!" return -1 if function == "sign": if (key_ini_path == "") and (key_cert_path == ""): print "key path is not given!" return -1 else: if (key_path == "" and key_ini_path == ""): print "key path is not given!" return -1 out_path = os.path.dirname(os.path.abspath(function_out_path)) if not os.path.exists(out_path): os.makedirs(out_path) if function == "sign": bootloader_obj = bootloader(out_path, in_bootloader_path, function_out_path) bootloader_obj.create_gfh(gfh_config_ini_path) bootloader_obj.sign(key_ini_path, key_cert_path, content_config_ini_path) return 0 elif function == "keybin_pss": key = cert.ct_key("pss") key.create(key_path) key_bin = key.pack() out_file = open(function_out_path, "wb") out_file.write(key_bin) out_file.close() return 0 elif function == "keybin_legacy": key = cert.ct_key("legacy") key.create(key_path) key_bin = key.pack() out_file = open(function_out_path, "wb") out_file.write(key_bin) out_file.close() return 0 elif function == "keyhash_pss": key = cert.ct_key("pss") key.create(key_path) key_bin = key.pack() tmp_key_bin_path = os.path.join(out_path, "tmp_keybin.bin") out_file = open(tmp_key_bin_path, "wb") out_file.write(key_bin) out_file.close() cert.hash_gen(tmp_key_bin_path, function_out_path) os.remove(tmp_key_bin_path) return 0 elif function == "keyhash_legacy": key = cert.ct_key("legacy") key.create(key_path) key_bin = key.pack() tmp_key_bin_path = os.path.join(out_path, "tmp_keybin.bin") out_file = open(tmp_key_bin_path, "wb") out_file.write(key_bin) out_file.close() cert.hash_gen(tmp_key_bin_path, function_out_path) os.remove(tmp_key_bin_path) return 0 if __name__ == '__main__': main()