• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()