1#!/usr/bin/env python 2# coding:utf-8 3 4# 5# Copyright (C) 2022 Huawei Technologies Co., Ltd. 6# Licensed under the Mulan PSL v2. 7# You can use this software according to the terms and conditions of the Mulan 8# PSL v2. 9# You may obtain a copy of Mulan PSL v2 at: 10# http://license.coscl.org.cn/MulanPSL2 11# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY 12# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13# NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14# See the Mulan PSL v2 for more details. 15# 16 17import struct 18import os 19import stat 20import binascii 21import shutil 22import argparse 23import configparser 24import re 25import logging 26 27from manifest import process_manifest_file 28from generate_signature import gen_ta_signature 29from Crypto.Hash import SHA256 30from Crypto.Cipher import PKCS1_OAEP 31from Crypto.PublicKey import RSA 32from Crypto.Cipher import AES 33from Crypto.Random import get_random_bytes 34 35from memctrl_checker import check_memory_baseline 36 37TYPE_PUBKEY = 0 38TYPE_CERT = 1 39TYPE_CERT_CHAIN = 2 40 41MAGIC1 = 0xA5A55A5A 42MAGIC2 = 0xAAAA 43 44# ELF Definitions 45ELF_TYPE = 32 46ELF_HDR_SIZE = 52 47ELF_PHDR_SIZE = 32 48ELF_INFO_MAGIC0_INDEX = 0 49ELF_INFO_MAGIC1_INDEX = 1 50ELF_INFO_MAGIC2_INDEX = 2 51ELF_INFO_MAGIC3_INDEX = 3 52#'\x7f' 53ELF_INFO_MAGIC0 = 127 54#'E' 55ELF_INFO_MAGIC1 = 69 56#'L' 57ELF_INFO_MAGIC2 = 76 58#'F' 59ELF_INFO_MAGIC3 = 70 60ELF_INFO_CLASS_INDEX = 4 61ELF_INFO_CLASS_32 = 1 62ELF_INFO_CLASS_64 = 2 63ELF_INFO_VERSION_INDEX = 6 64ELF_INFO_VERSION_CURRENT = 1 65ELF_BLOCK_ALIGN = 0x1000 66 67DEFAULT_INI_NAME = "config_cbg_release.ini" 68DEFAULT_INI_PATH = "../../../../../../vendor/huawei/base/tee/tee_dev_kit_ext/config/" 69 70SEC_HEADER_BYTES = 16 71logging.basicConfig(level=logging.INFO) 72 73 74def check_cfg_whitelist_format(intput_str): 75 if intput_str != "": 76 if whitelist_check(intput_str): 77 return 1 78 return 0 79 80 81def whitelist_check(intput_str): 82 if not re.match(r"^[A-Za-z0-9\/\-_.${}]+$", intput_str): 83 return 1 84 return 0 85 86 87def check_cfg_integer_format(intput_str): 88 if intput_str != "": 89 if integer_check(intput_str): 90 return 1 91 return 0 92 93 94def integer_check(intput_str): 95 if not str(intput_str).isdigit(): 96 return 1 97 return 0 98 99 100#---------------------------------------------------------------------------- 101# Verify ELF header contents from an input ELF file 102#---------------------------------------------------------------------------- 103def verify_elf_header(elf_path): 104 elf_type = 0 105 with open(elf_path, 'rb') as elf: 106 elf_data = struct.unpack('B' * 16, elf.read(16)) 107 elf_type = elf_data[4] 108 if ((elf_data[ELF_INFO_MAGIC0_INDEX] != ELF_INFO_MAGIC0) or \ 109 (elf_data[ELF_INFO_MAGIC1_INDEX] != ELF_INFO_MAGIC1) or \ 110 (elf_data[ELF_INFO_MAGIC2_INDEX] != ELF_INFO_MAGIC2) or \ 111 (elf_data[ELF_INFO_MAGIC3_INDEX] != ELF_INFO_MAGIC3) or \ 112 (elf_data[ELF_INFO_VERSION_INDEX] != \ 113 ELF_INFO_VERSION_CURRENT)): 114 logging.error("invalid elf header info") 115 raise RuntimeError 116 117 if ((elf_type == 1 and elf_data[ELF_INFO_CLASS_INDEX] != \ 118 ELF_INFO_CLASS_32) or \ 119 (elf_type == 2 and elf_data[ELF_INFO_CLASS_INDEX] != \ 120 ELF_INFO_CLASS_64) or \ 121 (elf_type != 1 and elf_type != 2)): 122 logging.error("invalid elf format") 123 raise RuntimeError 124 return 125 126 127class AllCfg: 128 release_type = "1" 129 otrp_flag = "0" 130 sign_type = "1" 131 enc_key_alg = "0" 132 public_key = "" 133 pub_key_len = "" 134 enc_cont_alg = "0" 135 key_protect_v = "2" 136 server_ip = "" 137 config_path = "" 138 sign_key = "" 139 sign_key_type = "0" 140 sign_alg = "RSA" 141 ta_cert_chain = "" 142 ta_version = 3 143 in_path = "" 144 out_path = "" 145 sign_ta_alg = "0" 146 ini_path = "" 147 memctrl_path = "" 148 disable_memctrl = "0" 149 150class PublicCfg: 151 def __init__(self, file_name, all_cfg): 152 153 if not os.path.exists(file_name): 154 return 155 156 cfg_section = "signSecPublicCfg" 157 parser = configparser.ConfigParser() 158 parser.read(file_name) 159 160 if parser.has_option(cfg_section, "secReleaseType"): 161 all_cfg.release_type = parser.get(cfg_section, "secReleaseType") 162 if parser.has_option(cfg_section, "secOtrpFlag"): 163 all_cfg.otrp_flag = parser.get(cfg_section, "secOtrpFlag") 164 165 all_cfg.sign_type = parser.get(cfg_section, "secSignType") 166 if parser.has_option(cfg_section, "secSignServerIp"): 167 all_cfg.server_ip = parser.get(cfg_section, "secSignServerIp") 168 169 all_cfg.config_path = parser.get(cfg_section, "configPath") 170 all_cfg.sign_key = parser.get(cfg_section, "secSignKey") 171 if parser.has_option(cfg_section, "secTaVersion"): 172 all_cfg.ta_version = int(parser.get(cfg_section, "secTaVersion")) 173 else: 174 all_cfg.ta_version = 3 175 if parser.has_option(cfg_section, "secSignKeyType"): 176 all_cfg.sign_key_type = parser.get(cfg_section, "secSignKeyType") 177 if parser.has_option(cfg_section, "secTaCertChain"): 178 all_cfg.ta_cert_chain = parser.get(cfg_section, "secTaCertChain") 179 if parser.has_option(cfg_section, "disableMemctrlCheck"): 180 all_cfg.disable_memctrl = parser.get(cfg_section, "disableMemctrlCheck") 181 182class PrivateCfg: 183 def __init__(self, file_name, all_cfg): 184 cfg_section = 'signSecPrivateCfg' 185 parser = configparser.ConfigParser() 186 parser.read(file_name) 187 188 if parser.has_option(cfg_section, "secEncryptKey"): 189 all_cfg.public_key = parser.get(cfg_section, "secEncryptKey") 190 191 if parser.has_option(cfg_section, "secEncryptKeyLen"): 192 all_cfg.pub_key_len = parser.get(cfg_section, "secEncryptKeyLen") 193 194 all_cfg.hash_type = parser.get(cfg_section, "secHashType") 195 all_cfg.sign_key_len = parser.get(cfg_section, "secSignKeyLen") 196 all_cfg.padding_type = parser.get(cfg_section, "secPaddingType") 197 198 if parser.has_option(cfg_section, "secSignAlg"): 199 all_cfg.sign_alg = parser.get(cfg_section, "secSignAlg") 200 201 if parser.has_option(cfg_section, "secEncryptKeyInfoAlg"): 202 all_cfg.enc_key_alg = parser.get(cfg_section, "secEncryptKeyInfoAlg") 203 if parser.has_option(cfg_section, "secEncryptContentAlg"): 204 all_cfg.enc_cont_alg = parser.get(cfg_section, "secEncryptContentAlg") 205 if parser.has_option(cfg_section, "secKeyProtectVersion"): 206 all_cfg.key_protect_v = parser.get(cfg_section, "secKeyProtectVersion") 207 if parser.has_option(cfg_section, "secSignTaAlg"): 208 all_cfg.sign_ta_alg = parser.get(cfg_section, "secSignTaAlg") 209 if parser.has_option(cfg_section, "jdkVersion"): 210 all_cfg.jdk_version = parser.get(cfg_section, "jdkVersion") 211 else: 212 all_cfg.jdk_version = "8" 213 214def check_key_info(cfg): 215 ''' check ini key info ''' 216 ret = 0 217 if check_cfg_whitelist_format(cfg.sign_key): 218 logging.error("secSignKey is invalid.") 219 ret = 1 220 if check_cfg_integer_format(cfg.sign_key_len): 221 logging.error("secSignKeyLen is invalid.") 222 ret = 1 223 if check_cfg_whitelist_format(cfg.public_key): 224 logging.error("secEncryptKey is invalid.") 225 ret = 1 226 if check_cfg_integer_format(cfg.pub_key_len): 227 logging.error("secEncryptKeyLen is invalid.") 228 ret = 1 229 return ret 230 231 232def check_cfg(cfg): 233 ret = 0 234 if check_cfg_integer_format(cfg.release_type): 235 logging.error("secReleaseType is invalid.") 236 ret = 1 237 if check_cfg_integer_format(cfg.otrp_flag): 238 logging.error("secOtrpFlag is invalid.") 239 ret = 1 240 if check_cfg_integer_format(cfg.sign_type): 241 logging.error("secSignType is invalid.") 242 ret = 1 243 if check_cfg_whitelist_format(cfg.server_ip): 244 logging.error("secSignServerIp is invalid.") 245 ret = 1 246 if check_cfg_whitelist_format(cfg.config_path): 247 logging.error("configPath is invalid.") 248 ret = 1 249 if check_cfg_integer_format(cfg.hash_type): 250 logging.error("secHashType is invalid.") 251 ret = 1 252 if check_cfg_integer_format(cfg.padding_type): 253 logging.error("secPaddingType is invalid.") 254 ret = 1 255 if check_cfg_whitelist_format(cfg.sign_alg): 256 logging.error("secSignAlg is invalid.") 257 ret = 1 258 if check_key_info(cfg) != 0: 259 ret = 1 260 return ret 261 262 263def gen_key_version(cfg): 264 key_version = 0 265 key_version = key_version | (int(cfg.enc_cont_alg) << 24) 266 key_version = key_version | (int(cfg.enc_key_alg) << 16) 267 if cfg.pub_key_len == '4096': 268 key_version = key_version | 0x0300 269 elif cfg.pub_key_len == '3072': 270 key_version = key_version | 0x0200 271 elif cfg.pub_key_len == '2048': 272 key_version = key_version | 0x0000 273 elif cfg.pub_key_len == '256': 274 key_version = key_version | 0x0100 275 elif cfg.pub_key_len == '': 276 return int(0x0000) 277 else: 278 logging.error("unhandled pulic key len %s", cfg.pub_key_len) 279 raise RuntimeError 280 key_version = key_version | (int(cfg.key_protect_v)) 281 return key_version 282 283 284def gen_header(content_len, cfg): 285 key_version = gen_key_version(cfg) 286 return struct.pack('IHHII', MAGIC1, MAGIC2, cfg.ta_version, content_len, \ 287 key_version) 288 289 290def get_sign_alg(cfg): 291 sign_alg = 0 292 sign_alg = sign_alg | (int(cfg.release_type) << 28) 293 sign_alg = sign_alg | (int(cfg.padding_type) << 27) 294 sign_alg = sign_alg | ((int(cfg.hash_type) & 1) << 26) 295 sign_alg = sign_alg | ((int(cfg.hash_type) & 2) << 25) 296 sign_alg = sign_alg | (int(cfg.sign_ta_alg) << 20) 297 if cfg.sign_alg == "RSA": 298 sign_alg = sign_alg | (2 << 20) 299 elif cfg.sign_alg == "ECDSA": 300 sign_alg = sign_alg | (1 << 20) 301 if cfg.sign_type in '4' '5': 302 sign_alg = sign_alg | 0x0000C000 303 else: 304 if cfg.sign_key_len == "2048": 305 sign_alg = sign_alg | 0x00002048 306 elif cfg.sign_key_len == "4096": 307 sign_alg = sign_alg | 0x00004096 308 elif cfg.sign_key_len == "256": 309 sign_alg = sign_alg | 0x00000256 310 return sign_alg 311 312 313def gen_aes_key_info(cfg): 314 iv_data = get_random_bytes(16) 315 key_data = get_random_bytes(32) 316 317 sign_alg = get_sign_alg(cfg) 318 key_info = struct.pack('<3I', 32, 16, sign_alg) 319 key_info += key_data 320 key_info += iv_data 321 return key_data, iv_data, key_info 322 323 324def gen_sign_alg_info(cfg, out_file_path): 325 sign_alg = get_sign_alg(cfg) 326 logging.info("sign_alg value is 0x%x", sign_alg) 327 328 fd_out = os.open(out_file_path, os.O_WRONLY | os.O_CREAT, \ 329 stat.S_IWUSR | stat.S_IRUSR) 330 out_file = os.fdopen(fd_out, "wb") 331 out_file.write(struct.pack('I', 0)) 332 out_file.write(struct.pack('I', 0)) 333 out_file.write(struct.pack('I', sign_alg)) 334 out_file.close() 335 336 return 337 338 339def encrypt_aes_key(pubkey_path, in_data, out_path): 340 with open(pubkey_path, 'rb') as pubkey_file_fd: 341 pubkey_file = pubkey_file_fd.read(os.path.getsize(pubkey_path)) 342 pubkey = RSA.importKey(pubkey_file) 343 cipher = PKCS1_OAEP.new(pubkey) 344 ciphertext = cipher.encrypt(in_data) 345 346 fd_out = os.open(out_path, os.O_WRONLY | os.O_CREAT, \ 347 stat.S_IWUSR | stat.S_IRUSR) 348 out_file = os.fdopen(fd_out, "wb") 349 out_file.write(ciphertext) 350 out_file.close() 351 return 352 353 354def gen_signature(cfg, uuid_str, data_for_sign, key_info_data, temp_path): 355 data_for_sign_path = os.path.join(temp_path, "dataForSign.bin") 356 signature_path = os.path.join(temp_path, "signature.bin") 357 hash_file_path = os.path.join(temp_path, "rawDataHash.bin") 358 359 gen_ta_signature(cfg, uuid_str, data_for_sign, data_for_sign_path, \ 360 hash_file_path, signature_path, cfg.out_path, key_info_data) 361 os.chmod(signature_path, stat.S_IWUSR | stat.S_IRUSR) 362 363 364def gen_raw_data(manifest_data_path, manifest_ext_path, elf_file_path, \ 365 config_path, raw_file_path, ta_version): 366 manifest_size = os.path.getsize(manifest_data_path) 367 manifest_ext_size = os.path.getsize(manifest_ext_path) 368 elf_size = os.path.getsize(elf_file_path) 369 config_size = 0 370 371 verify_elf_header(elf_file_path) 372 373 fd_op = os.open(raw_file_path, os.O_WRONLY | os.O_CREAT, \ 374 stat.S_IWUSR | stat.S_IRUSR) 375 file_op = os.fdopen(fd_op, "wb") 376 header = "" 377 if os.path.isfile(config_path): 378 config_size = os.path.getsize(config_path) 379 header = struct.pack('IIIII', ta_version, manifest_size, \ 380 manifest_ext_size, \ 381 elf_size, config_size) 382 file_op.write(header) 383 384 with open(manifest_data_path, 'rb') as manifest_data: 385 file_op.write(manifest_data.read(manifest_size)) 386 387 with open(manifest_ext_path, 'rb') as manifest_ext: 388 file_op.write(manifest_ext.read(manifest_ext_size)) 389 390 with open(elf_file_path, 'rb') as elf: 391 file_op.write(elf.read(elf_size)) 392 if config_size != 0: 393 with open(config_path, 'rb') as config: 394 file_op.write(config.read(config_size)) 395 file_op.close() 396 return 397 398 399def aes_encrypt(key_data, iv_data, in_file_path, out_file_path): 400 in_size = os.path.getsize(in_file_path) 401 with open(in_file_path, 'rb') as in_file: 402 in_data = in_file.read(in_size) 403 padding = 16 - in_size % 16 404 in_data += bytes([padding]) * padding 405 406 cipher = AES.new(key_data, AES.MODE_CBC, iv_data) 407 ciphertext = cipher.encrypt(in_data) 408 409 fd_out = os.open(out_file_path, os.O_WRONLY | os.O_CREAT, \ 410 stat.S_IWUSR | stat.S_IRUSR) 411 out_file = os.fdopen(fd_out, "wb") 412 out_file.write(ciphertext) 413 out_file.close() 414 415 return 416 417 418def parser_api_level(mk_compile_cfg, cmake_compile_cfg, mk_config_cfg, cmake_config_cfg): 419 default_api_level = 2 420 compile_cfg_file = '' 421 422 # Search the config.mk, config.cmake, Makefile, and CMakeLists.txt files in the input directory 423 # for the API_LEVEL macro definition. 424 # If multiple files exist in the input directory, the API_LEVEL defined in the first file is preferred. 425 # If the API_LEVEL macro is not defined in either of the four files, the default value LEVEL 2 is used. 426 if os.path.exists(mk_config_cfg): 427 compile_cfg_file = mk_config_cfg 428 elif os.path.exists(cmake_config_cfg): 429 compile_cfg_file = cmake_config_cfg 430 elif os.path.exists(mk_compile_cfg): 431 compile_cfg_file = mk_compile_cfg 432 elif os.path.exists(cmake_compile_cfg): 433 compile_cfg_file = cmake_compile_cfg 434 else: 435 logging.error("Build config file doesn't exist, ignore it") 436 return default_api_level 437 438 with open(compile_cfg_file) as file_op: 439 for line in file_op: 440 if line.startswith("#") or "-DAPI_LEVEL" not in line: 441 continue 442 key, value = line.strip().split("-DAPI_LEVEL=") 443 return value[0] 444 445 logging.error("Build Config file doesn't define API_LEVEL") 446 return default_api_level 447 448 449def update_api_level(cfg, manifest): 450 mk_compile_cfg = os.path.join(cfg.in_path, "Makefile") 451 cmake_compile_cfg = os.path.join(cfg.in_path, "CMakeLists.txt") 452 mk_config_cfg = os.path.join(cfg.in_path, "config.mk") 453 cmake_config_cfg = os.path.join(cfg.in_path, "config.cmake") 454 data = '' 455 with open(manifest, 'r') as file_op: 456 for line in file_op: 457 if line.startswith("#") or "gpd.ta.api_level" not in line: 458 data += line 459 460 api_level = parser_api_level(mk_compile_cfg, cmake_compile_cfg, mk_config_cfg, cmake_config_cfg) 461 line = "\ngpd.ta.api_level:{}\n".format(api_level) 462 data += line 463 fd_op = os.open(manifest, os.O_WRONLY | os.O_CREAT, \ 464 stat.S_IWUSR | stat.S_IRUSR) 465 file_op = os.fdopen(fd_op, "w") 466 file_op.writelines(data) 467 file_op.close() 468 469 470def update_otrp_flag(manifest): 471 data = '' 472 with open(manifest, 'r') as file_op: 473 for line in file_op: 474 if line.startswith("#") or "gpd.ta.otrp_flag" not in line: 475 data += line 476 line = "\ngpd.ta.otrp_flag:{}\n".format('true') 477 data += line 478 fd_op = os.open(manifest, os.O_WRONLY | os.O_CREAT, \ 479 stat.S_IWUSR | stat.S_IRUSR) 480 file_op = os.fdopen(fd_op, "w") 481 file_op.writelines(data) 482 file_op.close() 483 484 485def gen_data_for_sign(cfg, content_len, key_data, raw_file): 486 header = gen_header(int(content_len), cfg) 487 raw_file_len = os.path.getsize(raw_file) 488 with open(raw_file, 'rb') as raw_fp: 489 raw_data = raw_fp.read(raw_file_len) 490 491 data_sign = header 492 data_sign += key_data 493 data_sign += raw_data 494 return data_sign 495 496 497def pack_signature(signature_path, signature_size): 498 add_size = 72 - signature_size 499 with open(signature_path, 'rb+') as signature_file: 500 signature_buf = signature_file.read(signature_size) 501 signature_file.seek(0) 502 for _ in range(0, add_size): 503 signature_file.write(b'\x00') 504 signature_file.write(signature_buf) 505 506 507def check_if_is_drv(manifest_path): 508 with open(manifest_path, 'r') as mani_fp: 509 for each_line in mani_fp: 510 if each_line.startswith("#") or not each_line.strip(): 511 continue 512 name = each_line.split(":")[0].strip() 513 if name == "gpd.ta.target_type" and \ 514 str(each_line.split(":")[1].strip()) == "1": 515 return 1 516 return 0 517 518 519def get_sign_cert_block_buffer(cfg, signature_path, signature_size): 520 with open(signature_path, 'rb') as signature_file: 521 signature_buf = signature_file.read(signature_size) 522 ta_cert_len = 0 523 if cfg.sign_key_type == TYPE_PUBKEY: 524 sign_verify_buf = struct.pack('II', TYPE_PUBKEY, 0) + signature_buf 525 else: 526 ta_cert_path = cfg.ta_cert_chain 527 ta_cert_len = os.path.getsize(ta_cert_path) 528 with open(ta_cert_path, 'rb') as ta_cert_file: 529 ta_cert_buf = ta_cert_file.read(ta_cert_len) 530 if cfg.sign_key_type == TYPE_CERT: 531 sign_verify_buf = struct.pack('II', TYPE_CERT, ta_cert_len) + ta_cert_buf + signature_buf 532 else: 533 sign_verify_buf = struct.pack('II', TYPE_CERT_CHAIN, ta_cert_len) + ta_cert_buf + signature_buf 534 return sign_verify_buf 535 536 537def get_ta_sign_len(cfg): 538 ''' get ta sign len ''' 539 if cfg.sign_type == '4': 540 sign_len = 0 541 else: 542 if int(cfg.sign_key_len) == 256: 543 sign_len = 72 544 else: 545 sign_len = int(cfg.sign_key_len) / 8 546 return sign_len 547 548 549def parser_config(cfg, manifest_path, manifest_ext_path): 550 ''' parser config ''' 551 dyn_conf_xml_file_path = os.path.join(cfg.in_path, "dyn_perm.xml") 552 tag_parse_dict_file_path = os.path.join(os.getcwd(), "tag_parse_dict.csv") 553 if os.path.exists(dyn_conf_xml_file_path): 554 # V3.1 ta/drv do not need manifest_ext 555 if not os.path.exists(cfg.config_path): 556 from dyn_conf_parser import parser_dyn_conf 557 parser_dyn_conf(dyn_conf_xml_file_path, manifest_ext_path, \ 558 tag_parse_dict_file_path, cfg.in_path) 559 else: 560 if check_if_is_drv(manifest_path) == 1: 561 if not os.path.exists(cfg.config_path): 562 ans = "gpd.ta.dynConf:00000\n" 563 manifest_ext_path_fd = os.open(manifest_ext_path, \ 564 os.O_RDWR, 0o600) 565 with os.fdopen(manifest_ext_path_fd, 'a+') as mani_ext_fp: 566 mani_ext_fp.write(ans) 567 568 569def get_key_info_data(cfg, raw_file_path, key_data_path, raw_data_path): 570 ''' get key info data ''' 571 is_encrypt_sec = True 572 if cfg.public_key == "" or cfg.pub_key_len == "": 573 is_encrypt_sec = False 574 575 if is_encrypt_sec is True: 576 # generate AES key info to encrypt raw data 577 key_data, iv_data, key_info_data = gen_aes_key_info(cfg) 578 encrypt_aes_key(cfg.public_key, key_info_data, key_data_path) 579 aes_encrypt(key_data, iv_data, raw_file_path, raw_data_path) 580 key_data = 0 581 else: 582 gen_sign_alg_info(cfg, key_data_path) 583 with open(key_data_path, 'rb') as key_info_fp: 584 key_info_data = key_info_fp.read(os.path.getsize(key_data_path)) 585 return key_info_data 586 587 588def get_content_len(cfg, key_data_path, raw_data_path): 589 ''' get content len ''' 590 sign_len = get_ta_sign_len(cfg) 591 if cfg.ta_version == 5: 592 ta_cert_path = cfg.ta_cert_chain 593 if cfg.sign_key_type == TYPE_PUBKEY: 594 ta_cert_len = 0 595 else: 596 ta_cert_len = os.path.getsize(ta_cert_path) 597 content_len = os.path.getsize(key_data_path) \ 598 + 4 + 4 + ta_cert_len + sign_len \ 599 + os.path.getsize(raw_data_path) 600 else: 601 content_len = os.path.getsize(key_data_path) \ 602 + sign_len \ 603 + os.path.getsize(raw_data_path) 604 return content_len 605 606 607def get_data_path(cfg, temp_path): 608 ''' get data path ''' 609 enc_key_path = os.path.join(temp_path, "KeyInfo.enc") 610 enc_raw_path = os.path.join(temp_path, "rawData.enc") 611 key_info_path = os.path.join(temp_path, "KeyInfo") 612 raw_file_path = os.path.join(temp_path, "rawData") 613 614 is_encrypt_sec = True 615 if cfg.public_key == "" or cfg.pub_key_len == "": 616 is_encrypt_sec = False 617 618 if is_encrypt_sec is True: 619 key_data_path = enc_key_path 620 raw_data_path = enc_raw_path 621 else: 622 key_data_path = key_info_path 623 raw_data_path = raw_file_path 624 return key_data_path, raw_data_path 625 626 627def find_so(in_path): 628 path_list = os.listdir(in_path) 629 for file_name in path_list: 630 if os.path.splitext(file_name)[1] == ".so": 631 logging.info(file_name) 632 return file_name 633 return "" 634 635 636def prepare_data(cfg, temp_path): 637 ''' gen sec image ''' 638 manifest_path = os.path.join(cfg.in_path, "manifest.txt") 639 manifest_data_path = os.path.join(temp_path, "manifestData.bin") 640 manifest_ext_path = os.path.join(temp_path, "manifestExt.bin") 641 elf_file_path = os.path.join(cfg.in_path, find_so(cfg.in_path)) 642 raw_file_path = os.path.join(temp_path, "rawData") 643 key_data_path, raw_data_path = get_data_path(cfg, temp_path) 644 645 xml_config_path = os.path.join(cfg.in_path, "configs.xml") 646 647 # 1. parser_manifest 648 manifest_info, manifest_val = process_manifest_file(xml_config_path, \ 649 manifest_path, manifest_data_path, manifest_ext_path) 650 if manifest_info.ret is False: 651 raise RuntimeError 652 653 # 2. update_api_level 654 update_api_level(cfg, manifest_ext_path) 655 656 # 3. update_otrp_flag 657 if cfg.otrp_flag == "1": 658 logging.info("package otrp sec file") 659 update_otrp_flag(manifest_ext_path) 660 661 # 4. parser_dyn_conf 662 parser_config(cfg, manifest_path, manifest_ext_path) 663 664 # 5. gen_raw_data 665 gen_raw_data(manifest_data_path, manifest_ext_path, elf_file_path, \ 666 cfg.config_path, raw_file_path, cfg.ta_version) 667 668 # 6. gen aes key, and encrypt aes key with RSA key 669 # and encrypt raw data with aes key 670 key_info_data = get_key_info_data(cfg, raw_file_path, key_data_path, raw_data_path) 671 672 # 7. generate content_len and data_for_sign 673 content_len = get_content_len(cfg, key_data_path, raw_data_path) 674 data_for_sign = gen_data_for_sign(cfg, content_len, key_info_data, raw_file_path) 675 676 if manifest_info.manifest_txt_exist is False and os.path.exists(manifest_path): 677 os.remove(manifest_path) 678 679 return manifest_info, data_for_sign, key_info_data, manifest_val 680 681 682def update_content_len(cfg, key_data_path, raw_data_path, signature_path): 683 ''' update content len ''' 684 sign_len = get_ta_sign_len(cfg) 685 signature_size = os.path.getsize(signature_path) 686 content_len = get_content_len(cfg, key_data_path, raw_data_path) 687 if sign_len == 72: 688 if signature_size != 72: 689 pack_signature(signature_path, signature_size) 690 elif sign_len == 0: 691 sign_len = signature_size 692 # generate Main Header 693 content_len = os.path.getsize(key_data_path) \ 694 + sign_len \ 695 + os.path.getsize(raw_data_path) 696 return content_len 697 698 699def pack_sec_img(cfg, manifest_info, temp_path): 700 ''' pack sec img: header || key || signature || raw_data ''' 701 signature_path = os.path.join(temp_path, "signature.bin") 702 key_data_path, raw_data_path = get_data_path(cfg, temp_path) 703 704 content_len = update_content_len(cfg, key_data_path, raw_data_path, signature_path) 705 header = gen_header(int(content_len), cfg) 706 sec_img_path = os.path.join(cfg.out_path, manifest_info.product_name) 707 fd_image = os.open(sec_img_path, os.O_WRONLY | os.O_CREAT, \ 708 stat.S_IWUSR | stat.S_IRUSR) 709 sec_image = os.fdopen(fd_image, "wb") 710 # write to sec file [1.header info] 711 sec_image.write(header) 712 # write to sec file [2.key info] 713 with open(key_data_path, 'rb') as key_data_fp: 714 sec_image.write(key_data_fp.read(os.path.getsize(key_data_path))) 715 716 # write to sec file [3.signature] 717 if cfg.ta_version == 5: 718 sign_cert_buf = get_sign_cert_block_buffer(cfg, signature_path, os.path.getsize(signature_path)) 719 sec_image.write(sign_cert_buf) 720 else: 721 with open(signature_path, 'rb') as signature_file: 722 sec_image.write(signature_file.read(os.path.getsize(signature_path))) 723 724 # write to sec file [4.raw data] 725 with open(raw_data_path, 'rb') as raw_data_fp: 726 sec_image.write(raw_data_fp.read(os.path.getsize(raw_data_path))) 727 sec_image.truncate(int(SEC_HEADER_BYTES) + int(content_len)) 728 sec_image.close() 729 730 logging.info("=========================SUCCESS============================") 731 logging.info("generate sec(common format) load image success: ") 732 logging.info(sec_img_path) 733 logging.info("============================================================") 734 735 736def gen_sec_image(temp_path, cfg): 737 # temporary files 738 shutil.rmtree(temp_path, ignore_errors=True) 739 os.mkdir(temp_path) 740 os.chmod(temp_path, stat.S_IRWXU) 741 manifest_info, data_for_sign, key_info_data, manifest_val = prepare_data(cfg, temp_path) 742 743 uuid_str = manifest_info.uuid_str 744 uuid_str = uuid_str[0:36] 745 logging.info("uuid str %s", uuid_str) 746 if cfg.disable_memctrl != "1" and not check_memory_baseline(cfg, uuid_str, manifest_val): 747 logging.error("memory baseline checking failed, but sign will continue temporarily.") 748 gen_signature(cfg, uuid_str, data_for_sign, key_info_data, temp_path) 749 750 pack_sec_img(cfg, manifest_info, temp_path) 751 return True 752 753 754def check_path_invalid(in_path, out_path, ini_path): 755 if not os.path.exists(in_path): 756 logging.error("input_path does not exist.") 757 return 1 758 if not os.path.exists(out_path): 759 logging.error("out_path does not exist.") 760 return 1 761 if not os.path.exists(ini_path): 762 logging.error("ini_path does not exist, %s", ini_path) 763 return 1 764 if whitelist_check(in_path): 765 logging.error("input_path is incorrect.") 766 return 1 767 if whitelist_check(out_path): 768 logging.error("out_path is incorrect.") 769 return 1 770 if whitelist_check(ini_path): 771 logging.error("ini_path is incorrect.") 772 return 1 773 return 0 774 775 776def define_parser(): 777 parser = argparse.ArgumentParser() 778 parser.add_argument("--in_path", help="input path of data to be signed. \ 779 (libcombine.so; manifest.txt; ...", type=str) 780 parser.add_argument("--out_path", help="input path of signed file. \ 781 (xxx.sec)", type=str) 782 parser.add_argument("--publicCfg", \ 783 help="sign cfg for ta developer", type=str) 784 parser.add_argument("--privateCfg", \ 785 help="sign cfg for product developer", type=str) 786 parser.add_argument("--memctrl_path", \ 787 help="path to memory baseline control cfgs", type=str, default="") 788 return parser 789 790 791def init_cfg(args): 792 cfg = AllCfg() 793 if args.privateCfg: 794 private_cfg_name = os.path.basename(args.privateCfg) 795 if private_cfg_name != DEFAULT_INI_NAME: 796 logging.warning("The sec signature of a non-release version cannot be loaded on a commercial device.") 797 PrivateCfg(args.privateCfg, cfg) 798 else: 799 args.privateCfg = os.path.join(DEFAULT_INI_PATH, DEFAULT_INI_NAME) 800 PrivateCfg(args.privateCfg, cfg) 801 802 if args.publicCfg: 803 PublicCfg(args.publicCfg, cfg) 804 else: 805 PublicCfg(args.privateCfg, cfg) 806 807 if check_cfg(cfg): 808 logging.error("the configuration file field is incorrect.") 809 raise RuntimeError 810 cfg.in_path = os.path.realpath(args.in_path) 811 cfg.out_path = os.path.realpath(args.out_path) 812 ini_path = os.path.dirname(args.privateCfg) 813 if check_path_invalid(cfg.in_path, cfg.out_path, ini_path): 814 raise RuntimeError 815 cfg.ini_path = os.path.realpath(ini_path) 816 cfg.public_key = os.path.join(cfg.ini_path, cfg.public_key) 817 cfg.memctrl_path = args.memctrl_path if cfg.release_type != "0" else "" 818 return cfg 819 820 821def main(): 822 sign_tool_dir = os.path.dirname(os.path.realpath(__file__)) 823 parser = define_parser() 824 args = parser.parse_args() 825 cfg = init_cfg(args) 826 os.chdir(sign_tool_dir) 827 828 temp_path = os.path.join(cfg.out_path, "temp") 829 ok = gen_sec_image(temp_path, cfg) 830 #remove temp files 831 shutil.rmtree(temp_path) 832 if not ok: 833 raise RuntimeError 834 835 836if __name__ == '__main__': 837 main()