mirror of
https://github.com/openharmony/tee_tee_dev_kit.git
synced 2026-08-24 19:13:10 -04:00
6c50b5560d
Signed-off-by: jiezixumihp <hupeng76@huawei.com>
847 lines
29 KiB
Python
847 lines
29 KiB
Python
#!/usr/bin/env python
|
|
# coding:utf-8
|
|
|
|
#
|
|
# Copyright (C) 2022 Huawei Technologies Co., Ltd.
|
|
# Licensed under the Mulan PSL v2.
|
|
# You can use this software according to the terms and conditions of the Mulan
|
|
# PSL v2.
|
|
# You may obtain a copy of Mulan PSL v2 at:
|
|
# http://license.coscl.org.cn/MulanPSL2
|
|
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
|
# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
# NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
# See the Mulan PSL v2 for more details.
|
|
#
|
|
|
|
import struct
|
|
import os
|
|
import stat
|
|
import binascii
|
|
import shutil
|
|
import argparse
|
|
import configparser
|
|
import re
|
|
import logging
|
|
|
|
from manifest import process_manifest_file
|
|
from generate_signature import gen_ta_signature
|
|
from Crypto.Hash import SHA256
|
|
from Crypto.Cipher import PKCS1_OAEP
|
|
from Crypto.PublicKey import RSA
|
|
from Crypto.Cipher import AES
|
|
from Crypto.Random import get_random_bytes
|
|
|
|
from memctrl_checker import check_memory_baseline
|
|
|
|
TYPE_PUBKEY = 0
|
|
TYPE_CERT = 1
|
|
TYPE_CERT_CHAIN = 2
|
|
|
|
MAGIC1 = 0xA5A55A5A
|
|
MAGIC2 = 0xAAAA
|
|
|
|
# ELF Definitions
|
|
ELF_TYPE = 32
|
|
ELF_HDR_SIZE = 52
|
|
ELF_PHDR_SIZE = 32
|
|
ELF_INFO_MAGIC0_INDEX = 0
|
|
ELF_INFO_MAGIC1_INDEX = 1
|
|
ELF_INFO_MAGIC2_INDEX = 2
|
|
ELF_INFO_MAGIC3_INDEX = 3
|
|
#'\x7f'
|
|
ELF_INFO_MAGIC0 = 127
|
|
#'E'
|
|
ELF_INFO_MAGIC1 = 69
|
|
#'L'
|
|
ELF_INFO_MAGIC2 = 76
|
|
#'F'
|
|
ELF_INFO_MAGIC3 = 70
|
|
ELF_INFO_CLASS_INDEX = 4
|
|
ELF_INFO_CLASS_32 = 1
|
|
ELF_INFO_CLASS_64 = 2
|
|
ELF_INFO_VERSION_INDEX = 6
|
|
ELF_INFO_VERSION_CURRENT = 1
|
|
ELF_BLOCK_ALIGN = 0x1000
|
|
|
|
DEFAULT_INI_NAME = "config_cbg_release.ini"
|
|
DEFAULT_INI_PATH = "../../../../../../vendor/huawei/base/tee/tee_dev_kit_ext/config/"
|
|
|
|
SEC_HEADER_BYTES = 16
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
def check_cfg_whitelist_format(intput_str):
|
|
if intput_str != "":
|
|
if whitelist_check(intput_str):
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def whitelist_check(intput_str):
|
|
if not re.match(r"^[A-Za-z0-9\/\\_.$:{}-]+$", intput_str):
|
|
logging.error(f"Path Invalid: '{intput_str}', Allowed Characters: Letters(A-Z a-z), Special Symbols(/ - _ . {{ }} \ $ :)")
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def check_cfg_integer_format(intput_str):
|
|
if intput_str != "":
|
|
if integer_check(intput_str):
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def integer_check(intput_str):
|
|
if not str(intput_str).isdigit():
|
|
return 1
|
|
return 0
|
|
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Verify ELF header contents from an input ELF file
|
|
#----------------------------------------------------------------------------
|
|
def verify_elf_header(elf_path):
|
|
elf_type = 0
|
|
with open(elf_path, 'rb') as elf:
|
|
elf_data = struct.unpack('B' * 16, elf.read(16))
|
|
elf_type = elf_data[4]
|
|
if ((elf_data[ELF_INFO_MAGIC0_INDEX] != ELF_INFO_MAGIC0) or \
|
|
(elf_data[ELF_INFO_MAGIC1_INDEX] != ELF_INFO_MAGIC1) or \
|
|
(elf_data[ELF_INFO_MAGIC2_INDEX] != ELF_INFO_MAGIC2) or \
|
|
(elf_data[ELF_INFO_MAGIC3_INDEX] != ELF_INFO_MAGIC3) or \
|
|
(elf_data[ELF_INFO_VERSION_INDEX] != \
|
|
ELF_INFO_VERSION_CURRENT)):
|
|
logging.error("invalid elf header info")
|
|
raise RuntimeError
|
|
|
|
if ((elf_type == 1 and elf_data[ELF_INFO_CLASS_INDEX] != \
|
|
ELF_INFO_CLASS_32) or \
|
|
(elf_type == 2 and elf_data[ELF_INFO_CLASS_INDEX] != \
|
|
ELF_INFO_CLASS_64) or \
|
|
(elf_type != 1 and elf_type != 2)):
|
|
logging.error("invalid elf format")
|
|
raise RuntimeError
|
|
return
|
|
|
|
|
|
class AllCfg:
|
|
release_type = "1"
|
|
otrp_flag = "0"
|
|
sign_type = "1"
|
|
enc_key_alg = "0"
|
|
public_key = ""
|
|
pub_key_len = ""
|
|
enc_cont_alg = "0"
|
|
key_protect_v = "2"
|
|
server_ip = ""
|
|
config_path = ""
|
|
sign_key = ""
|
|
sign_key_type = "0"
|
|
sign_alg = "RSA"
|
|
ta_cert_chain = ""
|
|
ta_version = 3
|
|
in_path = ""
|
|
out_path = ""
|
|
sign_ta_alg = "0"
|
|
ini_path = ""
|
|
memctrl_path = ""
|
|
disable_memctrl = "0"
|
|
force_memctrl = False
|
|
|
|
|
|
class PublicCfg:
|
|
def __init__(self, file_name, all_cfg):
|
|
|
|
if not os.path.exists(file_name):
|
|
return
|
|
|
|
cfg_section = "signSecPublicCfg"
|
|
parser = configparser.ConfigParser()
|
|
parser.read(file_name)
|
|
|
|
if parser.has_option(cfg_section, "secReleaseType"):
|
|
all_cfg.release_type = parser.get(cfg_section, "secReleaseType")
|
|
if parser.has_option(cfg_section, "secOtrpFlag"):
|
|
all_cfg.otrp_flag = parser.get(cfg_section, "secOtrpFlag")
|
|
|
|
all_cfg.sign_type = parser.get(cfg_section, "secSignType")
|
|
if parser.has_option(cfg_section, "secSignServerIp"):
|
|
all_cfg.server_ip = parser.get(cfg_section, "secSignServerIp")
|
|
|
|
all_cfg.config_path = parser.get(cfg_section, "configPath")
|
|
all_cfg.sign_key = parser.get(cfg_section, "secSignKey")
|
|
if parser.has_option(cfg_section, "secTaVersion"):
|
|
all_cfg.ta_version = int(parser.get(cfg_section, "secTaVersion"))
|
|
else:
|
|
all_cfg.ta_version = 3
|
|
if parser.has_option(cfg_section, "secSignKeyType"):
|
|
all_cfg.sign_key_type = parser.get(cfg_section, "secSignKeyType")
|
|
if parser.has_option(cfg_section, "secTaCertChain"):
|
|
all_cfg.ta_cert_chain = parser.get(cfg_section, "secTaCertChain")
|
|
if parser.has_option(cfg_section, "disableMemctrlCheck"):
|
|
all_cfg.disable_memctrl = parser.get(cfg_section, "disableMemctrlCheck")
|
|
|
|
|
|
class PrivateCfg:
|
|
def __init__(self, file_name, all_cfg):
|
|
cfg_section = 'signSecPrivateCfg'
|
|
parser = configparser.ConfigParser()
|
|
parser.read(file_name)
|
|
|
|
if parser.has_option(cfg_section, "secEncryptKey"):
|
|
all_cfg.public_key = parser.get(cfg_section, "secEncryptKey")
|
|
|
|
if parser.has_option(cfg_section, "secEncryptKeyLen"):
|
|
all_cfg.pub_key_len = parser.get(cfg_section, "secEncryptKeyLen")
|
|
|
|
all_cfg.hash_type = parser.get(cfg_section, "secHashType")
|
|
all_cfg.sign_key_len = parser.get(cfg_section, "secSignKeyLen")
|
|
all_cfg.padding_type = parser.get(cfg_section, "secPaddingType")
|
|
|
|
if parser.has_option(cfg_section, "secSignAlg"):
|
|
all_cfg.sign_alg = parser.get(cfg_section, "secSignAlg")
|
|
|
|
if parser.has_option(cfg_section, "secEncryptKeyInfoAlg"):
|
|
all_cfg.enc_key_alg = parser.get(cfg_section, "secEncryptKeyInfoAlg")
|
|
if parser.has_option(cfg_section, "secEncryptContentAlg"):
|
|
all_cfg.enc_cont_alg = parser.get(cfg_section, "secEncryptContentAlg")
|
|
if parser.has_option(cfg_section, "secKeyProtectVersion"):
|
|
all_cfg.key_protect_v = parser.get(cfg_section, "secKeyProtectVersion")
|
|
if parser.has_option(cfg_section, "secSignTaAlg"):
|
|
all_cfg.sign_ta_alg = parser.get(cfg_section, "secSignTaAlg")
|
|
if parser.has_option(cfg_section, "jdkVersion"):
|
|
all_cfg.jdk_version = parser.get(cfg_section, "jdkVersion")
|
|
else:
|
|
all_cfg.jdk_version = "8"
|
|
|
|
|
|
def check_key_info(cfg):
|
|
''' check ini key info '''
|
|
ret = 0
|
|
if check_cfg_whitelist_format(cfg.sign_key):
|
|
logging.error("secSignKey is invalid.")
|
|
ret = 1
|
|
if check_cfg_integer_format(cfg.sign_key_len):
|
|
logging.error("secSignKeyLen is invalid.")
|
|
ret = 1
|
|
if check_cfg_whitelist_format(cfg.public_key):
|
|
logging.error("secEncryptKey is invalid.")
|
|
ret = 1
|
|
if check_cfg_integer_format(cfg.pub_key_len):
|
|
logging.error("secEncryptKeyLen is invalid.")
|
|
ret = 1
|
|
return ret
|
|
|
|
|
|
def check_cfg(cfg):
|
|
ret = 0
|
|
if check_cfg_integer_format(cfg.release_type):
|
|
logging.error("secReleaseType is invalid.")
|
|
ret = 1
|
|
if check_cfg_integer_format(cfg.otrp_flag):
|
|
logging.error("secOtrpFlag is invalid.")
|
|
ret = 1
|
|
if check_cfg_integer_format(cfg.sign_type):
|
|
logging.error("secSignType is invalid.")
|
|
ret = 1
|
|
if check_cfg_whitelist_format(cfg.server_ip):
|
|
logging.error("secSignServerIp is invalid.")
|
|
ret = 1
|
|
if check_cfg_whitelist_format(cfg.config_path):
|
|
logging.error("configPath is invalid.")
|
|
ret = 1
|
|
if check_cfg_integer_format(cfg.hash_type):
|
|
logging.error("secHashType is invalid.")
|
|
ret = 1
|
|
if check_cfg_integer_format(cfg.padding_type):
|
|
logging.error("secPaddingType is invalid.")
|
|
ret = 1
|
|
if check_cfg_whitelist_format(cfg.sign_alg):
|
|
logging.error("secSignAlg is invalid.")
|
|
ret = 1
|
|
if check_key_info(cfg) != 0:
|
|
ret = 1
|
|
return ret
|
|
|
|
|
|
def gen_key_version(cfg):
|
|
key_version = 0
|
|
key_version = key_version | (int(cfg.enc_cont_alg) << 24)
|
|
key_version = key_version | (int(cfg.enc_key_alg) << 16)
|
|
if cfg.pub_key_len == '4096':
|
|
key_version = key_version | 0x0300
|
|
elif cfg.pub_key_len == '3072':
|
|
key_version = key_version | 0x0200
|
|
elif cfg.pub_key_len == '2048':
|
|
key_version = key_version | 0x0000
|
|
elif cfg.pub_key_len == '256':
|
|
key_version = key_version | 0x0100
|
|
elif cfg.pub_key_len == '':
|
|
return int(0x0000)
|
|
else:
|
|
logging.error("unhandled pulic key len %s", cfg.pub_key_len)
|
|
raise RuntimeError
|
|
key_version = key_version | (int(cfg.key_protect_v))
|
|
return key_version
|
|
|
|
|
|
def gen_header(content_len, cfg):
|
|
key_version = gen_key_version(cfg)
|
|
return struct.pack('IHHII', MAGIC1, MAGIC2, cfg.ta_version, content_len, \
|
|
key_version)
|
|
|
|
|
|
def get_sign_alg(cfg):
|
|
sign_alg = 0
|
|
sign_alg = sign_alg | (int(cfg.release_type) << 28)
|
|
sign_alg = sign_alg | (int(cfg.padding_type) << 27)
|
|
sign_alg = sign_alg | ((int(cfg.hash_type) & 1) << 26)
|
|
sign_alg = sign_alg | ((int(cfg.hash_type) & 2) << 25)
|
|
sign_alg = sign_alg | (int(cfg.sign_ta_alg) << 20)
|
|
if cfg.sign_alg == "RSA":
|
|
sign_alg = sign_alg | (2 << 20)
|
|
elif cfg.sign_alg == "ECDSA":
|
|
sign_alg = sign_alg | (1 << 20)
|
|
if cfg.sign_type in '4' '5':
|
|
sign_alg = sign_alg | 0x0000C000
|
|
else:
|
|
if cfg.sign_key_len == "2048":
|
|
sign_alg = sign_alg | 0x00002048
|
|
elif cfg.sign_key_len == "4096":
|
|
sign_alg = sign_alg | 0x00004096
|
|
elif cfg.sign_key_len == "256":
|
|
sign_alg = sign_alg | 0x00000256
|
|
return sign_alg
|
|
|
|
|
|
def gen_aes_key_info(cfg):
|
|
iv_data = get_random_bytes(16)
|
|
key_data = get_random_bytes(32)
|
|
|
|
sign_alg = get_sign_alg(cfg)
|
|
key_info = struct.pack('<3I', 32, 16, sign_alg)
|
|
key_info += key_data
|
|
key_info += iv_data
|
|
return key_data, iv_data, key_info
|
|
|
|
|
|
def gen_sign_alg_info(cfg, out_file_path):
|
|
sign_alg = get_sign_alg(cfg)
|
|
logging.info("sign_alg value is 0x%x", sign_alg)
|
|
|
|
fd_out = os.open(out_file_path, os.O_WRONLY | os.O_CREAT, \
|
|
stat.S_IWUSR | stat.S_IRUSR)
|
|
out_file = os.fdopen(fd_out, "wb")
|
|
out_file.write(struct.pack('I', 0))
|
|
out_file.write(struct.pack('I', 0))
|
|
out_file.write(struct.pack('I', sign_alg))
|
|
out_file.close()
|
|
|
|
return
|
|
|
|
|
|
def encrypt_aes_key(pubkey_path, in_data, out_path):
|
|
with open(pubkey_path, 'rb') as pubkey_file_fd:
|
|
pubkey_file = pubkey_file_fd.read(os.path.getsize(pubkey_path))
|
|
pubkey = RSA.importKey(pubkey_file)
|
|
cipher = PKCS1_OAEP.new(pubkey)
|
|
ciphertext = cipher.encrypt(in_data)
|
|
|
|
fd_out = os.open(out_path, os.O_WRONLY | os.O_CREAT, \
|
|
stat.S_IWUSR | stat.S_IRUSR)
|
|
out_file = os.fdopen(fd_out, "wb")
|
|
out_file.write(ciphertext)
|
|
out_file.close()
|
|
return
|
|
|
|
|
|
def gen_signature(cfg, uuid_str, data_for_sign, key_info_data, temp_path):
|
|
data_for_sign_path = os.path.join(temp_path, "dataForSign.bin")
|
|
signature_path = os.path.join(temp_path, "signature.bin")
|
|
hash_file_path = os.path.join(temp_path, "rawDataHash.bin")
|
|
|
|
gen_ta_signature(cfg, uuid_str, data_for_sign, data_for_sign_path, \
|
|
hash_file_path, signature_path, cfg.out_path, key_info_data)
|
|
os.chmod(signature_path, stat.S_IWUSR | stat.S_IRUSR)
|
|
|
|
|
|
def gen_raw_data(manifest_data_path, manifest_ext_path, elf_file_path, \
|
|
config_path, raw_file_path, ta_version):
|
|
manifest_size = os.path.getsize(manifest_data_path)
|
|
manifest_ext_size = os.path.getsize(manifest_ext_path)
|
|
elf_size = os.path.getsize(elf_file_path)
|
|
config_size = 0
|
|
|
|
verify_elf_header(elf_file_path)
|
|
|
|
fd_op = os.open(raw_file_path, os.O_WRONLY | os.O_CREAT, \
|
|
stat.S_IWUSR | stat.S_IRUSR)
|
|
file_op = os.fdopen(fd_op, "wb")
|
|
header = ""
|
|
if os.path.isfile(config_path):
|
|
config_size = os.path.getsize(config_path)
|
|
header = struct.pack('IIIII', ta_version, manifest_size, \
|
|
manifest_ext_size, \
|
|
elf_size, config_size)
|
|
file_op.write(header)
|
|
|
|
with open(manifest_data_path, 'rb') as manifest_data:
|
|
file_op.write(manifest_data.read(manifest_size))
|
|
|
|
with open(manifest_ext_path, 'rb') as manifest_ext:
|
|
file_op.write(manifest_ext.read(manifest_ext_size))
|
|
|
|
with open(elf_file_path, 'rb') as elf:
|
|
file_op.write(elf.read(elf_size))
|
|
if config_size != 0:
|
|
with open(config_path, 'rb') as config:
|
|
file_op.write(config.read(config_size))
|
|
file_op.close()
|
|
return
|
|
|
|
|
|
def aes_encrypt(key_data, iv_data, in_file_path, out_file_path):
|
|
in_size = os.path.getsize(in_file_path)
|
|
with open(in_file_path, 'rb') as in_file:
|
|
in_data = in_file.read(in_size)
|
|
padding = 16 - in_size % 16
|
|
in_data += bytes([padding]) * padding
|
|
|
|
cipher = AES.new(key_data, AES.MODE_CBC, iv_data)
|
|
ciphertext = cipher.encrypt(in_data)
|
|
|
|
fd_out = os.open(out_file_path, os.O_WRONLY | os.O_CREAT, \
|
|
stat.S_IWUSR | stat.S_IRUSR)
|
|
out_file = os.fdopen(fd_out, "wb")
|
|
out_file.write(ciphertext)
|
|
out_file.close()
|
|
|
|
return
|
|
|
|
|
|
def parser_api_level(mk_compile_cfg, cmake_compile_cfg, mk_config_cfg, cmake_config_cfg):
|
|
default_api_level = 2
|
|
compile_cfg_file = ''
|
|
|
|
# Search the config.mk, config.cmake, Makefile, and CMakeLists.txt files in the input directory
|
|
# for the API_LEVEL macro definition.
|
|
# If multiple files exist in the input directory, the API_LEVEL defined in the first file is preferred.
|
|
# If the API_LEVEL macro is not defined in either of the four files, the default value LEVEL 2 is used.
|
|
if os.path.exists(mk_config_cfg):
|
|
compile_cfg_file = mk_config_cfg
|
|
elif os.path.exists(cmake_config_cfg):
|
|
compile_cfg_file = cmake_config_cfg
|
|
elif os.path.exists(mk_compile_cfg):
|
|
compile_cfg_file = mk_compile_cfg
|
|
elif os.path.exists(cmake_compile_cfg):
|
|
compile_cfg_file = cmake_compile_cfg
|
|
else:
|
|
logging.error("Build config file doesn't exist, ignore it")
|
|
return default_api_level
|
|
|
|
with open(compile_cfg_file, encoding="utf-8") as file_op:
|
|
for line in file_op:
|
|
if line.startswith("#") or "-DAPI_LEVEL" not in line:
|
|
continue
|
|
key, value = line.strip().split("-DAPI_LEVEL=")
|
|
return value[0]
|
|
|
|
logging.error("Build Config file doesn't define API_LEVEL")
|
|
return default_api_level
|
|
|
|
|
|
def update_api_level(cfg, manifest):
|
|
mk_compile_cfg = os.path.join(cfg.in_path, "Makefile")
|
|
cmake_compile_cfg = os.path.join(cfg.in_path, "CMakeLists.txt")
|
|
mk_config_cfg = os.path.join(cfg.in_path, "config.mk")
|
|
cmake_config_cfg = os.path.join(cfg.in_path, "config.cmake")
|
|
data = ''
|
|
with open(manifest, 'r') as file_op:
|
|
for line in file_op:
|
|
if line.startswith("#") or "gpd.ta.api_level" not in line:
|
|
data += line
|
|
|
|
api_level = parser_api_level(mk_compile_cfg, cmake_compile_cfg, mk_config_cfg, cmake_config_cfg)
|
|
line = "gpd.ta.api_level:{}\n".format(api_level)
|
|
data += line
|
|
fd_op = os.open(manifest, os.O_WRONLY | os.O_CREAT, \
|
|
stat.S_IWUSR | stat.S_IRUSR)
|
|
file_op = os.fdopen(fd_op, "w")
|
|
file_op.writelines(data)
|
|
file_op.close()
|
|
|
|
|
|
def update_otrp_flag(manifest):
|
|
data = ''
|
|
with open(manifest, 'r') as file_op:
|
|
for line in file_op:
|
|
if line.startswith("#") or "gpd.ta.otrp_flag" not in line:
|
|
data += line
|
|
line = "\ngpd.ta.otrp_flag:{}\n".format('true')
|
|
data += line
|
|
fd_op = os.open(manifest, os.O_WRONLY | os.O_CREAT, \
|
|
stat.S_IWUSR | stat.S_IRUSR)
|
|
file_op = os.fdopen(fd_op, "w")
|
|
file_op.writelines(data)
|
|
file_op.close()
|
|
|
|
|
|
def gen_data_for_sign(cfg, content_len, key_data, raw_file):
|
|
header = gen_header(int(content_len), cfg)
|
|
raw_file_len = os.path.getsize(raw_file)
|
|
with open(raw_file, 'rb') as raw_fp:
|
|
raw_data = raw_fp.read(raw_file_len)
|
|
|
|
data_sign = header
|
|
data_sign += key_data
|
|
data_sign += raw_data
|
|
return data_sign
|
|
|
|
|
|
def pack_signature(signature_path, signature_size):
|
|
add_size = 72 - signature_size
|
|
with open(signature_path, 'rb+') as signature_file:
|
|
signature_buf = signature_file.read(signature_size)
|
|
signature_file.seek(0)
|
|
for _ in range(0, add_size):
|
|
signature_file.write(b'\x00')
|
|
signature_file.write(signature_buf)
|
|
|
|
|
|
def check_if_is_drv(manifest_path):
|
|
with open(manifest_path, 'r') as mani_fp:
|
|
for each_line in mani_fp:
|
|
if each_line.startswith("#") or not each_line.strip():
|
|
continue
|
|
name = each_line.split(":")[0].strip()
|
|
if name == "gpd.ta.target_type" and \
|
|
str(each_line.split(":")[1].strip()) == "1":
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def get_sign_cert_block_buffer(cfg, signature_path, signature_size):
|
|
with open(signature_path, 'rb') as signature_file:
|
|
signature_buf = signature_file.read(signature_size)
|
|
ta_cert_len = 0
|
|
if cfg.sign_key_type == TYPE_PUBKEY:
|
|
sign_verify_buf = struct.pack('II', TYPE_PUBKEY, 0) + signature_buf
|
|
else:
|
|
ta_cert_path = cfg.ta_cert_chain
|
|
ta_cert_len = os.path.getsize(ta_cert_path)
|
|
with open(ta_cert_path, 'rb') as ta_cert_file:
|
|
ta_cert_buf = ta_cert_file.read(ta_cert_len)
|
|
if cfg.sign_key_type == TYPE_CERT:
|
|
sign_verify_buf = struct.pack('II', TYPE_CERT, ta_cert_len) + ta_cert_buf + signature_buf
|
|
else:
|
|
sign_verify_buf = struct.pack('II', TYPE_CERT_CHAIN, ta_cert_len) + ta_cert_buf + signature_buf
|
|
return sign_verify_buf
|
|
|
|
|
|
def get_ta_sign_len(cfg):
|
|
''' get ta sign len '''
|
|
if cfg.sign_type == '4':
|
|
sign_len = 0
|
|
else:
|
|
if int(cfg.sign_key_len) == 256:
|
|
sign_len = 72
|
|
else:
|
|
sign_len = int(cfg.sign_key_len) / 8
|
|
return sign_len
|
|
|
|
|
|
def parser_config(cfg, manifest_path, manifest_ext_path):
|
|
''' parser config '''
|
|
dyn_conf_xml_file_path = os.path.join(cfg.in_path, "dyn_perm.xml")
|
|
tag_parse_dict_file_path = os.path.join(os.getcwd(), "tag_parse_dict.csv")
|
|
if os.path.exists(dyn_conf_xml_file_path):
|
|
# V3.1 ta/drv do not need manifest_ext
|
|
if not os.path.exists(cfg.config_path):
|
|
from dyn_conf_parser import parser_dyn_conf
|
|
parser_dyn_conf(dyn_conf_xml_file_path, manifest_ext_path, \
|
|
tag_parse_dict_file_path, cfg.in_path)
|
|
else:
|
|
if check_if_is_drv(manifest_path) == 1:
|
|
if not os.path.exists(cfg.config_path):
|
|
ans = "gpd.ta.dynConf:00000\n"
|
|
manifest_ext_path_fd = os.open(manifest_ext_path, \
|
|
os.O_RDWR, 0o600)
|
|
with os.fdopen(manifest_ext_path_fd, 'a+') as mani_ext_fp:
|
|
mani_ext_fp.write(ans)
|
|
|
|
|
|
def get_key_info_data(cfg, raw_file_path, key_data_path, raw_data_path):
|
|
''' get key info data '''
|
|
is_encrypt_sec = True
|
|
if cfg.public_key == "" or cfg.pub_key_len == "":
|
|
is_encrypt_sec = False
|
|
|
|
if is_encrypt_sec is True:
|
|
# generate AES key info to encrypt raw data
|
|
key_data, iv_data, key_info_data = gen_aes_key_info(cfg)
|
|
encrypt_aes_key(cfg.public_key, key_info_data, key_data_path)
|
|
aes_encrypt(key_data, iv_data, raw_file_path, raw_data_path)
|
|
key_data = 0
|
|
else:
|
|
gen_sign_alg_info(cfg, key_data_path)
|
|
with open(key_data_path, 'rb') as key_info_fp:
|
|
key_info_data = key_info_fp.read(os.path.getsize(key_data_path))
|
|
return key_info_data
|
|
|
|
|
|
def get_content_len(cfg, key_data_path, raw_data_path):
|
|
''' get content len '''
|
|
sign_len = get_ta_sign_len(cfg)
|
|
if cfg.ta_version == 5:
|
|
ta_cert_path = cfg.ta_cert_chain
|
|
if cfg.sign_key_type == TYPE_PUBKEY:
|
|
ta_cert_len = 0
|
|
else:
|
|
ta_cert_len = os.path.getsize(ta_cert_path)
|
|
content_len = os.path.getsize(key_data_path) \
|
|
+ 4 + 4 + ta_cert_len + sign_len \
|
|
+ os.path.getsize(raw_data_path)
|
|
else:
|
|
content_len = os.path.getsize(key_data_path) \
|
|
+ sign_len \
|
|
+ os.path.getsize(raw_data_path)
|
|
return content_len
|
|
|
|
|
|
def get_data_path(cfg, temp_path):
|
|
''' get data path '''
|
|
enc_key_path = os.path.join(temp_path, "KeyInfo.enc")
|
|
enc_raw_path = os.path.join(temp_path, "rawData.enc")
|
|
key_info_path = os.path.join(temp_path, "KeyInfo")
|
|
raw_file_path = os.path.join(temp_path, "rawData")
|
|
|
|
is_encrypt_sec = True
|
|
if cfg.public_key == "" or cfg.pub_key_len == "":
|
|
is_encrypt_sec = False
|
|
|
|
if is_encrypt_sec is True:
|
|
key_data_path = enc_key_path
|
|
raw_data_path = enc_raw_path
|
|
else:
|
|
key_data_path = key_info_path
|
|
raw_data_path = raw_file_path
|
|
return key_data_path, raw_data_path
|
|
|
|
|
|
def find_so(in_path):
|
|
path_list = os.listdir(in_path)
|
|
for file_name in path_list:
|
|
if os.path.splitext(file_name)[1] == ".so":
|
|
logging.info(file_name)
|
|
return file_name
|
|
return ""
|
|
|
|
|
|
def prepare_data(cfg, temp_path):
|
|
''' gen sec image '''
|
|
manifest_path = os.path.join(cfg.in_path, "manifest.txt")
|
|
manifest_data_path = os.path.join(temp_path, "manifestData.bin")
|
|
manifest_ext_path = os.path.join(temp_path, "manifestExt.bin")
|
|
elf_file_path = os.path.join(cfg.in_path, find_so(cfg.in_path))
|
|
raw_file_path = os.path.join(temp_path, "rawData")
|
|
key_data_path, raw_data_path = get_data_path(cfg, temp_path)
|
|
|
|
xml_config_path = os.path.join(cfg.in_path, "configs.xml")
|
|
|
|
# 1. parser_manifest
|
|
manifest_info, manifest_val = process_manifest_file(xml_config_path, \
|
|
manifest_path, manifest_data_path, manifest_ext_path)
|
|
if manifest_info.ret is False:
|
|
raise RuntimeError
|
|
|
|
# 2. update_api_level
|
|
update_api_level(cfg, manifest_ext_path)
|
|
|
|
# 3. update_otrp_flag
|
|
if cfg.otrp_flag == "1":
|
|
logging.info("package otrp sec file")
|
|
update_otrp_flag(manifest_ext_path)
|
|
|
|
# 4. parser_dyn_conf
|
|
parser_config(cfg, manifest_path, manifest_ext_path)
|
|
|
|
# 5. gen_raw_data
|
|
gen_raw_data(manifest_data_path, manifest_ext_path, elf_file_path, \
|
|
cfg.config_path, raw_file_path, cfg.ta_version)
|
|
|
|
# 6. gen aes key, and encrypt aes key with RSA key
|
|
# and encrypt raw data with aes key
|
|
key_info_data = get_key_info_data(cfg, raw_file_path, key_data_path, raw_data_path)
|
|
|
|
# 7. generate content_len and data_for_sign
|
|
content_len = get_content_len(cfg, key_data_path, raw_data_path)
|
|
data_for_sign = gen_data_for_sign(cfg, content_len, key_info_data, raw_file_path)
|
|
|
|
if manifest_info.manifest_txt_exist is False and os.path.exists(manifest_path):
|
|
os.remove(manifest_path)
|
|
|
|
return manifest_info, data_for_sign, key_info_data, manifest_val
|
|
|
|
|
|
def update_content_len(cfg, key_data_path, raw_data_path, signature_path):
|
|
''' update content len '''
|
|
sign_len = get_ta_sign_len(cfg)
|
|
signature_size = os.path.getsize(signature_path)
|
|
content_len = get_content_len(cfg, key_data_path, raw_data_path)
|
|
if sign_len == 72:
|
|
if signature_size != 72:
|
|
pack_signature(signature_path, signature_size)
|
|
elif sign_len == 0:
|
|
sign_len = signature_size
|
|
# generate Main Header
|
|
content_len = os.path.getsize(key_data_path) \
|
|
+ sign_len \
|
|
+ os.path.getsize(raw_data_path)
|
|
return content_len
|
|
|
|
|
|
def pack_sec_img(cfg, manifest_info, temp_path):
|
|
''' pack sec img: header || key || signature || raw_data '''
|
|
signature_path = os.path.join(temp_path, "signature.bin")
|
|
key_data_path, raw_data_path = get_data_path(cfg, temp_path)
|
|
|
|
content_len = update_content_len(cfg, key_data_path, raw_data_path, signature_path)
|
|
header = gen_header(int(content_len), cfg)
|
|
sec_img_path = os.path.join(cfg.out_path, manifest_info.product_name)
|
|
fd_image = os.open(sec_img_path, os.O_WRONLY | os.O_CREAT, \
|
|
stat.S_IWUSR | stat.S_IRUSR)
|
|
sec_image = os.fdopen(fd_image, "wb")
|
|
# write to sec file [1.header info]
|
|
sec_image.write(header)
|
|
# write to sec file [2.key info]
|
|
with open(key_data_path, 'rb') as key_data_fp:
|
|
sec_image.write(key_data_fp.read(os.path.getsize(key_data_path)))
|
|
|
|
# write to sec file [3.signature]
|
|
if cfg.ta_version == 5:
|
|
sign_cert_buf = get_sign_cert_block_buffer(cfg, signature_path, os.path.getsize(signature_path))
|
|
sec_image.write(sign_cert_buf)
|
|
else:
|
|
with open(signature_path, 'rb') as signature_file:
|
|
sec_image.write(signature_file.read(os.path.getsize(signature_path)))
|
|
|
|
# write to sec file [4.raw data]
|
|
with open(raw_data_path, 'rb') as raw_data_fp:
|
|
sec_image.write(raw_data_fp.read(os.path.getsize(raw_data_path)))
|
|
sec_image.truncate(int(SEC_HEADER_BYTES) + int(content_len))
|
|
sec_image.close()
|
|
|
|
logging.info("=========================SUCCESS============================")
|
|
logging.info("generate sec(common format) load image success: ")
|
|
logging.info(sec_img_path)
|
|
logging.info("============================================================")
|
|
|
|
|
|
def gen_sec_image(temp_path, cfg):
|
|
# temporary files
|
|
shutil.rmtree(temp_path, ignore_errors=True)
|
|
os.mkdir(temp_path)
|
|
os.chmod(temp_path, stat.S_IRWXU)
|
|
manifest_info, data_for_sign, key_info_data, manifest_val = prepare_data(cfg, temp_path)
|
|
|
|
uuid_str = manifest_info.uuid_str
|
|
uuid_str = uuid_str[0:36]
|
|
logging.info("uuid str %s", uuid_str)
|
|
need_check_memctrl = cfg.disable_memctrl != "1" and (cfg.release_type != "0" or cfg.force_memctrl)
|
|
if need_check_memctrl and not check_memory_baseline(cfg, uuid_str, manifest_val):
|
|
logging.error("memory baseline checking failed, but sign will continue temporarily.")
|
|
gen_signature(cfg, uuid_str, data_for_sign, key_info_data, temp_path)
|
|
|
|
pack_sec_img(cfg, manifest_info, temp_path)
|
|
return True
|
|
|
|
|
|
def check_path_invalid(in_path, out_path, ini_path):
|
|
if not os.path.exists(in_path):
|
|
logging.error("input_path does not exist.")
|
|
return 1
|
|
if not os.path.exists(out_path):
|
|
logging.error("out_path does not exist.")
|
|
return 1
|
|
if not os.path.exists(ini_path):
|
|
logging.error("ini_path does not exist, %s", ini_path)
|
|
return 1
|
|
if whitelist_check(in_path):
|
|
logging.error("input_path is incorrect.")
|
|
return 1
|
|
if whitelist_check(out_path):
|
|
logging.error("out_path is incorrect.")
|
|
return 1
|
|
if whitelist_check(ini_path):
|
|
logging.error("ini_path is incorrect.")
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def define_parser():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--in_path", help="input path of data to be signed. \
|
|
(libcombine.so; manifest.txt; ...", type=str)
|
|
parser.add_argument("--out_path", help="input path of signed file. \
|
|
(xxx.sec)", type=str)
|
|
parser.add_argument("--publicCfg", \
|
|
help="sign cfg for ta developer", type=str)
|
|
parser.add_argument("--privateCfg", \
|
|
help="sign cfg for product developer", type=str)
|
|
parser.add_argument("--memctrl_path", \
|
|
help="path to memory baseline control cfgs", type=str, default="")
|
|
parser.add_argument("--force-memctrl", \
|
|
help="force enable memctrl checking", action="store_true")
|
|
return parser
|
|
|
|
|
|
def init_cfg(args):
|
|
cfg = AllCfg()
|
|
if args.privateCfg:
|
|
private_cfg_name = os.path.basename(args.privateCfg)
|
|
if private_cfg_name != DEFAULT_INI_NAME:
|
|
logging.warning("The sec signature of a non-release version cannot be loaded on a commercial device.")
|
|
PrivateCfg(args.privateCfg, cfg)
|
|
else:
|
|
args.privateCfg = os.path.join(DEFAULT_INI_PATH, DEFAULT_INI_NAME)
|
|
PrivateCfg(args.privateCfg, cfg)
|
|
|
|
if args.publicCfg:
|
|
PublicCfg(args.publicCfg, cfg)
|
|
else:
|
|
PublicCfg(args.privateCfg, cfg)
|
|
|
|
if check_cfg(cfg):
|
|
logging.error("the configuration file field is incorrect.")
|
|
raise RuntimeError
|
|
cfg.in_path = os.path.realpath(args.in_path)
|
|
cfg.out_path = os.path.realpath(args.out_path)
|
|
ini_path = os.path.dirname(args.privateCfg)
|
|
if check_path_invalid(cfg.in_path, cfg.out_path, ini_path):
|
|
raise RuntimeError
|
|
cfg.ini_path = os.path.realpath(ini_path)
|
|
cfg.public_key = os.path.join(cfg.ini_path, cfg.public_key)
|
|
cfg.memctrl_path = args.memctrl_path if cfg.release_type != "0" else ""
|
|
if args.force_memctrl:
|
|
cfg.force_memctrl = args.force_memctrl
|
|
return cfg
|
|
|
|
|
|
def main():
|
|
sign_tool_dir = os.path.dirname(os.path.realpath(__file__))
|
|
parser = define_parser()
|
|
args = parser.parse_args()
|
|
cfg = init_cfg(args)
|
|
os.chdir(sign_tool_dir)
|
|
|
|
temp_path = os.path.join(cfg.out_path, "temp")
|
|
ok = gen_sec_image(temp_path, cfg)
|
|
#remove temp files
|
|
shutil.rmtree(temp_path)
|
|
if not ok:
|
|
raise RuntimeError
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main() |