blob: 47c86af055e74c87f0c9ad5bc7e2a2ffb3039b4c [file] [log] [blame]
#!/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()