140681896Sopenharmony_ci#!/usr/bin/env python3
240681896Sopenharmony_ci# -*- coding: utf-8 -*-
340681896Sopenharmony_ci
440681896Sopenharmony_ci# Copyright (c) 2022 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_ciDescription : Generate the update.bin file
1840681896Sopenharmony_ci"""
1940681896Sopenharmony_ciimport os
2040681896Sopenharmony_ciimport struct
2140681896Sopenharmony_ciimport hashlib
2240681896Sopenharmony_ciimport subprocess
2340681896Sopenharmony_cifrom log_exception import UPDATE_LOGGER
2440681896Sopenharmony_cifrom utils import OPTIONS_MANAGER
2540681896Sopenharmony_cifrom create_hashdata import HashType
2640681896Sopenharmony_cifrom create_hashdata import CreateHash
2740681896Sopenharmony_cifrom create_hashdata import HASH_BLOCK_SIZE
2840681896Sopenharmony_cifrom cryptography.hazmat.primitives import serialization
2940681896Sopenharmony_cifrom cryptography.hazmat.primitives import hashes
3040681896Sopenharmony_cifrom cryptography.hazmat.backends import default_backend
3140681896Sopenharmony_cifrom cryptography.hazmat.primitives.asymmetric import padding
3240681896Sopenharmony_ci
3340681896Sopenharmony_ciUPGRADE_FILE_HEADER_LEN = 180
3440681896Sopenharmony_ciUPGRADE_RESERVE_LEN = 16
3540681896Sopenharmony_ciSIGN_SHA256_LEN = 256
3640681896Sopenharmony_ciSIGN_SHA384_LEN = 384
3740681896Sopenharmony_ciUPGRADE_SIGNATURE_LEN = SIGN_SHA256_LEN + SIGN_SHA384_LEN
3840681896Sopenharmony_ciTLV_SIZE = 4
3940681896Sopenharmony_ciUPGRADE_PKG_HEADER_SIZE = 136
4040681896Sopenharmony_ciUPGRADE_PKG_TIME_SIZE = 32
4140681896Sopenharmony_ciUPGRADE_COMPINFO_SIZE = 71
4240681896Sopenharmony_ciUPGRADE_COMPINFO_SIZE_L2 = 87
4340681896Sopenharmony_ciCOMPONENT_ADDR_SIZE = 16
4440681896Sopenharmony_ciCOMPONENT_ADDR_SIZE_L2 = 32
4540681896Sopenharmony_ciCOMPONENT_INFO_FMT_SIZE = 5
4640681896Sopenharmony_ciCOMPONENT_VERSION_SIZE = 10
4740681896Sopenharmony_ciCOMPONENT_SIZE_FMT_SIZE = 8
4840681896Sopenharmony_ciCOMPONENT_DIGEST_SIZE = 32
4940681896Sopenharmony_ciBLOCK_SIZE = 8192
5040681896Sopenharmony_ciHEADER_TLV_TYPE = 0x11
5140681896Sopenharmony_ciHEADER_TLV_TYPE_L2 = 0x01
5240681896Sopenharmony_ci# signature algorithm
5340681896Sopenharmony_ciSIGN_ALGO_RSA = "SHA256withRSA"
5440681896Sopenharmony_ciSIGN_ALGO_PSS = "SHA256withPSS"
5540681896Sopenharmony_ci
5640681896Sopenharmony_ci"""
5740681896Sopenharmony_ciFormat
5840681896Sopenharmony_ciH: unsigned short
5940681896Sopenharmony_ciI: unsigned int
6040681896Sopenharmony_ciB: unsigned char
6140681896Sopenharmony_cis: char[]
6240681896Sopenharmony_ci"""
6340681896Sopenharmony_ciTLV_FMT = "2H"
6440681896Sopenharmony_ciUPGRADE_PKG_HEADER_FMT = "2I64s64s"
6540681896Sopenharmony_ciUPGRADE_PKG_TIME_FMT = "16s16s"
6640681896Sopenharmony_ciCOMPONENT_INFO_FMT = "H3B"
6740681896Sopenharmony_ciCOMPONENT_SIZE_FMT = "iI"
6840681896Sopenharmony_ci
6940681896Sopenharmony_ci
7040681896Sopenharmony_ciclass CreatePackage(object):
7140681896Sopenharmony_ci    """
7240681896Sopenharmony_ci    Create the update.bin file
7340681896Sopenharmony_ci    """
7440681896Sopenharmony_ci
7540681896Sopenharmony_ci    def __init__(self, head_list, component_list, save_path, key_path):
7640681896Sopenharmony_ci        self.head_list = head_list
7740681896Sopenharmony_ci        self.component_list = component_list
7840681896Sopenharmony_ci        self.save_path = save_path
7940681896Sopenharmony_ci        self.key_path = key_path
8040681896Sopenharmony_ci        self.compinfo_offset = 0
8140681896Sopenharmony_ci        self.component_offset = 0
8240681896Sopenharmony_ci        self.sign_offset = 0
8340681896Sopenharmony_ci        self.hash_info_offset = 0
8440681896Sopenharmony_ci
8540681896Sopenharmony_ci        if OPTIONS_MANAGER.not_l2:
8640681896Sopenharmony_ci            self.upgrade_compinfo_size = UPGRADE_COMPINFO_SIZE
8740681896Sopenharmony_ci            self.header_tlv_type = HEADER_TLV_TYPE
8840681896Sopenharmony_ci        else:
8940681896Sopenharmony_ci            self.upgrade_compinfo_size = UPGRADE_COMPINFO_SIZE_L2
9040681896Sopenharmony_ci            self.header_tlv_type = HEADER_TLV_TYPE_L2
9140681896Sopenharmony_ci
9240681896Sopenharmony_ci    def verify_param(self):
9340681896Sopenharmony_ci        if self.head_list is None or self.component_list is None or \
9440681896Sopenharmony_ci            self.save_path is None or self.key_path is None:
9540681896Sopenharmony_ci            UPDATE_LOGGER.print_log("Check param failed!", UPDATE_LOGGER.ERROR_LOG)
9640681896Sopenharmony_ci            return False
9740681896Sopenharmony_ci        if os.path.isdir(self.key_path):
9840681896Sopenharmony_ci            UPDATE_LOGGER.print_log("Invalid keyname", UPDATE_LOGGER.ERROR_LOG)
9940681896Sopenharmony_ci            return False
10040681896Sopenharmony_ci        if self.head_list.__sizeof__() <= 0 or self.component_list.__sizeof__() <= 0:
10140681896Sopenharmony_ci            UPDATE_LOGGER.print_log("Invalid param", UPDATE_LOGGER.ERROR_LOG)
10240681896Sopenharmony_ci            return False
10340681896Sopenharmony_ci        return True
10440681896Sopenharmony_ci
10540681896Sopenharmony_ci    def write_pkginfo(self, package_file):
10640681896Sopenharmony_ci        try:
10740681896Sopenharmony_ci            # Type is 1 for package header in TLV format
10840681896Sopenharmony_ci            header_tlv = struct.pack(TLV_FMT, self.header_tlv_type, UPGRADE_PKG_HEADER_SIZE)
10940681896Sopenharmony_ci            pkg_info_length = \
11040681896Sopenharmony_ci                UPGRADE_RESERVE_LEN + TLV_SIZE + TLV_SIZE + TLV_SIZE + \
11140681896Sopenharmony_ci                UPGRADE_PKG_HEADER_SIZE + UPGRADE_PKG_TIME_SIZE + \
11240681896Sopenharmony_ci                self.upgrade_compinfo_size * self.head_list.entry_count
11340681896Sopenharmony_ci            upgrade_pkg_header = struct.pack(
11440681896Sopenharmony_ci                UPGRADE_PKG_HEADER_FMT, pkg_info_length, self.head_list.update_file_version,
11540681896Sopenharmony_ci                self.head_list.product_update_id, self.head_list.software_version)
11640681896Sopenharmony_ci
11740681896Sopenharmony_ci            # Type is 2 for time in TLV format
11840681896Sopenharmony_ci            time_tlv = struct.pack(TLV_FMT, 0x02, UPGRADE_PKG_TIME_SIZE)
11940681896Sopenharmony_ci            upgrade_pkg_time = struct.pack(
12040681896Sopenharmony_ci                UPGRADE_PKG_TIME_FMT, self.head_list.date, self.head_list.time)
12140681896Sopenharmony_ci
12240681896Sopenharmony_ci            # Type is 5 for component in TLV format
12340681896Sopenharmony_ci            component_tlv = struct.pack(
12440681896Sopenharmony_ci                TLV_FMT, 0x05, self.upgrade_compinfo_size * self.head_list.entry_count)
12540681896Sopenharmony_ci        except struct.error:
12640681896Sopenharmony_ci            UPDATE_LOGGER.print_log("Pack fail!", log_type=UPDATE_LOGGER.ERROR_LOG)
12740681896Sopenharmony_ci            return False
12840681896Sopenharmony_ci
12940681896Sopenharmony_ci        # write pkginfo
13040681896Sopenharmony_ci        pkginfo = header_tlv + upgrade_pkg_header + time_tlv + upgrade_pkg_time + component_tlv
13140681896Sopenharmony_ci        try:
13240681896Sopenharmony_ci            package_file.write(pkginfo)
13340681896Sopenharmony_ci        except IOError:
13440681896Sopenharmony_ci            UPDATE_LOGGER.print_log("write fail!", log_type=UPDATE_LOGGER.ERROR_LOG)
13540681896Sopenharmony_ci            return False
13640681896Sopenharmony_ci        UPDATE_LOGGER.print_log("Write package header complete")
13740681896Sopenharmony_ci        return True
13840681896Sopenharmony_ci
13940681896Sopenharmony_ci    def write_component_info(self, component, package_file):
14040681896Sopenharmony_ci        UPDATE_LOGGER.print_log("component information  StartOffset:%s"\
14140681896Sopenharmony_ci            % self.compinfo_offset)
14240681896Sopenharmony_ci        if OPTIONS_MANAGER.not_l2:
14340681896Sopenharmony_ci            component_addr_size = COMPONENT_ADDR_SIZE
14440681896Sopenharmony_ci        else:
14540681896Sopenharmony_ci            component_addr_size = COMPONENT_ADDR_SIZE_L2
14640681896Sopenharmony_ci
14740681896Sopenharmony_ci        try:
14840681896Sopenharmony_ci            package_file.seek(self.compinfo_offset)
14940681896Sopenharmony_ci            package_file.write(component.component_addr)
15040681896Sopenharmony_ci            self.compinfo_offset += component_addr_size
15140681896Sopenharmony_ci
15240681896Sopenharmony_ci            package_file.seek(self.compinfo_offset)
15340681896Sopenharmony_ci            component_info = struct.pack(
15440681896Sopenharmony_ci                COMPONENT_INFO_FMT, component.id, component.res_type,
15540681896Sopenharmony_ci                component.flags, component.type)
15640681896Sopenharmony_ci            package_file.write(component_info)
15740681896Sopenharmony_ci            self.compinfo_offset += COMPONENT_INFO_FMT_SIZE
15840681896Sopenharmony_ci
15940681896Sopenharmony_ci            package_file.seek(self.compinfo_offset)
16040681896Sopenharmony_ci            package_file.write(component.version)
16140681896Sopenharmony_ci            self.compinfo_offset += COMPONENT_VERSION_SIZE
16240681896Sopenharmony_ci
16340681896Sopenharmony_ci            package_file.seek(self.compinfo_offset)
16440681896Sopenharmony_ci            component_size = struct.pack(
16540681896Sopenharmony_ci                COMPONENT_SIZE_FMT, component.size, component.original_size)
16640681896Sopenharmony_ci            package_file.write(component_size)
16740681896Sopenharmony_ci            self.compinfo_offset += COMPONENT_SIZE_FMT_SIZE
16840681896Sopenharmony_ci
16940681896Sopenharmony_ci            package_file.seek(self.compinfo_offset)
17040681896Sopenharmony_ci            package_file.write(component.digest)
17140681896Sopenharmony_ci            self.compinfo_offset += COMPONENT_DIGEST_SIZE
17240681896Sopenharmony_ci        except (struct.error, IOError):
17340681896Sopenharmony_ci            return False
17440681896Sopenharmony_ci        return True
17540681896Sopenharmony_ci
17640681896Sopenharmony_ci    def write_component(self, component, package_file):
17740681896Sopenharmony_ci        UPDATE_LOGGER.print_log("Add component to package  StartOffset:%s"\
17840681896Sopenharmony_ci            % self.component_offset)
17940681896Sopenharmony_ci        try:
18040681896Sopenharmony_ci            with open(component.file_path, "rb") as component_file:
18140681896Sopenharmony_ci                component_data = component_file.read()
18240681896Sopenharmony_ci                package_file.seek(self.component_offset)
18340681896Sopenharmony_ci                package_file.write(component_data)
18440681896Sopenharmony_ci                component_len = len(component_data)
18540681896Sopenharmony_ci                self.component_offset += component_len
18640681896Sopenharmony_ci        except IOError:
18740681896Sopenharmony_ci            return False
18840681896Sopenharmony_ci        UPDATE_LOGGER.print_log("Write component complete  ComponentSize:%s"\
18940681896Sopenharmony_ci            % component_len)
19040681896Sopenharmony_ci        return True
19140681896Sopenharmony_ci
19240681896Sopenharmony_ci    def calculate_hash(self, package_file):
19340681896Sopenharmony_ci        hash_sha256 = hashlib.sha256()
19440681896Sopenharmony_ci        remain_len = self.component_offset
19540681896Sopenharmony_ci
19640681896Sopenharmony_ci        package_file.seek(0)
19740681896Sopenharmony_ci        while remain_len > BLOCK_SIZE:
19840681896Sopenharmony_ci            hash_sha256.update(package_file.read(BLOCK_SIZE))
19940681896Sopenharmony_ci            remain_len -= BLOCK_SIZE
20040681896Sopenharmony_ci        if remain_len > 0:
20140681896Sopenharmony_ci            hash_sha256.update(package_file.read(remain_len))
20240681896Sopenharmony_ci        return hash_sha256.digest()
20340681896Sopenharmony_ci
20440681896Sopenharmony_ci    def calculate_header_hash(self, package_file):
20540681896Sopenharmony_ci        hash_sha256 = hashlib.sha256()
20640681896Sopenharmony_ci        remain_len = self.hash_info_offset
20740681896Sopenharmony_ci
20840681896Sopenharmony_ci        package_file.seek(0)
20940681896Sopenharmony_ci        while remain_len > BLOCK_SIZE:
21040681896Sopenharmony_ci            hash_sha256.update(package_file.read(BLOCK_SIZE))
21140681896Sopenharmony_ci            remain_len -= BLOCK_SIZE
21240681896Sopenharmony_ci        if remain_len > 0:
21340681896Sopenharmony_ci            hash_sha256.update(package_file.read(remain_len))
21440681896Sopenharmony_ci        return hash_sha256.digest()
21540681896Sopenharmony_ci
21640681896Sopenharmony_ci    def sign_digest_with_pss(self, digest):
21740681896Sopenharmony_ci        try:
21840681896Sopenharmony_ci            with open(self.key_path, 'rb') as f_r:
21940681896Sopenharmony_ci                key_data = f_r.read()
22040681896Sopenharmony_ci            private_key = serialization.load_pem_private_key(
22140681896Sopenharmony_ci                key_data,
22240681896Sopenharmony_ci                password=None,
22340681896Sopenharmony_ci                backend=default_backend())
22440681896Sopenharmony_ci
22540681896Sopenharmony_ci            pad = padding.PSS(
22640681896Sopenharmony_ci                mgf=padding.MGF1(hashes.SHA256()),
22740681896Sopenharmony_ci                salt_length=padding.PSS.MAX_LENGTH)
22840681896Sopenharmony_ci
22940681896Sopenharmony_ci            signature = private_key.sign(digest, pad, hashes.SHA256())
23040681896Sopenharmony_ci        except (OSError, ValueError):
23140681896Sopenharmony_ci            return False
23240681896Sopenharmony_ci        return signature
23340681896Sopenharmony_ci
23440681896Sopenharmony_ci    def sign_digest(self, digest):
23540681896Sopenharmony_ci        try:
23640681896Sopenharmony_ci            with open(self.key_path, 'rb') as f_r:
23740681896Sopenharmony_ci                key_data = f_r.read()
23840681896Sopenharmony_ci            private_key = serialization.load_pem_private_key(
23940681896Sopenharmony_ci                key_data,
24040681896Sopenharmony_ci                password=None,
24140681896Sopenharmony_ci                backend=default_backend())
24240681896Sopenharmony_ci            signature = private_key.sign(digest, padding.PKCS1v15(), hashes.SHA256())
24340681896Sopenharmony_ci        except (OSError, ValueError):
24440681896Sopenharmony_ci            return False
24540681896Sopenharmony_ci        return signature
24640681896Sopenharmony_ci
24740681896Sopenharmony_ci    def sign(self, sign_algo):
24840681896Sopenharmony_ci        with open(self.save_path, "rb+") as package_file:
24940681896Sopenharmony_ci            # calculate hash for .bin package
25040681896Sopenharmony_ci            digest = self.calculate_hash(package_file)
25140681896Sopenharmony_ci            if not digest:
25240681896Sopenharmony_ci                UPDATE_LOGGER.print_log("calculate hash for .bin package failed",
25340681896Sopenharmony_ci                    log_type=UPDATE_LOGGER.ERROR_LOG)
25440681896Sopenharmony_ci                return False
25540681896Sopenharmony_ci
25640681896Sopenharmony_ci            # sign .bin package
25740681896Sopenharmony_ci            if sign_algo == SIGN_ALGO_RSA:
25840681896Sopenharmony_ci                signature = self.sign_digest(digest)
25940681896Sopenharmony_ci            elif sign_algo == SIGN_ALGO_PSS:
26040681896Sopenharmony_ci                signature = self.sign_digest_with_pss(digest)
26140681896Sopenharmony_ci            else:
26240681896Sopenharmony_ci                UPDATE_LOGGER.print_log("invalid sign_algo!", log_type=UPDATE_LOGGER.ERROR_LOG)
26340681896Sopenharmony_ci                return False
26440681896Sopenharmony_ci            if not signature:
26540681896Sopenharmony_ci                UPDATE_LOGGER.print_log("sign .bin package failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
26640681896Sopenharmony_ci                return False
26740681896Sopenharmony_ci
26840681896Sopenharmony_ci            if len(signature) == SIGN_SHA384_LEN:
26940681896Sopenharmony_ci                self.sign_offset += SIGN_SHA256_LEN
27040681896Sopenharmony_ci
27140681896Sopenharmony_ci            # write signed .bin package
27240681896Sopenharmony_ci            package_file.seek(self.sign_offset)
27340681896Sopenharmony_ci            package_file.write(signature)
27440681896Sopenharmony_ci            UPDATE_LOGGER.print_log(
27540681896Sopenharmony_ci                ".bin package signing success! SignOffset: %s" % self.sign_offset)
27640681896Sopenharmony_ci            return True
27740681896Sopenharmony_ci
27840681896Sopenharmony_ci    def sign_header(self, sign_algo, hash_check_data, package_file):
27940681896Sopenharmony_ci        # calculate hash for .bin package
28040681896Sopenharmony_ci        digest = self.calculate_header_hash(package_file)
28140681896Sopenharmony_ci        if not digest:
28240681896Sopenharmony_ci            UPDATE_LOGGER.print_log("calculate hash for .bin package failed",
28340681896Sopenharmony_ci                log_type=UPDATE_LOGGER.ERROR_LOG)
28440681896Sopenharmony_ci            return False
28540681896Sopenharmony_ci
28640681896Sopenharmony_ci        # sign .bin header
28740681896Sopenharmony_ci        if sign_algo == SIGN_ALGO_RSA:
28840681896Sopenharmony_ci            signature = self.sign_digest(digest)
28940681896Sopenharmony_ci        elif sign_algo == SIGN_ALGO_PSS:
29040681896Sopenharmony_ci            signature = self.sign_digest_with_pss(digest)
29140681896Sopenharmony_ci        else:
29240681896Sopenharmony_ci            UPDATE_LOGGER.print_log("invalid sign_algo!", log_type=UPDATE_LOGGER.ERROR_LOG)
29340681896Sopenharmony_ci            return False
29440681896Sopenharmony_ci        if not signature:
29540681896Sopenharmony_ci            UPDATE_LOGGER.print_log("sign .bin package failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
29640681896Sopenharmony_ci            return False
29740681896Sopenharmony_ci
29840681896Sopenharmony_ci        # write signed .bin header
29940681896Sopenharmony_ci        hash_check_data.write_signdata(signature)
30040681896Sopenharmony_ci        package_file.seek(self.hash_info_offset)
30140681896Sopenharmony_ci        package_file.write(hash_check_data.signdata)
30240681896Sopenharmony_ci        self.hash_info_offset += len(hash_check_data.signdata)
30340681896Sopenharmony_ci        UPDATE_LOGGER.print_log(
30440681896Sopenharmony_ci            ".bin package header signing success! SignOffset: %s" % self.hash_info_offset)
30540681896Sopenharmony_ci        return True
30640681896Sopenharmony_ci
30740681896Sopenharmony_ci    def create_package(self):
30840681896Sopenharmony_ci        """
30940681896Sopenharmony_ci        Create the update.bin file
31040681896Sopenharmony_ci        return: update package creation result
31140681896Sopenharmony_ci        """
31240681896Sopenharmony_ci        if not self.verify_param():
31340681896Sopenharmony_ci            UPDATE_LOGGER.print_log("verify param failed!", UPDATE_LOGGER.ERROR_LOG)
31440681896Sopenharmony_ci            return False
31540681896Sopenharmony_ci
31640681896Sopenharmony_ci        hash_check_data = CreateHash(HashType.SHA256, self.head_list.entry_count)
31740681896Sopenharmony_ci        hash_check_data.write_hashinfo()
31840681896Sopenharmony_ci        package_fd = os.open(self.save_path, os.O_RDWR | os.O_CREAT, 0o755)
31940681896Sopenharmony_ci        with os.fdopen(package_fd, "wb+") as package_file:
32040681896Sopenharmony_ci            # Add information to package
32140681896Sopenharmony_ci            if not self.write_pkginfo(package_file):
32240681896Sopenharmony_ci                UPDATE_LOGGER.print_log("Write pkginfo failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
32340681896Sopenharmony_ci                return False
32440681896Sopenharmony_ci            # Add component to package
32540681896Sopenharmony_ci            self.compinfo_offset = UPGRADE_FILE_HEADER_LEN
32640681896Sopenharmony_ci            self.component_offset = UPGRADE_FILE_HEADER_LEN + \
32740681896Sopenharmony_ci                self.head_list.entry_count * self.upgrade_compinfo_size + \
32840681896Sopenharmony_ci                UPGRADE_RESERVE_LEN + SIGN_SHA256_LEN + SIGN_SHA384_LEN
32940681896Sopenharmony_ci            for i in range(0, self.head_list.entry_count):
33040681896Sopenharmony_ci                UPDATE_LOGGER.print_log("Add component %s" % self.component_list[i].component_addr)
33140681896Sopenharmony_ci                if not self.write_component_info(self.component_list[i], package_file):
33240681896Sopenharmony_ci                    UPDATE_LOGGER.print_log("write component info failed: %s"
33340681896Sopenharmony_ci                        % self.component_list[i].component_addr, UPDATE_LOGGER.ERROR_LOG)
33440681896Sopenharmony_ci                    return False
33540681896Sopenharmony_ci                if OPTIONS_MANAGER.sd_card and (not hash_check_data.write_component_hash_data(self.component_list[i])):
33640681896Sopenharmony_ci                    UPDATE_LOGGER.print_log("write component hash data failed: %s"
33740681896Sopenharmony_ci                        % self.component_list[i].component_addr, UPDATE_LOGGER.ERROR_LOG)
33840681896Sopenharmony_ci                    return False
33940681896Sopenharmony_ci
34040681896Sopenharmony_ci            try:
34140681896Sopenharmony_ci                # Add descriptPackageId to package
34240681896Sopenharmony_ci                package_file.seek(self.compinfo_offset)
34340681896Sopenharmony_ci                package_file.write(
34440681896Sopenharmony_ci                    (self.head_list.describe_package_id.decode().ljust(UPGRADE_RESERVE_LEN, "\0")).encode())
34540681896Sopenharmony_ci            except IOError:
34640681896Sopenharmony_ci                UPDATE_LOGGER.print_log("Add descriptPackageId failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
34740681896Sopenharmony_ci                return False
34840681896Sopenharmony_ci            self.hash_info_offset = self.compinfo_offset + UPGRADE_RESERVE_LEN
34940681896Sopenharmony_ci            if OPTIONS_MANAGER.sd_card:
35040681896Sopenharmony_ci                try:
35140681896Sopenharmony_ci                    # Add hash check data to package
35240681896Sopenharmony_ci                    hash_check_data.write_hashdata()
35340681896Sopenharmony_ci                    package_file.seek(self.hash_info_offset)
35440681896Sopenharmony_ci                    package_file.write(hash_check_data.hashinfo_value + hash_check_data.hashdata)
35540681896Sopenharmony_ci                    self.hash_info_offset += len(hash_check_data.hashinfo_value + hash_check_data.hashdata)
35640681896Sopenharmony_ci
35740681896Sopenharmony_ci                except IOError:
35840681896Sopenharmony_ci                    UPDATE_LOGGER.print_log("Add hash check data failed!", log_type=UPDATE_LOGGER.ERROR_LOG)
35940681896Sopenharmony_ci                    return False
36040681896Sopenharmony_ci            self.sign_header(SIGN_ALGO_RSA, hash_check_data, package_file)
36140681896Sopenharmony_ci            self.component_offset = self.hash_info_offset
36240681896Sopenharmony_ci            for i in range(0, self.head_list.entry_count):
36340681896Sopenharmony_ci                if not self.write_component(self.component_list[i], package_file):
36440681896Sopenharmony_ci                    UPDATE_LOGGER.print_log("write component failed: %s"
36540681896Sopenharmony_ci                        % self.component_list[i].component_addr, UPDATE_LOGGER.ERROR_LOG)
36640681896Sopenharmony_ci                    return False
36740681896Sopenharmony_ci        UPDATE_LOGGER.print_log("Write update package complete")
36840681896Sopenharmony_ci        return True