140681896Sopenharmony_ci#!/usr/bin/env python3
240681896Sopenharmony_ci# -*- coding: utf-8 -*-
340681896Sopenharmony_ci
440681896Sopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd.
540681896Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
640681896Sopenharmony_ci# you may not use this file except in compliance with the License.
740681896Sopenharmony_ci# You may obtain a copy of the License at
840681896Sopenharmony_ci#
940681896Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0
1040681896Sopenharmony_ci#
1140681896Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
1240681896Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
1340681896Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1440681896Sopenharmony_ci# See the License for the specific language governing permissions and
1540681896Sopenharmony_ci# limitations under the License.
1640681896Sopenharmony_ci
1740681896Sopenharmony_ci"""
1840681896Sopenharmony_ciThe tool for making module package.
1940681896Sopenharmony_ci
2040681896Sopenharmony_cipositional arguments:
2140681896Sopenharmony_ci  target_package        Target package file path.
2240681896Sopenharmony_ci  update_package        Update package file path.
2340681896Sopenharmony_ci  -pn PACKAGE_NAME, --package_name PACKAGE_NAME
2440681896Sopenharmony_ci                        Module package name.
2540681896Sopenharmony_ci  -pk PRIVATE_KEY, --private_key PRIVATE_KEY
2640681896Sopenharmony_ci                        Private key file path.
2740681896Sopenharmony_ci  -sc SIGN_CERT, --sign_cert SIGN_CERT
2840681896Sopenharmony_ci                        Sign cert file path.
2940681896Sopenharmony_ci"""
3040681896Sopenharmony_ciimport os
3140681896Sopenharmony_ciimport sys
3240681896Sopenharmony_ciimport argparse
3340681896Sopenharmony_ciimport subprocess
3440681896Sopenharmony_ciimport hashlib
3540681896Sopenharmony_ciimport zipfile
3640681896Sopenharmony_ciimport io
3740681896Sopenharmony_ciimport struct
3840681896Sopenharmony_ciimport logging
3940681896Sopenharmony_ci
4040681896Sopenharmony_cifrom asn1crypto import cms
4140681896Sopenharmony_cifrom asn1crypto import pem
4240681896Sopenharmony_cifrom asn1crypto import util
4340681896Sopenharmony_cifrom asn1crypto import x509
4440681896Sopenharmony_cifrom cryptography.hazmat.backends import default_backend
4540681896Sopenharmony_cifrom cryptography.hazmat.primitives import serialization
4640681896Sopenharmony_cifrom cryptography.hazmat.primitives.asymmetric import padding
4740681896Sopenharmony_cifrom cryptography.hazmat.primitives import hashes
4840681896Sopenharmony_ci
4940681896Sopenharmony_ci
5040681896Sopenharmony_ci# 1000000: max number of function recursion depth
5140681896Sopenharmony_ciMAXIMUM_RECURSION_DEPTH = 1000000
5240681896Sopenharmony_cisys.setrecursionlimit(MAXIMUM_RECURSION_DEPTH)
5340681896Sopenharmony_ci
5440681896Sopenharmony_ciBLCOK_SIZE = 8192
5540681896Sopenharmony_ciFOOTER_LENGTH = 6
5640681896Sopenharmony_ciZIP_ECOD_LENGTH = 22
5740681896Sopenharmony_ciDIGEST_SHA256 = 672
5840681896Sopenharmony_ciSHA256_HASH_LEN = 32
5940681896Sopenharmony_ci
6040681896Sopenharmony_ciCONTENT_INFO_FORMAT = "<2H32s"
6140681896Sopenharmony_ci# the length of zip eocd comment
6240681896Sopenharmony_ciZIP_EOCD_COMMENT_LEN_FORMAT = "<H"
6340681896Sopenharmony_ci# signed package footer
6440681896Sopenharmony_ciSIGANTURE_FOOTER_FORMAT = "<3H"
6540681896Sopenharmony_ci
6640681896Sopenharmony_ciSIGN_TOOL_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'zipalign.jar')
6740681896Sopenharmony_ci
6840681896Sopenharmony_ci
6940681896Sopenharmony_cidef target_package_check(arg):
7040681896Sopenharmony_ci    """
7140681896Sopenharmony_ci    Argument check, which is used to check whether the specified arg is a file path.
7240681896Sopenharmony_ci    :param arg: the arg to check.
7340681896Sopenharmony_ci    :return:  Check result, which is False if the arg is invalid.
7440681896Sopenharmony_ci    """
7540681896Sopenharmony_ci    if not os.path.isdir(arg):
7640681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
7740681896Sopenharmony_ci            "Target package error, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
7840681896Sopenharmony_ci        return False
7940681896Sopenharmony_ci    return arg
8040681896Sopenharmony_ci
8140681896Sopenharmony_ci
8240681896Sopenharmony_cidef package_name_check(arg):
8340681896Sopenharmony_ci    """
8440681896Sopenharmony_ci    Argument check, which is used to check whether the specified arg is none.
8540681896Sopenharmony_ci    :param arg: the arg to check.
8640681896Sopenharmony_ci    :return: Check result, which is False if the arg is invalid.
8740681896Sopenharmony_ci    """
8840681896Sopenharmony_ci    if arg is None:
8940681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
9040681896Sopenharmony_ci            "Package name error: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
9140681896Sopenharmony_ci        return False
9240681896Sopenharmony_ci    return arg
9340681896Sopenharmony_ci
9440681896Sopenharmony_ci
9540681896Sopenharmony_cidef private_key_check(arg):
9640681896Sopenharmony_ci    """
9740681896Sopenharmony_ci    Argument check, which is used to check whether
9840681896Sopenharmony_ci    the specified arg is a private key.
9940681896Sopenharmony_ci    :param arg: the arg to check.
10040681896Sopenharmony_ci    :return: Check result, which is False if the arg is invalid.
10140681896Sopenharmony_ci    """
10240681896Sopenharmony_ci    if arg != "ON_SERVER" and not os.path.isfile(arg):
10340681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
10440681896Sopenharmony_ci            "FileNotFoundError, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
10540681896Sopenharmony_ci        return False
10640681896Sopenharmony_ci    return arg
10740681896Sopenharmony_ci
10840681896Sopenharmony_ci
10940681896Sopenharmony_cidef sign_cert_check(arg):
11040681896Sopenharmony_ci    """
11140681896Sopenharmony_ci    Argument check, which is used to check whether
11240681896Sopenharmony_ci    the specified arg is a sign cert.
11340681896Sopenharmony_ci    :param arg: the arg to check.
11440681896Sopenharmony_ci    :return: Check result, which is False if the arg is invalid.
11540681896Sopenharmony_ci    """
11640681896Sopenharmony_ci    if arg != "ON_SERVER" and not os.path.isfile(arg):
11740681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
11840681896Sopenharmony_ci            "FileNotFoundError, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
11940681896Sopenharmony_ci        return False
12040681896Sopenharmony_ci    return arg
12140681896Sopenharmony_ci
12240681896Sopenharmony_ci
12340681896Sopenharmony_cidef check_update_package(arg):
12440681896Sopenharmony_ci    """
12540681896Sopenharmony_ci    Argument check, which is used to check whether
12640681896Sopenharmony_ci    the update package path exists.
12740681896Sopenharmony_ci    :param arg: The arg to check.
12840681896Sopenharmony_ci    :return: Check result
12940681896Sopenharmony_ci    """
13040681896Sopenharmony_ci    make_dir_path = None
13140681896Sopenharmony_ci    if os.path.exists(arg):
13240681896Sopenharmony_ci        if os.path.isfile(arg):
13340681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
13440681896Sopenharmony_ci                "Update package must be a dir path, not a file path. "
13540681896Sopenharmony_ci                "path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
13640681896Sopenharmony_ci            return False
13740681896Sopenharmony_ci    else:
13840681896Sopenharmony_ci        try:
13940681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
14040681896Sopenharmony_ci                "Update package path does not exist. The dir will be created!"
14140681896Sopenharmony_ci                "path: %s" % arg, UPDATE_LOGGER.WARNING_LOG)
14240681896Sopenharmony_ci            os.makedirs(arg)
14340681896Sopenharmony_ci            make_dir_path = arg
14440681896Sopenharmony_ci        except OSError:
14540681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
14640681896Sopenharmony_ci                "Make update package path dir failed! "
14740681896Sopenharmony_ci                "path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
14840681896Sopenharmony_ci            return False
14940681896Sopenharmony_ci    return arg
15040681896Sopenharmony_ci
15140681896Sopenharmony_ci
15240681896Sopenharmony_ciclass UpdateToolLogger:
15340681896Sopenharmony_ci    """
15440681896Sopenharmony_ci    Global log class
15540681896Sopenharmony_ci    """
15640681896Sopenharmony_ci    INFO_LOG = 'INFO_LOG'
15740681896Sopenharmony_ci    WARNING_LOG = 'WARNING_LOG'
15840681896Sopenharmony_ci    ERROR_LOG = 'ERROR_LOG'
15940681896Sopenharmony_ci    LOG_TYPE = (INFO_LOG, WARNING_LOG, ERROR_LOG)
16040681896Sopenharmony_ci
16140681896Sopenharmony_ci    def __init__(self, output_type='console'):
16240681896Sopenharmony_ci        self.__logger_obj = self.__get_logger_obj(output_type=output_type)
16340681896Sopenharmony_ci
16440681896Sopenharmony_ci    @staticmethod
16540681896Sopenharmony_ci    def __get_logger_obj(output_type='console'):
16640681896Sopenharmony_ci        ota_logger = logging.getLogger(__name__)
16740681896Sopenharmony_ci        ota_logger.setLevel(level=logging.INFO)
16840681896Sopenharmony_ci        formatter = logging.Formatter(
16940681896Sopenharmony_ci            '%(asctime)s %(levelname)s : %(message)s',
17040681896Sopenharmony_ci            "%Y-%m-%d %H:%M:%S")
17140681896Sopenharmony_ci        if output_type == 'console':
17240681896Sopenharmony_ci            console_handler = logging.StreamHandler()
17340681896Sopenharmony_ci            console_handler.setLevel(logging.INFO)
17440681896Sopenharmony_ci            console_handler.setFormatter(formatter)
17540681896Sopenharmony_ci            ota_logger.addHandler(console_handler)
17640681896Sopenharmony_ci        elif output_type == 'file':
17740681896Sopenharmony_ci            file_handler = logging.FileHandler("UpdateToolLog.txt")
17840681896Sopenharmony_ci            file_handler.setLevel(logging.INFO)
17940681896Sopenharmony_ci            file_handler.setFormatter(formatter)
18040681896Sopenharmony_ci            ota_logger.addHandler(file_handler)
18140681896Sopenharmony_ci        return ota_logger
18240681896Sopenharmony_ci
18340681896Sopenharmony_ci    def print_log(self, msg, log_type=INFO_LOG):
18440681896Sopenharmony_ci        """
18540681896Sopenharmony_ci        Print log information.
18640681896Sopenharmony_ci        :param msg: log information
18740681896Sopenharmony_ci        :param log_type: log type
18840681896Sopenharmony_ci        :return:
18940681896Sopenharmony_ci        """
19040681896Sopenharmony_ci        if log_type == self.LOG_TYPE[0]:
19140681896Sopenharmony_ci            self.__logger_obj.info(msg)
19240681896Sopenharmony_ci        elif log_type == self.LOG_TYPE[1]:
19340681896Sopenharmony_ci            self.__logger_obj.warning(msg)
19440681896Sopenharmony_ci        elif log_type == self.LOG_TYPE[2]:
19540681896Sopenharmony_ci            self.__logger_obj.error(msg)
19640681896Sopenharmony_ci        else:
19740681896Sopenharmony_ci            self.__logger_obj.error("Unknown log type! %s", log_type)
19840681896Sopenharmony_ci            return False
19940681896Sopenharmony_ci        return True
20040681896Sopenharmony_ci
20140681896Sopenharmony_ci    def print_uncaught_exception_msg(self, msg, exc_info):
20240681896Sopenharmony_ci        """
20340681896Sopenharmony_ci        Print log when an uncaught exception occurs.
20440681896Sopenharmony_ci        :param msg: Uncaught exception
20540681896Sopenharmony_ci        :param exc_info: information about the uncaught exception
20640681896Sopenharmony_ci        """
20740681896Sopenharmony_ci        self.__logger_obj.error(msg, exc_info=exc_info)
20840681896Sopenharmony_ci
20940681896Sopenharmony_ci
21040681896Sopenharmony_ciUPDATE_LOGGER = UpdateToolLogger()
21140681896Sopenharmony_ci
21240681896Sopenharmony_ci
21340681896Sopenharmony_cidef load_public_cert(sign_cert):
21440681896Sopenharmony_ci    with open(sign_cert, 'rb') as cert_file:
21540681896Sopenharmony_ci        der_bytes = cert_file.read()
21640681896Sopenharmony_ci        if pem.detect(der_bytes):
21740681896Sopenharmony_ci            type_name, headers, der_bytes = pem.unarmor(der_bytes)
21840681896Sopenharmony_ci
21940681896Sopenharmony_ci    return x509.Certificate.load(der_bytes)
22040681896Sopenharmony_ci
22140681896Sopenharmony_ci
22240681896Sopenharmony_cidef calculate_package_hash(package_path):
22340681896Sopenharmony_ci    """
22440681896Sopenharmony_ci    :return: (hash) for path using hashlib.sha256()
22540681896Sopenharmony_ci    """
22640681896Sopenharmony_ci    hash_sha256 = hashlib.sha256()
22740681896Sopenharmony_ci    length = 0
22840681896Sopenharmony_ci
22940681896Sopenharmony_ci    remain_len = os.path.getsize(package_path) - ZIP_ECOD_LENGTH
23040681896Sopenharmony_ci    with open(package_path, 'rb') as package_file:
23140681896Sopenharmony_ci        while remain_len > BLCOK_SIZE:
23240681896Sopenharmony_ci            hash_sha256.update(package_file.read(BLCOK_SIZE))
23340681896Sopenharmony_ci            remain_len -= BLCOK_SIZE
23440681896Sopenharmony_ci        if remain_len > 0:
23540681896Sopenharmony_ci            hash_sha256.update(package_file.read(remain_len))
23640681896Sopenharmony_ci
23740681896Sopenharmony_ci    return hash_sha256.digest()
23840681896Sopenharmony_ci
23940681896Sopenharmony_ci
24040681896Sopenharmony_cidef sign_digest_with_pss(digset, private_key_file):
24140681896Sopenharmony_ci    # read private key from pem file
24240681896Sopenharmony_ci    try:
24340681896Sopenharmony_ci        with open(private_key_file, 'rb') as f_r:
24440681896Sopenharmony_ci            key_data = f_r.read()
24540681896Sopenharmony_ci
24640681896Sopenharmony_ci        private_key = serialization.load_pem_private_key(
24740681896Sopenharmony_ci            key_data,
24840681896Sopenharmony_ci            password=None,
24940681896Sopenharmony_ci            backend=default_backend())
25040681896Sopenharmony_ci        pad = padding.PSS(
25140681896Sopenharmony_ci            mgf=padding.MGF1(hashes.SHA256()),
25240681896Sopenharmony_ci            salt_length=padding.PSS.MAX_LENGTH)
25340681896Sopenharmony_ci
25440681896Sopenharmony_ci        signature = private_key.sign(
25540681896Sopenharmony_ci            digset,
25640681896Sopenharmony_ci            pad,
25740681896Sopenharmony_ci            hashes.SHA256()
25840681896Sopenharmony_ci        )
25940681896Sopenharmony_ci    except (OSError, ValueError):
26040681896Sopenharmony_ci        return False
26140681896Sopenharmony_ci    return signature
26240681896Sopenharmony_ci
26340681896Sopenharmony_ci
26440681896Sopenharmony_cidef sign_digest(digset, private_key_file):
26540681896Sopenharmony_ci    # read private key from pem file
26640681896Sopenharmony_ci    try:
26740681896Sopenharmony_ci        with open(private_key_file, 'rb') as f_r:
26840681896Sopenharmony_ci            key_data = f_r.read()
26940681896Sopenharmony_ci
27040681896Sopenharmony_ci        private_key = serialization.load_pem_private_key(
27140681896Sopenharmony_ci            key_data,
27240681896Sopenharmony_ci            password=None,
27340681896Sopenharmony_ci            backend=default_backend())
27440681896Sopenharmony_ci
27540681896Sopenharmony_ci        signature = private_key.sign(
27640681896Sopenharmony_ci            digset,
27740681896Sopenharmony_ci            padding.PKCS1v15(),
27840681896Sopenharmony_ci            hashes.SHA256()
27940681896Sopenharmony_ci        )
28040681896Sopenharmony_ci    except (OSError, ValueError):
28140681896Sopenharmony_ci        return False
28240681896Sopenharmony_ci    return signature
28340681896Sopenharmony_ci
28440681896Sopenharmony_ci
28540681896Sopenharmony_cidef create_encap_content_info(diget):
28640681896Sopenharmony_ci    if not diget:
28740681896Sopenharmony_ci        UPDATE_LOGGER.print_log("calc package hash failed! file: %s",
28840681896Sopenharmony_ci            log_type=UPDATE_LOGGER.ERROR_LOG)
28940681896Sopenharmony_ci        return False
29040681896Sopenharmony_ci    content_header = struct.pack(CONTENT_INFO_FORMAT, DIGEST_SHA256,
29140681896Sopenharmony_ci        SHA256_HASH_LEN, diget)
29240681896Sopenharmony_ci    return content_header
29340681896Sopenharmony_ci
29440681896Sopenharmony_ci
29540681896Sopenharmony_cidef write_signed_package(unsigned_package, signature, signed_package):
29640681896Sopenharmony_ci    """
29740681896Sopenharmony_ci    :Write signature to signed package
29840681896Sopenharmony_ci    """
29940681896Sopenharmony_ci    signature_size = len(signature)
30040681896Sopenharmony_ci    signature_total_size = signature_size + FOOTER_LENGTH
30140681896Sopenharmony_ci
30240681896Sopenharmony_ci    package_fd = os.open(signed_package, os.O_RDWR | os.O_CREAT, 0o755)
30340681896Sopenharmony_ci    f_signed = os.fdopen(package_fd, 'wb')
30440681896Sopenharmony_ci
30540681896Sopenharmony_ci    remain_len = os.path.getsize(unsigned_package) - 2
30640681896Sopenharmony_ci    with open(unsigned_package, 'rb') as f_unsign:
30740681896Sopenharmony_ci        while remain_len > BLCOK_SIZE:
30840681896Sopenharmony_ci            f_signed.write(f_unsign.read(BLCOK_SIZE))
30940681896Sopenharmony_ci            remain_len -= BLCOK_SIZE
31040681896Sopenharmony_ci        if remain_len > 0:
31140681896Sopenharmony_ci            f_signed.write(f_unsign.read(remain_len))
31240681896Sopenharmony_ci
31340681896Sopenharmony_ci    zip_comment_len = struct.pack(ZIP_EOCD_COMMENT_LEN_FORMAT,
31440681896Sopenharmony_ci            signature_total_size)
31540681896Sopenharmony_ci    f_signed.write(zip_comment_len)
31640681896Sopenharmony_ci
31740681896Sopenharmony_ci    f_signed.write(signature)
31840681896Sopenharmony_ci    footter = struct.pack(SIGANTURE_FOOTER_FORMAT, signature_total_size,
31940681896Sopenharmony_ci            0xffff, signature_total_size)
32040681896Sopenharmony_ci    f_signed.write(footter)
32140681896Sopenharmony_ci    f_signed.close()
32240681896Sopenharmony_ci
32340681896Sopenharmony_ci
32440681896Sopenharmony_cidef sign_ota_package(package_path, signed_package, private_key, sign_cert):
32540681896Sopenharmony_ci    digest = calculate_package_hash(package_path)
32640681896Sopenharmony_ci    data = create_encap_content_info(digest)
32740681896Sopenharmony_ci    signature = sign_digest(digest, private_key)
32840681896Sopenharmony_ci
32940681896Sopenharmony_ci    digest_fd = os.open("digest", os.O_RDWR | os.O_CREAT, 0o755)
33040681896Sopenharmony_ci    digest_file = os.fdopen(digest_fd, 'wb')
33140681896Sopenharmony_ci    digest_file.write(digest)
33240681896Sopenharmony_ci    digest_file.close()
33340681896Sopenharmony_ci
33440681896Sopenharmony_ci    signatute_fd = os.open("signature", os.O_RDWR | os.O_CREAT, 0o755)
33540681896Sopenharmony_ci    signatute_file = os.fdopen(signatute_fd, 'wb')
33640681896Sopenharmony_ci    signatute_file.write(signature)
33740681896Sopenharmony_ci    signatute_file.close()
33840681896Sopenharmony_ci
33940681896Sopenharmony_ci    # Creating a SignedData object from cms
34040681896Sopenharmony_ci    signed_data = cms.SignedData()
34140681896Sopenharmony_ci    signed_data['version'] = 'v1'
34240681896Sopenharmony_ci    signed_data['encap_content_info'] = util.OrderedDict([
34340681896Sopenharmony_ci        ('content_type', 'data'),
34440681896Sopenharmony_ci        ('content', data)])
34540681896Sopenharmony_ci
34640681896Sopenharmony_ci    signed_data['digest_algorithms'] = [util.OrderedDict([
34740681896Sopenharmony_ci        ('algorithm', 'sha256'),
34840681896Sopenharmony_ci        ('parameters', None)])]
34940681896Sopenharmony_ci
35040681896Sopenharmony_ci    cert = load_public_cert(sign_cert)
35140681896Sopenharmony_ci
35240681896Sopenharmony_ci    # Adding this certificate to SignedData object
35340681896Sopenharmony_ci    signed_data['certificates'] = [cert]
35440681896Sopenharmony_ci
35540681896Sopenharmony_ci    # Setting signer info section
35640681896Sopenharmony_ci    signer_info = cms.SignerInfo()
35740681896Sopenharmony_ci    signer_info['version'] = 'v1'
35840681896Sopenharmony_ci    signer_info['digest_algorithm'] = util.OrderedDict([
35940681896Sopenharmony_ci                ('algorithm', 'sha256'),
36040681896Sopenharmony_ci                ('parameters', None)])
36140681896Sopenharmony_ci    signer_info['signature_algorithm'] = util.OrderedDict([
36240681896Sopenharmony_ci                ('algorithm', 'sha256_rsa'),
36340681896Sopenharmony_ci                ('parameters', None)])
36440681896Sopenharmony_ci
36540681896Sopenharmony_ci    issuer = cert.issuer
36640681896Sopenharmony_ci    serial_number = cert.serial_number
36740681896Sopenharmony_ci    issuer_and_serial = cms.IssuerAndSerialNumber()
36840681896Sopenharmony_ci    issuer_and_serial['issuer'] = cert.issuer
36940681896Sopenharmony_ci    issuer_and_serial['serial_number'] = cert.serial_number
37040681896Sopenharmony_ci
37140681896Sopenharmony_ci    key_id = cert.key_identifier_value.native
37240681896Sopenharmony_ci    signer_info['sid'] = cms.SignerIdentifier({
37340681896Sopenharmony_ci        'issuer_and_serial_number': issuer_and_serial})
37440681896Sopenharmony_ci
37540681896Sopenharmony_ci    signer_info['signature'] = signature
37640681896Sopenharmony_ci    # Adding SignerInfo object to SignedData object
37740681896Sopenharmony_ci    signed_data['signer_infos'] = [signer_info]
37840681896Sopenharmony_ci
37940681896Sopenharmony_ci    # Writing everything into ASN.1 object
38040681896Sopenharmony_ci    asn1obj = cms.ContentInfo()
38140681896Sopenharmony_ci    asn1obj['content_type'] = 'signed_data'
38240681896Sopenharmony_ci    asn1obj['content'] = signed_data
38340681896Sopenharmony_ci
38440681896Sopenharmony_ci    # This asn1obj can be dumped to a disk using dump() method (DER format)
38540681896Sopenharmony_ci    write_signed_package(package_path, asn1obj.dump(), signed_package)
38640681896Sopenharmony_ci    return True
38740681896Sopenharmony_ci
38840681896Sopenharmony_ci
38940681896Sopenharmony_cidef build_module_package(package_name, target_package, update_package, private_key, sign_cert):
39040681896Sopenharmony_ci    unsigned_package = os.path.join(
39140681896Sopenharmony_ci        update_package, '%s_unsigned.zip' % package_name)
39240681896Sopenharmony_ci
39340681896Sopenharmony_ci    zip_file = zipfile.ZipFile(unsigned_package, 'w')
39440681896Sopenharmony_ci    # add module.img to update package
39540681896Sopenharmony_ci    img_file_path = os.path.join(target_package, 'module.img')
39640681896Sopenharmony_ci    if os.path.exists(img_file_path):
39740681896Sopenharmony_ci        zip_file.write(img_file_path, "module.img")
39840681896Sopenharmony_ci    # add config.json to update package
39940681896Sopenharmony_ci    module_file_path = os.path.join(target_package, 'config.json')
40040681896Sopenharmony_ci    zip_file.write(module_file_path, "config.json")
40140681896Sopenharmony_ci    # add pub_key.pem to update package
40240681896Sopenharmony_ci    pub_key_file_path = os.path.join(target_package, 'pub_key.pem')
40340681896Sopenharmony_ci    if os.path.exists(pub_key_file_path):
40440681896Sopenharmony_ci        zip_file.write(pub_key_file_path, 'pub_key.pem')
40540681896Sopenharmony_ci    zip_file.close()
40640681896Sopenharmony_ci
40740681896Sopenharmony_ci    # align package
40840681896Sopenharmony_ci    align_package = os.path.join(
40940681896Sopenharmony_ci        update_package, '%s_align.zip' % package_name)
41040681896Sopenharmony_ci    align_cmd = ['java', '-jar', SIGN_TOOL_PATH, unsigned_package, align_package, '4096']
41140681896Sopenharmony_ci    subprocess.call(align_cmd, shell=False)
41240681896Sopenharmony_ci    if not os.path.exists(align_package):
41340681896Sopenharmony_ci        UPDATE_LOGGER.print_log("align package failed", log_type=UPDATE_LOGGER.ERROR_LOG)
41440681896Sopenharmony_ci        return False
41540681896Sopenharmony_ci
41640681896Sopenharmony_ci    # sign package
41740681896Sopenharmony_ci    signed_package = os.path.join(
41840681896Sopenharmony_ci        update_package, '%s.zip' % package_name)
41940681896Sopenharmony_ci    if os.path.exists(signed_package):
42040681896Sopenharmony_ci        os.remove(signed_package)
42140681896Sopenharmony_ci
42240681896Sopenharmony_ci    sign_result = sign_ota_package(
42340681896Sopenharmony_ci        align_package,
42440681896Sopenharmony_ci        signed_package,
42540681896Sopenharmony_ci        private_key,
42640681896Sopenharmony_ci        sign_cert)
42740681896Sopenharmony_ci
42840681896Sopenharmony_ci    if not sign_result:
42940681896Sopenharmony_ci        UPDATE_LOGGER.print_log("Sign module package fail", UPDATE_LOGGER.ERROR_LOG)
43040681896Sopenharmony_ci        return False
43140681896Sopenharmony_ci    if os.path.exists(align_package):
43240681896Sopenharmony_ci        os.remove(align_package)
43340681896Sopenharmony_ci    if os.path.exists(unsigned_package):
43440681896Sopenharmony_ci        os.remove(unsigned_package)
43540681896Sopenharmony_ci
43640681896Sopenharmony_ci    return True
43740681896Sopenharmony_ci
43840681896Sopenharmony_ci
43940681896Sopenharmony_cidef main(argv):
44040681896Sopenharmony_ci    """
44140681896Sopenharmony_ci    Entry function.
44240681896Sopenharmony_ci    """
44340681896Sopenharmony_ci    parser = argparse.ArgumentParser()
44440681896Sopenharmony_ci    parser.add_argument("target_package", type=target_package_check,
44540681896Sopenharmony_ci                        help="Target package file path.")
44640681896Sopenharmony_ci    parser.add_argument("update_package", type=check_update_package,
44740681896Sopenharmony_ci                        help="Update package file path.")
44840681896Sopenharmony_ci    parser.add_argument("-pk", "--private_key", type=private_key_check,
44940681896Sopenharmony_ci                        default=None, help="Private key file path.")
45040681896Sopenharmony_ci    parser.add_argument("-sc", "--sign_cert", type=sign_cert_check,
45140681896Sopenharmony_ci                        default=None, help="Sign cert file path.")
45240681896Sopenharmony_ci    parser.add_argument("-pn", "--package_name", type=package_name_check,
45340681896Sopenharmony_ci                        default=None, help="Package name.")
45440681896Sopenharmony_ci
45540681896Sopenharmony_ci    args = parser.parse_args(argv)
45640681896Sopenharmony_ci
45740681896Sopenharmony_ci    # Generate the module package.
45840681896Sopenharmony_ci    build_re = build_module_package(args.package_name, args.target_package,
45940681896Sopenharmony_ci        args.update_package, args.private_key, args.sign_cert)
46040681896Sopenharmony_ci
46140681896Sopenharmony_ciif __name__ == '__main__':
46240681896Sopenharmony_ci    main(sys.argv[1:])
463