[Feature]add MT2731_MP2_MR2_SVN388 baseline version
Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/meta/meta-mediatek-mt2731/recipes-bsp/mdcert/files/sign_image/sign.py b/meta/meta-mediatek-mt2731/recipes-bsp/mdcert/files/sign_image/sign.py
new file mode 100644
index 0000000..47c86af
--- /dev/null
+++ b/meta/meta-mediatek-mt2731/recipes-bsp/mdcert/files/sign_image/sign.py
@@ -0,0 +1,1132 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+"""
+This module supports image signing, including single bin and multi bin.
+Multi bin means a composite image composed of multiple sub-images.
+"""
+import sys
+import os
+import struct
+import re
+import subprocess
+import ntpath
+import shutil
+import stat
+import lib.mkimghdr
+import lib.getPublicKey
+import lib.cert
+import cert_gen
+
+CERT1_REPLACE_TARGET = r"(\s)*pubk2"
+CERT2_REPLACE_HASH = r"(\s)*imgHash EXTERNAL_BITSTRING"
+CERT2_REPLACE_HEADER_HASH = r"(\s)*imgHdrHash EXTERNAL_BITSTRING"
+CERT2_REPLACE_IMG_HASH_MULTI = r"(\s)*imgHash_Multi EXTERNAL_BITSTRING"
+CERT2_REPLACE_SOCID = r"(\s)*socid PRINTABLESTRING"
+CERT1MD_REPLACE_TARGET = r"(\s)*pubkHash EXTERNAL_BITSTRING"
+SW_ID_REPLACE_TARGET = r"(\s)*swID INTEGER"
+IMG_VER_REPLACE_TARGET = r"(\s)*imgVer INTEGER"
+IMG_GROUP_REPLACE_TARGET = r"(\s)*imgGroup INTEGER"
+MKIMAGE_HDR_MAGIC = 0x58881688
+MKIMAGE_HDR_FMT = "<2I 32s 2I 8I"
+BOOTIMG_HDR_MAGIC = "ANDROID"
+BOOTIMG_HDR_FMT = "<8c 10I 16c 512c 8I 1024c I Q I I Q"
+CCCI_HDR_FMT = "<8c 10I 16c 512c 8I"
+DTBO_HDR_MAGIC = 0xD7B7AB1E
+DTBO_HDR_FMT = ">8I"
+
+class Sign(object):
+ """
+ Sign is used to pass parameter to module 'sign'.
+ """
+ def __init__(self):
+ """
+ initialization of arguments
+ """
+ self.args = {}
+ self.context = {}
+
+ self.args['type'] = 0
+ self.args['img'] = 0
+ self.args['privk'] = 0
+ self.args['pubk'] = 0
+ self.args['cert1'] = 0
+ self.args['swID'] = 0
+ self.args['ver'] = 0
+ self.args['name'] = ''
+ self.args['group'] = 0
+ self.args['root_key_padding'] = 0
+ self.args['getHashList'] = 0
+ self.args['platform'] = 'NOT_SET'
+ self.args['project'] = 'NOT_SET'
+ self.args['env_cfg'] = os.path.join(os.path.dirname(__file__), \
+ 'env.cfg')
+ self.args['socid'] = '0'
+
+ return
+
+ def reset(self):
+ """
+ reset all arguments
+ """
+ self.__init__()
+
+ def get_arg(self, field_name):
+ """
+ get value of field and returns 'NOT_SET' if it's not defined
+ """
+ try:
+ return self.args[field_name]
+ except KeyError, error:
+ print 'KeyError: ' + str(error)
+ return 'NOT_SET'
+
+ def set_context(self):
+ """
+ Set temporary path for certificate generation.
+ """
+ img_name = self.args['name']
+ if self.args['img'] != 0:
+ package_name = os.path.splitext(os.path.basename(self.args['img']))[0]
+ else:
+ package_name = ''
+
+ print '=============================='
+ print 'env_cfg parsing'
+ print '=============================='
+ cfg_file = open(self.args['env_cfg'], 'r')
+ cfg_file_dir = os.path.dirname(os.path.abspath(self.args['env_cfg']))
+ for line in cfg_file.readlines():
+ line = line.strip()
+ if line:
+ elements = line.split('=')
+ field = elements[0].strip()
+ value = elements[1].strip()
+ value = value.replace("${PLATFORM}", self.get_arg('platform'))
+ value = value.replace("${PROJECT}", self.get_arg('project'))
+ if field == 'out_path':
+ self.context['out'] = os.environ.get('PRODUCT_OUT')
+ if self.context['out'] is None:
+ print 'Use out path in env.cfg'
+ self.context['out'] = os.path.join(cfg_file_dir, value)
+ else:
+ print 'Use out path in Android'
+ self.context['out_path'] = os.path.join(self.context['out'], "resign")
+ elif field == 'x509_template_path':
+ x509_template_path = os.path.join(cfg_file_dir, value)
+ elif field == 'mkimage_tool_path':
+ mkimage_tool_path = os.path.join(cfg_file_dir, value)
+ else:
+ print 'ignored: ' + field
+ print '=============================='
+
+ self.context['bin_path'] = os.path.join(self.context['out_path'], "bin")
+ self.context['tmpcert_name'] = os.path.join(self.context['out_path'], \
+ "cert", \
+ package_name, \
+ img_name, \
+ "tmp.der")
+
+ #tool path
+ mkimage_config = os.path.join(mkimage_tool_path, "img_hdr.cfg")
+ cert_out = os.path.join(self.context['out_path'], "cert", package_name, img_name)
+
+ self.context['mkimage_config'] = mkimage_config
+
+ mkimage_config_out = ""
+ if self.args['type'] == "cert1md":
+ cert1md_tmp = os.path.join(cert_out, "cert1md", "intermediate")
+ cert1md_name = os.path.join(cert_out, "cert1md", "cert1md.der")
+ cert1md_hash_path = os.path.join(cert1md_tmp, "hash")
+ cert1md_config = os.path.join(x509_template_path, "cert1md.cfg")
+ cert1md_config_out = os.path.join(cert1md_tmp, "cert1md.cfg")
+ mkimage_config_out = os.path.join(cert1md_tmp, "img_hdr.cfg")
+ self.context['cert1md_name'] = cert1md_name
+ self.context['cert1md_config'] = cert1md_config
+ self.context['cert1md_config_out'] = cert1md_config_out
+ self.context['cert1md_hash_path'] = cert1md_hash_path
+ elif self.args['type'] == "cert1":
+ cert1_tmp = os.path.join(cert_out, "cert1", "intermediate")
+ cert1_name = os.path.join(cert_out, "cert1", "cert1.der")
+ cert1_config = os.path.join(x509_template_path, "cert1.cfg")
+ cert1_config_out = os.path.join(cert1_tmp, "cert1.cfg")
+ mkimage_config_out = os.path.join(cert1_tmp, "img_hdr.cfg")
+ self.context['cert1_name'] = cert1_name
+ self.context['cert1_config'] = cert1_config
+ self.context['cert1_config_out'] = cert1_config_out
+ elif self.args['type'] == "cert2":
+ cert2_tmp = os.path.join(cert_out, "cert2", "intermediate")
+ cert2_name = os.path.join(cert_out, "cert2", "cert2.der")
+ cert2_hash_path = os.path.join(cert2_tmp, "hash")
+ cert2_config = os.path.join(x509_template_path, "cert2.cfg")
+ cert2_config_out = os.path.join(cert2_tmp, "cert2.cfg")
+ dm_cert = os.path.join(cert2_tmp, "dm_cert.der")
+ bin_tmp_path = os.path.join(cert2_tmp, "tmp_bin")
+ sig_path = os.path.join(self.context['out'], "sig", package_name)
+ mkimage_config_out = os.path.join(cert2_tmp, "img_hdr.cfg")
+ self.context['bin_tmp_path'] = bin_tmp_path
+ self.context['cert2_name'] = cert2_name
+ self.context['cert2_config'] = cert2_config
+ self.context['cert2_config_out'] = cert2_config_out
+ self.context['cert2_hash_path'] = cert2_hash_path
+ self.context['dm_cert'] = dm_cert
+ self.context['sig_path'] = sig_path
+
+ self.context['mkimage_config_out'] = mkimage_config_out
+ return
+
+ def __create_out_dir(self, path):
+ """
+ create output folder
+ """
+ dir_path = os.path.dirname(path)
+ print "Create dir:" + dir_path
+
+ try:
+ os.makedirs(dir_path)
+ except OSError, error:
+ if error.errno != os.errno.EEXIST:
+ raise
+
+ def __create_abs_dir(self, path):
+ """
+ create output folder based on absolute path
+ """
+ dir_path = os.path.abspath(path)
+ print "Create dir:" + dir_path
+
+ try:
+ os.makedirs(dir_path)
+ except OSError, error:
+ if error.errno != os.errno.EEXIST:
+ raise
+
+ def __create_folder(self):
+ """
+ Create output folder for certificate generation.
+ """
+ mkimage_config_out = self.context['mkimage_config_out']
+ bin_path = self.context['bin_path']
+
+ self.__create_out_dir(mkimage_config_out)
+ self.__create_abs_dir(bin_path)
+
+ if self.args['type'] == "cert1md":
+ cert1md_name = self.context['cert1md_name']
+ cert1md_hash_path = self.context['cert1md_hash_path']
+ self.__create_out_dir(cert1md_name)
+ self.__create_abs_dir(cert1md_hash_path)
+ elif self.args['type'] == "cert1":
+ cert1_name = self.context['cert1_name']
+ cert1_config_out = self.context['cert1_config_out']
+ self.__create_out_dir(cert1_name)
+ self.__create_out_dir(cert1_config_out)
+ elif self.args['type'] == "cert2":
+ cert2_name = self.context['cert2_name']
+ cert2_hash_path = self.context['cert2_hash_path']
+ sig_path = self.context['sig_path']
+ bin_tmp_path = self.context['bin_tmp_path']
+ self.__create_out_dir(cert2_name)
+ self.__create_abs_dir(cert2_hash_path)
+ self.__create_abs_dir(sig_path)
+ self.__create_abs_dir(bin_tmp_path)
+ return
+
+ def gen_cert(self, cert_config, privk_key, cert_der, root_key_padding):
+ """
+ Generate certificate based on the configuration given.
+ """
+ cert_gen_args = cert_gen.CertGenArgs()
+ cert_gen_args.config_file = cert_config
+ cert_gen_args.prvk_file_path = privk_key
+ #root key padding will be set to 'legacy' by default
+ if root_key_padding != 0:
+ cert_gen_args.root_key_padding = root_key_padding
+ cert_gen_args.x509cert_file = cert_der
+ cert_gen.cert_gen_op(cert_gen_args)
+
+ def gen_cert1(self):
+ """
+ Generate cert1, which is key certificate for images
+ other than modem image.
+ """
+ cert1_config = self.context['cert1_config']
+ cert1_config_out = self.context['cert1_config_out']
+ #copy cert1 config
+ shutil.copy2(cert1_config, cert1_config_out)
+ sw_id = self.args['swID']
+ img_ver = self.args['ver']
+ img_group = self.args['group']
+
+ cert1_name = self.context['cert1_name']
+
+ if self.args['root_key_padding'] == 0:
+ root_key_padding = 'legacy'
+ else:
+ root_key_padding = self.args['root_key_padding']
+ print "root_key_padding = " + root_key_padding
+
+ if int(sw_id) != 0:
+ fill_cert_config(cert1_config_out, sw_id, SW_ID_REPLACE_TARGET)
+ if int(img_ver) != 0:
+ fill_cert_config(cert1_config_out, img_ver, IMG_VER_REPLACE_TARGET)
+ if int(img_group) != 0:
+ fill_cert_config(cert1_config_out, img_group, IMG_GROUP_REPLACE_TARGET)
+
+ fill_cert_config(cert1_config_out, self.args['pubk'], CERT1_REPLACE_TARGET)
+ #gen cert
+ self.gen_cert(cert1_config_out, \
+ self.args['privk'], \
+ cert1_name, \
+ root_key_padding)
+ cert1_img_type = 0x2 << 24
+ add_mkimg_header(cert1_name, 0, cert1_img_type, "cert1", self.context)
+ print "output path:" + cert1_name
+ return
+
+ def gen_cert1md(self):
+ """
+ Generate cert1md, which is key certificate for modem image.
+ """
+ img_file = self.args['img']
+ cert_privk = self.args['privk']
+ cert1md_hash_path = self.context['cert1md_hash_path']
+ cert1md_config = self.context['cert1md_config']
+ cert1md_config_out = self.context['cert1md_config_out']
+
+ if self.args['root_key_padding'] == 0:
+ root_key_padding = 'legacy'
+ else:
+ root_key_padding = self.args['root_key_padding']
+ print "root_key_padding = " + root_key_padding
+
+ print img_file
+ #check is Raw
+ is_raw, is_md, hdr_size = check_is_raw(img_file)
+
+ if is_raw == 0:
+ print "Is not raw image"
+ return
+
+ if is_md < 1:
+ print "Wrong MD image type"
+ return
+
+ cert1md_name = self.context['cert1md_name']
+
+ #SV5 Image(MD)
+ split_header, split_image = img_split(img_file, cert1md_hash_path, hdr_size)
+ key_hash_tmp = os.path.join(cert1md_hash_path, "key_tmp.hash")
+ key_hash = os.path.join(cert1md_hash_path, "key.hash")
+ header_hash = os.path.join(cert1md_hash_path, "header.hash")
+
+ #get md key
+ md_key = get_md_key(split_image, is_md, self.context)
+ #gen header hash
+ lib.cert.hash_gen(split_header, header_hash)
+ #gen key hash
+ lib.cert.hash_gen(md_key, key_hash_tmp)
+ #Endiness conversion
+ endiness_convert(key_hash_tmp, key_hash)
+
+ #fill config
+ shutil.copy2(cert1md_config, cert1md_config_out)
+ fill_cert_config(cert1md_config_out, key_hash, CERT1MD_REPLACE_TARGET)
+ fill_cert_config(cert1md_config_out, self.args['pubk'], CERT1_REPLACE_TARGET)
+
+ sw_id = self.args['swID']
+ img_ver = self.args['ver']
+ img_group = self.args['group']
+ if int(sw_id) != 0:
+ fill_cert_config(cert1md_config_out, sw_id, SW_ID_REPLACE_TARGET)
+ if int(img_ver) != 0:
+ fill_cert_config(cert1md_config_out, img_ver, IMG_VER_REPLACE_TARGET)
+ if int(img_group) != 0:
+ fill_cert_config(cert1md_config_out, img_group, IMG_GROUP_REPLACE_TARGET)
+ #gen cert
+ self.gen_cert(cert1md_config_out, cert_privk, cert1md_name, root_key_padding)
+ #add mkimage header on cert1md
+
+ cert1md_img_type = 0x2 << 24 | 0x1
+ add_mkimg_header(cert1md_name, 0, cert1md_img_type, "cert1md", self.context)
+ print "output path:" + cert1md_name
+
+ def gen_cert2(self):
+ """
+ Generate cert2, which is content certificate.
+ """
+ img_file = self.args['img']
+ cert1 = self.args['cert1']
+ cert_privk = self.args['privk']
+ img_name = self.args['name']
+ img_ver = self.args['ver']
+ socid = self.args['socid']
+ is_img_hash_list = 0
+ is_raw = 0
+ is_boot = 0
+ is_dtbo = 0
+
+ if self.get_arg('getHashList') is '1':
+ is_img_hash_list = 1
+
+ img_array = []
+ size_array = []
+ offset_array = []
+ img_name_array = []
+
+ bin_path = self.context['bin_path']
+ bin_tmp_path = self.context['bin_tmp_path']
+ cert2_name = self.context['cert2_name']
+ cert2_config = self.context['cert2_config']
+ cert2_config_out = self.context['cert2_config_out']
+ cert2_hash_path = self.context['cert2_hash_path']
+ dm_cert = self.context['dm_cert']
+ sig_path = self.context['sig_path']
+ out = self.context['out']
+
+ is_raw, is_md, hdr_size = check_is_raw(img_file)
+ if not is_raw:
+ is_boot, boot_img_size, hdr_size = check_is_boot(img_file)
+
+ if is_boot:
+ has_dm_cert = get_vboot10_cert(img_file, boot_img_size, self.context)
+
+ if (not is_raw) and (not is_boot):
+ is_dtbo, dtbo_img_size, hdr_size = check_is_dtbo(img_file)
+
+ if is_raw:
+ img_array, \
+ size_array, \
+ offset_array, \
+ img_name_array = parse_multi_bin(img_file, img_name, self.context)
+ if img_array is None:
+ return
+ elif is_boot:
+ img_array.append(os.path.join(bin_tmp_path, "tmp.bin"))
+ size_array.append(boot_img_size)
+ offset_array.append(0)
+ img_name_array.append(img_name)
+ elif is_dtbo:
+ img_array.append(os.path.join(bin_tmp_path, "tmp.bin"))
+ size_array.append(dtbo_img_size)
+ offset_array.append(0)
+ img_name_array.append(img_name)
+ elif not is_img_hash_list:
+ print "wrong image format"
+ return
+
+ if is_img_hash_list:
+ print "get pure image hash..."
+ self.gen_img_hash_list(img_file, cert1, cert_privk, img_name, img_ver)
+ return
+
+ get_pure_img(img_file, img_array, size_array, offset_array)
+ print "bin_number:" + str(len(img_array))
+ #Get hash from image
+ i = 0
+ img_list_end = 0
+ for img in img_array:
+ if i == len(img_array) - 1:
+ img_list_end = 1
+
+ if is_raw == 1 or is_boot == 1 or is_md == 1 or is_md == 2 or is_dtbo:
+ #Raw Image
+ if img_name_array[i] == img_name:
+ split_header, split_image = img_split(img, cert2_hash_path, hdr_size)
+
+ image_hash = os.path.join(cert2_hash_path, "image.hash")
+ header_hash = os.path.join(cert2_hash_path, "header.hash")
+
+ #gen header hash
+ lib.cert.hash_gen(split_header, header_hash)
+ #gen image hash
+ lib.cert.hash_gen(split_image, image_hash)
+
+ #if exist DM cert, append it after hash calculate
+ if is_boot == 1 and has_dm_cert == 1:
+ append_file(img, dm_cert)
+
+ #cat cert1
+ append_file(img, cert1)
+
+ #fill cert2 config
+ shutil.copy2(cert2_config, cert2_config_out)
+ fill_cert_config(cert2_config_out, image_hash, CERT2_REPLACE_HASH)
+ fill_cert_config(cert2_config_out, header_hash, CERT2_REPLACE_HEADER_HASH)
+ fill_cert_config(cert2_config_out, socid.upper(), CERT2_REPLACE_SOCID)
+
+ if int(img_ver) != 0:
+ fill_cert_config(cert2_config_out, img_ver, IMG_VER_REPLACE_TARGET)
+ #gen cert2
+ self.gen_cert(cert2_config_out, cert_privk, cert2_name, 0)
+ #add mkimage header on cert2
+ cert2_img_type = 0x2 << 24 | 0x2
+ add_mkimg_header(cert2_name, \
+ img_list_end, \
+ cert2_img_type, \
+ "cert2", \
+ self.context)
+ #cat cert2
+ append_file(img, cert2_name)
+ #cat sig file
+ sig_file = os.path.join(sig_path, img_name + ".sig")
+ print img_ver
+ print "sig:" + sig_file
+ shutil.copy2(cert1, sig_file)
+ append_file(sig_file, cert2_name)
+
+ i += 1
+
+ img_name = ntpath.split(img_file)[1]
+ img_name = img_name.split(".")[0] + "-verified." + img_name.split(".")[1]
+ final_bin = os.path.join(bin_tmp_path, img_name)
+
+ #cat all bin to img_array[0]
+ cat_img(img_array, final_bin)
+
+ #Post Process
+ shutil.copy2(final_bin, os.path.join(bin_path, img_name))
+ shutil.copy2(os.path.join(bin_path, img_name), os.path.join(out, img_name))
+ print "output path:" + os.path.join(out, img_name)
+ return
+
+ def gen_img_hash_list(self, img_file, cert1, cert_privk, img_name, img_ver):
+ """
+ Generate image hash list. This is a verified boot mechanism
+ for images that are too big to fit into DRAM at once. In this
+ case, image is split into 128MB chunks and sent to DA one by one.
+ DA will receive a signed image hash list and verifies it before
+ flashing. After that, DA will calculate hash on receiving a chunk
+ and compares it against the hash in signed image hash list.
+ """
+ data_size = 128 * 1048576
+
+ img_size = os.path.getsize(img_file)
+ print "img_size => "+ str(img_size)
+ file1 = open(img_file, 'rb')
+ package_num = (img_size + (data_size - 1)) / data_size
+ print "package_num => "+ str(package_num)
+ print "get " + img_name + " hash list..."
+
+ bin_tmp_path = self.context['bin_tmp_path']
+ cert2_name = self.context['cert2_name']
+ cert2_config = self.context['cert2_config']
+ cert2_config_out = self.context['cert2_config_out']
+ cert2_hash_path = self.context['cert2_hash_path']
+ sig_path = self.context['sig_path']
+ out = self.context['out']
+
+ for i in range(package_num):
+ div_out = os.path.join(bin_tmp_path, img_name + "_" + str(i) + ".bin")
+ div_hash_out = os.path.join(cert2_hash_path, img_name + "_" + str(i) + ".hash")
+ output_file = open(div_out, 'wb')
+ content = file1.read(data_size)
+ output_file.write(content)
+ output_file.close()
+ lib.cert.hash_gen(div_out, div_hash_out)
+ file1.close()
+
+ img_hash_file = os.path.join(cert2_hash_path, img_name + "_total.hash")
+ file2 = open(img_hash_file, 'wb')
+ for i in range(package_num):
+ hash_file = open(os.path.join(cert2_hash_path, img_name + "_" + str(i) + ".hash"), 'rb')
+ img_hash = hash_file.read()
+ file2.write(img_hash)
+ file2.close()
+
+ shutil.copy2(cert2_config, cert2_config_out)
+
+ fill_cert_config(cert2_config_out, img_hash_file, CERT2_REPLACE_IMG_HASH_MULTI)
+ if int(img_ver) != 0:
+ fill_cert_config(cert2_config_out, img_ver, IMG_VER_REPLACE_TARGET)
+ #gen cert2
+ self.gen_cert(cert2_config_out, cert_privk, cert2_name, 0)
+ img_list_end = 1
+ #add mkimage header on cert2
+ cert2_img_type = 0x2 << 24 | 0x2
+ add_mkimg_header(cert2_name, img_list_end, cert2_img_type, "cert2", self.context)
+ sig_file = os.path.join(sig_path, img_name + ".sig")
+ shutil.copy2(cert1, sig_file)
+ append_file(sig_file, cert2_name)
+ shutil.copy2(sig_file, os.path.join(out, img_name + ".sig"))
+
+ return
+
+ def sign_op(self):
+ """
+ perform image signing
+ """
+ self.set_context()
+
+ if self.args['type'] == "cert1":
+ self.__create_folder()
+ self.gen_cert1()
+ elif self.args['type'] == "cert2":
+ self.__create_folder()
+ self.gen_cert2()
+ elif self.args['type'] == "cert1md":
+ self.__create_folder()
+ self.gen_cert1md()
+ else:
+ print "wrong cert type !"
+
+ return
+
+ def dump(self):
+ """
+ dump parameters
+ """
+ print 'cert_type = ' + self.get_arg(self.args['type'])
+ print 'platform = ' + self.get_arg(self.args['platform'])
+ print 'project = ' + self.get_arg(self.args['project'])
+ print 'img = ' + self.get_arg(self.args['img'])
+ print 'name = ' + self.get_arg(self.args['name'])
+ print 'cert1_path = ' + self.get_arg(self.args['cert1'])
+ print 'root_prvk = ' + self.get_arg(self.args['privk'])
+ print 'img_pubk = ' + self.get_arg(self.args['pubk'])
+ print 'group = ' + self.get_arg(self.args['group'])
+ print 'ver = ' + self.get_arg(self.args['ver'])
+ print 'root_padding = ' + self.get_arg(self.args['root_key_padding'])
+ print 'getHashList = ' + self.get_arg(self.args['getHashList'])
+ print 'env_cfg = ' + self.get_arg(self.args['env_cfg'])
+ return
+
+def parse_multi_bin(img_file, target_img_name, context):
+ """
+ we may concatenate multiple images to form a composite image.
+ This function is used to parse the composite image to get
+ information of sub-image with name target_img_name.
+ """
+ #parse bin
+ img_size = 0
+ index = 0
+ file1 = open(img_file, 'rb')
+ last_pos = 0
+ pre_pos = 0
+
+ img_array = []
+ size_array = []
+ offset_array = []
+ img_name_array = []
+
+ file_size = os.path.getsize(img_file)
+ print "file_size: "+ str(hex(file_size))
+
+ first_img = 1
+ final_size = 0
+ match_target = 0
+ img_name = 0
+
+ bin_tmp_path = context['bin_tmp_path']
+
+ while True:
+ file1.seek(last_pos)
+ header_size = struct.calcsize(MKIMAGE_HDR_FMT)
+ fin = file1.read(header_size)
+ unpack_array = struct.unpack(MKIMAGE_HDR_FMT, fin)
+ file1.seek(last_pos)
+
+ magic_number = unpack_array[0]
+ dsize = unpack_array[1]
+ hdr_size = unpack_array[6]
+ align_size = unpack_array[10]
+ img_type = unpack_array[8]
+
+ if ~cmp(magic_number, int(MKIMAGE_HDR_MAGIC)) == 0:
+ print "wrong image header magic"
+ sys.exit()
+
+ # include header + image + padding size to 16 bytes align
+ img_size = (dsize + hdr_size + (align_size - 1)) / align_size * align_size
+ print "img-" + str(index) + " size:" + hex(img_size)
+
+ img_type_byte3 = (img_type >> 24) & 0xFF
+
+ if img_type_byte3 != 2:
+ # image not cert
+ pre_img_name = img_name
+ img_name = unpack_array[2].rstrip('\t\r\n\0')
+ if target_img_name == img_name:
+ print "Target image, remove cert for replace"
+ is_target = 1
+ match_target = 1
+ else:
+ print "Not target image, retain cert"
+ is_target = 0
+ is_raw = 1
+ else:
+ #image is cert
+ is_raw = 0
+
+ if is_raw and first_img == 0:
+ print "add index" + str(index) + " image"
+ img_str = os.path.join(bin_tmp_path, "tmp_" + str(index) + ".bin")
+ img_array.append(img_str)
+ size_array.append(final_size)
+ offset_array.append(pre_pos)
+ img_name_array.append(pre_img_name)
+ pre_pos = last_pos
+ final_size = 0
+ index += 1
+
+ first_img = 0
+
+ if is_target:
+ if is_raw:
+ final_size = img_size
+ else:
+ print "is cert, discard it"
+ else:
+ final_size += img_size
+
+ last_pos += img_size
+
+ if last_pos >= file_size:
+ print "add index" + str(index) + " image, this is final image"
+ img_str = os.path.join(bin_tmp_path, "tmp_" + str(index) + ".bin")
+ img_array.append(img_str)
+ size_array.append(final_size)
+ offset_array.append(pre_pos)
+ img_name_array.append(img_name)
+ pre_pos = last_pos
+ final_size = 0
+ break
+
+ file1.close()
+ if match_target == 0:
+ print "img name not match,exit!!"
+ return None, None, None, None
+ return img_array, size_array, offset_array, img_name_array
+
+def check_is_raw(img_file):
+ """
+ check whether image is raw image format, which includes
+ images with mkimage header and modem image.
+ """
+ is_raw = 0
+ is_md = 0
+ print img_file
+ file1 = open(img_file, 'rb')
+ header_size = struct.calcsize(MKIMAGE_HDR_FMT)
+ fin = file1.read(header_size)
+
+ unpack_array = struct.unpack(MKIMAGE_HDR_FMT, fin)
+ file1.close()
+
+ hdr_size = unpack_array[6]
+ img_type = unpack_array[8]
+
+ if cmp(unpack_array[0], int(MKIMAGE_HDR_MAGIC)) == 0:
+ img_type_byte0 = img_type & 0xFF
+ img_type_byte3 = (img_type >> 24) & 0xFF
+
+ if img_type == 0:
+ print "Raw IMG"
+ is_raw = 1
+ elif img_type_byte3 == 1:
+ if img_type_byte0 == 0:
+ print "MD IMG:LTE"
+ is_raw = 1
+ is_md = 1
+ elif img_type_byte0 == 1:
+ print "MD IMG:C2K"
+ is_raw = 1
+ is_md = 2
+ else:
+ print "Not Raw Img"
+ is_raw = 0
+ return is_raw, is_md, hdr_size
+
+def get_vboot10_cert(img_file, img_size, context):
+ """
+ parse certificate that follows boot image on vboot1.0
+ """
+ has_dm_cert = 0
+ dm_cert = context['dm_cert']
+ file_size = os.path.getsize(img_file)
+ if file_size <= img_size + 4:
+ return has_dm_cert
+
+ file1 = open(img_file, 'rb')
+ fin = file1.read(img_size)
+ fin = file1.read(4)
+
+ unpack_array = struct.unpack("<4c", fin)
+
+ if ord(unpack_array[0]) == 0x30:
+ cert_size = (ord(unpack_array[2]) << 8) + ord(unpack_array[3]) + 4
+ print hex(cert_size)
+ file2 = open(dm_cert, 'wb')
+ file1.seek(img_size)
+ file2.write(file1.read(cert_size))
+ file2.close()
+ has_dm_cert = 1
+ padding_file(dm_cert, 16)
+ file1.close()
+ return has_dm_cert
+
+
+def check_is_md(img_file):
+ """
+ check whether it's modem image.
+ """
+ #parse bin
+ file1 = open(img_file, 'rb')
+ header_size = struct.calcsize(CCCI_HDR_FMT)
+ fin = file1.read(header_size)
+ unpack_array = struct.unpack(CCCI_HDR_FMT, fin)
+ file1.close()
+ magic_str = ""
+ for i in range(0, 7):
+ magic_str = magic_str + unpack_array[i]
+ return 0
+
+def check_is_boot(img_file):
+ """
+ check whether it's boot/recovery image.
+ """
+ #parse bin
+ img_size = 0
+ is_boot = 0
+ hdr_size = 0
+
+ file1 = open(img_file, 'rb')
+ header_size = struct.calcsize(BOOTIMG_HDR_FMT)
+
+ fin = file1.read(header_size)
+ unpack_array = struct.unpack(BOOTIMG_HDR_FMT, fin)
+ file1.close()
+ magic_str = ""
+ for i in range(0, 7):
+ magic_str = magic_str + unpack_array[i]
+
+ if cmp(magic_str, BOOTIMG_HDR_MAGIC) == 0:
+ print "Is Boot Img"
+ page_size = unpack_array[15]
+ hdr_size = page_size
+ kernel_size = (unpack_array[8] + (page_size - 1)) / page_size * page_size
+ ramdisk_size = (unpack_array[10] + (page_size - 1)) / page_size * page_size
+ #recovery dtbo image
+ dtbo_size = (unpack_array[1578] + (page_size - 1)) / page_size * page_size
+ #dtb image
+ dtb_size = (unpack_array[1581] + (page_size - 1)) / page_size * page_size
+ print "Header size:" + `hex(header_size)`
+ print "Kernel size:" + `hex(kernel_size)`
+ print "Ramdisk size:" + `hex(ramdisk_size)`
+ print "DTBO size:" + `hex(dtbo_size)`
+ print "dtb size:" + `hex(dtb_size)`
+ print "page size:" + `hex(unpack_array[15])`
+ img_size = (kernel_size + ramdisk_size + hdr_size + dtbo_size + dtb_size + (16 - 1)) / 16 * 16
+ print "Total Size(include header and padding):" + `hex(img_size)`
+ print hex(img_size)
+ is_boot = 1
+ else:
+ print "Not Boot Img"
+
+ return is_boot, img_size, hdr_size
+
+def check_is_dtbo(img_file):
+ """
+ check whether it's dtbo image.
+ """
+ #parse bin
+ img_size = 0
+ is_dtbo = 0
+ hdr_size = 0
+ file1 = open(img_file, 'rb')
+ header_size = struct.calcsize(DTBO_HDR_FMT)
+
+ fin = file1.read(header_size)
+ unpack_array = struct.unpack(DTBO_HDR_FMT, fin)
+ file1.close()
+
+ if unpack_array[0] == DTBO_HDR_MAGIC:
+ print "Is DTBO Img"
+ hdr_size = unpack_array[2]
+ img_size = unpack_array[1]
+ print "Header size:" + `hex(hdr_size)`
+ print "Image size:" + `hex(img_size)`
+ print "Total Size" + `hex(unpack_array[1])`
+ is_dtbo = 1
+ else:
+ print "Not dtbo Img"
+
+ return is_dtbo, img_size, hdr_size
+
+def fill_cert_config(cert_path, replace_str, tgt_line_pattern):
+ """
+ We provide certificate configuration template and could
+ generate cerificate based on the configuration. Before that,
+ you need to fill up the configuration template so certificate
+ generation engine knows how to generate certificate.
+ """
+ os.chmod(cert_path, stat.S_IWRITE + stat.S_IREAD)
+
+ file1 = open(cert_path, 'r')
+ lines = file1.readlines()
+ file1.close()
+
+ file2 = open(cert_path, 'w')
+
+ format1 = re.compile(tgt_line_pattern)
+ for line in lines:
+ if format1.match(line):
+ print line
+ line2 = line.split("::=")[0] + "::= " + replace_str + "\n"
+ print line2
+ file2.write(line2)
+ else:
+ file2.write(line)
+
+def padding_file(input_file, align_num):
+ """
+ Fill 0 to make input_file size multiple of align_num.
+ """
+ filesize = os.stat(input_file).st_size
+ file1 = open(input_file, 'ab+')
+ padding = filesize % align_num
+ if padding != 0:
+ padding = align_num - padding
+ for _ in range(padding):
+ file1.write("\x00")
+ file1.close()
+
+def append_file(img_file, cert_file):
+ """
+ Append cert_file to the end of img_file.
+ """
+ padding_file(img_file, 16)
+ file1 = open(img_file, 'ab+')
+ file2 = open(cert_file, 'rb')
+ file1.write(file2.read())
+ file1.close()
+ file2.close()
+
+def get_pure_img(img_file, img_array, size_array, offset_array):
+ """
+ Put sub-image data into array for composite image.
+ """
+ index = 0
+ file2 = open(img_file, 'rb')
+ for sub_img in img_array:
+ img_size = size_array[index]
+ offset = offset_array[index]
+ file2.seek(offset)
+ file1 = open(sub_img, 'wb+')
+ file1.write(file2.read(img_size))
+ file1.close()
+ index += 1
+ file2.close()
+
+def backup_file(tmp_file, target_file, backup_file_path):
+ """
+ Backup target_file to backup_file_path
+ """
+ if backup_file_path != "":
+ shutil.move(target_file, backup_file_path)
+ shutil.move(tmp_file, target_file)
+
+def cat_img(img_array, final_bin):
+ """
+ Concatenate data in img_array to form final_bin,
+ which is a composite image.
+ """
+ file1 = open(final_bin, 'wb')
+ index = 0
+ for img in img_array:
+ file2 = open(img, 'rb')
+ file1.write(file2.read())
+ file2.close()
+ index += 1
+ file1.close()
+
+def add_mkimg_header(cert_name, img_list_end, img_type, img_name, context):
+ """
+ mkimage header is the header for Mediatek proprietary images.
+ This function is used to generate mkimage header for
+ certificate files.
+
+ """
+ mkimage_config = context['mkimage_config']
+ mkimage_config_out = context['mkimage_config_out']
+ tmpcert_name = context['tmpcert_name']
+ file1 = open(mkimage_config, 'r')
+ file2 = open(mkimage_config_out, 'w+')
+ format1 = re.compile("IMG_LIST_END")
+ format2 = re.compile("IMG_TYPE")
+ format3 = re.compile("NAME")
+ for line in file1:
+ if format1.match(line):
+ end = line.split("=")[1]
+ line2 = line.replace(end, str(img_list_end))
+ file2.write(line2 + "\n")
+ elif format2.match(line):
+ end = line.split("=")[1]
+ line2 = line.replace(end, str(img_type))
+ file2.write(line2 + "\n")
+ elif format3.match(line):
+ end = line.split("=")[1]
+ line2 = line.replace(end, str(img_name))
+ file2.write(line2 + "\n")
+ else:
+ file2.write(line)
+
+ file1.close()
+ file2.close()
+
+ img_hdr = lib.mkimghdr.mkimage_hdr()
+ img_hdr.update_mkimage_hdr(cert_name, mkimage_config_out)
+ img_hdr.pack()
+ img_hdr.output(cert_name, tmpcert_name)
+ shutil.move(tmpcert_name, cert_name)
+
+def get_md_key(md_img, is_md, context):
+ """
+ Get modem public key from modem image
+ """
+ found = 0
+ cert1md_hash_path = context['cert1md_hash_path']
+ md_key_path = os.path.join(cert1md_hash_path, "md_key.bin")
+
+ if is_md == 1:
+ md1_handler = lib.getPublicKey.md1_image()
+ found = md1_handler.parse(md_img)
+ if found:
+ md1_handler.output(md_img, md_key_path)
+ print "output file done"
+ elif is_md == 2:
+ md3_handler = lib.getPublicKey.md3_image()
+ found = md3_handler.parse(md_img)
+ if found:
+ md3_handler.output(md_img, md_key_path)
+ print "output file done"
+ else:
+ print "wrong md type!!!"
+
+ return md_key_path
+
+def img_split(img, split_path, hdr_size):
+ """
+ split image into header and image body
+ """
+ split_header = os.path.join(split_path, "header.bin")
+ split_image = os.path.join(split_path, "image.bin")
+
+ file1 = open(img, 'rb')
+ file2 = open(split_header, 'wb')
+ file2.write(file1.read(hdr_size))
+ file2.close()
+ file2 = open(split_image, 'wb')
+ file2.write(file1.read())
+ file2.close()
+ file1.close()
+ padding_file(split_image, 16)
+
+ return split_header, split_image
+
+def endiness_convert(in_file, out_file):
+ """
+ Converts endian of in_file and save result to out_file.
+ """
+ endian = sys.byteorder
+ if endian == "little":
+ file1 = open(out_file, "wb")
+ file2 = open(in_file, "rb")
+ from array import array
+ for _ in range(8, 0, -1):
+ tmp = array("B", file2.read(4))
+ tmp.reverse()
+ tmp.tofile(file1)
+ file2.close()
+ file1.close()
+
+def fill_arg_dict(input_string, key, args):
+ """
+ Fill up argument dictionary from input parameters
+ """
+ prefix = input_string.split("=")[0].strip()
+ fmt = re.compile(key, re.I)
+ if fmt.search(prefix):
+ val = input_string.split("=")[1].strip()
+ args[key] = val
+ print key + ": " + val
+ print args[key]
+ return args
+
+def parse_arg(argv):
+ """
+ Parse input arguments and save the result into argument dictionary.
+ """
+ args = {'type': 0, \
+ 'img': 0, \
+ 'privk': 0, \
+ 'pubk': 0, \
+ 'cert1': 0, \
+ 'swID': 0, \
+ 'ver': 0, \
+ 'name': '', \
+ 'group': 0, \
+ 'root_key_padding': 0, \
+ 'getHashList': 0, \
+ 'env_cfg': 0, \
+ 'platform': 'NOT_SET', \
+ 'project': 'NOT_SET', \
+ 'socid': '0'}
+ for input_string in argv:
+ for key in args:
+ args = fill_arg_dict(input_string, key, args)
+ input_wrong = 0
+
+ #check input
+ if args['type'] == "cert1":
+ if args['privk'] == "" or args['pubk'] == "":
+ print "wrong cert1 input"
+ input_wrong = 1
+ elif args['type'] == "cert2":
+ if args['privk'] == "" or args['cert1'] == "" or args['img'] == "" or args['name'] == "":
+ print "wrong cert2 input"
+ elif args['type'] == "cert1md":
+ if args['img'] == "" or args['privk'] == "":
+ print "wrong cert1md input"
+ else:
+ print "wrong cert type!"
+ input_wrong = 1
+ if input_wrong == 1:
+ help_menu()
+ sys.exit()
+
+ if args['env_cfg'] == 0:
+ #env_cfg is not given, we set it to env.cfg in path of this tool
+ args['env_cfg'] = os.path.join(os.path.dirname(__file__), 'env.cfg')
+ return args
+
+def help_menu():
+ """
+ Print usage for this tool.
+ """
+ print "Gen Cert1:"
+ print " usage: python sign.py type=cert1 privk=[cert1_privk.pem] pubk=[cert2_pubk.pem]"
+ print " optional: swID=[number] ver=[number] group=[number] "
+ print " output: cert1"
+ print "Gen Cert2 and append cert1,cert2 to the image:"
+ print " usage: python sign.py type=cert2 img=[xxx.bin] name=[img name] cert1=[cert1.der] \
+privk=[cert2_privk.pem]"
+ print " optional:ver=number"
+ print " output: image append with cert1 and cert2"
+ print "Gen Cert1md:"
+ print " usage: python sign.py type=cert1md img=[xxx.bin] privk=[cert1md_privk.pem] \
+pubk=[cert2_pubk.pem]"
+ print " output: cert1md"
+
+def main():
+ """
+ Main function when this tool is executed from command line.
+ """
+ if len(sys.argv) < 3:
+ help_menu()
+
+ sign = Sign()
+ sign.args = parse_arg(sys.argv)
+ sign.sign_op()
+
+if __name__ == '__main__':
+ main()