diff --git a/aosp/system/tools/mkbootimg/gki/Android.bp b/aosp/system/tools/mkbootimg/gki/Android.bp index 5173852..c62e7d8 100644 --- a/aosp/system/tools/mkbootimg/gki/Android.bp +++ b/aosp/system/tools/mkbootimg/gki/Android.bp @@ -16,20 +16,6 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } -python_binary_host { - name: "certify_bootimg", - defaults: ["mkbootimg_defaults"], - main: "certify_bootimg.py", - srcs: [ - "certify_bootimg.py", - "generate_gki_certificate.py", - ], - required: [ - "avbtool", - "unpack_bootimg", - ], -} - python_test_host { name: "certify_bootimg_test", defaults: ["mkbootimg_defaults"], diff --git a/aosp/system/tools/mkbootimg/gki/certify_bootimg.py b/aosp/system/tools/mkbootimg/gki/certify_bootimg.py index 5a99c1f..2c3d80e 100755 --- a/aosp/system/tools/mkbootimg/gki/certify_bootimg.py +++ b/aosp/system/tools/mkbootimg/gki/certify_bootimg.py @@ -25,7 +25,8 @@ import shutil import subprocess import tempfile -from generate_gki_certificate import generate_gki_certificate +from gki.generate_gki_certificate import generate_gki_certificate +from unpack_bootimg import unpack_bootimg BOOT_SIGNATURE_SIZE = 16 * 1024 @@ -33,14 +34,7 @@ BOOT_SIGNATURE_SIZE = 16 * 1024 def get_kernel(boot_img): """Extracts the kernel from |boot_img| and returns it.""" with tempfile.TemporaryDirectory() as unpack_dir: - unpack_bootimg_cmd = [ - 'unpack_bootimg', - '--boot_img', boot_img, - '--out', unpack_dir, - ] - subprocess.run(unpack_bootimg_cmd, check=True, - stdout=subprocess.DEVNULL) - + unpack_bootimg(boot_img, unpack_dir) with open(os.path.join(unpack_dir, 'kernel'), 'rb') as kernel: kernel_bytes = kernel.read() assert len(kernel_bytes) > 0 @@ -138,7 +132,7 @@ def get_avb_image_size(image): return 0 -def add_avb_footer(image, partition_size): +def add_avb_footer(image, partition_size, extra_footer_args): """Appends a AVB hash footer to the image.""" avbtool_cmd = ['avbtool', 'add_hash_footer', '--image', image, @@ -149,6 +143,7 @@ def add_avb_footer(image, partition_size): else: avbtool_cmd.extend(['--dynamic_partition_size']) + avbtool_cmd.extend(extra_footer_args) subprocess.check_call(avbtool_cmd) @@ -166,6 +161,40 @@ def load_dict_from_file(path): return d +def load_gki_info_file(gki_info_file, extra_args, extra_footer_args): + """Loads extra arguments from the gki info file. + + Args: + gki_info_file: path to a gki-info.txt. + extra_args: the extra arguments forwarded to avbtool when creating + the gki certificate. + extra_footer_args: the extra arguments forwarded to avbtool when + creating the avb footer. + + """ + info_dict = load_dict_from_file(gki_info_file) + if 'certify_bootimg_extra_args' in info_dict: + extra_args.extend( + shlex.split(info_dict['certify_bootimg_extra_args'])) + if 'certify_bootimg_extra_footer_args' in info_dict: + extra_footer_args.extend( + shlex.split(info_dict['certify_bootimg_extra_footer_args'])) + + +def get_archive_name_and_format_for_shutil(path): + """Returns archive name and format to shutil.make_archive() for the |path|. + + e.g., returns ('/path/to/boot-img', 'gztar') if |path| is + '/path/to/boot-img.tar.gz'. + """ + for format_name, format_extensions, _ in shutil.get_unpack_formats(): + for extension in format_extensions: + if path.endswith(extension): + return path[:-len(extension)], format_name + + raise ValueError(f"Unsupported archive format: '{path}'") + + def parse_cmdline(): """Parse command-line options.""" parser = ArgumentParser(add_help=True) @@ -175,30 +204,50 @@ def parse_cmdline(): input_group.add_argument( '--boot_img', help='path to the boot image to certify') input_group.add_argument( - '--boot_img_zip', help='path to the boot-img-*.zip archive to certify') + '--boot_img_archive', help='path to the boot images archive to certify') parser.add_argument('--algorithm', required=True, help='signing algorithm for the certificate') parser.add_argument('--key', required=True, help='path to the RSA private key') + parser.add_argument('--gki_info', + help='path to a gki-info.txt to append additional' + 'properties into the boot signature') parser.add_argument('-o', '--output', required=True, help='output file name') # Optional args. parser.add_argument('--extra_args', default=[], action='append', help='extra arguments to be forwarded to avbtool') + parser.add_argument('--extra_footer_args', default=[], action='append', + help='extra arguments for adding the avb footer') args = parser.parse_args() + if args.gki_info and args.boot_img_archive: + parser.error('--gki_info cannot be used with --boot_image_archive. ' + 'The gki_info file should be included in the archive.') + extra_args = [] for a in args.extra_args: extra_args.extend(shlex.split(a)) args.extra_args = extra_args + extra_footer_args = [] + for a in args.extra_footer_args: + extra_footer_args.extend(shlex.split(a)) + args.extra_footer_args = extra_footer_args + + if args.gki_info: + load_gki_info_file(args.gki_info, + args.extra_args, + args.extra_footer_args) + return args -def certify_bootimg(boot_img, output_img, algorithm, key, extra_args): +def certify_bootimg(boot_img, output_img, algorithm, key, extra_args, + extra_footer_args): """Certify a GKI boot image by generating and appending a boot_signature.""" with tempfile.TemporaryDirectory() as temp_dir: boot_tmp = os.path.join(temp_dir, 'boot.tmp') @@ -208,40 +257,53 @@ def certify_bootimg(boot_img, output_img, algorithm, key, extra_args): add_certificate(boot_tmp, algorithm, key, extra_args) avb_partition_size = get_avb_image_size(boot_img) - add_avb_footer(boot_tmp, avb_partition_size) + add_avb_footer(boot_tmp, avb_partition_size, extra_footer_args) # We're done, copy the temp image to the final output. shutil.copy2(boot_tmp, output_img) -def certify_bootimg_zip(boot_img_zip, output_zip, algorithm, key, extra_args): - """Similar to certify_bootimg(), but for a zip archive of boot images.""" - with tempfile.TemporaryDirectory() as unzip_dir: - shutil.unpack_archive(boot_img_zip, unzip_dir) +def certify_bootimg_archive(boot_img_archive, output_archive, + algorithm, key, extra_args, extra_footer_args): + """Similar to certify_bootimg(), but for an archive of boot images.""" + with tempfile.TemporaryDirectory() as unpack_dir: + shutil.unpack_archive(boot_img_archive, unpack_dir) - info_dict = load_dict_from_file(os.path.join(unzip_dir, 'gki-info.txt')) - extra_args.extend(shlex.split(info_dict['certify_bootimg_extra_args'])) + gki_info_file = os.path.join(unpack_dir, 'gki-info.txt') + if os.path.exists(gki_info_file): + load_gki_info_file(gki_info_file, extra_args, extra_footer_args) - for boot_img in glob.glob(os.path.join(unzip_dir, 'boot-*.img')): + for boot_img in glob.glob(os.path.join(unpack_dir, 'boot-*.img')): print(f'Certifying {os.path.basename(boot_img)} ...') certify_bootimg(boot_img=boot_img, output_img=boot_img, - algorithm=algorithm, key=key, extra_args=extra_args) - - print(f'Making certified archive: {output_zip}') - archive_base_name = os.path.splitext(output_zip)[0] - shutil.make_archive(archive_base_name, 'zip', unzip_dir) + algorithm=algorithm, key=key, extra_args=extra_args, + extra_footer_args=extra_footer_args) + + print(f'Making certified archive: {output_archive}') + archive_file_name, archive_format = ( + get_archive_name_and_format_for_shutil(output_archive)) + built_archive = shutil.make_archive(archive_file_name, + archive_format, + unpack_dir) + # shutil.make_archive() builds *.tar.gz when then |archive_format| is + # 'gztar'. However, the end user might specify |output_archive| with + # *.tgz. Renaming *.tar.gz to *.tgz for this case. + if built_archive != os.path.realpath(output_archive): + print(f'Renaming {built_archive} -> {output_archive} ...') + os.rename(built_archive, output_archive) def main(): """Parse arguments and certify the boot image.""" args = parse_cmdline() - if args.boot_img_zip: - certify_bootimg_zip(args.boot_img_zip, args.output, args.algorithm, - args.key, args.extra_args) + if args.boot_img_archive: + certify_bootimg_archive(args.boot_img_archive, args.output, + args.algorithm, args.key, args.extra_args, + args.extra_footer_args) else: certify_bootimg(args.boot_img, args.output, args.algorithm, - args.key, args.extra_args) + args.key, args.extra_args, args.extra_footer_args) if __name__ == '__main__': diff --git a/aosp/system/tools/mkbootimg/gki/certify_bootimg_test.py b/aosp/system/tools/mkbootimg/gki/certify_bootimg_test.py index 5fffed2..779c46f 100644 --- a/aosp/system/tools/mkbootimg/gki/certify_bootimg_test.py +++ b/aosp/system/tools/mkbootimg/gki/certify_bootimg_test.py @@ -68,18 +68,27 @@ def generate_test_boot_image(boot_img, kernel_size=4096, seed='kernel', subprocess.check_call(avbtool_cmd) -def generate_test_boot_image_archive(output_zip, boot_img_info): - """Generates a zip archive of test boot images. +def generate_test_boot_image_archive(archive_file_name, archive_format, + boot_img_info, gki_info=None): + """Generates an archive of test boot images. It also adds a file gki-info.txt, which contains additional settings for for `certify_bootimg --extra_args`. Args: - output_zip: the output zip archive, e.g., /path/to/boot-img.zip. + archive_file_name: the name of the archive file to create, including the + path, minus any format-specific extension. + archive_format: the |format| parameter for shutil.make_archive(). + e.g., 'zip', 'tar', or 'gztar', etc. boot_img_info: a list of (boot_image_name, kernel_size, partition_size) tuples. e.g., [('boot-1.0.img', 4096, 4 * 1024), ('boot-2.0.img', 8192, 8 * 1024)]. + gki_info: the file content to be written into 'gki-info.txt' in the + created archive. + + Returns: + The full path of the created archive. e.g., /path/to/boot-img.tar.gz. """ with tempfile.TemporaryDirectory() as temp_out_dir: for name, kernel_size, partition_size in boot_img_info: @@ -89,17 +98,14 @@ def generate_test_boot_image_archive(output_zip, boot_img_info): seed=name, avb_partition_size=partition_size) - gki_info = os.path.join(temp_out_dir, 'gki-info.txt') - with open(gki_info, 'w', encoding='utf-8') as f: - f.write('certify_bootimg_extra_args=' - '--prop KERNEL_RELEASE:5.10.42' - '-android13-0-00544-ged21d463f856 ' - '--prop BRANCH:android13-5.10-2022-05 ' - '--prop BUILD_NUMBER:ab8295296 ' - '--prop SPACE:"nice to meet you"\n') + if gki_info: + gki_info_path = os.path.join(temp_out_dir, 'gki-info.txt') + with open(gki_info_path, 'w', encoding='utf-8') as f: + f.write(gki_info) - archive_base_name = os.path.splitext(output_zip)[0] - shutil.make_archive(archive_base_name, 'zip', temp_out_dir) + return shutil.make_archive(archive_file_name, + archive_format, + temp_out_dir) def has_avb_footer(image): @@ -177,10 +183,10 @@ def extract_boot_signatures(boot_img, output_dir): boot_signature_bytes = boot_signature_bytes[next_signature_size:] -def extract_boot_archive_with_signatures(boot_img_zip, output_dir): +def extract_boot_archive_with_signatures(boot_img_archive, output_dir): """Extracts boot images and signatures of a boot images archive. - Suppose there are two boot images in |boot_img_zip|: boot-1.0.img + Suppose there are two boot images in |boot_img_archive|: boot-1.0.img and boot-2.0.img. This function then extracts each boot-*.img and their signatures as: - |output_dir|/boot-1.0.img @@ -190,7 +196,7 @@ def extract_boot_archive_with_signatures(boot_img_zip, output_dir): - |output_dir|/boot-2.0/boot_signature1 - |output_dir|/boot-2.0/boot_signature2 """ - shutil.unpack_archive(boot_img_zip, output_dir) + shutil.unpack_archive(boot_img_archive, output_dir) for boot_img in glob.glob(os.path.join(output_dir, 'boot-*.img')): img_name = os.path.splitext(os.path.basename(boot_img))[0] signature_output_dir = os.path.join(output_dir, img_name) @@ -213,6 +219,197 @@ class CertifyBootimgTest(unittest.TestCase): # C0103: invalid-name for maxDiff. self.maxDiff = None # pylint: disable=C0103 + # For AVB footers, we don't sign it so the Authentication block + # is zero bytes and the Algorithm is NONE. The footer will be + # replaced by device-specific settings when being incorporated into + # a device codebase. The footer here is just to pass some GKI + # pre-release test. + self._EXPECTED_AVB_FOOTER_BOOT_CERTIFIED = ( # pylint: disable=C0103 + 'Footer version: 1.0\n' + 'Image size: 131072 bytes\n' + 'Original image size: 24576 bytes\n' + 'VBMeta offset: 24576\n' + 'VBMeta size: 576 bytes\n' + '--\n' + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 0 bytes\n' + 'Auxiliary Block: 320 bytes\n' + 'Algorithm: NONE\n' + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 24576 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: boot\n' + ' Salt: a11ba11b\n' + ' Digest: ' + 'c9b4ad78fae6f72f7eff939dee6078ed' + '8a75132e53f6c11ba1ec0f4b57f9eab0\n' + ' Flags: 0\n' + " Prop: avb -> 'nice'\n" + " Prop: avb_space -> 'nice to meet you'\n" + ) + + self._EXPECTED_AVB_FOOTER_BOOT_CERTIFIED_2 = ( # pylint: disable=C0103 + 'Footer version: 1.0\n' + 'Image size: 131072 bytes\n' + 'Original image size: 24576 bytes\n' + 'VBMeta offset: 24576\n' + 'VBMeta size: 576 bytes\n' + '--\n' + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 0 bytes\n' + 'Auxiliary Block: 320 bytes\n' + 'Algorithm: NONE\n' + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 24576 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: boot\n' + ' Salt: a11ba11b\n' + ' Digest: ' + 'ae2538e78b2a30b1112cede30d858a5f' + '6f8dc2a1b109dd4a7bb28124b77d2ab0\n' + ' Flags: 0\n' + " Prop: avb -> 'nice'\n" + " Prop: avb_space -> 'nice to meet you'\n" + ) + + self._EXPECTED_AVB_FOOTER_WITH_GKI_INFO = ( # pylint: disable=C0103 + 'Footer version: 1.0\n' + 'Image size: 131072 bytes\n' + 'Original image size: 24576 bytes\n' + 'VBMeta offset: 24576\n' + 'VBMeta size: 704 bytes\n' + '--\n' + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 0 bytes\n' + 'Auxiliary Block: 448 bytes\n' + 'Algorithm: NONE\n' + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 24576 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: boot\n' + ' Salt: a11ba11b\n' + ' Digest: ' + '363d4f246a4a5e1bba8ba8b86f5eb0cf' + '9817e4e51663ba26edccf71c3861090a\n' + ' Flags: 0\n' + " Prop: avb -> 'nice'\n" + " Prop: avb_space -> 'nice to meet you'\n" + " Prop: com.android.build.boot.os_version -> '13'\n" + " Prop: com.android.build.boot.security_patch -> '2022-05-05'\n" + ) + + self._EXPECTED_AVB_FOOTER_BOOT_1_0 = ( # pylint: disable=C0103 + 'Footer version: 1.0\n' + 'Image size: 131072 bytes\n' + 'Original image size: 28672 bytes\n' + 'VBMeta offset: 28672\n' + 'VBMeta size: 704 bytes\n' + '--\n' + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 0 bytes\n' + 'Auxiliary Block: 448 bytes\n' + 'Algorithm: NONE\n' + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 28672 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: boot\n' + ' Salt: a11ba11b\n' + ' Digest: ' + '634e60e08f5b83842c70fa0efa05de87' + '643cd75357f06eff9acc3d1f93e26795\n' + ' Flags: 0\n' + " Prop: avb -> 'nice'\n" + " Prop: avb_space -> 'nice to meet you'\n" + " Prop: com.android.build.boot.os_version -> '13'\n" + " Prop: com.android.build.boot.security_patch -> '2022-05-05'\n" + ) + + self._EXPECTED_AVB_FOOTER_BOOT_2_0 = ( # pylint: disable=C0103 + 'Footer version: 1.0\n' + 'Image size: 262144 bytes\n' + 'Original image size: 36864 bytes\n' + 'VBMeta offset: 36864\n' + 'VBMeta size: 704 bytes\n' + '--\n' + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 0 bytes\n' + 'Auxiliary Block: 448 bytes\n' + 'Algorithm: NONE\n' + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 36864 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: boot\n' + ' Salt: a11ba11b\n' + ' Digest: ' + 'f9bb362d8d0e6559f9f8f42eeaf4da9f' + '0fca6093de74ac406f76719fd0b20102\n' + ' Flags: 0\n' + " Prop: avb -> 'nice'\n" + " Prop: avb_space -> 'nice to meet you'\n" + " Prop: com.android.build.boot.os_version -> '13'\n" + " Prop: com.android.build.boot.security_patch -> '2022-05-05'\n" + ) + + self._EXPECTED_AVB_FOOTER_BOOT_3_0 = ( # pylint: disable=C0103 + 'Footer version: 1.0\n' + 'Image size: 131072 bytes\n' + 'Original image size: 28672 bytes\n' + 'VBMeta offset: 28672\n' + 'VBMeta size: 576 bytes\n' + '--\n' + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 0 bytes\n' + 'Auxiliary Block: 320 bytes\n' + 'Algorithm: NONE\n' + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 28672 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: boot\n' + ' Salt: a11ba11b\n' + ' Digest: ' + 'fb0326a78b3794c79fad414d10f8d69a' + '86a0da49e5320bd5b4fc09272cb2cad9\n' + ' Flags: 0\n' + " Prop: avb -> 'nice'\n" + " Prop: avb_space -> 'nice to meet you'\n" + ) + self._EXPECTED_BOOT_SIGNATURE_RSA2048 = ( # pylint: disable=C0103 'Minimum libavb version: 1.0\n' 'Header Block: 256 bytes\n' @@ -317,6 +514,68 @@ class CertifyBootimgTest(unittest.TestCase): " Prop: space -> 'nice to meet you'\n" ) + self._EXPECTED_BOOT_SIGNATURE_WITH_GKI_INFO = ( # pylint: disable=C0103 + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 576 bytes\n' + 'Auxiliary Block: 1600 bytes\n' + 'Public key (sha1): ' + '2597c218aae470a130f61162feaae70afd97f011\n' + 'Algorithm: SHA256_RSA4096\n' # RSA4096 + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 8192 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: boot\n' # boot + ' Salt: d00df00d\n' + ' Digest: ' + 'faf1da72a4fba97ddab0b8f7a410db86' + '8fb72392a66d1440ff8bff490c73c771\n' + ' Flags: 0\n' + " Prop: gki -> 'nice'\n" + " Prop: space -> 'nice to meet you'\n" + " Prop: KERNEL_RELEASE -> '5.10.42-android13-0-00544-" + "ged21d463f856'\n" + " Prop: BRANCH -> 'android13-5.10-2022-05'\n" + " Prop: BUILD_NUMBER -> 'ab8295296'\n" + " Prop: GKI_INFO -> 'added here'\n" + ) + + self._EXPECTED_KERNEL_SIGNATURE_WITH_GKI_INFO = (# pylint: disable=C0103 + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 576 bytes\n' + 'Auxiliary Block: 1600 bytes\n' + 'Public key (sha1): ' + '2597c218aae470a130f61162feaae70afd97f011\n' + 'Algorithm: SHA256_RSA4096\n' # RSA4096 + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 4096 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: generic_kernel\n' # generic_kernel + ' Salt: d00df00d\n' + ' Digest: ' + '762c877f3af0d50a4a4fbc1385d5c7ce' + '52a1288db74b33b72217d93db6f2909f\n' + ' Flags: 0\n' + " Prop: gki -> 'nice'\n" + " Prop: space -> 'nice to meet you'\n" + " Prop: KERNEL_RELEASE -> '5.10.42-android13-0-00544-" + "ged21d463f856'\n" + " Prop: BRANCH -> 'android13-5.10-2022-05'\n" + " Prop: BUILD_NUMBER -> 'ab8295296'\n" + " Prop: GKI_INFO -> 'added here'\n" + ) + self._EXPECTED_BOOT_1_0_SIGNATURE1_RSA4096 = ( # pylint: disable=C0103 'Minimum libavb version: 1.0\n' 'Header Block: 256 bytes\n' @@ -441,6 +700,58 @@ class CertifyBootimgTest(unittest.TestCase): " Prop: SPACE -> 'nice to meet you'\n" ) + self._EXPECTED_BOOT_3_0_SIGNATURE1_RSA4096 = ( # pylint: disable=C0103 + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 576 bytes\n' + 'Auxiliary Block: 1344 bytes\n' + 'Public key (sha1): ' + '2597c218aae470a130f61162feaae70afd97f011\n' + 'Algorithm: SHA256_RSA4096\n' # RSA4096 + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 12288 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: boot\n' # boot + ' Salt: d00df00d\n' + ' Digest: ' + '9b9cd845a367d7fc9b61d6ac02b0e7c9' + 'dc3d3b219abf60dd6e19359f0353c917\n' + ' Flags: 0\n' + " Prop: gki -> 'nice'\n" + " Prop: space -> 'nice to meet you'\n" + ) + + self._EXPECTED_BOOT_3_0_SIGNATURE2_RSA4096 = ( # pylint: disable=C0103 + 'Minimum libavb version: 1.0\n' + 'Header Block: 256 bytes\n' + 'Authentication Block: 576 bytes\n' + 'Auxiliary Block: 1344 bytes\n' + 'Public key (sha1): ' + '2597c218aae470a130f61162feaae70afd97f011\n' + 'Algorithm: SHA256_RSA4096\n' # RSA4096 + 'Rollback Index: 0\n' + 'Flags: 0\n' + 'Rollback Index Location: 0\n' + "Release String: 'avbtool 1.2.0'\n" + 'Descriptors:\n' + ' Hash descriptor:\n' + ' Image Size: 8192 bytes\n' + ' Hash Algorithm: sha256\n' + ' Partition Name: generic_kernel\n' # generic_kernel + ' Salt: d00df00d\n' + ' Digest: ' + '0cd7d331ed9b32dcd92f00e2cac75595' + '52199170afe788a8fcf1954f9ea072d0\n' + ' Flags: 0\n' + " Prop: gki -> 'nice'\n" + " Prop: space -> 'nice to meet you'\n" + ) + def _test_boot_signatures(self, signatures_dir, expected_signatures_info): """Tests the info of each boot signature under the signature directory. @@ -527,6 +838,8 @@ class CertifyBootimgTest(unittest.TestCase): '--key', './testdata/testkey_rsa2048.pem', '--extra_args', '--prop gki:nice ' '--prop space:"nice to meet you"', + '--extra_footer_args', '--salt a11ba11b --prop avb:nice ' + '--prop avb_space:"nice to meet you"', '--output', boot_certified_img, ] subprocess.run(certify_bootimg_cmds, check=True, cwd=self._exec_dir) @@ -535,7 +848,13 @@ class CertifyBootimgTest(unittest.TestCase): self.assertTrue(has_avb_footer(boot_certified_img)) self.assertEqual(os.path.getsize(boot_img), os.path.getsize(boot_certified_img)) + # Checks the content in the AVB footer. + self._test_boot_signatures( + temp_out_dir, + {'boot-certified.img': + self._EXPECTED_AVB_FOOTER_BOOT_CERTIFIED}) + # Checks the content in the GKI certificate. extract_boot_signatures(boot_certified_img, temp_out_dir) self._test_boot_signatures( temp_out_dir, @@ -552,6 +871,8 @@ class CertifyBootimgTest(unittest.TestCase): '--key', './testdata/testkey_rsa4096.pem', '--extra_args', '--prop gki:nice ' '--prop space:"nice to meet you"', + '--extra_footer_args', '--salt a11ba11b --prop avb:nice ' + '--prop avb_space:"nice to meet you"', '--output', boot_certified2_img, ] subprocess.run(certify_bootimg_cmds, check=True, cwd=self._exec_dir) @@ -560,13 +881,77 @@ class CertifyBootimgTest(unittest.TestCase): self.assertTrue(has_avb_footer(boot_certified2_img)) self.assertEqual(os.path.getsize(boot_certified_img), os.path.getsize(boot_certified2_img)) + # Checks the content in the AVB footer. + self._test_boot_signatures( + temp_out_dir, + {'boot-certified2.img': + self._EXPECTED_AVB_FOOTER_BOOT_CERTIFIED_2}) + # Checks the content in the GKI certificate. extract_boot_signatures(boot_certified2_img, temp_out_dir) self._test_boot_signatures( temp_out_dir, {'boot_signature1': self._EXPECTED_BOOT_SIGNATURE_RSA4096, 'boot_signature2': self._EXPECTED_KERNEL_SIGNATURE_RSA4096}) + def test_certify_bootimg_with_gki_info(self): + """Tests certify_bootimg with --gki_info.""" + with tempfile.TemporaryDirectory() as temp_out_dir: + boot_img = os.path.join(temp_out_dir, 'boot.img') + generate_test_boot_image(boot_img=boot_img, + avb_partition_size=128 * 1024) + self.assertTrue(has_avb_footer(boot_img)) + + gki_info = ('certify_bootimg_extra_args=' + '--prop KERNEL_RELEASE:5.10.42' + '-android13-0-00544-ged21d463f856 ' + '--prop BRANCH:android13-5.10-2022-05 ' + '--prop BUILD_NUMBER:ab8295296 ' + '--prop GKI_INFO:"added here"\n' + 'certify_bootimg_extra_footer_args=' + '--prop com.android.build.boot.os_version:13 ' + '--prop com.android.build.boot.security_patch:' + '2022-05-05\n') + gki_info_path = os.path.join(temp_out_dir, 'gki-info.txt') + with open(gki_info_path, 'w', encoding='utf-8') as f: + f.write(gki_info) + + # Certifies the boot image with --gki_info. + boot_certified_img = os.path.join(temp_out_dir, + 'boot-certified.img') + certify_bootimg_cmds = [ + 'certify_bootimg', + '--boot_img', boot_img, + '--algorithm', 'SHA256_RSA4096', + '--key', './testdata/testkey_rsa4096.pem', + '--extra_args', '--prop gki:nice ' + '--prop space:"nice to meet you"', + '--extra_footer_args', '--salt a11ba11b --prop avb:nice ' + '--prop avb_space:"nice to meet you"', + '--gki_info', gki_info_path, + '--output', boot_certified_img, + ] + subprocess.run(certify_bootimg_cmds, check=True, cwd=self._exec_dir) + + # Checks an AVB footer exists and the image size remains. + self.assertTrue(has_avb_footer(boot_certified_img)) + self.assertEqual(os.path.getsize(boot_img), + os.path.getsize(boot_certified_img)) + + # Checks the content in the AVB footer. + self._test_boot_signatures( + temp_out_dir, + {'boot-certified.img': self._EXPECTED_AVB_FOOTER_WITH_GKI_INFO}) + + # Checks the content in the GKI certificate. + extract_boot_signatures(boot_certified_img, temp_out_dir) + self._test_boot_signatures( + temp_out_dir, + {'boot_signature1': + self._EXPECTED_BOOT_SIGNATURE_WITH_GKI_INFO, + 'boot_signature2': + self._EXPECTED_KERNEL_SIGNATURE_WITH_GKI_INFO}) + def test_certify_bootimg_exceed_size(self): """Tests the boot signature size exceeded max size of the signature.""" with tempfile.TemporaryDirectory() as temp_out_dir: @@ -597,30 +982,44 @@ class CertifyBootimgTest(unittest.TestCase): err.stderr) def test_certify_bootimg_archive(self): - """Tests certify_bootimg for a boot-img.zip.""" + """Tests certify_bootimg for a boot images archive..""" with tempfile.TemporaryDirectory() as temp_out_dir: - boot_img_zip = os.path.join(temp_out_dir, 'boot-img.zip') - generate_test_boot_image_archive( - boot_img_zip, + boot_img_archive_name = os.path.join(temp_out_dir, 'boot-img') + gki_info = ('certify_bootimg_extra_args=' + '--prop KERNEL_RELEASE:5.10.42' + '-android13-0-00544-ged21d463f856 ' + '--prop BRANCH:android13-5.10-2022-05 ' + '--prop BUILD_NUMBER:ab8295296 ' + '--prop SPACE:"nice to meet you"\n' + 'certify_bootimg_extra_footer_args=' + '--prop com.android.build.boot.os_version:13 ' + '--prop com.android.build.boot.security_patch:' + '2022-05-05\n') + boot_img_archive_path = generate_test_boot_image_archive( + boot_img_archive_name, + 'gztar', # A list of (boot_img_name, kernel_size, partition_size). [('boot-1.0.img', 8 * 1024, 128 * 1024), - ('boot-2.0.img', 16 * 1024, 256 * 1024)]) + ('boot-2.0.img', 16 * 1024, 256 * 1024)], + gki_info) # Certify the boot image archive, with a RSA4096 key. - boot_certified_img_zip = os.path.join(temp_out_dir, - 'boot-certified-img.zip') + boot_certified_img_archive = os.path.join( + temp_out_dir, 'boot-certified-img.tar.gz') certify_bootimg_cmds = [ 'certify_bootimg', - '--boot_img_zip', boot_img_zip, + '--boot_img_archive', boot_img_archive_path, '--algorithm', 'SHA256_RSA4096', '--key', './testdata/testkey_rsa4096.pem', '--extra_args', '--prop gki:nice ' '--prop space:"nice to meet you"', - '--output', boot_certified_img_zip, + '--extra_footer_args', '--salt a11ba11b --prop avb:nice ' + '--prop avb_space:"nice to meet you"', + '--output', boot_certified_img_archive, ] subprocess.run(certify_bootimg_cmds, check=True, cwd=self._exec_dir) - extract_boot_archive_with_signatures(boot_certified_img_zip, + extract_boot_archive_with_signatures(boot_certified_img_archive, temp_out_dir) # Checks an AVB footer exists and the image size remains. @@ -632,6 +1031,13 @@ class CertifyBootimgTest(unittest.TestCase): self.assertTrue(has_avb_footer(boot_2_img)) self.assertEqual(os.path.getsize(boot_2_img), 256 * 1024) + # Checks the content in the AVB footer. + self._test_boot_signatures( + temp_out_dir, + {'boot-1.0.img': self._EXPECTED_AVB_FOOTER_BOOT_1_0, + 'boot-2.0.img': self._EXPECTED_AVB_FOOTER_BOOT_2_0}) + + # Checks the content in the GKI certificate. self._test_boot_signatures( temp_out_dir, {'boot-1.0/boot_signature1': @@ -643,6 +1049,81 @@ class CertifyBootimgTest(unittest.TestCase): 'boot-2.0/boot_signature2': self._EXPECTED_BOOT_2_0_SIGNATURE2_RSA4096}) + def test_certify_bootimg_archive_without_gki_info(self): + """Tests certify_bootimg for a boot images archive.""" + with tempfile.TemporaryDirectory() as temp_out_dir: + boot_img_archive_name = os.path.join(temp_out_dir, 'boot-img') + + # Checks ceritfy_bootimg works for a boot images archive without a + # gki-info.txt. Using *.zip -> *.tar. + boot_img_archive_path = generate_test_boot_image_archive( + boot_img_archive_name, + 'zip', + # A list of (boot_img_name, kernel_size, partition_size). + [('boot-3.0.img', 8 * 1024, 128 * 1024)], + gki_info=None) + # Certify the boot image archive, with a RSA4096 key. + boot_certified_img_archive = os.path.join( + temp_out_dir, 'boot-certified-img.tar') + certify_bootimg_cmds = [ + 'certify_bootimg', + '--boot_img_archive', boot_img_archive_path, + '--algorithm', 'SHA256_RSA4096', + '--key', './testdata/testkey_rsa4096.pem', + '--extra_args', '--prop gki:nice ' + '--prop space:"nice to meet you"', + '--extra_footer_args', '--salt a11ba11b --prop avb:nice ' + '--prop avb_space:"nice to meet you"', + '--output', boot_certified_img_archive, + ] + subprocess.run(certify_bootimg_cmds, check=True, cwd=self._exec_dir) + + # Checks ceritfy_bootimg works for a boot images archive with a + # special gki-info.txt. Using *.tar -> *.tgz. + boot_img_archive_path = generate_test_boot_image_archive( + boot_img_archive_name, + 'tar', + # A list of (boot_img_name, kernel_size, partition_size). + [('boot-3.0.img', 8 * 1024, 128 * 1024)], + gki_info='a=b\n' + 'c=d\n') + # Certify the boot image archive, with a RSA4096 key. + boot_certified_img_archive2 = os.path.join( + temp_out_dir, 'boot-certified-img.tgz') + certify_bootimg_cmds = [ + 'certify_bootimg', + '--boot_img_archive', boot_img_archive_path, + '--algorithm', 'SHA256_RSA4096', + '--key', './testdata/testkey_rsa4096.pem', + '--extra_args', '--prop gki:nice ' + '--prop space:"nice to meet you"', + '--extra_footer_args', '--salt a11ba11b --prop avb:nice ' + '--prop avb_space:"nice to meet you"', + '--output', boot_certified_img_archive2, + ] + subprocess.run(certify_bootimg_cmds, check=True, cwd=self._exec_dir) + + extract_boot_archive_with_signatures(boot_certified_img_archive2, + temp_out_dir) + + # Checks an AVB footer exists and the image size remains. + boot_3_img = os.path.join(temp_out_dir, 'boot-3.0.img') + self.assertTrue(has_avb_footer(boot_3_img)) + self.assertEqual(os.path.getsize(boot_3_img), 128 * 1024) + + # Checks the content in the AVB footer. + self._test_boot_signatures( + temp_out_dir, + {'boot-3.0.img': self._EXPECTED_AVB_FOOTER_BOOT_3_0}) + + # Checks the content in the GKI certificate. + self._test_boot_signatures( + temp_out_dir, + {'boot-3.0/boot_signature1': + self._EXPECTED_BOOT_3_0_SIGNATURE1_RSA4096, + 'boot-3.0/boot_signature2': + self._EXPECTED_BOOT_3_0_SIGNATURE2_RSA4096}) + # I don't know how, but we need both the logger configuration and verbosity # level > 2 to make atest work. And yes this line needs to be at the very top diff --git a/bbootimg/build.gradle.kts b/bbootimg/build.gradle.kts index 8a6810d..4817699 100644 --- a/bbootimg/build.gradle.kts +++ b/bbootimg/build.gradle.kts @@ -34,8 +34,7 @@ dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("cc.cfig:io:0.2") - implementation("org.slf4j:slf4j-simple:1.7.36") - implementation("org.slf4j:slf4j-api:1.7.36") + implementation("ch.qos.logback:logback-classic:1.2.11") implementation("com.fasterxml.jackson.core:jackson-annotations:2.13.1") implementation("com.fasterxml.jackson.core:jackson-databind:2.13.1") implementation("com.google.guava:guava:31.0.1-jre") diff --git a/bbootimg/src/main/kotlin/bootimg/Common.kt b/bbootimg/src/main/kotlin/bootimg/Common.kt index a240100..7e72b0f 100644 --- a/bbootimg/src/main/kotlin/bootimg/Common.kt +++ b/bbootimg/src/main/kotlin/bootimg/Common.kt @@ -223,18 +223,6 @@ class Common { return md.digest() } - fun assertFileEquals(file1: String, file2: String) { - val hash1 = hashFileAndSize(file1) - val hash2 = hashFileAndSize(file2) - log.info("$file1 hash ${Helper.toHexString(hash1)}, $file2 hash ${Helper.toHexString(hash2)}") - if (hash1.contentEquals(hash2)) { - log.info("Hash verification passed: ${Helper.toHexString(hash1)}") - } else { - log.error("Hash verification failed") - throw UnknownError("Do not know why hash verification fails, maybe a bug") - } - } - //using mkbootfs fun packRootfs(rootDir: String, ramdiskGz: String, osMajor: Int = 10) { val mkbootfs = String.format(Locale.getDefault(), Helper.prop("mkbootfsBin"), osMajor) diff --git a/bbootimg/src/main/kotlin/bootimg/Signer.kt b/bbootimg/src/main/kotlin/bootimg/Signer.kt index 66b1106..1c7528a 100644 --- a/bbootimg/src/main/kotlin/bootimg/Signer.kt +++ b/bbootimg/src/main/kotlin/bootimg/Signer.kt @@ -69,7 +69,7 @@ class Signer { File("$output.clear").copyTo(File("$output.signed2"), overwrite = true) DefaultExecutor().execute(this) } - Common.assertFileEquals("$output.signed", "$output.signed2") + Helper.assertFileEquals("$output.signed", "$output.signed2") //TODO: decide what to verify //Parser.verifyAVBIntegrity(cfg.info.output + ".signed", avbtool) //Parser.verifyAVBIntegrity(cfg.info.output + ".signed2", avbtool) diff --git a/bbootimg/src/main/kotlin/bootimg/cpio/AndroidCpio.kt b/bbootimg/src/main/kotlin/bootimg/cpio/AndroidCpio.kt index 65af803..6f657ae 100644 --- a/bbootimg/src/main/kotlin/bootimg/cpio/AndroidCpio.kt +++ b/bbootimg/src/main/kotlin/bootimg/cpio/AndroidCpio.kt @@ -149,8 +149,15 @@ class AndroidCpio { else -> { //Issue #75: https://github.com/cfig/Android_boot_image_editor/issues/75 //Reason: cpio may have multiple entries with the same name, that's caused by man-made errors - throw IllegalArgumentException("${entry.name} has multiple exact-match fsConfig, " + - "check https://github.com/cfig/Android_boot_image_editor/issues/75") + val msg = "(${entry.name} has multiple exact-match fsConfig, " + + "check https://github.com/cfig/Android_boot_image_editor/issues/75" + errLog.warn("IllegalArgumentException$msg") + if (Helper.prop("config.allow_cpio_duplicate") == "true") { + log.warn("IllegalArgumentException$msg") + entry.statMode = itemConfig[0].statMode + } else { + throw IllegalArgumentException(msg) + } } } } @@ -198,6 +205,7 @@ class AndroidCpio { companion object { private val log = LoggerFactory.getLogger(AndroidCpio::class.java) + private val errLog = LoggerFactory.getLogger("uiderrors") private val PERM_MASK = java.lang.Long.valueOf("777", 8) fun decompressCPIO(cpioFile: String, outDir: String, fileList: String? = null) { run { //clean up diff --git a/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt b/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt index 459649f..52dce79 100644 --- a/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt +++ b/bbootimg/src/main/kotlin/bootimg/v2/BootV2.kt @@ -437,7 +437,7 @@ data class BootV2( DefaultExecutor().execute(this) } - Common.assertFileEquals("${info.output}.clear", "${info.output}.google") + Helper.assertFileEquals("${info.output}.clear", "${info.output}.google") return this } diff --git a/bbootimg/src/main/kotlin/bootimg/v2/BootV2Dialects.kt b/bbootimg/src/main/kotlin/bootimg/v2/BootV2Dialects.kt index 96105f5..807fab0 100644 --- a/bbootimg/src/main/kotlin/bootimg/v2/BootV2Dialects.kt +++ b/bbootimg/src/main/kotlin/bootimg/v2/BootV2Dialects.kt @@ -456,7 +456,7 @@ data class BootV2Dialects( DefaultExecutor().execute(this) } - Common.assertFileEquals("${info.output}.clear", "${info.output}.google") + Helper.assertFileEquals("${info.output}.clear", "${info.output}.google") return this } diff --git a/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt b/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt index 61524aa..6179e4f 100644 --- a/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt +++ b/bbootimg/src/main/kotlin/bootimg/v3/BootV3.kt @@ -44,6 +44,7 @@ data class BootV3( ) { companion object { private val log = LoggerFactory.getLogger(BootV3::class.java) + private val errLog = LoggerFactory.getLogger("uiderrors") private val mapper = ObjectMapper() private val workDir = Helper.prop("workDir") @@ -123,6 +124,16 @@ data class BootV3( //header FileOutputStream(this.info.output + ".clear", false).use { fos -> + //trim bootSig if it's not parsable + //https://github.com/cfig/Android_boot_image_editor/issues/88 + File(Avb.getJsonFileName(this.bootSignature.file)).let { bootSigJson -> + if (!bootSigJson.exists()) { + errLog.info( + "erase unparsable boot signature in header. Refer to https://github.com/cfig/Android_boot_image_editor/issues/88" + ) + this.info.signatureSize = 0 + } + } val encodedHeader = this.toHeader().encode() fos.write(encodedHeader) fos.write( @@ -160,9 +171,13 @@ data class BootV3( readBackBootSig.auxBlob!!.hashDescriptors.get(0).update(this.info.output + ".clear") bootSigBytes = readBackBootSig.encodePadded() } - //write V4 data - FileOutputStream("${this.info.output}.clear", true).use { fos -> - fos.write(bootSigBytes) + if (this.info.signatureSize > 0) { + //write V4 data + FileOutputStream("${this.info.output}.clear", true).use { fos -> + fos.write(bootSigBytes) + } + } else { + errLog.info("ignore bootsig for v4 boot.img") } } @@ -172,7 +187,7 @@ data class BootV3( DefaultExecutor().execute(it) } - C.assertFileEquals(this.info.output + ".clear", this.info.output + ".google") + Helper.assertFileEquals(this.info.output + ".clear", this.info.output + ".google") return this } diff --git a/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt b/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt index ddeb5dd..3ecdbb7 100644 --- a/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt +++ b/bbootimg/src/main/kotlin/bootimg/v3/VendorBoot.kt @@ -305,7 +305,7 @@ data class VendorBoot( DefaultExecutor().execute(it) } - C.assertFileEquals(this.info.output + ".clear", this.info.output + ".google") + Helper.assertFileEquals(this.info.output + ".clear", this.info.output + ".google") return this } diff --git a/bbootimg/src/main/resources/general.cfg b/bbootimg/src/main/resources/general.cfg index a2343b8..ea87eb3 100644 --- a/bbootimg/src/main/resources/general.cfg +++ b/bbootimg/src/main/resources/general.cfg @@ -10,3 +10,4 @@ kernelExtracter = aosp/build/tools/extract_kernel.py mkbootimg = aosp/system/tools/mkbootimg/mkbootimg.py dtboMaker = aosp/system/libufdt/utils/src/mkdtboimg.py payloadDir = build/payload/ +config.allow_cpio_duplicate = true diff --git a/bbootimg/src/main/resources/logback.xml b/bbootimg/src/main/resources/logback.xml new file mode 100644 index 0000000..caa698c --- /dev/null +++ b/bbootimg/src/main/resources/logback.xml @@ -0,0 +1,21 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + uiderrors + + %date %level [%thread] %logger{10} [%file:%line] %msg%n + + + + + + + + + + diff --git a/bbootimg/src/main/resources/simplelogger.properties b/bbootimg/src/main/resources/simplelogger.properties deleted file mode 100644 index 578abb6..0000000 --- a/bbootimg/src/main/resources/simplelogger.properties +++ /dev/null @@ -1,5 +0,0 @@ -org.slf4j.simpleLogger.defaultLogLevel = info -org.slf4j.simpleLogger.showDateTime = true -org.slf4j.simpleLogger.dateTimeFormat = HH:mm:ss:SSS -org.slf4j.simpleLogger.showThreadName = false -org.slf4j.simpleLogger.showShortLogName = true diff --git a/bbootimg/src/test/resources/simplelogger.properties b/bbootimg/src/test/resources/simplelogger.properties deleted file mode 100644 index 2c0452b..0000000 --- a/bbootimg/src/test/resources/simplelogger.properties +++ /dev/null @@ -1 +0,0 @@ -org.slf4j.simpleLogger.defaultLogLevel = debug diff --git a/helper/build.gradle.kts b/helper/build.gradle.kts index 8feb1bb..4731a6c 100644 --- a/helper/build.gradle.kts +++ b/helper/build.gradle.kts @@ -35,8 +35,7 @@ dependencies { implementation("cc.cfig:io:0.2") implementation("com.google.guava:guava:31.0.1-jre") - implementation("org.slf4j:slf4j-api:1.7.32") - implementation("org.slf4j:slf4j-simple:1.7.32") + implementation("ch.qos.logback:logback-classic:1.2.11") implementation("org.apache.commons:commons-exec:1.3") implementation("org.bouncycastle:bcprov-jdk15on:1.69") implementation("org.bouncycastle:bcpkix-jdk15on:1.69") //org.bouncycastle.pkcs diff --git a/integrationTest.py b/integrationTest.py index 6db1659..e2f1ecb 100755 --- a/integrationTest.py +++ b/integrationTest.py @@ -37,7 +37,7 @@ def deleteIfExists(inFile): def cleanUp(): log.info("clean up ...") - shutil.rmtree("build", ignore_errors = True) + shutil.rmtree("build/unzip_boot", ignore_errors = True) [deleteIfExists(item) for item in [ "boot.img", "boot.img.clear", "boot.img.google", "boot.img.signed", "boot.img.signed2", "recovery.img", "recovery.img.clear", "recovery.img.google", "recovery.img.signed", "recovery.img.signed2", @@ -165,6 +165,9 @@ def main(): verifySingleDir(resDir2, "issue_83") # Issue 86: vendor_boot with vrt and board name verifySingleDir(resDir2, "issue_86") + # Issue 88: boot image V4 without boot signature, + # and Issue 75: allow duplicated entry in cpio + verifySingleDir(resDir2, "issue_88") log.info(successLogo) diff --git a/src/integrationTest/resources_2 b/src/integrationTest/resources_2 index b4c46ec..ce834db 160000 --- a/src/integrationTest/resources_2 +++ b/src/integrationTest/resources_2 @@ -1 +1 @@ -Subproject commit b4c46ec5b4e9da09a1142058d63b054e9fd2cddc +Subproject commit ce834dbe0bb8b307b45480d6724a33ee928bbaff