[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/meta/meta-mediatek-mt2731/recipes-bsp/mdcert/files/sign_image/pbp.py b/meta/meta-mediatek-mt2731/recipes-bsp/mdcert/files/sign_image/pbp.py
new file mode 100644
index 0000000..6ca7326
--- /dev/null
+++ b/meta/meta-mediatek-mt2731/recipes-bsp/mdcert/files/sign_image/pbp.py
@@ -0,0 +1,367 @@
+"""
+pbp is a tool that signs/re-signs bootloader and generate data for root public key authentication.
+"""
+import os
+import shutil
+import argparse
+from lib import gfh
+from lib import cert
+
+
+def get_file_sizeb(file_path):
+    """
+    Get size of binary file
+    """
+    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):
+    """
+    Concatenate binary files
+    """
+    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 Bl(object):
+    """
+    Bl, which stands for preloader in Mediatek solution.
+    Mediatek preloader is loaded/verified by BootROM and its format is determined by BootROM
+    and is different from other images due to several reasons.
+    It has basic format as follows:
+    =======================
+    GFH
+    =======================
+    Preloader_NO_GFH.bin
+    =======================
+    Sig
+    =======================
+    Where Preloader_NO_GFH.bin is converted from preloader.elf.
+    """
+    def __init__(self, out_path, in_bootloader_file_path, out_bootloader_file_path):
+        self.m_gfh = gfh.ImageGFH()
+        self.m_out_path = out_path
+        if not os.path.exists(self.m_out_path):
+            os.makedirs(self.m_out_path)
+        self.m_in_bl_file_path = in_bootloader_file_path
+        self.m_out_bl_file_path = out_bootloader_file_path
+        self.m_bl_is_signed = False
+        self.m_bl_content_offset = 0
+        # initialize content size to bl file size
+        self.m_bl_content_length = get_file_sizeb(self.m_in_bl_file_path)
+        self.m_bl_sig_size = 0
+        # generate file path for bl without gfh and signature
+        bl_path = os.path.splitext(in_bootloader_file_path)
+        self.m_bl_no_gfh_file_path = bl_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):
+        """
+        GFH and signature are added after bootloader image has been processed by pbp.
+        We use this fact to determine whether bootloader image is signed.
+        """
+        if self.m_in_bl_file_path:
+            bl_file = open(self.m_in_bl_file_path, "rb")
+            gfh_hdr_obj = gfh.GFHHeader()
+            gfh_hdr_size = gfh_hdr_obj.get_size()
+            gfh_hdr_buf = bl_file.read(gfh_hdr_size)
+            self.m_bl_is_signed = gfh_hdr_obj.is_gfh(gfh_hdr_buf)
+            bl_file.close()
+        return self.m_bl_is_signed
+
+    def parse(self):
+        """
+        If image is signed, we remove GFH and signature. Removed GFH is parsed and
+        stored. Stored GFH will be used later if GFH ini file is not given.
+        """
+        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_bl_file_path)
+            self.m_bl_content_offset = gfh_total_size
+            self.m_bl_content_length -= gfh_total_size
+            self.m_bl_content_length -= self.m_gfh.get_sig_size()
+            self.m_bl_sig_size = self.m_gfh.get_sig_size()
+            in_file = open(self.m_in_bl_file_path, "rb")
+            out_file = open(self.m_bl_no_gfh_file_path, "wb")
+            in_file.seek(self.m_bl_content_offset)
+            out_file.write(in_file.read(self.m_bl_content_length))
+            out_file.close()
+            in_file.close()
+        else:
+            shutil.copyfile(self.m_in_bl_file_path, self.m_bl_no_gfh_file_path)
+        print "bootloader content size = " + hex(self.m_bl_content_length)
+
+    def create_gfh(self, gfh_config):
+        """
+        GFH creation. GFH may be created from parsed/stored GFH config or from GFH config file
+        provided by user.
+        """
+        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):
+        """
+        Sign bootloader according to its signature type, which is stored in GFH.
+        """
+        self.m_gfh.finalize(self.m_bl_content_length, key_ini_path)
+        # create tbs_bootloader.bin
+        tbs_bl_file_path = os.path.join(self.m_out_path, "tbs_preloader.bin")
+        tbs_bl_file = open(tbs_bl_file_path, "wb")
+        tbs_bl_file.write(self.m_gfh.pack())
+        bl_no_gfh_file = open(self.m_bl_no_gfh_file_path, "rb")
+        tbs_bl_file.write(bl_no_gfh_file.read(self.m_bl_content_length))
+        bl_no_gfh_file.close()
+        tbs_bl_file.close()
+        print "===sign==="
+        if self.m_gfh.get_sig_type() == "CERT_CHAIN":
+            self.m_sig_handler = cert.CertChainV2()
+            # 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_file_name = os.path.basename(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_bl_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_bl_file_path):
+                os.remove(self.m_out_bl_file_path)
+            concatb(self.m_out_bl_file_path, tbs_bl_file_path)
+            concatb(self.m_out_bl_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.SigSingleAndPhash(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_bl_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_bl_file_path):
+                os.remove(self.m_out_bl_file_path)
+            concatb(self.m_out_bl_file_path, tbs_bl_file_path)
+            concatb(self.m_out_bl_file_path, sig_file_path)
+        else:
+            print "unknown signature type"
+        # clean up
+        os.remove(self.m_bl_no_gfh_file_path)
+        os.remove(tbs_bl_file_path)
+        os.remove(sig_file_path)
+        return
+
+class PbpArgs(object):
+    """
+    PbpArgs is used to pass parameter to pbp.
+    This structure is both used when user executes this python script directly or imports
+    this module and use exported method.
+    """
+    def __init__(self):
+        self.op = None
+        self.padding = None
+        self.key_ini_path = None
+        self.key_path = None
+        self.gfh_cfg_ini_path = None
+        self.cnt_cfg_ini_path = None
+        self.key_cert_path = None
+        self.input_bl_path = None
+        self.tmp_output_path = None
+        self.output_path = None
+    def reset(self):
+        self.__init__()
+    def dump(self):
+        """
+        dump parameters.
+        """
+        f = lambda arg: 'Not Set' if arg is None else arg
+        print "op = " + f(self.op)
+        print "padding = " + f(self.padding)
+        print "key_ini_path = " + f(self.key_ini_path)
+        print "key_path = " + f(self.key_path)
+        print "gfh_cfg_ini_path = " + f(self.gfh_cfg_ini_path)
+        print "cnt_cfg_ini_path = " + f(self.cnt_cfg_ini_path)
+        print "key_cert_path = " + f(self.key_cert_path)
+        print "input_bl_path = " + f(self.input_bl_path)
+        print "tmp_output_path = " + f(self.tmp_output_path)
+        print "output_path = " + f(self.output_path)
+
+def _op_sign(args):
+    """
+    Sign/re-sign operation
+    """
+    bl_obj = Bl(args.tmp_output_path, args.input_bl_path, args.output_path)
+    bl_obj.create_gfh(args.gfh_cfg_ini_path)
+    bl_obj.sign(args.key_ini_path, args.key_cert_path, args.cnt_cfg_ini_path)
+    return 0
+
+def _op_keybin(args):
+    """
+    Generate root key data structure for root public key authentication.
+    """
+    key = cert.CtKey(args.padding)
+    key.create(args.key_path)
+    key_bin = key.pack()
+    out_file = open(args.output_path, "wb")
+    out_file.write(key_bin)
+    out_file.close()
+    return 0
+
+def _op_keybin_pss(args):
+    """
+    Root key data structures are different for different padding. Here we handles pss padding.
+    """
+    args.padding = 'pss'
+    return _op_keybin(args)
+
+def _op_keybin_legacy(args):
+    """
+    Root key data structures are different for different padding. Here we handles legacy padding.
+    """
+    args.padding = 'legacy'
+    return _op_keybin(args)
+
+def _op_keyhash(args):
+    """
+    Generate hash of root key data structure, which is dependent on padding used.
+    """
+    key = cert.CtKey(args.padding)
+    key.create(args.key_path)
+    key_bin = key.pack()
+    tmp_key_bin_path = os.path.join(args.tmp_output_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, args.output_path)
+    os.remove(tmp_key_bin_path)
+    return 0
+
+def _op_keyhash_pss(args):
+    """
+    Root key data struture hash for pss padding.
+    """
+    args.padding = 'pss'
+    return _op_keyhash(args)
+
+def _op_keyhash_legacy(args):
+    """
+    Root key data struture hash for legacy padding.
+    """
+    args.padding = 'legacy'
+    return _op_keyhash(args)
+
+def pbp_op(args):
+    """
+    Handles and dispatches all operations supported by pbp.
+    """
+    supported_ops = {
+        'sign': _op_sign,
+        'keybin_pss': _op_keybin_pss,
+        'keybin_legacy': _op_keybin_legacy,
+        'keyhash_pss': _op_keyhash_pss,
+        'keyhash_legacy': _op_keyhash_legacy
+    }
+
+    if args.output_path is None:
+        print "output path is not given!"
+        return -1
+
+    if args.op is None:
+        print "op is not given!"
+        return -1
+
+    if args.op == 'sign':
+        if not args.input_bl_path:
+            print "bootloader path is not given!"
+            return -1
+        if (args.key_ini_path is None) and (args.key_cert_path is None):
+            print "key path is not given!"
+            return -1
+    else:
+        if (args.key_ini_path is None) and (args.key_path is None):
+            print "key path is not given!"
+            return -1
+
+    args.tmp_output_path = os.path.dirname(os.path.abspath(args.output_path))
+    if not os.path.exists(args.tmp_output_path):
+        os.makedirs(args.tmp_output_path)
+
+    op_f = supported_ops.get(args.op)
+    return op_f(args)
+
+
+def main():
+    """
+    Main function for pbp, which is used when pbp.py is executed directly.
+    Note that we changed input bootloader parameter to -in_bl $BL_PATH.
+    Please remember to add -in_bl if you're migrating from previous version.
+    """
+    parser = argparse.ArgumentParser(description='pbp tool for preloader gfh \
+creation/replacement and signing/re-signing')
+    parser.add_argument('-i', dest='key_ini_path', help='key configuartion path')
+    parser.add_argument('-j', dest='key_path', help='key path (with pem format)')
+    parser.add_argument('-g', dest='gfh_cfg_ini_path', help='gfh(generaic file header) \
+configuration path')
+    parser.add_argument('-c', dest='cnt_cfg_ini_path', help='content certificate \
+configuration path')
+    parser.add_argument('-k', dest='key_cert_path', help='key certificate path')
+    parser.add_argument('-func', dest='op', help='operation to be performed', required=True)
+    parser.add_argument('-o', dest='output_path', help='output file path')
+    parser.add_argument('input_bl_path', nargs='?', help='input file path')
+
+    pbp_args = parser.parse_args()
+    return pbp_op(pbp_args)
+
+
+if __name__ == '__main__':
+    main()